diff --git a/build/three.core.js b/build/three.core.js index 5942e05e58665e..7a5c71f5e01a74 100644 --- a/build/three.core.js +++ b/build/three.core.js @@ -4169,10 +4169,6 @@ class Quaternion { const x = euler._x, y = euler._y, z = euler._z, order = euler._order; - // http://www.mathworks.com/matlabcentral/fileexchange/ - // 20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/ - // content/SpinCalc.m - const cos = Math.cos; const sin = Math.sin; @@ -4248,8 +4244,6 @@ class Quaternion { */ setFromAxisAngle( axis, angle ) { - // http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm - const halfAngle = angle / 2, s = Math.sin( halfAngle ); this._x = axis.x * s; @@ -4271,8 +4265,6 @@ class Quaternion { */ setFromRotationMatrix( m ) { - // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm - // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) const te = m.elements, @@ -4560,8 +4552,6 @@ class Quaternion { */ multiplyQuaternions( a, b ) { - // from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm - const qax = a._x, qay = a._y, qaz = a._z, qaw = a._w; const qbx = b._x, qby = b._y, qbz = b._z, qbw = b._w; @@ -8521,8 +8511,6 @@ class Vector4 { */ setAxisAngleFromQuaternion( q ) { - // http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/index.htm - // q is assumed to be normalized this.w = 2 * Math.acos( q.w ); @@ -8556,8 +8544,6 @@ class Vector4 { */ setAxisAngleFromRotationMatrix( m ) { - // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToAngle/index.htm - // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) let angle, x, y, z; // variables for result @@ -13511,6 +13497,27 @@ class Object3D extends EventDispatcher { } + /** + * Frees the GPU-related resources allocated by this instance. Call this + * method whenever this instance is no longer used in your app. + * + * Geometries, materials and textures are potentially shared with other + * 3D objects and must be disposed of separately. + * + * @fires Object3D#dispose + */ + dispose() { + + /** + * Fires when the 3D object has been disposed of. + * + * @event Object3D#dispose + * @type {Object} + */ + this.dispatchEvent( { type: 'dispose' } ); + + } + } /** @@ -25718,7 +25725,7 @@ class InstancedMesh extends Mesh { */ dispose() { - this.dispatchEvent( { type: 'dispose' } ); + super.dispose(); if ( this.morphTexture !== null ) { @@ -25914,6 +25921,10 @@ class Frustum { /** * Returns `true` if the given bounding sphere is intersecting this frustum. * + * This is a fast, conservative test that favors performance over precision. It can + * report false positives for spheres that lie outside the frustum but are not separated + * by a single frustum plane. It never reports false negatives, so it is safe for culling. + * * @param {Sphere} sphere - The bounding sphere to test. * @return {boolean} Whether the bounding sphere is intersecting this frustum or not. */ @@ -25942,6 +25953,11 @@ class Frustum { /** * Returns `true` if the given bounding box is intersecting this frustum. * + * This is a fast, conservative test that favors performance over precision. It can + * report false positives for large boxes that lie outside the frustum but are not + * separated by a single frustum plane. It never reports false negatives, so it is + * safe for culling. + * * @param {Box3} box - The bounding box to test. * @return {boolean} Whether the bounding box is intersecting this frustum or not. */ @@ -27422,6 +27438,7 @@ class BatchedMesh extends Mesh { this.validateGeometryId( geometryId ); this._instanceInfo[ instanceId ].geometryIndex = geometryId; + this._visibilityChanged = true; return this; @@ -27716,6 +27733,8 @@ class BatchedMesh extends Mesh { */ dispose() { + super.dispose(); + // Assuming the geometry is not shared with other meshes this.geometry.dispose(); @@ -45988,16 +46007,6 @@ class Light extends Object3D { } - /** - * Frees the GPU-related resources allocated by this instance. Call this - * method whenever this instance is no longer used in your app. - */ - dispose() { - - this.dispatchEvent( { type: 'dispose' } ); - - } - copy( source, recursive ) { super.copy( source, recursive ); @@ -50319,6 +50328,8 @@ class ImageBitmapLoader extends Loader { scope.manager.itemEnd( url ); + return imageBitmap; // see #34150 + } ).catch( function ( e ) { if ( onError ) onError( e ); @@ -55867,15 +55878,19 @@ class RenderTarget3D extends RenderTarget { this.depth = depth; - /** - * Overwritten with a different texture type. - * - * @type {Data3DTexture} - */ - this.texture = new Data3DTexture( null, width, height, depth ); - this._setTextureOptions( options ); + // overwrite attachments with 3D textures - this.texture.isRenderTargetTexture = true; + for ( let i = 0; i < this.textures.length; i ++ ) { + + const texture = new Data3DTexture( null, width, height, depth ); + texture.isRenderTargetTexture = true; + texture.renderTarget = this; + + this.textures[ i ] = texture; + + } + + this._setTextureOptions( options ); } @@ -57928,6 +57943,8 @@ class SpotLightHelper extends Object3D { */ dispose() { + super.dispose(); + this.cone.geometry.dispose(); this.cone.material.dispose(); @@ -58139,6 +58156,8 @@ class SkeletonHelper extends LineSegments { */ dispose() { + super.dispose(); + this.geometry.dispose(); this.material.dispose(); @@ -58230,6 +58249,8 @@ class PointLightHelper extends Mesh { */ dispose() { + super.dispose(); + this.geometry.dispose(); this.material.dispose(); @@ -58350,6 +58371,8 @@ class HemisphereLightHelper extends Object3D { */ dispose() { + super.dispose(); + this.children[ 0 ].geometry.dispose(); this.children[ 0 ].material.dispose(); @@ -58463,6 +58486,8 @@ class GridHelper extends LineSegments { */ dispose() { + super.dispose(); + this.geometry.dispose(); this.material.dispose(); @@ -58581,6 +58606,8 @@ class PolarGridHelper extends LineSegments { */ dispose() { + super.dispose(); + this.geometry.dispose(); this.material.dispose(); @@ -58686,6 +58713,8 @@ class DirectionalLightHelper extends Object3D { */ dispose() { + super.dispose(); + this.lightPlane.geometry.dispose(); this.lightPlane.material.dispose(); this.targetLine.geometry.dispose(); @@ -59036,6 +59065,8 @@ class CameraHelper extends LineSegments { */ dispose() { + super.dispose(); + this.geometry.dispose(); this.material.dispose(); @@ -59198,6 +59229,8 @@ class BoxHelper extends LineSegments { */ dispose() { + super.dispose(); + this.geometry.dispose(); this.material.dispose(); @@ -59275,6 +59308,8 @@ class Box3Helper extends LineSegments { */ dispose() { + super.dispose(); + this.geometry.dispose(); this.material.dispose(); @@ -59361,6 +59396,8 @@ class PlaneHelper extends Line { */ dispose() { + super.dispose(); + this.geometry.dispose(); this.material.dispose(); this.children[ 0 ].geometry.dispose(); @@ -59521,6 +59558,8 @@ class ArrowHelper extends Object3D { */ dispose() { + super.dispose(); + this.line.geometry.dispose(); this.line.material.dispose(); this.cone.geometry.dispose(); @@ -59611,6 +59650,8 @@ class AxesHelper extends LineSegments { */ dispose() { + super.dispose(); + this.geometry.dispose(); this.material.dispose(); diff --git a/build/three.module.js b/build/three.module.js index bbe71d42c8ebc6..4618de7be13afe 100644 --- a/build/three.module.js +++ b/build/three.module.js @@ -13845,6 +13845,7 @@ class WebXRManager extends EventDispatcher { const currentSize = new Vector2(); let currentPixelRatio = null; + let currentCameraSettings = null; // @@ -14040,6 +14041,18 @@ class WebXRManager extends EventDispatcher { renderer.setPixelRatio( currentPixelRatio ); renderer.setSize( currentSize.width, currentSize.height, false ); + if ( currentCameraSettings !== null ) { + + const camera = currentCameraSettings.camera; + + camera.fov = currentCameraSettings.fov; + camera.zoom = currentCameraSettings.zoom; + camera.updateProjectionMatrix(); + + currentCameraSettings = null; + + } + scope.dispatchEvent( { type: 'sessionend' } ); } @@ -14561,6 +14574,12 @@ class WebXRManager extends EventDispatcher { // update user camera and its children + if ( currentCameraSettings === null && camera.isPerspectiveCamera ) { + + currentCameraSettings = { camera: camera, fov: camera.fov, zoom: camera.zoom }; + + } + updateUserCamera( camera, cameraXR, parent ); }; diff --git a/build/three.tsl.js b/build/three.tsl.js index 87d142aeb2602b..c50e39db846648 100644 --- a/build/three.tsl.js +++ b/build/three.tsl.js @@ -57,7 +57,6 @@ const anisotropy = TSL.anisotropy; const anisotropyB = TSL.anisotropyB; const anisotropyT = TSL.anisotropyT; const any = TSL.any; -const append = TSL.append; const array = TSL.array; const asin = TSL.asin; const asinh = TSL.asinh; @@ -82,6 +81,7 @@ const backgroundBlurriness = TSL.backgroundBlurriness; const backgroundIntensity = TSL.backgroundIntensity; const backgroundRotation = TSL.backgroundRotation; const batch = TSL.batch; +const batchIndirectIndex = TSL.batchIndirectIndex; const bentNormalView = TSL.bentNormalView; const billboarding = TSL.billboarding; const bitAnd = TSL.bitAnd; @@ -416,6 +416,7 @@ const objectRadius = TSL.objectRadius; const objectScale = TSL.objectScale; const objectViewPosition = TSL.objectViewPosition; const objectWorldMatrix = TSL.objectWorldMatrix; +const OnAfterObjectUpdate = TSL.OnAfterObjectUpdate; const OnBeforeObjectUpdate = TSL.OnBeforeObjectUpdate; const OnBeforeMaterialUpdate = TSL.OnBeforeMaterialUpdate; const OnBeforeRenderPipeline = TSL.OnBeforeRenderPipeline; @@ -664,4 +665,4 @@ for ( const key of Object.keys( THREE.TSL ) ) { log( code ); //*/ -export { BRDF_GGX, BRDF_Lambert, BasicPointShadowFilter, BasicShadowFilter, Break, Const, Continue, DFGLUT, D_GGX, Discard, EPSILON, F_Schlick, Fn, HALF_PI, INFINITY, If, Loop, NodeAccess, NodeShaderStage, NodeType, NodeUpdateType, OnAfterRenderPipeline, OnBeforeMaterialUpdate, OnBeforeObjectUpdate, OnBeforeRenderPipeline, OnMaterialUpdate, OnObjectUpdate, PCFShadowFilter, PI, PI2, PointShadowFilter, Return, Schlick_to_F0, ShaderNode, Stack, Switch, TBNViewMatrix, TWO_PI, VSMShadowFilter, V_GGX_SmithCorrelated, Var, VarIntent, abs, acesFilmicToneMapping, acos, acosh, add, addMethodChaining, addNodeElement, agxToneMapping, all, alphaT, ambientOcclusion, and, anisotropy, anisotropyB, anisotropyT, any, append, array, asin, asinh, assign, atan, atanh, atomicAdd, atomicAnd, atomicFunc, atomicLoad, atomicMax, atomicMin, atomicOr, atomicStore, atomicSub, atomicXor, attenuationColor, attenuationDistance, attribute, attributeArray, backgroundBlurriness, backgroundIntensity, backgroundRotation, batch, bentNormalView, billboarding, bitAnd, bitNot, bitOr, bitXor, bitangentGeometry, bitangentLocal, bitangentView, bitangentWorld, bitcast, blendBurn, blendColor, blendDodge, blendOverlay, blendScreen, bool, buffer, bufferAttribute, builtin, builtinAOContext, builtinShadowContext, bumpMap, bvec2, bvec3, bvec4, bypass, cache, call, cameraFar, cameraIndex, cameraNear, cameraNormalMatrix, cameraPosition, cameraProjectionMatrix, cameraProjectionMatrixInverse, cameraViewMatrix, cameraViewport, cameraWorldMatrix, cbrt, cdl, ceil, checker, cineonToneMapping, clamp, clearcoat, clearcoatNormalView, clearcoatRoughness, clipSpace, code, color, colorSpaceToWorking, colorToDirection, compute, computeKernel, computeSkinning, context, convert, convertColorSpace, convertToTexture, cos, cosh, countLeadingZeros, countOneBits, countTrailingZeros, cross, cubeTexture, cubeTextureBase, dFdx, dFdy, dashSize, debug, decrement, decrementBefore, defaultBuildStages, defaultShaderStages, defined, degrees, deltaTime, densityFog, densityFogFactor, depth, depthPass, determinant, difference, diffuseColor, directPointLight, directionToColor, directionToFaceDirection, dispersion, distance, div, dot, drawIndex, dynamicBufferAttribute, element, emissive, equal, equirectDirection, equirectUV, exp, exp2, exponentialHeightFogFactor, expression, faceDirection, faceForward, faceforward, float, floatBitsToInt, floatBitsToUint, floor, fog, fract, frameGroup, frameId, frontFacing, fwidth, gain, gapSize, getConstNodeType, getCurrentStack, getDistanceAttenuation, getGeometryRoughness, getNormalFromDepth, getParallaxCorrectNormal, getRoughness, getScreenPosition, getScreenPositionFromClip, getShIrradianceAt, getShadowMaterial, getShadowRenderObjectFunction, getTextureIndex, getViewPosition, globalId, glsl, glslFn, grayscale, greaterThan, greaterThanEqual, hash, highpModelNormalViewMatrix, highpModelViewMatrix, hue, increment, incrementBefore, instance, instanceIndex, instancedArray, instancedBufferAttribute, instancedDynamicBufferAttribute, instancedMesh, int, intBitsToFloat, interleavedGradientNoise, inverse, inverseSqrt, inversesqrt, invocationLocalIndex, invocationSubgroupIndex, ior, iridescence, iridescenceIOR, iridescenceThickness, ivec2, ivec3, ivec4, js, label, length, lengthSq, lessThan, lessThanEqual, lightPosition, lightProjectionUV, lightShadowMatrix, lightTargetDirection, lightTargetPosition, lightViewPosition, lightingContext, lights, linearDepth, linearToneMapping, localId, log, log2, logarithmicDepthToViewZ, luminance, mat2, mat3, mat4, matcapUV, materialAO, materialAlphaTest, materialAnisotropy, materialAnisotropyVector, materialAttenuationColor, materialAttenuationDistance, materialClearcoat, materialClearcoatNormal, materialClearcoatRoughness, materialColor, materialDispersion, materialEmissive, materialEnvIntensity, materialEnvRotation, materialIOR, materialIridescence, materialIridescenceIOR, materialIridescenceThickness, materialLightMap, materialLineDashOffset, materialLineDashSize, materialLineGapSize, materialLineScale, materialLineWidth, materialMetalness, materialNormal, materialOpacity, materialPointSize, materialReference, materialReflectivity, materialRefractionRatio, materialRetroreflectivity, materialRotation, materialRoughness, materialSheen, materialSheenRoughness, materialShininess, materialSpecular, materialSpecularColor, materialSpecularIntensity, materialSpecularStrength, materialThickness, materialTransmission, max, maxMipLevel, mediumpModelViewMatrix, metalness, min, mix, mixElement, mod, modelDirection, modelNormalMatrix, modelPosition, modelRadius, modelScale, modelViewMatrix, modelViewPosition, modelViewProjection, modelWorldMatrix, modelWorldMatrixInverse, morphReference, mrt, mul, mx_aastep, mx_add, mx_atan2, mx_cell_noise_float, mx_cell_noise_vec3, mx_contrast, mx_divide, mx_fractal_noise_float, mx_fractal_noise_float_2d, mx_fractal_noise_vec2, mx_fractal_noise_vec3, mx_fractal_noise_vec4, mx_frame, mx_heighttonormal, mx_hsvtorgb, mx_ifequal, mx_ifgreater, mx_ifgreatereq, mx_invert, mx_modulo, mx_multiply, mx_noise_float, mx_noise_vec3, mx_noise_vec4, mx_place2d, mx_power, mx_ramp4, mx_ramplr, mx_ramptb, mx_rgbtohsv, mx_rotate2d, mx_rotate3d, mx_safepower, mx_separate, mx_smoothstep, mx_splitlr, mx_splittb, mx_srgb_texture_to_lin_rec709, mx_subtract, mx_timer, mx_transform_uv, mx_unifiednoise2d, mx_unifiednoise3d, mx_worley_noise_float, mx_worley_noise_float_2d, mx_worley_noise_float_3d, mx_worley_noise_vec2, mx_worley_noise_vec3, mx_worley_noise_vec3_style, negate, negateOnBackSide, neutralToneMapping, nodeArray, nodeImmutable, nodeObject, nodeObjectIntent, nodeObjects, nodeProxy, nodeProxyIntent, normalFlat, normalGeometry, normalLocal, normalMap, normalView, normalViewGeometry, normalWorld, normalWorldGeometry, normalize, not, notEqual, numWorkgroups, objectDirection, objectGroup, objectPosition, objectRadius, objectScale, objectViewPosition, objectWorldMatrix, oneMinus, or, orthographicDepthToViewZ, oscSawtooth, oscSine, oscSquare, oscTriangle, output, outputStruct, overloadingFn, overrideNode, overrideNodes, packHalf2x16, packNormalToRGB, packSnorm2x16, packUnorm2x16, parabola, parallaxDirection, parallaxUV, parameter, pass, passTexture, pcurve, perspectiveDepthToViewZ, pmremTexture, pointShadow, pointUV, pointWidth, positionGeometry, positionLocal, positionPrevious, positionView, positionViewDirection, positionWorld, positionWorldDirection, posterize, pow, pow2, pow3, pow4, premultiplyAlpha, property, radians, rand, range, rangeFog, rangeFogFactor, reciprocal, reference, referenceBuffer, reflect, reflectVector, reflectView, reflector, refract, refractVector, refractView, reinhardToneMapping, remap, remapClamp, renderGroup, renderOutput, rendererReference, replaceDefaultUV, retroreflectivity, rotate, rotateUV, roughness, round, rtt, sRGBTransferEOTF, sRGBTransferOETF, sample, sampler, samplerComparison, saturate, saturation, screen, screenCoordinate, screenDPR, screenSize, screenUV, select, setCurrentStack, setName, shaderStages, shadow, shadowPositionWorld, shapeCircle, sharedUniformGroup, sheen, sheenRoughness, shiftLeft, shiftRight, shininess, sign, sin, sinc, sinh, skinning, smoothstep, smoothstepElement, specularColor, specularF90, spherizeUV, split, spritesheetUV, sqrt, stack, step, stepElement, storage, storageBarrier, storageTexture, storageTexture3D, struct, sub, subBuild, subgroupAdd, subgroupAll, subgroupAnd, subgroupAny, subgroupBallot, subgroupBroadcast, subgroupBroadcastFirst, subgroupElect, subgroupExclusiveAdd, subgroupExclusiveMul, subgroupInclusiveAdd, subgroupInclusiveMul, subgroupIndex, subgroupMax, subgroupMin, subgroupMul, subgroupOr, subgroupShuffle, subgroupShuffleDown, subgroupShuffleUp, subgroupShuffleXor, subgroupSize, subgroupXor, tan, tangentGeometry, tangentLocal, tangentView, tangentWorld, tanh, texture, texture3D, textureBarrier, textureBicubic, textureBicubicLevel, textureLevel, textureLoad, textureSize, textureStore, thickness, time, toneMapping, toneMappingExposure, toonOutlinePass, transformDirection, transformNormal, transformNormalByInverseViewMatrix, transformNormalByViewMatrix, transformNormalToView, transformedClearcoatNormalView, transformedNormalView, transformedNormalWorld, transmission, transpose, triNoise3D, triplanarTexture, triplanarTextures, trunc, uint, uintBitsToFloat, uniform, uniformArray, uniformCubeTexture, uniformFlow, uniformGroup, uniformTexture, unpackHalf2x16, unpackRGBToNormal, unpackSnorm2x16, unpackUnorm2x16, unpremultiplyAlpha, userData, uv, uvec2, uvec3, uvec4, varying, varyingProperty, vec2, vec3, vec4, vectorComponents, velocity, vertexColor, vertexIndex, vertexStage, vibrance, viewZToLogarithmicDepth, viewZToOrthographicDepth, viewZToPerspectiveDepth, viewZToReversedOrthographicDepth, viewZToReversedPerspectiveDepth, viewport, viewportCoordinate, viewportDepthTexture, viewportLinearDepth, viewportMipTexture, viewportOpaqueMipTexture, viewportSafeUV, viewportSharedTexture, viewportSize, viewportTexture, viewportUV, vogelDiskSample, wgsl, wgslFn, workgroupArray, workgroupBarrier, workgroupId, workingToColorSpace, xor }; +export { BRDF_GGX, BRDF_Lambert, BasicPointShadowFilter, BasicShadowFilter, Break, Const, Continue, DFGLUT, D_GGX, Discard, EPSILON, F_Schlick, Fn, HALF_PI, INFINITY, If, Loop, NodeAccess, NodeShaderStage, NodeType, NodeUpdateType, OnAfterObjectUpdate, OnAfterRenderPipeline, OnBeforeMaterialUpdate, OnBeforeObjectUpdate, OnBeforeRenderPipeline, OnMaterialUpdate, OnObjectUpdate, PCFShadowFilter, PI, PI2, PointShadowFilter, Return, Schlick_to_F0, ShaderNode, Stack, Switch, TBNViewMatrix, TWO_PI, VSMShadowFilter, V_GGX_SmithCorrelated, Var, VarIntent, abs, acesFilmicToneMapping, acos, acosh, add, addMethodChaining, addNodeElement, agxToneMapping, all, alphaT, ambientOcclusion, and, anisotropy, anisotropyB, anisotropyT, any, array, asin, asinh, assign, atan, atanh, atomicAdd, atomicAnd, atomicFunc, atomicLoad, atomicMax, atomicMin, atomicOr, atomicStore, atomicSub, atomicXor, attenuationColor, attenuationDistance, attribute, attributeArray, backgroundBlurriness, backgroundIntensity, backgroundRotation, batch, batchIndirectIndex, bentNormalView, billboarding, bitAnd, bitNot, bitOr, bitXor, bitangentGeometry, bitangentLocal, bitangentView, bitangentWorld, bitcast, blendBurn, blendColor, blendDodge, blendOverlay, blendScreen, bool, buffer, bufferAttribute, builtin, builtinAOContext, builtinShadowContext, bumpMap, bvec2, bvec3, bvec4, bypass, cache, call, cameraFar, cameraIndex, cameraNear, cameraNormalMatrix, cameraPosition, cameraProjectionMatrix, cameraProjectionMatrixInverse, cameraViewMatrix, cameraViewport, cameraWorldMatrix, cbrt, cdl, ceil, checker, cineonToneMapping, clamp, clearcoat, clearcoatNormalView, clearcoatRoughness, clipSpace, code, color, colorSpaceToWorking, colorToDirection, compute, computeKernel, computeSkinning, context, convert, convertColorSpace, convertToTexture, cos, cosh, countLeadingZeros, countOneBits, countTrailingZeros, cross, cubeTexture, cubeTextureBase, dFdx, dFdy, dashSize, debug, decrement, decrementBefore, defaultBuildStages, defaultShaderStages, defined, degrees, deltaTime, densityFog, densityFogFactor, depth, depthPass, determinant, difference, diffuseColor, directPointLight, directionToColor, directionToFaceDirection, dispersion, distance, div, dot, drawIndex, dynamicBufferAttribute, element, emissive, equal, equirectDirection, equirectUV, exp, exp2, exponentialHeightFogFactor, expression, faceDirection, faceForward, faceforward, float, floatBitsToInt, floatBitsToUint, floor, fog, fract, frameGroup, frameId, frontFacing, fwidth, gain, gapSize, getConstNodeType, getCurrentStack, getDistanceAttenuation, getGeometryRoughness, getNormalFromDepth, getParallaxCorrectNormal, getRoughness, getScreenPosition, getScreenPositionFromClip, getShIrradianceAt, getShadowMaterial, getShadowRenderObjectFunction, getTextureIndex, getViewPosition, globalId, glsl, glslFn, grayscale, greaterThan, greaterThanEqual, hash, highpModelNormalViewMatrix, highpModelViewMatrix, hue, increment, incrementBefore, instance, instanceIndex, instancedArray, instancedBufferAttribute, instancedDynamicBufferAttribute, instancedMesh, int, intBitsToFloat, interleavedGradientNoise, inverse, inverseSqrt, inversesqrt, invocationLocalIndex, invocationSubgroupIndex, ior, iridescence, iridescenceIOR, iridescenceThickness, ivec2, ivec3, ivec4, js, label, length, lengthSq, lessThan, lessThanEqual, lightPosition, lightProjectionUV, lightShadowMatrix, lightTargetDirection, lightTargetPosition, lightViewPosition, lightingContext, lights, linearDepth, linearToneMapping, localId, log, log2, logarithmicDepthToViewZ, luminance, mat2, mat3, mat4, matcapUV, materialAO, materialAlphaTest, materialAnisotropy, materialAnisotropyVector, materialAttenuationColor, materialAttenuationDistance, materialClearcoat, materialClearcoatNormal, materialClearcoatRoughness, materialColor, materialDispersion, materialEmissive, materialEnvIntensity, materialEnvRotation, materialIOR, materialIridescence, materialIridescenceIOR, materialIridescenceThickness, materialLightMap, materialLineDashOffset, materialLineDashSize, materialLineGapSize, materialLineScale, materialLineWidth, materialMetalness, materialNormal, materialOpacity, materialPointSize, materialReference, materialReflectivity, materialRefractionRatio, materialRetroreflectivity, materialRotation, materialRoughness, materialSheen, materialSheenRoughness, materialShininess, materialSpecular, materialSpecularColor, materialSpecularIntensity, materialSpecularStrength, materialThickness, materialTransmission, max, maxMipLevel, mediumpModelViewMatrix, metalness, min, mix, mixElement, mod, modelDirection, modelNormalMatrix, modelPosition, modelRadius, modelScale, modelViewMatrix, modelViewPosition, modelViewProjection, modelWorldMatrix, modelWorldMatrixInverse, morphReference, mrt, mul, mx_aastep, mx_add, mx_atan2, mx_cell_noise_float, mx_cell_noise_vec3, mx_contrast, mx_divide, mx_fractal_noise_float, mx_fractal_noise_float_2d, mx_fractal_noise_vec2, mx_fractal_noise_vec3, mx_fractal_noise_vec4, mx_frame, mx_heighttonormal, mx_hsvtorgb, mx_ifequal, mx_ifgreater, mx_ifgreatereq, mx_invert, mx_modulo, mx_multiply, mx_noise_float, mx_noise_vec3, mx_noise_vec4, mx_place2d, mx_power, mx_ramp4, mx_ramplr, mx_ramptb, mx_rgbtohsv, mx_rotate2d, mx_rotate3d, mx_safepower, mx_separate, mx_smoothstep, mx_splitlr, mx_splittb, mx_srgb_texture_to_lin_rec709, mx_subtract, mx_timer, mx_transform_uv, mx_unifiednoise2d, mx_unifiednoise3d, mx_worley_noise_float, mx_worley_noise_float_2d, mx_worley_noise_float_3d, mx_worley_noise_vec2, mx_worley_noise_vec3, mx_worley_noise_vec3_style, negate, negateOnBackSide, neutralToneMapping, nodeArray, nodeImmutable, nodeObject, nodeObjectIntent, nodeObjects, nodeProxy, nodeProxyIntent, normalFlat, normalGeometry, normalLocal, normalMap, normalView, normalViewGeometry, normalWorld, normalWorldGeometry, normalize, not, notEqual, numWorkgroups, objectDirection, objectGroup, objectPosition, objectRadius, objectScale, objectViewPosition, objectWorldMatrix, oneMinus, or, orthographicDepthToViewZ, oscSawtooth, oscSine, oscSquare, oscTriangle, output, outputStruct, overloadingFn, overrideNode, overrideNodes, packHalf2x16, packNormalToRGB, packSnorm2x16, packUnorm2x16, parabola, parallaxDirection, parallaxUV, parameter, pass, passTexture, pcurve, perspectiveDepthToViewZ, pmremTexture, pointShadow, pointUV, pointWidth, positionGeometry, positionLocal, positionPrevious, positionView, positionViewDirection, positionWorld, positionWorldDirection, posterize, pow, pow2, pow3, pow4, premultiplyAlpha, property, radians, rand, range, rangeFog, rangeFogFactor, reciprocal, reference, referenceBuffer, reflect, reflectVector, reflectView, reflector, refract, refractVector, refractView, reinhardToneMapping, remap, remapClamp, renderGroup, renderOutput, rendererReference, replaceDefaultUV, retroreflectivity, rotate, rotateUV, roughness, round, rtt, sRGBTransferEOTF, sRGBTransferOETF, sample, sampler, samplerComparison, saturate, saturation, screen, screenCoordinate, screenDPR, screenSize, screenUV, select, setCurrentStack, setName, shaderStages, shadow, shadowPositionWorld, shapeCircle, sharedUniformGroup, sheen, sheenRoughness, shiftLeft, shiftRight, shininess, sign, sin, sinc, sinh, skinning, smoothstep, smoothstepElement, specularColor, specularF90, spherizeUV, split, spritesheetUV, sqrt, stack, step, stepElement, storage, storageBarrier, storageTexture, storageTexture3D, struct, sub, subBuild, subgroupAdd, subgroupAll, subgroupAnd, subgroupAny, subgroupBallot, subgroupBroadcast, subgroupBroadcastFirst, subgroupElect, subgroupExclusiveAdd, subgroupExclusiveMul, subgroupInclusiveAdd, subgroupInclusiveMul, subgroupIndex, subgroupMax, subgroupMin, subgroupMul, subgroupOr, subgroupShuffle, subgroupShuffleDown, subgroupShuffleUp, subgroupShuffleXor, subgroupSize, subgroupXor, tan, tangentGeometry, tangentLocal, tangentView, tangentWorld, tanh, texture, texture3D, textureBarrier, textureBicubic, textureBicubicLevel, textureLevel, textureLoad, textureSize, textureStore, thickness, time, toneMapping, toneMappingExposure, toonOutlinePass, transformDirection, transformNormal, transformNormalByInverseViewMatrix, transformNormalByViewMatrix, transformNormalToView, transformedClearcoatNormalView, transformedNormalView, transformedNormalWorld, transmission, transpose, triNoise3D, triplanarTexture, triplanarTextures, trunc, uint, uintBitsToFloat, uniform, uniformArray, uniformCubeTexture, uniformFlow, uniformGroup, uniformTexture, unpackHalf2x16, unpackRGBToNormal, unpackSnorm2x16, unpackUnorm2x16, unpremultiplyAlpha, userData, uv, uvec2, uvec3, uvec4, varying, varyingProperty, vec2, vec3, vec4, vectorComponents, velocity, vertexColor, vertexIndex, vertexStage, vibrance, viewZToLogarithmicDepth, viewZToOrthographicDepth, viewZToPerspectiveDepth, viewZToReversedOrthographicDepth, viewZToReversedPerspectiveDepth, viewport, viewportCoordinate, viewportDepthTexture, viewportLinearDepth, viewportMipTexture, viewportOpaqueMipTexture, viewportSafeUV, viewportSharedTexture, viewportSize, viewportTexture, viewportUV, vogelDiskSample, wgsl, wgslFn, workgroupArray, workgroupBarrier, workgroupId, workingToColorSpace, xor }; diff --git a/build/three.webgpu.js b/build/three.webgpu.js index a687502dcdf44d..d77665149cbeed 100644 --- a/build/three.webgpu.js +++ b/build/three.webgpu.js @@ -3,8 +3,8 @@ * Copyright 2010-2026 Three.js Authors * SPDX-License-Identifier: MIT */ -import { Color, Vector2, Vector3, Vector4, Matrix2, Matrix3, Matrix4, UnsignedIntType, IntType, error, RedFormat, RedIntegerFormat, DepthFormat, DepthStencilFormat, AlphaFormat, RGFormat, RGIntegerFormat, RGBFormat, RGBIntegerFormat, EventDispatcher, MathUtils, warn, WebGLCoordinateSystem, WebGPUCoordinateSystem, ColorManagement, SRGBTransfer, NoToneMapping, StaticDrawUsage, InterleavedBufferAttribute, InterleavedBuffer, DynamicDrawUsage, NoColorSpace, log as log$1, warnOnce, Texture, Compatibility, LessCompare, LessEqualCompare, GreaterCompare, GreaterEqualCompare, NearestFilter, Sphere, BackSide, DoubleSide, CubeTexture, CubeReflectionMapping, CubeRefractionMapping, TangentSpaceNormalMap, NoNormalPacking, NormalRGPacking, NormalGAPacking, ObjectSpaceNormalMap, RED_GREEN_RGTC2_Format, RG11_EAC_Format, InstancedBufferAttribute, InstancedInterleavedBuffer, DataArrayTexture, FloatType, FramebufferTexture, LinearMipmapLinearFilter, DepthTexture, Material, LineBasicMaterial, LineDashedMaterial, NoBlending, MeshNormalMaterial, SRGBColorSpace, RenderTarget, BoxGeometry, Mesh, Scene, LinearFilter, CubeCamera, EquirectangularReflectionMapping, EquirectangularRefractionMapping, AddOperation, MixOperation, MultiplyOperation, MeshBasicMaterial, MeshLambertMaterial, MeshPhongMaterial, DataTexture, HalfFloatType, ClampToEdgeWrapping, BufferGeometry, OrthographicCamera, PerspectiveCamera, LinearSRGBColorSpace, RGBAFormat, CubeUVReflectionMapping, BufferAttribute, MeshStandardMaterial, MeshPhysicalMaterial, MeshToonMaterial, MeshMatcapMaterial, SpriteMaterial, PointsMaterial, ShadowMaterial, Uint32BufferAttribute, Uint16BufferAttribute, ByteType, UnsignedByteType, ShortType, UnsignedShortType, UnsignedShort4444Type, UnsignedShort5551Type, UnsignedInt248Type, UnsignedInt5999Type, UnsignedInt101111Type, NormalBlending, SrcAlphaFactor, OneMinusSrcAlphaFactor, AddEquation, MaterialBlending, Object3D, LinearMipMapLinearFilter, Plane, Float32BufferAttribute, UVMapping, PCFShadowMap, VSMShadowMap, BasicShadowMap, CubeDepthTexture, SphereGeometry, LinearMipmapNearestFilter, NearestMipmapLinearFilter, Float16BufferAttribute, yieldToMain, REVISION, ArrayCamera, PlaneGeometry, FrontSide, CustomBlending, ZeroFactor, CylinderGeometry, Quaternion, WebXRController, RAD2DEG, PCFSoftShadowMap, FrustumArray, Frustum, RGBAIntegerFormat, TimestampQuery, createCanvasElement, ReverseSubtractEquation, SubtractEquation, OneMinusDstAlphaFactor, OneMinusDstColorFactor, OneMinusSrcColorFactor, DstAlphaFactor, DstColorFactor, SrcAlphaSaturateFactor, SrcColorFactor, OneFactor, CullFaceNone, CullFaceBack, CullFaceFront, MultiplyBlending, SubtractiveBlending, AdditiveBlending, NotEqualDepth, GreaterDepth, GreaterEqualDepth, EqualDepth, LessEqualDepth, LessDepth, AlwaysDepth, NeverDepth, ReversedDepthFuncs, RGB_S3TC_DXT1_Format, RGBA_S3TC_DXT1_Format, RGBA_S3TC_DXT3_Format, RGBA_S3TC_DXT5_Format, RGB_PVRTC_4BPPV1_Format, RGB_PVRTC_2BPPV1_Format, RGBA_PVRTC_4BPPV1_Format, RGBA_PVRTC_2BPPV1_Format, RGB_ETC1_Format, RGB_ETC2_Format, RGBA_ETC2_EAC_Format, R11_EAC_Format, SIGNED_R11_EAC_Format, SIGNED_RG11_EAC_Format, RGBA_ASTC_4x4_Format, RGBA_ASTC_5x4_Format, RGBA_ASTC_5x5_Format, RGBA_ASTC_6x5_Format, RGBA_ASTC_6x6_Format, RGBA_ASTC_8x5_Format, RGBA_ASTC_8x6_Format, RGBA_ASTC_8x8_Format, RGBA_ASTC_10x5_Format, RGBA_ASTC_10x6_Format, RGBA_ASTC_10x8_Format, RGBA_ASTC_10x10_Format, RGBA_ASTC_12x10_Format, RGBA_ASTC_12x12_Format, RGBA_BPTC_Format, RGB_BPTC_SIGNED_Format, RGB_BPTC_UNSIGNED_Format, RED_RGTC1_Format, SIGNED_RED_RGTC1_Format, SIGNED_RED_GREEN_RGTC2_Format, MirroredRepeatWrapping, RepeatWrapping, NearestMipmapNearestFilter, NotEqualCompare, EqualCompare, AlwaysCompare, NeverCompare, LinearTransfer, getByteLength, isTypedArray, NotEqualStencilFunc, GreaterStencilFunc, GreaterEqualStencilFunc, EqualStencilFunc, LessEqualStencilFunc, LessStencilFunc, AlwaysStencilFunc, NeverStencilFunc, DecrementWrapStencilOp, IncrementWrapStencilOp, DecrementStencilOp, IncrementStencilOp, InvertStencilOp, ReplaceStencilOp, ZeroStencilOp, KeepStencilOp, MaxEquation, MinEquation, SpotLight, PointLight, DirectionalLight, RectAreaLight, AmbientLight, HemisphereLight, LightProbe, LinearToneMapping, ReinhardToneMapping, CineonToneMapping, ACESFilmicToneMapping, AgXToneMapping, NeutralToneMapping, Group, Loader, FileLoader, MaterialLoader, ObjectLoader } from './three.core.js'; -export { AdditiveAnimationBlendMode, AnimationAction, AnimationClip, AnimationLoader, AnimationMixer, AnimationObjectGroup, AnimationUtils, ArcCurve, ArrowHelper, AttachedBindMode, Audio, AudioAnalyser, AudioContext, AudioListener, AudioLoader, AxesHelper, BasicDepthPacking, BatchedMesh, BezierInterpolant, Bone, BooleanKeyframeTrack, Box2, Box3, Box3Helper, BoxHelper, BufferGeometryLoader, Cache, Camera, CameraHelper, CanvasTexture, CapsuleGeometry, CatmullRomCurve3, CircleGeometry, Clock, ColorKeyframeTrack, CompressedArrayTexture, CompressedCubeTexture, CompressedTexture, CompressedTextureLoader, ConeGeometry, ConstantAlphaFactor, ConstantColorFactor, Controls, CubeTextureLoader, CubicBezierCurve, CubicBezierCurve3, CubicInterpolant, CullFaceFrontBack, Curve, CurvePath, CustomToneMapping, Cylindrical, Data3DTexture, DataTextureLoader, DataUtils, DefaultLoadingManager, DetachedBindMode, DirectionalLightHelper, DiscreteInterpolant, DodecahedronGeometry, DynamicCopyUsage, DynamicReadUsage, EdgesGeometry, EllipseCurve, Euler, ExternalTexture, ExtrudeGeometry, Fog, FogExp2, GLBufferAttribute, GLSL1, GLSL3, GridHelper, HTMLTexture, HemisphereLightHelper, IcosahedronGeometry, ImageBitmapLoader, ImageLoader, ImageUtils, InstancedBufferGeometry, InstancedMesh, Int16BufferAttribute, Int32BufferAttribute, Int8BufferAttribute, Interpolant, InterpolateBezier, InterpolateDiscrete, InterpolateLinear, InterpolateSmooth, InterpolationSamplingMode, InterpolationSamplingType, KeyframeTrack, LOD, LatheGeometry, Layers, Light, Line, Line3, LineCurve, LineCurve3, LineLoop, LineSegments, LinearInterpolant, LinearMipMapNearestFilter, LoaderUtils, LoadingManager, LoopOnce, LoopPingPong, LoopRepeat, MOUSE, MeshDepthMaterial, MeshDistanceMaterial, NearestMipMapLinearFilter, NearestMipMapNearestFilter, NormalAnimationBlendMode, NumberKeyframeTrack, OctahedronGeometry, OneMinusConstantAlphaFactor, OneMinusConstantColorFactor, Path, PlaneHelper, PointLightHelper, Points, PolarGridHelper, PolyhedronGeometry, PositionalAudio, PropertyBinding, PropertyMixer, QuadraticBezierCurve, QuadraticBezierCurve3, QuaternionKeyframeTrack, QuaternionLinearInterpolant, RGBADepthPacking, RGBDepthPacking, RGDepthPacking, RawShaderMaterial, Ray, Raycaster, RenderTarget3D, RingGeometry, ShaderMaterial, Shape, ShapeGeometry, ShapePath, ShapeUtils, Skeleton, SkeletonHelper, SkinnedMesh, Source, Spherical, SphericalHarmonics3, SplineCurve, SpotLightHelper, Sprite, StaticCopyUsage, StaticReadUsage, StereoCamera, StreamCopyUsage, StreamDrawUsage, StreamReadUsage, StringKeyframeTrack, TOUCH, TetrahedronGeometry, TextureLoader, TextureUtils, Timer, TorusGeometry, TorusKnotGeometry, Triangle, TriangleFanDrawMode, TriangleStripDrawMode, TrianglesDrawMode, TubeGeometry, Uint8BufferAttribute, Uint8ClampedBufferAttribute, Uniform, UniformsGroup, VectorKeyframeTrack, VideoFrameTexture, VideoTexture, WebGL3DRenderTarget, WebGLArrayRenderTarget, WebGLRenderTarget, WireframeGeometry, WrapAroundEnding, ZeroCurvatureEnding, ZeroSlopeEnding, getConsoleFunction, setConsoleFunction } from './three.core.js'; +import { Color, Vector2, Vector3, Vector4, Matrix2, Matrix3, Matrix4, UnsignedIntType, IntType, error, RedFormat, RedIntegerFormat, DepthFormat, DepthStencilFormat, AlphaFormat, RGFormat, RGIntegerFormat, RGBFormat, RGBIntegerFormat, EventDispatcher, MathUtils, warn, WebGLCoordinateSystem, WebGPUCoordinateSystem, ColorManagement, SRGBTransfer, NoToneMapping, StaticDrawUsage, InterleavedBufferAttribute, InterleavedBuffer, DynamicDrawUsage, NoColorSpace, log as log$1, warnOnce, Texture, Compatibility, LessCompare, LessEqualCompare, GreaterCompare, GreaterEqualCompare, NearestFilter, Sphere, BackSide, DoubleSide, CubeTexture, CubeReflectionMapping, CubeRefractionMapping, TangentSpaceNormalMap, NoNormalPacking, NormalRGPacking, NormalGAPacking, ObjectSpaceNormalMap, RED_GREEN_RGTC2_Format, RG11_EAC_Format, InstancedBufferAttribute, InstancedInterleavedBuffer, DataTexture, DataArrayTexture, FloatType, FramebufferTexture, LinearMipmapLinearFilter, DepthTexture, Material, LineBasicMaterial, LineDashedMaterial, NoBlending, MeshNormalMaterial, SRGBColorSpace, RenderTarget, BoxGeometry, Mesh, Scene, LinearFilter, CubeCamera, EquirectangularReflectionMapping, EquirectangularRefractionMapping, AddOperation, MixOperation, MultiplyOperation, MeshBasicMaterial, MeshLambertMaterial, MeshPhongMaterial, HalfFloatType, ClampToEdgeWrapping, BufferGeometry, OrthographicCamera, PerspectiveCamera, LinearSRGBColorSpace, RGBAFormat, CubeUVReflectionMapping, BufferAttribute, MeshStandardMaterial, MeshPhysicalMaterial, MeshToonMaterial, MeshMatcapMaterial, SpriteMaterial, PointsMaterial, ShadowMaterial, Uint32BufferAttribute, Uint16BufferAttribute, ByteType, UnsignedByteType, ShortType, UnsignedShortType, UnsignedShort4444Type, UnsignedShort5551Type, UnsignedInt248Type, UnsignedInt5999Type, UnsignedInt101111Type, NormalBlending, SrcAlphaFactor, OneMinusSrcAlphaFactor, AddEquation, MaterialBlending, Object3D, LinearMipMapLinearFilter, Plane, Float32BufferAttribute, UVMapping, PCFShadowMap, VSMShadowMap, BasicShadowMap, CubeDepthTexture, SphereGeometry, LinearMipmapNearestFilter, NearestMipmapLinearFilter, Float16BufferAttribute, yieldToMain, REVISION, ArrayCamera, PlaneGeometry, FrontSide, CustomBlending, ZeroFactor, CylinderGeometry, Quaternion, WebXRController, RAD2DEG, PCFSoftShadowMap, FrustumArray, Frustum, RGBAIntegerFormat, TimestampQuery, createCanvasElement, MaxEquation, MinEquation, ReverseSubtractEquation, SubtractEquation, OneMinusConstantAlphaFactor, ConstantAlphaFactor, OneMinusConstantColorFactor, ConstantColorFactor, OneMinusDstAlphaFactor, OneMinusDstColorFactor, OneMinusSrcColorFactor, DstAlphaFactor, DstColorFactor, SrcAlphaSaturateFactor, SrcColorFactor, OneFactor, CullFaceNone, CullFaceBack, CullFaceFront, MultiplyBlending, SubtractiveBlending, AdditiveBlending, NotEqualDepth, GreaterDepth, GreaterEqualDepth, EqualDepth, LessEqualDepth, LessDepth, AlwaysDepth, NeverDepth, ReversedDepthFuncs, RGB_S3TC_DXT1_Format, RGBA_S3TC_DXT1_Format, RGBA_S3TC_DXT3_Format, RGBA_S3TC_DXT5_Format, RGB_PVRTC_4BPPV1_Format, RGB_PVRTC_2BPPV1_Format, RGBA_PVRTC_4BPPV1_Format, RGBA_PVRTC_2BPPV1_Format, RGB_ETC1_Format, RGB_ETC2_Format, RGBA_ETC2_EAC_Format, R11_EAC_Format, SIGNED_R11_EAC_Format, SIGNED_RG11_EAC_Format, RGBA_ASTC_4x4_Format, RGBA_ASTC_5x4_Format, RGBA_ASTC_5x5_Format, RGBA_ASTC_6x5_Format, RGBA_ASTC_6x6_Format, RGBA_ASTC_8x5_Format, RGBA_ASTC_8x6_Format, RGBA_ASTC_8x8_Format, RGBA_ASTC_10x5_Format, RGBA_ASTC_10x6_Format, RGBA_ASTC_10x8_Format, RGBA_ASTC_10x10_Format, RGBA_ASTC_12x10_Format, RGBA_ASTC_12x12_Format, RGBA_BPTC_Format, RGB_BPTC_SIGNED_Format, RGB_BPTC_UNSIGNED_Format, RED_RGTC1_Format, SIGNED_RED_RGTC1_Format, SIGNED_RED_GREEN_RGTC2_Format, MirroredRepeatWrapping, RepeatWrapping, NearestMipmapNearestFilter, NotEqualCompare, EqualCompare, AlwaysCompare, NeverCompare, LinearTransfer, getByteLength, isTypedArray, NotEqualStencilFunc, GreaterStencilFunc, GreaterEqualStencilFunc, EqualStencilFunc, LessEqualStencilFunc, LessStencilFunc, AlwaysStencilFunc, NeverStencilFunc, DecrementWrapStencilOp, IncrementWrapStencilOp, DecrementStencilOp, IncrementStencilOp, InvertStencilOp, ReplaceStencilOp, ZeroStencilOp, KeepStencilOp, SpotLight, PointLight, DirectionalLight, RectAreaLight, AmbientLight, HemisphereLight, LightProbe, LinearToneMapping, ReinhardToneMapping, CineonToneMapping, ACESFilmicToneMapping, AgXToneMapping, NeutralToneMapping, Group, Loader, FileLoader, MaterialLoader, ObjectLoader } from './three.core.js'; +export { AdditiveAnimationBlendMode, AnimationAction, AnimationClip, AnimationLoader, AnimationMixer, AnimationObjectGroup, AnimationUtils, ArcCurve, ArrowHelper, AttachedBindMode, Audio, AudioAnalyser, AudioContext, AudioListener, AudioLoader, AxesHelper, BasicDepthPacking, BatchedMesh, BezierInterpolant, Bone, BooleanKeyframeTrack, Box2, Box3, Box3Helper, BoxHelper, BufferGeometryLoader, Cache, Camera, CameraHelper, CanvasTexture, CapsuleGeometry, CatmullRomCurve3, CircleGeometry, Clock, ColorKeyframeTrack, CompressedArrayTexture, CompressedCubeTexture, CompressedTexture, CompressedTextureLoader, ConeGeometry, Controls, CubeTextureLoader, CubicBezierCurve, CubicBezierCurve3, CubicInterpolant, CullFaceFrontBack, Curve, CurvePath, CustomToneMapping, Cylindrical, Data3DTexture, DataTextureLoader, DataUtils, DefaultLoadingManager, DetachedBindMode, DirectionalLightHelper, DiscreteInterpolant, DodecahedronGeometry, DynamicCopyUsage, DynamicReadUsage, EdgesGeometry, EllipseCurve, Euler, ExternalTexture, ExtrudeGeometry, Fog, FogExp2, GLBufferAttribute, GLSL1, GLSL3, GridHelper, HTMLTexture, HemisphereLightHelper, IcosahedronGeometry, ImageBitmapLoader, ImageLoader, ImageUtils, InstancedBufferGeometry, InstancedMesh, Int16BufferAttribute, Int32BufferAttribute, Int8BufferAttribute, Interpolant, InterpolateBezier, InterpolateDiscrete, InterpolateLinear, InterpolateSmooth, InterpolationSamplingMode, InterpolationSamplingType, KeyframeTrack, LOD, LatheGeometry, Layers, Light, Line, Line3, LineCurve, LineCurve3, LineLoop, LineSegments, LinearInterpolant, LinearMipMapNearestFilter, LoaderUtils, LoadingManager, LoopOnce, LoopPingPong, LoopRepeat, MOUSE, MeshDepthMaterial, MeshDistanceMaterial, NearestMipMapLinearFilter, NearestMipMapNearestFilter, NormalAnimationBlendMode, NumberKeyframeTrack, OctahedronGeometry, Path, PlaneHelper, PointLightHelper, Points, PolarGridHelper, PolyhedronGeometry, PositionalAudio, PropertyBinding, PropertyMixer, QuadraticBezierCurve, QuadraticBezierCurve3, QuaternionKeyframeTrack, QuaternionLinearInterpolant, RGBADepthPacking, RGBDepthPacking, RGDepthPacking, RawShaderMaterial, Ray, Raycaster, RenderTarget3D, RingGeometry, ShaderMaterial, Shape, ShapeGeometry, ShapePath, ShapeUtils, Skeleton, SkeletonHelper, SkinnedMesh, Source, Spherical, SphericalHarmonics3, SplineCurve, SpotLightHelper, Sprite, StaticCopyUsage, StaticReadUsage, StereoCamera, StreamCopyUsage, StreamDrawUsage, StreamReadUsage, StringKeyframeTrack, TOUCH, TetrahedronGeometry, TextureLoader, TextureUtils, Timer, TorusGeometry, TorusKnotGeometry, Triangle, TriangleFanDrawMode, TriangleStripDrawMode, TrianglesDrawMode, TubeGeometry, Uint8BufferAttribute, Uint8ClampedBufferAttribute, Uniform, UniformsGroup, VectorKeyframeTrack, VideoFrameTexture, VideoTexture, WebGL3DRenderTarget, WebGLArrayRenderTarget, WebGLRenderTarget, WireframeGeometry, WrapAroundEnding, ZeroCurvatureEnding, ZeroSlopeEnding, getConsoleFunction, setConsoleFunction } from './three.core.js'; const refreshUniforms = [ 'alphaMap', @@ -1372,6 +1372,12 @@ function base64ToArrayBuffer( base64 ) { } +function isArrayAsParameter( params ) { + + return ( params[ 0 ] !== undefined && params[ 0 ] !== null ) && ( params[ 0 ].isNode || Object.getPrototypeOf( params[ 0 ] ) !== Object.prototype ); + +} + var NodeUtils = /*#__PURE__*/Object.freeze({ __proto__: null, arrayBufferToBase64: arrayBufferToBase64, @@ -1387,7 +1393,8 @@ var NodeUtils = /*#__PURE__*/Object.freeze({ getValueType: getValueType, hash: hash$1, hashArray: hashArray, - hashString: hashString + hashString: hashString, + isArrayAsParameter: isArrayAsParameter }); /** @@ -4432,12 +4439,6 @@ class ShaderCallNodeInternal extends Node { } -function isArrayAsParameter( params ) { - - return params[ 0 ] && ( params[ 0 ].isNode || Object.getPrototypeOf( params[ 0 ] ) !== Object.prototype ); - -} - function getLayoutParameters( params ) { let output; @@ -13246,6 +13247,18 @@ class TextureNode extends UniformNode { } + /** + * Returns `true` if the texture is sampled with a plain gather (`textureGather`), + * meaning a gather without a compare value. + * + * @return {boolean} Whether a plain gather is used or not. + */ + isPlainGather() { + + return this.gatherNode !== null && this.compareNode === null; + + } + /** * Samples the texture by defining a depth node. * @@ -17740,6 +17753,10 @@ class EventNode extends Node { this.updateType = NodeUpdateType.FRAME; + } else if ( eventType === EventNode.AFTER_OBJECT ) { + + this.updateAfterType = NodeUpdateType.OBJECT; + } else if ( eventType === EventNode.BEFORE_OBJECT ) { this.updateBeforeType = NodeUpdateType.OBJECT; @@ -17798,11 +17815,18 @@ class EventNode extends Node { } + updateAfter( frame ) { + + this.callback( frame ); + + } + } EventNode.OBJECT = 'object'; EventNode.MATERIAL = 'material'; EventNode.FRAME = 'frame'; +EventNode.AFTER_OBJECT = 'afterObject'; EventNode.BEFORE_OBJECT = 'beforeObject'; EventNode.BEFORE_MATERIAL = 'beforeMaterial'; EventNode.BEFORE_FRAME = 'beforeFrame'; @@ -17848,6 +17872,16 @@ const OnMaterialUpdate = ( callback ) => createEvent( EventNode.MATERIAL, callba */ const OnFrameUpdate = ( callback ) => createEvent( EventNode.FRAME, callback ); +/** + * Creates an event that triggers a function every time an object (Mesh|Sprite) has been rendered. + * + * The event will be bound to the declared TSL function `Fn()`; it must be declared within a `Fn()` or the JS function call must be inherited from one. + * + * @param {Function} callback - The callback function. + * @returns {EventNode} + */ +const OnAfterObjectUpdate = ( callback ) => createEvent( EventNode.AFTER_OBJECT, callback ); + /** * Creates an event that triggers a function before an object (Mesh|Sprite) is updated. * @@ -18633,11 +18667,18 @@ const instance = /*@__PURE__*/ Fn( ( [ matrices, colors = null ], builder ) => { const instancedMesh = builder.object; - OnObjectUpdate( ( { object } ) => { + OnAfterObjectUpdate( ( { object } ) => { - const previousInstanceData = _previousInstanceMatrices.get( object ); + const { previousInstanceMatrix } = _previousInstanceMatrices.get( object ); - previousInstanceData.previousInstanceMatrix.array.set( matrices.array ); + previousInstanceMatrix.array.set( matrices.array ); + previousInstanceMatrix.version = matrices.version; + + // handle interleaved path + + const previousInterleavedMatrix = _matrixBuffers.get( previousInstanceMatrix ); + + if ( previousInterleavedMatrix !== undefined ) previousInterleavedMatrix.version = matrices.version; } ); @@ -18680,6 +18721,8 @@ const instancedMesh = /*@__PURE__*/ Fn( ( [ instancedMesh ] ) => { }, 'void' ); +const _previousBatchingMatrices = /*@__PURE__*/ new WeakMap(); + /** * TSL function that retrieves the batching color for a given instance ID from a colors texture. * @@ -18713,6 +18756,61 @@ const getIndirectIndex = /*@__PURE__*/ Fn( ( [ indirectTexture, id ] ) => { } ); +/** + * Creates the node that reads a batching matrix from the given matrices texture. + * + * @param {Texture} matricesTexture - The matrices texture. + * @param {Node} id - The indirect instance ID. + * @returns {Node} The matrix node. + */ +function createBatchingMatrixNode( matricesTexture, id ) { + + const size = int( textureSize( textureLoad( matricesTexture ), 0 ).x ).toConst(); + const j = float( id ).mul( 4 ).toInt().toConst(); + + const x = j.mod( size ).toConst(); + const y = j.div( size ).toConst(); + + return mat4( + textureLoad( matricesTexture, ivec2( x, y ) ), + textureLoad( matricesTexture, ivec2( x.add( 1 ), y ) ), + textureLoad( matricesTexture, ivec2( x.add( 2 ), y ) ), + textureLoad( matricesTexture, ivec2( x.add( 3 ), y ) ) + ); + +} + +/** + * Retrieves or initializes the previous frame batching matrix node for motion vectors. + * Uses a WeakMap to cache previous frame matrices textures and their TSL nodes. + * + * @param {BatchedMesh} batchMesh - The batched mesh. + * @param {Node} id - The indirect instance ID. + * @returns {Node} The previous frame batching matrix node. + */ +function getPreviousNode( batchMesh, id ) { + + let data = _previousBatchingMatrices.get( batchMesh ); + + if ( data === undefined ) { + + const { image, format, type } = batchMesh._matricesTexture; + + const previousMatricesTexture = new DataTexture( image.data.slice(), image.width, image.height, format, type ); + + data = { + previousMatricesTexture, + node: createBatchingMatrixNode( previousMatricesTexture, id ) + }; + + _previousBatchingMatrices.set( batchMesh, data ); + + } + + return data.node; + +} + /** * TSL object representing a varying property for the batching color vector. * @@ -18720,6 +18818,13 @@ const getIndirectIndex = /*@__PURE__*/ Fn( ( [ indirectTexture, id ] ) => { */ const batchColor = /*@__PURE__*/ varyingProperty( 'vec4', 'vBatchColor' ); +/** + * TSL object representing a varying property for the batch indirect index (instance ID). + * + * @type {VaryingNode} + */ +const batchIndirectIndex = /*@__PURE__*/ varyingProperty( 'uint', 'vBatchIndirectId' ); + /** * TSL function representing the vertex shader batching setup. * Applies the batch transformation matrix to positionLocal, normalLocal, and tangentLocal. @@ -18735,19 +18840,9 @@ const batch = /*@__PURE__*/ Fn( ( [ batchMesh ], builder ) => { const indirectId = getIndirectIndex( batchMesh._indirectTexture, int( batchingIdNode ) ); - const matricesTexture = batchMesh._matricesTexture; + batchIndirectIndex.assign( indirectId ); - const size = int( textureSize( textureLoad( matricesTexture ), 0 ).x ).toConst(); - const j = float( indirectId ).mul( 4 ).toInt().toConst(); - - const x = j.mod( size ).toConst(); - const y = j.div( size ).toConst(); - const batchingMatrix = mat4( - textureLoad( matricesTexture, ivec2( x, y ) ), - textureLoad( matricesTexture, ivec2( x.add( 1 ), y ) ), - textureLoad( matricesTexture, ivec2( x.add( 2 ), y ) ), - textureLoad( matricesTexture, ivec2( x.add( 3 ), y ) ) - ); + const batchingMatrix = createBatchingMatrixNode( batchMesh._matricesTexture, indirectId ); const colorsTexture = batchMesh._colorsTexture; @@ -18763,6 +18858,22 @@ const batch = /*@__PURE__*/ Fn( ( [ batchMesh ], builder ) => { positionLocal.assign( batchingMatrix.mul( positionLocal ) ); + if ( builder.needsPreviousData() ) { + + OnAfterObjectUpdate( ( { object } ) => { + + const previousBatchData = _previousBatchingMatrices.get( object ); + + previousBatchData.previousMatricesTexture.image.data.set( object._matricesTexture.image.data ); + previousBatchData.previousMatricesTexture.needsUpdate = true; + + } ); + + const previousBatchingMatrixNode = getPreviousNode( batchMesh, indirectId ); + positionPrevious.assign( previousBatchingMatrixNode.mul( positionPrevious ).xyz ); + + } + const transformedNormal = normalLocal.div( vec3( bm[ 0 ].dot( bm[ 0 ] ), bm[ 1 ].dot( bm[ 1 ] ), bm[ 2 ].dot( bm[ 2 ] ) ) ); const batchingNormal = bm.mul( transformedNormal ).xyz; @@ -24808,10 +24919,10 @@ const getTransmissionSample = /*@__PURE__*/ Fn( ( [ fragCoord, roughness, ior ], const vTexture = material.side === BackSide ? viewportBackSideTexture : viewportFrontSideTexture; - const transmissionSample = vTexture.sample( fragCoord ); + const transmissionSample = vTexture.sample( fragCoord.mul( cameraViewport.zw ).add( cameraViewport.xy ).div( screenSize ) ); //const transmissionSample = viewportMipTexture( fragCoord ); - const lod = log2( screenSize.x ).mul( applyIorToRoughness( roughness, ior ) ); + const lod = log2( cameraViewport.z ).mul( applyIorToRoughness( roughness, ior ) ); return textureBicubicLevel( transmissionSample, lod ); @@ -28042,11 +28153,13 @@ class MeshPhysicalNodeMaterial extends MeshStandardNodeMaterial { setupSpecular() { const iorNode = this.iorNode ? float( this.iorNode ) : materialIOR; + const specularColorNode = this.specularColorNode ? vec3( this.specularColorNode ) : materialSpecularColor; + const specularIntensityNode = this.specularIntensityNode ? float( this.specularIntensityNode ) : materialSpecularIntensity; ior.assign( iorNode ); - specularColor.assign( min$1( pow2( ior.sub( 1.0 ).div( ior.add( 1.0 ) ) ).mul( materialSpecularColor ), vec3( 1.0 ) ).mul( materialSpecularIntensity ) ); + specularColor.assign( min$1( pow2( ior.sub( 1.0 ).div( ior.add( 1.0 ) ) ).mul( specularColorNode ), vec3( 1.0 ) ).mul( specularIntensityNode ) ); specularColorBlended.assign( mix( specularColor, diffuseColor.rgb, metalness ) ); - specularF90.assign( mix( materialSpecularIntensity, 1.0, metalness ) ); + specularF90.assign( mix( specularIntensityNode, 1.0, metalness ) ); } @@ -30040,6 +30153,19 @@ class RenderObject { }; + /** + * An event listener which is executed when `dispose()` is called on + * the 3D object of this render object. + * + * @method + */ + this.onObjectDispose = () => { + + this.dispose(); + + }; + + this.object.addEventListener( 'dispose', this.onObjectDispose ); this.material.addEventListener( 'dispose', this.onMaterialDispose ); this.geometry.addEventListener( 'dispose', this.onGeometryDispose ); @@ -30654,6 +30780,7 @@ class RenderObject { */ dispose() { + this.object.removeEventListener( 'dispose', this.onObjectDispose ); this.material.removeEventListener( 'dispose', this.onMaterialDispose ); this.geometry.removeEventListener( 'dispose', this.onGeometryDispose ); @@ -30983,11 +31110,6 @@ const AttributeType = { const GPU_CHUNK_BYTES = 16; -// @TODO: Move to src/constants.js - -const BlendColorFactor = 211; -const OneMinusBlendColorFactor = 212; - /** * This renderer module manages geometry attributes. * @@ -32319,9 +32441,10 @@ class Pipelines extends DataMap { * * @param {Node} computeNode - The compute node. * @param {Array} bindings - The bindings. + * @param {?Array} [promises=null] - An array of compilation promises which is only relevant in context of `Renderer.compileComputeAsync()`. * @return {ComputePipeline} The compute pipeline. */ - getForCompute( computeNode, bindings ) { + getForCompute( computeNode, bindings, promises = null ) { const { backend } = this; @@ -32368,7 +32491,7 @@ class Pipelines extends DataMap { if ( previousPipeline && previousPipeline.usedTimes === 0 ) this._releasePipeline( previousPipeline ); - pipeline = this._getComputePipeline( computeNode, stageCompute, cacheKey, bindings ); + pipeline = this._getComputePipeline( computeNode, stageCompute, cacheKey, bindings, promises ); } @@ -32580,9 +32703,10 @@ class Pipelines extends DataMap { * @param {ProgrammableStage} stageCompute - The programmable stage representing the compute shader. * @param {string} cacheKey - The cache key. * @param {Array} bindings - The bindings. + * @param {?Array} promises - An array of compilation promises which is only relevant in context of `Renderer.compileComputeAsync()`. * @return {ComputePipeline} The compute pipeline. */ - _getComputePipeline( computeNode, stageCompute, cacheKey, bindings ) { + _getComputePipeline( computeNode, stageCompute, cacheKey, bindings, promises ) { // check for existing pipeline @@ -32596,7 +32720,7 @@ class Pipelines extends DataMap { this.caches.set( cacheKey, pipeline ); - this.backend.createComputePipeline( pipeline, bindings ); + this.backend.createComputePipeline( pipeline, bindings, promises ); } @@ -35816,7 +35940,7 @@ const struct = ( membersLayout, name = null ) => { if ( params.length > 0 ) { - if ( params[ 0 ].isNode ) { + if ( isArrayAsParameter( params ) ) { values = {}; @@ -35824,7 +35948,7 @@ const struct = ( membersLayout, name = null ) => { for ( let i = 0; i < params.length; i ++ ) { - values[ names[ i ] ] = params[ i ]; + values[ names[ i ] ] = nodeObject( params[ i ] ); } @@ -42021,7 +42145,7 @@ class CodeNode extends Node { for ( const include of includes ) { - include.build( builder ); + include.build( builder, 'void' ); } @@ -48717,6 +48841,7 @@ var TSL = /*#__PURE__*/Object.freeze({ NodeShaderStage: NodeShaderStage, NodeType: NodeType, NodeUpdateType: NodeUpdateType, + OnAfterObjectUpdate: OnAfterObjectUpdate, OnAfterRenderPipeline: OnAfterRenderPipeline, OnBeforeFrameUpdate: OnBeforeFrameUpdate, OnBeforeMaterialUpdate: OnBeforeMaterialUpdate, @@ -48781,6 +48906,7 @@ var TSL = /*#__PURE__*/Object.freeze({ backgroundRotation: backgroundRotation, batch: batch, batchColor: batchColor, + batchIndirectIndex: batchIndirectIndex, bentNormalView: bentNormalView, billboarding: billboarding, bitAnd: bitAnd, @@ -56102,9 +56228,10 @@ class NodeManager extends DataMap { * Returns a node builder state for the given compute node. * * @param {Node} computeNode - The compute node. - * @return {NodeBuilderState} The node builder state. + * @param {boolean} [useAsync=false] - Whether to use async build with yielding. + * @return {NodeBuilderState|Promise} The node builder state (or Promise if async). */ - getForCompute( computeNode ) { + getForCompute( computeNode, useAsync = false ) { const computeData = this.get( computeNode ); @@ -56117,6 +56244,21 @@ class NodeManager extends DataMap { if ( onNodeBuilderCreated !== null ) onNodeBuilderCreated( nodeBuilder, computeNode ); + if ( useAsync ) { + + return nodeBuilder.buildAsync().then( () => { + + nodeBuilderState = this._createNodeBuilderState( nodeBuilder ); + + computeData.nodeBuilderState = nodeBuilderState; + computeData.version = computeNode.version; + + return nodeBuilderState; + + } ); + + } + nodeBuilder.build(); nodeBuilderState = this._createNodeBuilderState( nodeBuilder ); @@ -56130,6 +56272,27 @@ class NodeManager extends DataMap { } + /** + * Async version of getForCompute() that yields to main thread during build. + * Use this in compileComputeAsync() to prevent blocking the main thread. + * + * @param {Node} computeNode - The compute node. + * @return {Promise} A promise that resolves to the node builder state. + */ + getForComputeAsync( computeNode ) { + + const result = this.getForCompute( computeNode, true ); + + if ( result.then ) { + + return result; + + } + + return Promise.resolve( result ); + + } + /** * Creates a node builder state for the given node builder. * @@ -56392,6 +56555,27 @@ class NodeManager extends DataMap { if ( node === undefined || forceUpdate ) { + if ( node === undefined && object.isTexture === true ) { + + const onTextureDispose = () => { + + object.removeEventListener( 'dispose', onTextureDispose ); + + const node = nodeCache.get( object ); + + if ( node !== undefined ) { + + nodeCache.delete( object ); + node.dispose(); + + } + + }; + + object.addEventListener( 'dispose', onTextureDispose ); + + } + node = callback(); nodeCache.set( object, node ); @@ -57647,22 +57831,22 @@ class XRManager extends EventDispatcher { this._currentPixelRatio = null; /** - * The renderer's sample count before XR temporarily overrides it. + * The current size of the renderer's canvas + * in logical pixel unit. * * @private - * @type {?number} - * @default null + * @type {Vector2} */ - this._currentSamples = null; + this._currentSize = new Vector2(); /** - * The current size of the renderer's canvas - * in logical pixel unit. + * Holds a reference to the user camera and its current settings. * * @private - * @type {Vector2} + * @type {?Object} + * @default null */ - this._currentSize = new Vector2(); + this._currentCameraSettings = null; /** * The default event listener for handling events inside a XR session. @@ -58065,11 +58249,11 @@ class XRManager extends EventDispatcher { * Browser-side `XRWebGLBinding.foveateBoundTexture()` failures are treated as * non-fatal so they do not interrupt rendering. * - * @param {RenderTarget} renderTarget - The internal render target. + * @param {?RenderTarget} renderTarget - The internal render target. */ foveateBoundTexture( renderTarget ) { - if ( renderTarget.isPostProcessingRenderTarget !== true ) return; + if ( renderTarget === null || renderTarget.isPostProcessingRenderTarget !== true ) return; if ( this.isPresenting !== true ) return; if ( this._glProjLayer === null ) return; @@ -58154,9 +58338,7 @@ class XRManager extends EventDispatcher { */ _validateWebGPUSession() { - const renderer = this._renderer; - - if ( renderer.backend.isWebGPUBackend !== true ) return; + if ( this._renderer.backend.isWebGPUBackend !== true ) return; if ( this._session.enabledFeatures.includes( 'webgpu' ) === false ) { @@ -58164,15 +58346,6 @@ class XRManager extends EventDispatcher { } - if ( renderer.samples > 0 ) { - - warnOnce( 'THREE.XRManager: WebGPU XR does not support MSAA yet. Disabling MSAA for this XR session.' ); - - if ( this._currentSamples === null ) this._currentSamples = renderer.samples; - renderer._samples = 0; - - } - } /** @@ -58187,8 +58360,7 @@ class XRManager extends EventDispatcher { const webgpuBinding = this.getWebGPUBinding(); const glProjLayer = webgpuBinding.createProjectionLayer( { - colorFormat: webgpuBinding.getPreferredColorFormat(), - depthStencilFormat: 'depth24plus' + colorFormat: webgpuBinding.getPreferredColorFormat() } ); this._glProjLayer = glProjLayer; @@ -58204,7 +58376,10 @@ class XRManager extends EventDispatcher { depthBuffer: true, multiview: false, useArrayDepthTexture: true, - samples: 0 + storeMultisampledColorBuffer: false, + storeMultisampledDepthBuffer: false, + storeMultisampledStencilBuffer: false, + samples: this._renderer.samples } ); this._xrRenderTarget.texture.isArrayTexture = true; @@ -58227,46 +58402,27 @@ class XRManager extends EventDispatcher { _disposeWebGPUSession() { const renderer = this._renderer; - const xrRenderTarget = this._xrRenderTarget; - - if ( xrRenderTarget === null || renderer.backend.isWebGPUBackend !== true ) return; - - // XR textures are external (from XRGPUBinding), so clear cached state before disposal. const backend = renderer.backend; - const texturesModule = renderer._textures; - - const renderTargetData = backend.get ? backend.get( xrRenderTarget ) : null; - if ( renderTargetData ) { - - renderTargetData.descriptors = undefined; - - } - - const deleteResource = ( resource ) => { - - if ( resource === null || resource === undefined ) return; + const xrRenderTarget = this._xrRenderTarget; - if ( backend.delete ) backend.delete( resource ); - if ( texturesModule.delete ) texturesModule.delete( resource ); + if ( xrRenderTarget === null || backend.isWebGPUBackend !== true ) return; - }; - - for ( let i = 0; i < xrRenderTarget.textures.length; i ++ ) { + if ( renderer._renderContexts && renderer._renderContexts.dispose ) { - deleteResource( xrRenderTarget.textures[ i ] ); + renderer._renderContexts.dispose(); } - deleteResource( xrRenderTarget.depthTexture ); - deleteResource( xrRenderTarget ); + xrRenderTarget.dispose(); - if ( renderer._renderContexts && renderer._renderContexts.dispose ) { + // The external texture can be registered before the render target is initialized. + for ( const texture of xrRenderTarget.textures ) { - renderer._renderContexts.dispose(); + if ( backend.has( texture ) ) backend.destroyTexture( texture ); } - xrRenderTarget.dispose(); + backend.delete( xrRenderTarget ); } @@ -58345,6 +58501,7 @@ class XRManager extends EventDispatcher { * @param {Function} rendercall - A callback function that renders the layer. Similar to code in * the default animation loop, this method can be used to update/transform 3D object in the layer's scene. * @param {Object} [attributes={}] - Allows to configure the layer's render target. + * @param {number} [attributes.samples] - The scene MSAA sample count. Defaults to the renderer's sample count. * @return {Mesh} A mesh representing the quadratic XR layer. This mesh should be added to the XR scene. */ createQuadLayer( width, height, translation, quaternion, pixelwidth, pixelheight, rendercall, attributes = {} ) { @@ -58369,14 +58526,14 @@ class XRManager extends EventDispatcher { attributes.stencil ? DepthStencilFormat : DepthFormat ), stencilBuffer: attributes.stencil, + samples: attributes.samples ?? this._renderer.samples, resolveDepthBuffer: false, resolveStencilBuffer: false, + storeMultisampledColorBuffer: false, storeMultisampledDepthBuffer: false, storeMultisampledStencilBuffer: false } ); - renderTarget._autoAllocateDepthBuffer = true; - const material = new MeshBasicMaterial( { color: 0xffffff, side: FrontSide } ); material.map = renderTarget.texture; material.map.offset.y = 1; @@ -58393,6 +58550,7 @@ class XRManager extends EventDispatcher { quaternion: quaternion, pixelwidth: pixelwidth, pixelheight: pixelheight, + samples: renderTarget.samples, plane: plane, material: material, rendercall: rendercall, @@ -58438,6 +58596,7 @@ class XRManager extends EventDispatcher { * @param {Function} rendercall - A callback function that renders the layer. Similar to code in * the default animation loop, this method can be used to update/transform 3D object in the layer's scene. * @param {Object} [attributes={}] - Allows to configure the layer's render target. + * @param {number} [attributes.samples] - The scene MSAA sample count. Defaults to the renderer's sample count. * @return {Mesh} A mesh representing the cylindrical XR layer. This mesh should be added to the XR scene. */ createCylinderLayer( radius, centralAngle, aspectratio, translation, quaternion, pixelwidth, pixelheight, rendercall, attributes = {} ) { @@ -58462,14 +58621,14 @@ class XRManager extends EventDispatcher { attributes.stencil ? DepthStencilFormat : DepthFormat ), stencilBuffer: attributes.stencil, + samples: attributes.samples ?? this._renderer.samples, resolveDepthBuffer: false, resolveStencilBuffer: false, + storeMultisampledColorBuffer: false, storeMultisampledDepthBuffer: false, storeMultisampledStencilBuffer: false } ); - renderTarget._autoAllocateDepthBuffer = true; - const material = new MeshBasicMaterial( { color: 0xffffff, side: BackSide } ); material.map = renderTarget.texture; material.map.offset.y = 1; @@ -58487,6 +58646,7 @@ class XRManager extends EventDispatcher { quaternion: quaternion, pixelwidth: pixelwidth, pixelheight: pixelheight, + samples: renderTarget.samples, plane: plane, material: material, rendercall: rendercall, @@ -58784,11 +58944,7 @@ class XRManager extends EventDispatcher { format: RGBAFormat, type: UnsignedByteType, colorSpace: renderer.outputColorSpace, - stencilBuffer: renderer.stencil, - resolveDepthBuffer: ( glBaseLayer.ignoreDepthValues === false ), - resolveStencilBuffer: ( glBaseLayer.ignoreDepthValues === false ), - storeMultisampledDepthBuffer: ( glBaseLayer.ignoreDepthValues === false ), - storeMultisampledStencilBuffer: ( glBaseLayer.ignoreDepthValues === false ), + stencilBuffer: renderer.stencil } ); @@ -58882,6 +59038,12 @@ class XRManager extends EventDispatcher { // update user camera and its children + if ( this._currentCameraSettings === null && camera.isPerspectiveCamera ) { + + this._currentCameraSettings = { camera: camera, fov: camera.fov, zoom: camera.zoom }; + + } + updateUserCamera( camera, cameraXR, parent ); @@ -59096,13 +59258,6 @@ function onSessionEnd() { this._currentDepthNear = null; this._currentDepthFar = null; - if ( this._currentSamples !== null ) { - - renderer._samples = this._currentSamples; - this._currentSamples = null; - - } - // restore framebuffer/rendering state renderer._resetXRState(); @@ -59141,8 +59296,10 @@ function onSessionEnd() { layer.stencilBuffer ? DepthStencilFormat : DepthFormat ), stencilBuffer: layer.stencilBuffer, + samples: layer.samples, resolveDepthBuffer: false, resolveStencilBuffer: false, + storeMultisampledColorBuffer: false, storeMultisampledDepthBuffer: false, storeMultisampledStencilBuffer: false } ); @@ -59172,6 +59329,18 @@ function onSessionEnd() { renderer.setPixelRatio( this._currentPixelRatio ); renderer.setSize( this._currentSize.width, this._currentSize.height, false ); + if ( this._currentCameraSettings !== null ) { + + const camera = this._currentCameraSettings.camera; + + camera.fov = this._currentCameraSettings.fov; + camera.zoom = this._currentCameraSettings.zoom; + camera.updateProjectionMatrix(); + + this._currentCameraSettings = null; + + } + this.dispatchEvent( { type: 'sessionend' } ); } @@ -59396,6 +59565,14 @@ function onAnimationFrame( time, frame ) { renderer.setOutputRenderTarget( this._xrRenderTarget ); const frameBufferTarget = renderer._getFrameBufferTarget(); + + if ( webgpuViewData !== null ) { + + this._xrRenderTarget.samples = frameBufferTarget === null ? renderer.samples : 0; + this._xrRenderTarget.depthBuffer = frameBufferTarget === null; + + } + renderer.xr.foveateBoundTexture( frameBufferTarget ); } @@ -60620,9 +60797,10 @@ class Renderer { * @param {Object3D} scene - The scene or 3D object to precompile. * @param {Camera} camera - The camera that is used to render the scene. * @param {?Scene} targetScene - If the first argument is a 3D object, this parameter must represent the scene the 3D object is going to be added. + * @param {onProgressCallback} [onProgress] - Executed while the compilation is in progress. * @return {Promise} A Promise that resolves when the compile has been finished. */ - async compileAsync( scene, camera, targetScene = null ) { + async compileAsync( scene, camera, targetScene = null, onProgress = null ) { if ( this._isDeviceLost === true ) return; @@ -60656,7 +60834,9 @@ class Renderer { // Match render()'s logic: use frameBufferTarget when needsFrameBufferTarget is true const useFrameBufferTarget = this.needsFrameBufferTarget && this._renderTarget === null; - const renderTarget = useFrameBufferTarget ? this._getFrameBufferTarget() : ( this._renderTarget || this._outputRenderTarget ); + const outputRenderTarget = this._renderTarget || this._outputRenderTarget; + const useXRCamera = this.xr.isPresenting === true && this.isOutputTarget; + const renderTarget = useFrameBufferTarget ? this._getFrameBufferTarget() : outputRenderTarget; const renderContext = this._renderContexts.get( renderTarget, this._mrt ); const activeMipmapLevel = this._activeMipmapLevel; @@ -60687,7 +60867,7 @@ class Renderer { if ( scene.matrixWorldAutoUpdate === true ) scene.updateMatrixWorld(); - camera = this._updateCamera( camera ); + camera = this._updateCamera( camera, useXRCamera ); // @@ -60782,6 +60962,9 @@ class Renderer { // Process compilation work items sequentially to avoid freezing // Yields between objects to keep animation smooth + const total = compilationPromises.length; + let loaded = 0; + for ( const item of compilationPromises ) { const renderObject = this._objects.get( item.object, item.material, item.scene, item.camera, item.lightsNode, item.renderContext, item.clippingContext, item.passId ); @@ -60811,6 +60994,14 @@ class Renderer { this._nodes.updateAfter( renderObject ); this._isPreCompiling = false; + loaded ++; + + if ( onProgress !== null ) { + + onProgress( new ProgressEvent( 'progress', { lengthComputable: true, loaded, total } ) ); + + } + // Yield between objects to allow animation frames await yieldToMain(); @@ -60818,6 +61009,90 @@ class Renderer { } + /** + * Compile compute programs. This can be useful to avoid a + * phenomenon which is called "shader compilation stutter", which occurs when + * rendering an object with a new shader for the first time. + * + * @async + * @param {Node|Array} computeNodes - The compute node(s). + * @param {onProgressCallback} [onProgress] - Executed while the compilation is in progress. + * @return {Promise} A Promise that resolves when the compile has been finished. + */ + async compileComputeAsync( computeNodes, onProgress = null ) { + + if ( this._isDeviceLost === true ) return; + + if ( this._initialized === false ) await this.init(); + + const computeList = Array.isArray( computeNodes ) ? computeNodes : [ computeNodes ]; + + if ( computeList.length === 0 || computeList.some( ( computeNode ) => computeNode === undefined || computeNode === null || computeNode.isComputeNode !== true ) ) { + + throw new Error( 'THREE.Renderer: .compileComputeAsync() expects a ComputeNode.' ); + + } + + const total = computeList.length; + let loaded = 0; + + // + + const pipelines = this._pipelines; + const bindings = this._bindings; + const nodes = this._nodes; + + for ( const computeNode of computeList ) { + + if ( pipelines.has( computeNode ) === false ) { + + const dispose = () => { + + computeNode.removeEventListener( 'dispose', dispose ); + + pipelines.delete( computeNode ); + bindings.deleteForCompute( computeNode ); + nodes.delete( computeNode ); + + }; + + computeNode.addEventListener( 'dispose', dispose ); + + const onInitFn = computeNode.onInitFunction; + + if ( onInitFn !== null ) { + + onInitFn.call( computeNode, { renderer: this } ); + + } + + } + + await nodes.getForComputeAsync( computeNode ); + + nodes.updateForCompute( computeNode ); + bindings.updateForCompute( computeNode ); + + const computeBindings = bindings.getForCompute( computeNode ); + const compilationPromises = []; + + pipelines.getForCompute( computeNode, computeBindings, compilationPromises ); + await Promise.all( compilationPromises ); + + loaded ++; + + if ( onProgress !== null ) { + + onProgress( new ProgressEvent( 'progress', { lengthComputable: true, loaded, total } ) ); + + } + + if ( loaded < total ) await yieldToMain(); + + } + + } + /** * Renders the scene in an async fashion. * @@ -61137,7 +61412,9 @@ class Renderer { _renderOutputLayers( quad, renderTarget ) { - if ( renderTarget.texture.isArrayTexture !== true || renderTarget.texture.image.depth <= 1 ) { + const useMultiview = this.backend.isWebGLBackend === true && renderTarget.multiview === true; + + if ( useMultiview || renderTarget.texture.isArrayTexture !== true || renderTarget.texture.image.depth <= 1 ) { this._renderScene( quad, quad.camera, false ); return; @@ -61176,12 +61453,7 @@ class Renderer { */ _getFrameBufferTarget() { - const { currentToneMapping, currentColorSpace } = this; - - const useToneMapping = currentToneMapping !== NoToneMapping; - const useColorSpace = currentColorSpace !== ColorManagement.workingColorSpace; - - if ( useToneMapping === false && useColorSpace === false ) return null; + if ( this.needsFrameBufferTarget === false ) return null; const { width, height } = this.getDrawingBufferSize( _drawingBufferSize ); const { depth, stencil } = this; @@ -61306,6 +61578,7 @@ class Renderer { const sceneRef = ( scene.isScene === true ) ? scene : _scene; const outputRenderTarget = this._renderTarget || this._outputRenderTarget; + const useXRCamera = this.xr.isPresenting === true && this.isOutputTarget; const activeCubeFace = this._activeCubeFace; const activeMipmapLevel = this._activeMipmapLevel; @@ -61374,7 +61647,7 @@ class Renderer { if ( scene.matrixWorldAutoUpdate === true ) scene.updateMatrixWorld(); - camera = this._updateCamera( camera ); + camera = this._updateCamera( camera, useXRCamera ); // @@ -62224,6 +62497,7 @@ class Renderer { * Returns `true` if a framebuffer target is needed to perform tone mapping or color space conversion. * If this is the case, the renderer allocates an internal render target for that purpose. * + * @type {boolean} */ get needsFrameBufferTarget() { @@ -62839,7 +63113,7 @@ class Renderer { * @param {number} width - The width of the copy region. * @param {number} height - The height of the copy region. * @param {number} [textureIndex=0] - The texture index of a MRT render target. - * @param {number} [faceIndex=0] - The active cube face index. + * @param {number} [faceIndex=0] - The cube face, depth slice or array layer index. * @return {Promise} A Promise that resolves when the read has been finished. The resolve provides the read data as a typed array. */ async readRenderTargetPixelsAsync( renderTarget, x, y, width, height, textureIndex = 0, faceIndex = 0 ) { @@ -63221,13 +63495,14 @@ class Renderer { * * @private * @param {Camera} camera - The camera to update. + * @param {boolean} useXRCamera - Whether the XR camera should be used when presenting. * @return {Camera} The returned camera might be different depending on whether XR is used or not. */ - _updateCamera( camera ) { + _updateCamera( camera, useXRCamera ) { const xr = this.xr; - if ( xr.isPresenting === false ) { + if ( xr.isPresenting === false || useXRCamera === false ) { let projectionMatrixNeedsUpdate = false; @@ -63297,7 +63572,7 @@ class Renderer { // handle XR - if ( xr.enabled === true && xr.isPresenting === true ) { + if ( useXRCamera === true && xr.enabled === true && xr.isPresenting === true ) { if ( xr.cameraAutoUpdate === true ) xr.updateCamera( camera ); camera = xr.getCamera(); // use XR camera for rendering @@ -63588,7 +63863,8 @@ class Renderer { * @param {Object3D} scene - The scene or 3D object to precompile. * @param {Camera} camera - The camera that is used to render the scene. * @param {Scene} targetScene - If the first argument is a 3D object, this parameter must represent the scene the 3D object is going to be added. - * @return {function(Object3D, Camera, ?Scene): Promise|undefined} A Promise that resolves when the compile has been finished. + * @param {onProgressCallback} [onProgress] - Executed while the compilation is in progress. + * @return {function(Object3D, Camera, ?Scene, ?onProgressCallback): Promise|undefined} A Promise that resolves when the compile has been finished. */ get compile() { @@ -65773,7 +66049,7 @@ ${ flowData.code } snippet = `${typePrefix}sampler3D ${ uniform.name };`; - } else if ( texture.compareFunction && textureNode.compareNode !== null ) { + } else if ( texture.compareFunction && textureNode.isPlainGather() === false ) { if ( texture.isArrayTexture === true ) { @@ -66982,8 +67258,9 @@ class Backend { * @abstract * @param {ComputePipeline} computePipeline - The compute pipeline. * @param {Array} bindings - The bindings. + * @param {?Array} [promises=null] - Optional compilation promises. */ - createComputePipeline( /*computePipeline, bindings*/ ) { } + createComputePipeline( /*computePipeline, bindings, promises*/ ) { } // cache key @@ -67090,7 +67367,7 @@ class Backend { * @param {number} y - The y coordinate of the copy origin. * @param {number} width - The width of the copy. * @param {number} height - The height of the copy. - * @param {number} faceIndex - The face index. + * @param {number} faceIndex - The cube face, depth slice or array layer index. * @return {Promise} A Promise that resolves with a typed array when the copy operation has finished. */ async copyTextureToBuffer( /*texture, x, y, width, height, faceIndex*/ ) {} @@ -67964,6 +68241,8 @@ class WebGLState { this.currentBlendDst = null; this.currentBlendSrcAlpha = null; this.currentBlendDstAlpha = null; + this.currentBlendColor = new Color( 0, 0, 0 ); + this.currentBlendAlpha = 0; this.currentPremultipledAlpha = null; this.currentPolygonOffsetFactor = null; this.currentPolygonOffsetUnits = null; @@ -68010,7 +68289,9 @@ class WebGLState { equationToGL = { [ AddEquation ]: gl.FUNC_ADD, [ SubtractEquation ]: gl.FUNC_SUBTRACT, - [ ReverseSubtractEquation ]: gl.FUNC_REVERSE_SUBTRACT + [ ReverseSubtractEquation ]: gl.FUNC_REVERSE_SUBTRACT, + [ MinEquation ]: gl.MIN, + [ MaxEquation ]: gl.MAX }; factorToGL = { @@ -68024,7 +68305,11 @@ class WebGLState { [ OneMinusSrcColorFactor ]: gl.ONE_MINUS_SRC_COLOR, [ OneMinusSrcAlphaFactor ]: gl.ONE_MINUS_SRC_ALPHA, [ OneMinusDstColorFactor ]: gl.ONE_MINUS_DST_COLOR, - [ OneMinusDstAlphaFactor ]: gl.ONE_MINUS_DST_ALPHA + [ 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 }; const scissorParam = gl.getParameter( gl.SCISSOR_BOX ); @@ -68326,7 +68611,7 @@ class WebGLState { * Defines the blending. * * This method caches the state so `gl.blendEquation()`, `gl.blendEquationSeparate()`, - * `gl.blendFunc()` and `gl.blendFuncSeparate()` are only called when necessary. + * `gl.blendFunc()`, `gl.blendFuncSeparate()` and `gl.blendColor()` are only called when necessary. * * @param {number} blending - The blending type. * @param {number} blendEquation - The blending equation. @@ -68335,9 +68620,11 @@ class WebGLState { * @param {number} blendEquationAlpha - Only relevant for custom blending. The blending equation for alpha. * @param {number} blendSrcAlpha - Only relevant for custom blending. The alpha source blending factor. * @param {number} blendDstAlpha - Only relevant for custom blending. The alpha destination blending factor. + * @param {Color} blendColor - Only relevant for custom blending. The RGB values of the constant blend color. + * @param {number} blendAlpha - Only relevant for custom blending. The alpha value of the constant blend color. * @param {boolean} premultipliedAlpha - Whether premultiplied alpha is enabled or not. */ - setBlending( blending, blendEquation, blendSrc, blendDst, blendEquationAlpha, blendSrcAlpha, blendDstAlpha, premultipliedAlpha ) { + setBlending( blending, blendEquation, blendSrc, blendDst, blendEquationAlpha, blendSrcAlpha, blendDstAlpha, blendColor, blendAlpha, premultipliedAlpha ) { const { gl } = this; @@ -68468,6 +68755,15 @@ class WebGLState { } + if ( blendColor.equals( this.currentBlendColor ) === false || blendAlpha !== this.currentBlendAlpha ) { + + gl.blendColor( blendColor.r, blendColor.g, blendColor.b, blendAlpha ); + + this.currentBlendColor.copy( blendColor ); + this.currentBlendAlpha = blendAlpha; + + } + this.currentBlending = blending; this.currentPremultipledAlpha = false; @@ -68817,7 +69113,7 @@ class WebGLState { ( material.blending === NormalBlending && material.transparent === false ) ? this.setBlending( NoBlending ) - : this.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.premultipliedAlpha ); + : this.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.blendColor, material.blendAlpha, material.premultipliedAlpha ); this.setDepthFunc( material.depthFunc ); this.setDepthTest( material.depthTest ); @@ -69344,6 +69640,8 @@ class WebGLState { this.currentBlendDst = null; this.currentBlendSrcAlpha = null; this.currentBlendDstAlpha = null; + this.currentBlendColor.set( 0, 0, 0 ); + this.currentBlendAlpha = 0; this.currentPremultipledAlpha = null; this.currentPolygonOffsetFactor = null; this.currentPolygonOffsetUnits = null; @@ -70929,7 +71227,7 @@ class WebGLTextureUtils { * @param {number} y - The y coordinate of the copy origin. * @param {number} width - The width of the copy. * @param {number} height - The height of the copy. - * @param {number} faceIndex - The face index. + * @param {number} faceIndex - The cube face, depth slice or array layer index. * @return {Promise} A Promise that resolves with a typed array when the copy operation has finished. */ async copyTextureToBuffer( texture, x, y, width, height, faceIndex ) { @@ -70942,9 +71240,17 @@ class WebGLTextureUtils { backend.state.bindFramebuffer( gl.READ_FRAMEBUFFER, fb ); - const target = texture.isCubeTexture ? gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex : gl.TEXTURE_2D; + if ( texture.isData3DTexture || texture.isDataArrayTexture || texture.isArrayTexture ) { + + gl.framebufferTextureLayer( gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, textureGPU, 0, faceIndex ); + + } else { + + const target = texture.isCubeTexture ? gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex : gl.TEXTURE_2D; - gl.framebufferTexture2D( gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, target, textureGPU, 0 ); + gl.framebufferTexture2D( gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, target, textureGPU, 0 ); + + } const typedArrayType = this._getTypedArrayType( glType ); const bytesPerTexel = this._getBytesPerTexel( glType, glFormat ); @@ -73321,7 +73627,7 @@ class WebGLBackend extends Backend { * @param {number} y - The y coordinate of the copy origin. * @param {number} width - The width of the copy. * @param {number} height - The height of the copy. - * @param {number} faceIndex - The face index. + * @param {number} faceIndex - The cube face, depth slice or array layer index. * @return {Promise} A Promise that resolves with a typed array when the copy operation has finished. */ async copyTextureToBuffer( texture, x, y, width, height, faceIndex ) { @@ -73605,10 +73911,11 @@ class WebGLBackend extends Backend { * * @param {ComputePipeline} computePipeline - The compute pipeline. * @param {Array} bindings - The bindings. + * @param {?Array} [promises=null] - Optional compilation promises. */ - createComputePipeline( computePipeline, bindings ) { + createComputePipeline( computePipeline, bindings, promises = null ) { - const { state, gl } = this; + const { gl } = this; // Program @@ -73651,19 +73958,6 @@ class WebGLBackend extends Backend { gl.linkProgram( programGPU ); - if ( gl.getProgramParameter( programGPU, gl.LINK_STATUS ) === false ) { - - this._logProgramError( programGPU, fragmentShader, vertexShader ); - - - } - - state.useProgram( programGPU ); - - // Bindings - - this._setupBindings( bindings, programGPU ); - const attributeNodes = computeProgram.attributes; const attributes = []; const transformBuffers = []; @@ -73690,14 +73984,73 @@ class WebGLBackend extends Backend { } - // + // Store pipeline data this.set( computePipeline, { programGPU, + fragmentShader, + vertexShader, transformBuffers, attributes } ); + if ( promises !== null && this.parallel ) { + + const parallel = this.parallel; + + const p = new Promise( ( resolve ) => { + + const checkStatus = () => { + + if ( gl.getProgramParameter( programGPU, parallel.COMPLETION_STATUS_KHR ) ) { + + this._completeComputeCompile( computePipeline, bindings ); + resolve(); + + } else { + + requestAnimationFrame( checkStatus ); + + } + + }; + + checkStatus(); + + } ); + + promises.push( p ); + return; + + } + + // Sync fallback + this._completeComputeCompile( computePipeline, bindings ); + + } + + /** + * Completes the compute pipeline setup for the given compute pipeline. + * + * @param {ComputePipeline} computePipeline - The compute pipeline. + * @param {Array} bindings - Array of bind groups. + */ + _completeComputeCompile( computePipeline, bindings ) { + + const { state, gl } = this; + const { programGPU, fragmentShader, vertexShader } = this.get( computePipeline ); + + if ( gl.getProgramParameter( programGPU, gl.LINK_STATUS ) === false ) { + + this._logProgramError( programGPU, fragmentShader, vertexShader ); + + } + + state.useProgram( programGPU ); + + // Bindings (must be after link completion) + this._setupBindings( bindings, programGPU ); + } /** @@ -74722,7 +75075,8 @@ class WebGLBackend extends Backend { } - } else if ( renderTarget.storeMultisampledDepthBuffer === false && renderTargetContextData.framebuffers ) { + } else if ( this._supportsInvalidateFramebuffer === true && renderTargetContextData.framebuffers && + ( renderTarget._autoAllocateDepthBuffer === true || ( renderTarget.samples > 0 && renderTarget.storeMultisampledDepthBuffer === false ) ) ) { const fb = renderTargetContextData.framebuffers[ renderContext.getCacheKey() ]; state.bindFramebuffer( gl.DRAW_FRAMEBUFFER, fb ); @@ -75363,10 +75717,21 @@ class WebGPUUtils { } else if ( texture.isDepthTexture && ! texture.renderTarget ) { - const renderer = this.backend.renderer; - const renderTarget = renderer.getRenderTarget(); + const textureData = this.backend.get( texture ); + + if ( textureData.texture !== undefined ) { + + // use the effective sample count of the allocated texture + + samples = textureData.texture.sampleCount; + + } else { - samples = renderTarget ? renderTarget.samples : renderer.currentSamples; + // otherwise use the current samples of the renderer + + samples = this.backend.renderer.currentSamples; + + } } else if ( texture.renderTarget ) { @@ -75377,7 +75742,8 @@ class WebGPUUtils { samples = this.getSampleCount( samples || 1 ); const isMSAA = samples > 1 && texture.renderTarget !== null && ( texture.isDepthTexture !== true && texture.isFramebufferTexture !== true ); - const primarySamples = isMSAA ? 1 : samples; + const isMSAAArrayDepthTexture = samples > 1 && texture.renderTarget !== null && texture.isDepthTexture === true && texture.isArrayTexture === true; + const primarySamples = isMSAA || isMSAAArrayDepthTexture ? 1 : samples; return { samples, primarySamples, isMSAA }; @@ -76287,7 +76653,7 @@ const _renderPassDescriptor = new GPURenderPassDescriptor(); const _renderPipelineDescriptor$1 = new GPURenderPipelineDescriptor(); const _colorAttachment = new GPURenderPassColorAttachment(); const _shaderModuleDescriptor$1 = new GPUShaderModuleDescriptor(); -const _textureDescriptor$1 = new GPUTextureDescriptor(); +const _textureDescriptor$2 = new GPUTextureDescriptor(); const _viewDescriptor$2 = new GPUTextureViewDescriptor(); /** @@ -76498,14 +76864,14 @@ fn main_cube( Varys: VarysStruct ) -> @location( 0 ) vec4 { const format = textureGPUDescriptor.format; const { width, height } = textureGPUDescriptor.size; - _textureDescriptor$1.size.width = width; - _textureDescriptor$1.size.height = height; - _textureDescriptor$1.format = format; - _textureDescriptor$1.usage = GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING; + _textureDescriptor$2.size.width = width; + _textureDescriptor$2.size.height = height; + _textureDescriptor$2.format = format; + _textureDescriptor$2.usage = GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING; - const tempTexture = this.device.createTexture( _textureDescriptor$1 ); + const tempTexture = this.device.createTexture( _textureDescriptor$2 ); - _textureDescriptor$1.reset(); + _textureDescriptor$2.reset(); const copyTransferPipeline = this.getTransferPipeline( format, textureGPU.textureBindingViewDimension ); const flipTransferPipeline = this.getTransferPipeline( format, tempTexture.textureBindingViewDimension ); @@ -77148,7 +77514,7 @@ const _texelCopyBufferInfo = new GPUTexelCopyBufferInfo(); const _texelCopyBufferLayout = new GPUTexelCopyBufferLayout(); const _copyExternalImageSourceInfo = new GPUCopyExternalImageSourceInfo(); const _copyExternalImageDestInfo = new GPUCopyExternalImageDestInfo(); -const _textureDescriptor = new GPUTextureDescriptor(); +const _textureDescriptor$1 = new GPUTextureDescriptor(); const _extent3D$1 = new GPUExtent3D(); const _compareToWebGPU = { @@ -77264,10 +77630,12 @@ class WebGPUTextureUtils { const texture = binding.texture; const textureNode = binding.textureNode; + const isComparison = texture.isDepthTexture === true && texture.compareFunction !== null && textureNode.isPlainGather() === false && backend.hasCompatibility( Compatibility.TEXTURE_COMPARE ); + const samplerKey = texture.minFilter + '-' + texture.magFilter + '-' + texture.wrapS + '-' + texture.wrapT + '-' + ( texture.wrapR || '0' ) + '-' + texture.anisotropy + '-' + ( texture.isDepthTexture === true ? 1 : 0 ) + '-' + - ( texture.compareFunction !== null && textureNode.compareNode !== null ? texture.compareFunction : 0 ); + ( isComparison ? texture.compareFunction : 0 ); let samplerData = this._samplerCache.get( samplerKey ); @@ -77281,7 +77649,7 @@ class WebGPUTextureUtils { _samplerDescriptor.mipmapFilter = this._convertMipmapFilterMode( texture.minFilter ); // Depth textures without compare function must use non-filtering (nearest) sampling - if ( texture.isDepthTexture && ( texture.compareFunction === null || textureNode.compareNode === null ) ) { + if ( texture.isDepthTexture && isComparison === false ) { _samplerDescriptor.magFilter = GPUFilterMode.Nearest; _samplerDescriptor.minFilter = GPUFilterMode.Nearest; @@ -77297,7 +77665,7 @@ class WebGPUTextureUtils { } - if ( texture.isDepthTexture && texture.compareFunction !== null && textureNode.compareNode !== null && backend.hasCompatibility( Compatibility.TEXTURE_COMPARE ) ) { + if ( isComparison ) { _samplerDescriptor.compare = _compareToWebGPU[ texture.compareFunction ]; @@ -77457,6 +77825,20 @@ class WebGPUTextureUtils { textureData.format = format; const { samples, primarySamples, isMSAA } = backend.utils.getTextureSampleData( texture ); + const renderTarget = texture.renderTarget; + + // WebGPU multisampled 2D textures can only have a single array layer. + const useSeparateMSAATextures = samples > 1 && renderTarget !== null && depth > 1 && dimension === GPUTextureDimension.TwoD; + const supportsTransientAttachments = GPUTextureUsage.TRANSIENT_ATTACHMENT !== undefined; + // Layered rendering can resume after a framebuffer copy, so its attachments must support loading. + const useTransientAttachments = supportsTransientAttachments && useSeparateMSAATextures === false; + const useTransientDepthAttachment = texture.isDepthTexture === true && + useTransientAttachments && + renderTarget?.storeMultisampledDepthBuffer === false && + ( renderTarget.stencilBuffer === false || renderTarget.storeMultisampledStencilBuffer === false ); + const useTransientColorAttachment = texture.isDepthTexture !== true && + useTransientAttachments && + renderTarget?.storeMultisampledColorBuffer === false; let usage = GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.COPY_SRC; @@ -77472,17 +77854,11 @@ class WebGPUTextureUtils { } - const renderTarget = texture.renderTarget; - // when the multisampled data are discarded, try to use a transient attachment if possible - if ( texture.isDepthTexture === true && primarySamples > 1 && GPUTextureUsage.TRANSIENT_ATTACHMENT !== undefined ) { - - if ( renderTarget?.storeMultisampledDepthBuffer === false && ( renderTarget.stencilBuffer === false || renderTarget.storeMultisampledStencilBuffer === false ) ) { + if ( primarySamples > 1 && useTransientDepthAttachment ) { - usage = GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TRANSIENT_ATTACHMENT; - - } + usage = GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TRANSIENT_ATTACHMENT; } @@ -77526,7 +77902,7 @@ class WebGPUTextureUtils { } - if ( isMSAA ) { + if ( isMSAA || useSeparateMSAATextures ) { const msaaTextureDescriptorGPU = Object.assign( {}, textureDescriptorGPU ); @@ -77536,13 +77912,30 @@ class WebGPUTextureUtils { // when the multisampled data are discarded, try to use a transient attachment if possible - if ( renderTarget?.storeMultisampledColorBuffer === false && GPUTextureUsage.TRANSIENT_ATTACHMENT !== undefined ) { + if ( useTransientDepthAttachment || useTransientColorAttachment ) { msaaTextureDescriptorGPU.usage = GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TRANSIENT_ATTACHMENT; } - textureData.msaaTexture = backend.device.createTexture( msaaTextureDescriptorGPU ); + if ( useSeparateMSAATextures ) { + + msaaTextureDescriptorGPU.size = Object.assign( {}, msaaTextureDescriptorGPU.size, { depthOrArrayLayers: 1 } ); + + textureData.msaaTextures = []; + + for ( let i = 0; i < depth; i ++ ) { + + msaaTextureDescriptorGPU.label = textureDescriptorGPU.label + '-msaa-' + i; + textureData.msaaTextures.push( backend.device.createTexture( msaaTextureDescriptorGPU ) ); + + } + + } else { + + textureData.msaaTexture = backend.device.createTexture( msaaTextureDescriptorGPU ); + + } } @@ -77563,10 +77956,16 @@ class WebGPUTextureUtils { const backend = this.backend; const textureData = backend.get( texture ); - if ( textureData.texture !== undefined && isDefaultTexture === false && texture.isExternalTexture !== true ) textureData.texture.destroy(); + if ( textureData.texture !== undefined && isDefaultTexture === false && texture.isExternalTexture !== true && textureData.externalTexture !== true ) textureData.texture.destroy(); if ( textureData.msaaTexture !== undefined ) textureData.msaaTexture.destroy(); + if ( textureData.msaaTextures !== undefined ) { + + for ( const msaaTexture of textureData.msaaTextures ) msaaTexture.destroy(); + + } + backend.delete( texture ); } @@ -77613,16 +78012,16 @@ class WebGPUTextureUtils { if ( colorBuffer ) colorBuffer.destroy(); - _textureDescriptor.label = 'colorBuffer'; - _textureDescriptor.size.width = width; - _textureDescriptor.size.height = height; - _textureDescriptor.sampleCount = backend.utils.getSampleCount( backend.renderer.currentSamples ); - _textureDescriptor.format = backend.utils.getPreferredCanvasFormat(); - _textureDescriptor.usage = GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.COPY_SRC; + _textureDescriptor$1.label = 'colorBuffer'; + _textureDescriptor$1.size.width = width; + _textureDescriptor$1.size.height = height; + _textureDescriptor$1.sampleCount = backend.utils.getSampleCount( backend.renderer.currentSamples ); + _textureDescriptor$1.format = backend.utils.getPreferredCanvasFormat(); + _textureDescriptor$1.usage = GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.COPY_SRC; - colorBuffer = backend.device.createTexture( _textureDescriptor ); + colorBuffer = backend.device.createTexture( _textureDescriptor$1 ); - _textureDescriptor.reset(); + _textureDescriptor$1.reset(); // @@ -77871,7 +78270,7 @@ class WebGPUTextureUtils { * @param {number} y - The y coordinate of the copy origin. * @param {number} width - The width of the copy. * @param {number} height - The height of the copy. - * @param {number} faceIndex - The face index. + * @param {number} faceIndex - The cube face, depth slice or array layer index. * @return {Promise} A Promise that resolves with a typed array when the copy operation has finished. */ async copyTextureToBuffer( texture, x, y, width, height, faceIndex ) { @@ -79004,6 +79403,7 @@ const wgslTypeLib$1 = { 'mat4x4f': 'mat4', 'sampler': 'sampler', + 'sampler_comparison': 'samplerComparison', 'texture_1d': 'texture', @@ -81280,7 +81680,7 @@ ${ flowData.code } if ( needsSampler ) { - if ( this.isSampleCompare( texture ) && textureNode.compareNode !== null ) { + if ( this.isSampleCompare( texture ) && textureNode.isPlainGather() === false ) { bindingSnippets.push( `@binding( ${ uniformIndexes.binding ++ } ) @group( ${ uniformIndexes.group } ) var ${ uniform.name }_sampler : sampler_comparison;` ); @@ -81893,8 +82293,8 @@ const typedArraysToVertexFormatPrefix = new Map( [ [ Uint8Array, [ 'uint8', 'unorm8' ]], [ Int16Array, [ 'sint16', 'snorm16' ]], [ Uint16Array, [ 'uint16', 'unorm16' ]], - [ Int32Array, [ 'sint32', 'snorm32' ]], - [ Uint32Array, [ 'uint32', 'unorm32' ]], + [ Int32Array, [ 'sint32' ]], + [ Uint32Array, [ 'uint32' ]], [ Float32Array, [ 'float32', ]], ] ); @@ -81910,9 +82310,7 @@ const typedAttributeToVertexFormatPrefix = new Map( [ const typeArraysToVertexFormatPrefixForItemSize1 = new Map( [ [ Int32Array, 'sint32' ], - [ Int16Array, 'sint32' ], // patch for INT16 [ Uint32Array, 'uint32' ], - [ Uint16Array, 'uint32' ], // patch for UINT16 [ Float32Array, 'float32' ] ] ); @@ -81961,7 +82359,7 @@ class WebGPUAttributeUtils { let array = bufferAttribute.array; // patch for INT16 and UINT16 - if ( attribute.normalized === false ) { + if ( attribute.normalized === false && attribute.isInterleavedBufferAttribute !== true ) { if ( array.constructor === Int16Array || array.constructor === Int8Array ) { @@ -82200,13 +82598,6 @@ class WebGPUAttributeUtils { } - // patch for INT16 and UINT16 - if ( geometryAttribute.normalized === false && ( geometryAttribute.array.constructor === Int16Array || geometryAttribute.array.constructor === Uint16Array ) ) { - - arrayStride = 4; - - } - vertexBufferLayout = { arrayStride, attributes: [], @@ -83030,7 +83421,7 @@ class WebGPUBindingUtils { if ( binding.texture.isDepthTexture ) { - if ( binding.texture.compareFunction !== null && binding.textureNode.compareNode !== null && backend.hasCompatibility( Compatibility.TEXTURE_COMPARE ) ) { + if ( binding.texture.compareFunction !== null && binding.textureNode.isPlainGather() === false && backend.hasCompatibility( Compatibility.TEXTURE_COMPARE ) ) { sampler.type = GPUSamplerBindingType.Comparison; @@ -83585,8 +83976,9 @@ class WebGPUPipelineUtils { * * @param {ComputePipeline} pipeline - The compute pipeline. * @param {Array} bindings - The bindings. + * @param {?Array} [promises=null] - Optional compilation promises. */ - createComputePipeline( pipeline, bindings ) { + createComputePipeline( pipeline, bindings, promises = null ) { const backend = this.backend; const device = backend.device; @@ -83623,23 +84015,87 @@ class WebGPUPipelineUtils { _computePipelineDescriptor.compute = computeProgram; _computePipelineDescriptor.layout = pipelineLayout; - pipelineGPU.pipeline = device.createComputePipeline( _computePipelineDescriptor ); + if ( promises === null ) { - _computePipelineDescriptor.reset(); + pipelineGPU.pipeline = device.createComputePipeline( _computePipelineDescriptor ); - device.popErrorScope().then( ( err ) => { + _computePipelineDescriptor.reset(); - if ( err !== null ) { + device.popErrorScope().then( ( err ) => { - pipelineGPU.error = true; + if ( err !== null ) { - error( `WebGPURenderer: Compute pipeline creation failed (${ pipelineLabel }): ${ err.message }` ); + pipelineGPU.error = true; - this._reportShaderDiagnostics( [ { program: computeStage, module: computeProgram.module } ], pipelineLabel ); + error( `WebGPURenderer: Compute pipeline creation failed (${ pipelineLabel }): ${ err.message }` ); - } + this._reportShaderDiagnostics( [ { program: computeStage, module: computeProgram.module } ], pipelineLabel ); - } ); + } + + } ); + + } else { + + const promise = new Promise( async ( resolve /*, reject*/ ) => { + + try { + + let asyncError = null; + let pipelinePromise = null; + + try { + + pipelinePromise = device.createComputePipelineAsync( _computePipelineDescriptor ); + + } catch ( err ) { + + asyncError = err; + + } + + _computePipelineDescriptor.reset(); + + if ( pipelinePromise !== null ) { + + try { + + pipelineGPU.pipeline = await pipelinePromise; + + } catch ( err ) { + + asyncError = err; + + } + + } + + const errorScope = await device.popErrorScope(); + + if ( errorScope !== null || asyncError !== null ) { + + pipelineGPU.error = true; + + const reason = ( errorScope && errorScope.message ) || ( asyncError && asyncError.message ) || 'unknown'; + error( `WebGPURenderer: Async compute pipeline creation failed (${ pipelineLabel }): ${ reason }` ); + + await this._reportShaderDiagnostics( [ { program: computeStage, module: computeProgram.module } ], pipelineLabel ); + + } + + } finally { + + // Guarantee resolution so `compileComputeAsync`'s Promise.all cannot hang on an + // unexpected throw from any await above. + resolve(); + + } + + } ); + + promises.push( promise ); + + } } @@ -83858,11 +84314,13 @@ class WebGPUPipelineUtils { blendFactor = GPUBlendFactor.SrcAlphaSaturated; break; - case BlendColorFactor: + case ConstantColorFactor: + case ConstantAlphaFactor: // WebGPU has no dedicated constant alpha blend factors blendFactor = GPUBlendFactor.Constant; break; - case OneMinusBlendColorFactor: + case OneMinusConstantColorFactor: + case OneMinusConstantAlphaFactor: // WebGPU has no dedicated constant alpha blend factors blendFactor = GPUBlendFactor.OneMinusConstant; break; @@ -84698,6 +85156,7 @@ class GPURenderPassTimestampWrites { const _clearValue = { r: 0, g: 0, b: 0, a: 1 }; +const _blendConstant = { r: 0, g: 0, b: 0, a: 0 }; const _bufferDescriptor = new GPUBufferDescriptor(); const _commandEncoderDescriptor = new GPUCommandEncoderDescriptor(); const _computePassDescriptor = new GPUComputePassDescriptor(); @@ -84706,6 +85165,7 @@ const _shaderModuleDescriptor = new GPUShaderModuleDescriptor(); const _renderPassTimestampWrites = new GPURenderPassTimestampWrites(); const _texelCopyTextureInfoSrc = new GPUTexelCopyTextureInfo(); const _texelCopyTextureInfoDst = new GPUTexelCopyTextureInfo(); +const _textureDescriptor = new GPUTextureDescriptor(); const _viewDescriptor = new GPUTextureViewDescriptor(); const _extent3D = new GPUExtent3D(); @@ -84973,13 +85433,14 @@ class WebGPUBackend extends Backend { */ setXRRenderTargetTextures( renderTarget, colorTexture, viewDescriptors = null ) { - this.set( renderTarget.texture, { - texture: colorTexture, - format: colorTexture.format, - externalTexture: true, - xrViewDescriptors: viewDescriptors, - initialized: true - } ); + // Update the external XR texture without replacing the cached MSAA attachments. + const textureData = this.get( renderTarget.texture ); + + textureData.texture = colorTexture; + textureData.format = colorTexture.format; + textureData.externalTexture = true; + textureData.xrViewDescriptors = viewDescriptors; + textureData.initialized = true; } @@ -85195,6 +85656,81 @@ class WebGPUBackend extends Backend { } + /** + * Returns multisampled color textures for an external render target. + * + * @private + * @param {RenderContext} renderContext - The render context. + * @param {Object} textureData - The backend data for the external texture. + * @param {number} count - The number of textures to create. + * @return {?Array} The multisampled textures. + */ + _getExternalMSAATextures( renderContext, textureData, count ) { + + const samples = this.utils.getSampleCount( renderContext.sampleCount ); + + if ( samples === 1 ) { + + if ( textureData.msaaTextures !== undefined ) { + + for ( const texture of textureData.msaaTextures ) texture.destroy(); + + textureData.msaaTextures = undefined; + + } + + return null; + + } + + const renderTarget = renderContext.renderTarget; + const width = renderTarget.width; + const height = renderTarget.height; + const format = textureData.format; + + if ( textureData.msaaTextures === undefined || + textureData.msaaTextures.length !== count || + textureData.msaaWidth !== width || + textureData.msaaHeight !== height || + textureData.msaaSamples !== samples || + textureData.msaaFormat !== format ) { + + if ( textureData.msaaTextures !== undefined ) { + + for ( const texture of textureData.msaaTextures ) texture.destroy(); + + } + + _textureDescriptor.size.width = width; + _textureDescriptor.size.height = height; + _textureDescriptor.sampleCount = samples; + _textureDescriptor.format = format; + // Layered rendering can resume after a framebuffer copy, + // so these attachments must support loading. + _textureDescriptor.usage = GPUTextureUsage.RENDER_ATTACHMENT; + + textureData.msaaTextures = []; + + for ( let i = 0; i < count; i ++ ) { + + _textureDescriptor.label = renderTarget.texture.name + '-msaa-' + i; + textureData.msaaTextures.push( this.device.createTexture( _textureDescriptor ) ); + + } + + _textureDescriptor.reset(); + + textureData.msaaWidth = width; + textureData.msaaHeight = height; + textureData.msaaSamples = samples; + textureData.msaaFormat = format; + + } + + return textureData.msaaTextures; + + } + /** * Creates attachment views for an external texture render target. * @@ -85207,14 +85743,19 @@ class WebGPUBackend extends Backend { const textureViews = []; const camera = renderContext.camera; + const viewDescriptors = textureData.xrViewDescriptors; + const viewCount = Math.max( viewDescriptors?.length || 0, renderContext.activeCubeFace + 1, 1 ); + const msaaTextures = this._getExternalMSAATextures( renderContext, textureData, viewCount ); - if ( textureData.xrViewDescriptors && camera !== null && camera.isArrayCamera === true ) { + if ( viewDescriptors && camera !== null && camera.isArrayCamera === true ) { - for ( let i = 0; i < textureData.xrViewDescriptors.length; i ++ ) { + for ( let i = 0; i < viewDescriptors.length; i ++ ) { + + const textureView = textureData.texture.createView( viewDescriptors[ i ] ); textureViews.push( { - view: textureData.texture.createView( textureData.xrViewDescriptors[ i ] ), - resolveTarget: undefined, + view: msaaTextures !== null ? msaaTextures[ i ].createView() : textureView, + resolveTarget: msaaTextures !== null && renderContext.renderTarget.resolveColorBuffer === true ? textureView : undefined, depthSlice: undefined } ); @@ -85222,13 +85763,16 @@ class WebGPUBackend extends Backend { } else { + const layer = renderContext.activeCubeFace; + const textureView = textureData.texture.createView( { + dimension: GPUTextureViewDimension.TwoD, + baseArrayLayer: layer, + arrayLayerCount: 1 + } ); + textureViews.push( { - view: textureData.texture.createView( { - dimension: GPUTextureViewDimension.TwoD, - baseArrayLayer: renderContext.activeCubeFace, - arrayLayerCount: 1 - } ), - resolveTarget: undefined, + view: msaaTextures !== null ? msaaTextures[ layer ].createView() : textureView, + resolveTarget: msaaTextures !== null && renderContext.renderTarget.resolveColorBuffer === true ? textureView : undefined, depthSlice: undefined } ); @@ -85316,9 +85860,10 @@ class WebGPUBackend extends Backend { _viewDescriptor.dimension = GPUTextureViewDimension.TwoD; const textureView = textureData.texture.createView( _viewDescriptor ); + const msaaTexture = textureData.msaaTextures?.[ layer ]; textureViews.push( { - view: textureView, - resolveTarget: undefined, + view: msaaTexture !== undefined ? msaaTexture.createView() : textureView, + resolveTarget: msaaTexture !== undefined && renderTarget.resolveColorBuffer === true ? textureView : undefined, depthSlice: undefined } ); @@ -85343,6 +85888,11 @@ class WebGPUBackend extends Backend { view = textureData.msaaTexture.createView(); resolveTarget = renderTarget.resolveColorBuffer === true ? textureView : undefined; + } else if ( textureData.msaaTextures !== undefined ) { + + view = textureData.msaaTextures[ renderContext.activeCubeFace ].createView(); + resolveTarget = renderTarget.resolveColorBuffer === true ? textureView : undefined; + } else { view = textureView; @@ -85394,7 +85944,8 @@ class WebGPUBackend extends Backend { } const depthStencilAttachment = new GPURenderPassDepthStencilAttachment(); - depthStencilAttachment.view = depthTextureData.texture.createView( _viewDescriptor ); + const msaaDepthTexture = depthTextureData.msaaTextures?.[ renderContext.activeCubeFace ]; + depthStencilAttachment.view = msaaDepthTexture !== undefined ? msaaDepthTexture.createView() : depthTextureData.texture.createView( _viewDescriptor ); descriptorBase.depthStencilAttachment = depthStencilAttachment; _viewDescriptor.reset(); @@ -85518,6 +86069,12 @@ class WebGPUBackend extends Backend { const depthStencilAttachment = descriptor.depthStencilAttachment; const renderTarget = renderContext.renderTarget; + const discardColor = renderContext.sampleCount > 1 && renderTarget?.storeMultisampledColorBuffer === false; + const discardDepth = renderContext.sampleCount > 1 && renderTarget?.storeMultisampledDepthBuffer === false; + const discardStencil = renderContext.sampleCount > 1 && renderTarget?.storeMultisampledStencilBuffer === false; + + // A fullscreen pass overwrites the external texture, so its previous contents do not need to be loaded. + const clearExternalColor = renderContext.fullscreenPass === true && this._hasExternalTexture( renderContext ); if ( renderContext.textures !== null ) { @@ -85527,7 +86084,7 @@ class WebGPUBackend extends Backend { const colorAttachment = colorAttachments[ i ]; - if ( renderContext.clearColor ) { + if ( renderContext.clearColor || discardColor || clearExternalColor ) { if ( i === 0 ) { @@ -85552,7 +86109,7 @@ class WebGPUBackend extends Backend { } - if ( renderContext.sampleCount > 1 && renderTarget?.storeMultisampledColorBuffer === false ) { + if ( discardColor ) { colorAttachment.storeOp = GPUStoreOp.Discard; @@ -85587,7 +86144,7 @@ class WebGPUBackend extends Backend { if ( renderContext.depth ) { - if ( renderContext.clearDepth ) { + if ( renderContext.clearDepth || discardDepth ) { depthStencilAttachment.depthClearValue = renderContext.clearDepthValue; depthStencilAttachment.depthLoadOp = GPULoadOp.Clear; @@ -85598,7 +86155,7 @@ class WebGPUBackend extends Backend { } - if ( renderContext.sampleCount > 1 && renderTarget?.storeMultisampledDepthBuffer === false ) { + if ( discardDepth ) { depthStencilAttachment.depthStoreOp = GPUStoreOp.Discard; @@ -85612,7 +86169,7 @@ class WebGPUBackend extends Backend { if ( renderContext.stencil ) { - if ( renderContext.clearStencil ) { + if ( renderContext.clearStencil || discardStencil ) { depthStencilAttachment.stencilClearValue = renderContext.clearStencilValue; depthStencilAttachment.stencilLoadOp = GPULoadOp.Clear; @@ -85623,7 +86180,7 @@ class WebGPUBackend extends Backend { } - if ( renderContext.sampleCount > 1 && renderTarget?.storeMultisampledStencilBuffer === false ) { + if ( discardStencil ) { depthStencilAttachment.stencilStoreOp = GPUStoreOp.Discard; @@ -85653,40 +86210,22 @@ class WebGPUBackend extends Backend { } else { - this._updateArrayCameraLayerDescriptors( renderContext, renderContextData, cameras ); + this._updateArrayCameraLayerDescriptors( renderContext, renderContextData, descriptor, cameras ); } - // Create bundle encoders for each layer - renderContextData.bundleEncoders = []; - renderContextData.bundleSets = []; - - // Create separate bundle encoders for each camera in the array - for ( let i = 0; i < cameras.length; i ++ ) { - - const bundleEncoder = this.pipelineUtils.createBundleEncoder( - renderContext, - 'renderBundleArrayCamera_' + i - ); - - // Initialize state tracking for this bundle - const bundleSets = { - attributes: {}, - bindingGroups: [], - pipeline: null, - index: null - }; - - renderContextData.bundleEncoders.push( bundleEncoder ); - renderContextData.bundleSets.push( bundleSets ); - - } + this._createArrayCameraBundleEncoders( renderContext, renderContextData ); + renderContextData.arrayCameraRenderStages = []; // We'll complete the bundles in finishRender renderContextData.currentPass = null; } else { + renderContextData.bundleEncoders = undefined; + renderContextData.bundleSets = undefined; + renderContextData.arrayCameraRenderStages = undefined; + const currentPass = encoder.beginRenderPass( descriptor ); renderContextData.currentPass = currentPass; @@ -85708,9 +86247,87 @@ class WebGPUBackend extends Backend { renderContextData.descriptor = descriptor; renderContextData.encoder = encoder; - renderContextData.currentSets = { attributes: {}, bindingGroups: [], pipeline: null, index: null }; renderContextData.renderBundles = []; + this._resetRenderContextData( renderContextData ); + + } + + /** + * Resets the state cache of the given render context data. + * + * A new render pass encoder starts with a blend constant and a stencil reference + * of zero so the cached values must be reset as well. + * + * @private + * @param {Object} renderContextData - The render context data. + */ + _resetRenderContextData( renderContextData ) { + + renderContextData.currentSets = { attributes: {}, bindingGroups: [], pipeline: null, index: null }; + + if ( renderContextData.currentBlendColor === undefined ) renderContextData.currentBlendColor = new Color(); + + renderContextData.currentBlendColor.setRGB( 0, 0, 0 ); + renderContextData.currentBlendAlpha = 0; + renderContextData.currentStencilRef = 0; + + } + + /** + * Creates a render bundle encoder and state cache for each camera layer. + * + * @param {RenderContext} renderContext - The render context. + * @param {Object} renderContextData - The render context data. + * @private + */ + _createArrayCameraBundleEncoders( renderContext, renderContextData ) { + + const cameras = renderContext.camera.cameras; + + renderContextData.bundleEncoders = []; + renderContextData.bundleSets = []; + + for ( let i = 0; i < cameras.length; i ++ ) { + + const bundleEncoder = this.pipelineUtils.createBundleEncoder( + renderContext, + 'renderBundleArrayCamera_' + i + ); + + const bundleSets = { + attributes: {}, + bindingGroups: [], + pipeline: null, + index: null + }; + + renderContextData.bundleEncoders.push( bundleEncoder ); + renderContextData.bundleSets.push( bundleSets ); + + } + + } + + /** + * Finishes the render bundle encoders for all camera layers. + * + * @param {Object} renderContextData - The render context data. + * @return {Array} The completed render bundles. + * @private + */ + _finishArrayCameraBundleEncoders( renderContextData ) { + + const bundles = []; + + for ( const bundleEncoder of renderContextData.bundleEncoders ) { + + bundles.push( bundleEncoder.finish() ); + + } + + return bundles; + } /** @@ -85738,11 +86355,12 @@ class WebGPUBackend extends Backend { for ( let i = 0; i < cameras.length; i ++ ) { const sourceAttachment = descriptor.colorAttachments[ 0 ]; + const layerAttachment = descriptor.colorAttachments[ i ]; const layerColorAttachment = new GPURenderPassColorAttachment(); - layerColorAttachment.view = descriptor.colorAttachments[ i ].view; - layerColorAttachment.depthSlice = sourceAttachment.depthSlice; - layerColorAttachment.resolveTarget = sourceAttachment.resolveTarget; + layerColorAttachment.view = layerAttachment.view; + layerColorAttachment.depthSlice = layerAttachment.depthSlice; + layerColorAttachment.resolveTarget = layerAttachment.resolveTarget; layerColorAttachment.loadOp = sourceAttachment.loadOp; layerColorAttachment.storeOp = sourceAttachment.storeOp; layerColorAttachment.clearValue = sourceAttachment.clearValue; @@ -85759,11 +86377,21 @@ class WebGPUBackend extends Backend { if ( ! depthTextureData.viewCache[ layerIndex ] ) { - _viewDescriptor.dimension = GPUTextureViewDimension.TwoD; - _viewDescriptor.baseArrayLayer = i; - _viewDescriptor.arrayLayerCount = 1; + const msaaTexture = depthTextureData.msaaTextures?.[ layerIndex ]; - depthTextureData.viewCache[ layerIndex ] = depthTextureData.texture.createView( _viewDescriptor ); + if ( msaaTexture !== undefined ) { + + depthTextureData.viewCache[ layerIndex ] = msaaTexture.createView(); + + } else { + + _viewDescriptor.dimension = GPUTextureViewDimension.TwoD; + _viewDescriptor.baseArrayLayer = i; + _viewDescriptor.arrayLayerCount = 1; + + depthTextureData.viewCache[ layerIndex ] = depthTextureData.texture.createView( _viewDescriptor ); + + } _viewDescriptor.reset(); @@ -85812,14 +86440,29 @@ class WebGPUBackend extends Backend { * * @param {RenderContext} renderContext - The render context. * @param {Object} renderContextData - The render context data. + * @param {Object} descriptor - The render pass descriptor. * @param {ArrayCamera} cameras - The array camera. * */ - _updateArrayCameraLayerDescriptors( renderContext, renderContextData, cameras ) { + _updateArrayCameraLayerDescriptors( renderContext, renderContextData, descriptor, cameras ) { + + const renderTarget = renderContext.renderTarget; + const discardDepth = renderContext.sampleCount > 1 && renderTarget?.storeMultisampledDepthBuffer === false; + const discardStencil = renderContext.sampleCount > 1 && renderTarget?.storeMultisampledStencilBuffer === false; for ( let i = 0; i < cameras.length; i ++ ) { const layerDescriptor = renderContextData.layerDescriptors[ i ]; + const sourceColorAttachment = descriptor.colorAttachments[ 0 ]; + const layerColorAttachment = descriptor.colorAttachments[ i ]; + const colorAttachment = layerDescriptor.colorAttachments[ 0 ]; + + colorAttachment.view = layerColorAttachment.view; + colorAttachment.resolveTarget = layerColorAttachment.resolveTarget; + colorAttachment.depthSlice = layerColorAttachment.depthSlice; + colorAttachment.loadOp = sourceColorAttachment.loadOp; + colorAttachment.storeOp = sourceColorAttachment.storeOp; + colorAttachment.clearValue = sourceColorAttachment.clearValue; if ( layerDescriptor.depthStencilAttachment ) { @@ -85827,7 +86470,7 @@ class WebGPUBackend extends Backend { if ( renderContext.depth ) { - if ( renderContext.clearDepth ) { + if ( renderContext.clearDepth || discardDepth ) { depthAttachment.depthClearValue = renderContext.clearDepthValue; depthAttachment.depthLoadOp = GPULoadOp.Clear; @@ -85842,7 +86485,7 @@ class WebGPUBackend extends Backend { if ( renderContext.stencil ) { - if ( renderContext.clearStencil ) { + if ( renderContext.clearStencil || discardStencil ) { depthAttachment.stencilClearValue = renderContext.clearStencilValue; depthAttachment.stencilLoadOp = GPULoadOp.Clear; @@ -85892,20 +86535,49 @@ class WebGPUBackend extends Backend { if ( this._isRenderCameraDepthArray( renderContext ) === true ) { - const bundles = []; + const bundles = this._finishArrayCameraBundleEncoders( renderContextData ); + const renderStages = renderContextData.arrayCameraRenderStages; + renderStages.push( { bundles } ); - for ( let i = 0; i < renderContextData.bundleEncoders.length; i ++ ) { + // A viewport texture is 2D, so each layer must be captured immediately before that layer samples it. + for ( let i = 0; i < renderContextData.layerDescriptors.length; i ++ ) { - const bundleEncoder = renderContextData.bundleEncoders[ i ]; - bundles.push( bundleEncoder.finish() ); + const layerDescriptor = renderContextData.layerDescriptors[ i ]; + const colorLoadOps = layerDescriptor.colorAttachments.map( attachment => attachment.loadOp ); + const colorStoreOps = layerDescriptor.colorAttachments.map( attachment => attachment.storeOp ); + const depthLoadOp = layerDescriptor.depthStencilAttachment?.depthLoadOp; + const depthStoreOp = layerDescriptor.depthStencilAttachment?.depthStoreOp; + const stencilLoadOp = layerDescriptor.depthStencilAttachment?.stencilLoadOp; + const stencilStoreOp = layerDescriptor.depthStencilAttachment?.stencilStoreOp; - } + for ( let stageIndex = 0; stageIndex < renderStages.length; stageIndex ++ ) { + + const renderStage = renderStages[ stageIndex ]; + const bundle = renderStage.bundles[ i ]; + const isLastStage = stageIndex === renderStages.length - 1; + + for ( let j = 0; j < layerDescriptor.colorAttachments.length; j ++ ) { + + const attachment = layerDescriptor.colorAttachments[ j ]; + attachment.loadOp = stageIndex === 0 ? colorLoadOps[ j ] : GPULoadOp.Load; + attachment.storeOp = isLastStage ? colorStoreOps[ j ] : GPUStoreOp.Store; + + } + + if ( renderContext.depth ) { - for ( let i = 0; i < renderContextData.layerDescriptors.length; i ++ ) { + layerDescriptor.depthStencilAttachment.depthLoadOp = stageIndex === 0 ? depthLoadOp : GPULoadOp.Load; + layerDescriptor.depthStencilAttachment.depthStoreOp = isLastStage ? depthStoreOp : GPUStoreOp.Store; + + } - if ( i < bundles.length ) { + if ( renderContext.stencil ) { + + layerDescriptor.depthStencilAttachment.stencilLoadOp = stageIndex === 0 ? stencilLoadOp : GPULoadOp.Load; + layerDescriptor.depthStencilAttachment.stencilStoreOp = isLastStage ? stencilStoreOp : GPUStoreOp.Store; + + } - const layerDescriptor = renderContextData.layerDescriptors[ i ]; const renderPass = encoder.beginRenderPass( layerDescriptor ); if ( renderContext.viewport ) { @@ -85922,10 +86594,39 @@ class WebGPUBackend extends Backend { } - renderPass.executeBundles( [ bundles[ i ] ] ); + renderPass.executeBundles( [ bundle ] ); renderPass.end(); + if ( renderStage.framebufferCopy !== undefined ) { + + const { texture, sourceGPU, destinationGPU, rectangle, generateMipmaps } = renderStage.framebufferCopy; + + this._copyFramebufferToTexture( encoder, texture, sourceGPU, destinationGPU, rectangle, i, generateMipmaps ); + + } + + } + + for ( let j = 0; j < layerDescriptor.colorAttachments.length; j ++ ) { + + layerDescriptor.colorAttachments[ j ].loadOp = colorLoadOps[ j ]; + layerDescriptor.colorAttachments[ j ].storeOp = colorStoreOps[ j ]; + + } + + if ( renderContext.depth ) { + + layerDescriptor.depthStencilAttachment.depthLoadOp = depthLoadOp; + layerDescriptor.depthStencilAttachment.depthStoreOp = depthStoreOp; + + } + + if ( renderContext.stencil ) { + + layerDescriptor.depthStencilAttachment.stencilLoadOp = stencilLoadOp; + layerDescriptor.depthStencilAttachment.stencilStoreOp = stencilStoreOp; + } } @@ -86508,6 +87209,29 @@ class WebGPUBackend extends Backend { } + // blend constant + + if ( material.blending === CustomBlending && passEncoderGPU.setBlendConstant !== undefined ) { + + const blendColor = material.blendColor; + const blendAlpha = material.blendAlpha; + + if ( blendColor.equals( renderContextData.currentBlendColor ) === false || blendAlpha !== renderContextData.currentBlendAlpha ) { + + _blendConstant.r = blendColor.r; + _blendConstant.g = blendColor.g; + _blendConstant.b = blendColor.b; + _blendConstant.a = blendAlpha; + + passEncoderGPU.setBlendConstant( _blendConstant ); + + renderContextData.currentBlendColor.copy( blendColor ); + renderContextData.currentBlendAlpha = blendAlpha; + + } + + } + if ( object.isBatchedMesh === true ) { const starts = object._multiDrawStarts; @@ -86941,7 +87665,7 @@ class WebGPUBackend extends Backend { * @param {number} y - The y coordinate of the copy origin. * @param {number} width - The width of the copy. * @param {number} height - The height of the copy. - * @param {number} faceIndex - The face index. + * @param {number} faceIndex - The cube face, depth slice or array layer index. * @return {Promise} A Promise that resolves with a typed array when the copy operation has finished. */ async copyTextureToBuffer( texture, x, y, width, height, faceIndex ) { @@ -87049,10 +87773,11 @@ class WebGPUBackend extends Backend { * * @param {ComputePipeline} computePipeline - The compute pipeline. * @param {Array} bindings - The bindings. + * @param {?Array} [promises=null] - Optional compilation promises. */ - createComputePipeline( computePipeline, bindings ) { + createComputePipeline( computePipeline, bindings, promises = null ) { - this.pipelineUtils.createComputePipeline( computePipeline, bindings ); + this.pipelineUtils.createComputePipeline( computePipeline, bindings, promises ); } @@ -87482,6 +88207,29 @@ class WebGPUBackend extends Backend { } + if ( this._isRenderCameraDepthArray( renderContext ) === true ) { + + // Layered draws are only executed in finishRender(), so preserve this copy as a render-stage boundary. + const bundles = this._finishArrayCameraBundleEncoders( renderContextData ); + + renderContextData.arrayCameraRenderStages.push( { + bundles, + framebufferCopy: { + texture, + sourceGPU, + destinationGPU, + rectangle: { x: rectangle.x, y: rectangle.y, z: rectangle.z, w: rectangle.w }, + // ViewportTextureNode restores this flag before the deferred copy executes. + generateMipmaps: texture.generateMipmaps + } + } ); + + this._createArrayCameraBundleEncoders( renderContext, renderContextData ); + + return; + + } + let encoder; if ( renderContextData.currentPass ) { @@ -87498,33 +88246,10 @@ class WebGPUBackend extends Backend { } - _texelCopyTextureInfoSrc.texture = sourceGPU; - _texelCopyTextureInfoSrc.origin.x = rectangle.x; - _texelCopyTextureInfoSrc.origin.y = rectangle.y; - - _texelCopyTextureInfoDst.texture = destinationGPU; - - _extent3D.width = rectangle.z; - _extent3D.height = rectangle.w; - - encoder.copyTextureToTexture( - _texelCopyTextureInfoSrc, - _texelCopyTextureInfoDst, - _extent3D - ); - - _texelCopyTextureInfoSrc.reset(); - _texelCopyTextureInfoDst.reset(); - _extent3D.reset(); - // mipmaps must be genereated with the same encoder otherwise the copied texture data // might be out-of-sync, see #31768 - if ( texture.generateMipmaps ) { - - this.textureUtils.generateMipmaps( texture, encoder ); - - } + this._copyFramebufferToTexture( encoder, texture, sourceGPU, destinationGPU, rectangle ); if ( renderContextData.currentPass ) { @@ -87540,7 +88265,8 @@ class WebGPUBackend extends Backend { if ( renderContext.stencil ) descriptor.depthStencilAttachment.stencilLoadOp = GPULoadOp.Load; renderContextData.currentPass = encoder.beginRenderPass( descriptor ); - renderContextData.currentSets = { attributes: {}, bindingGroups: [], pipeline: null, index: null }; + + this._resetRenderContextData( renderContextData ); if ( renderContext.viewport ) { @@ -87562,6 +88288,48 @@ class WebGPUBackend extends Backend { } + /** + * Encodes a framebuffer copy from a specific texture-array layer. + * + * @param {GPUCommandEncoder} encoder - The command encoder. + * @param {Texture} texture - The destination texture. + * @param {GPUTexture} sourceGPU - The source GPU texture. + * @param {GPUTexture} destinationGPU - The destination GPU texture. + * @param {Object} rectangle - The source rectangle. + * @param {number} [sourceLayer=0] - The source array layer. + * @param {boolean} [generateMipmaps=texture.generateMipmaps] - Whether mipmaps should be generated. + * @private + */ + _copyFramebufferToTexture( encoder, texture, sourceGPU, destinationGPU, rectangle, sourceLayer = 0, generateMipmaps = texture.generateMipmaps ) { + + _texelCopyTextureInfoSrc.texture = sourceGPU; + _texelCopyTextureInfoSrc.origin.x = rectangle.x; + _texelCopyTextureInfoSrc.origin.y = rectangle.y; + _texelCopyTextureInfoSrc.origin.z = sourceLayer; + + _texelCopyTextureInfoDst.texture = destinationGPU; + + _extent3D.width = rectangle.z; + _extent3D.height = rectangle.w; + + encoder.copyTextureToTexture( + _texelCopyTextureInfoSrc, + _texelCopyTextureInfoDst, + _extent3D + ); + + _texelCopyTextureInfoSrc.reset(); + _texelCopyTextureInfoDst.reset(); + _extent3D.reset(); + + if ( generateMipmaps ) { + + this.textureUtils.generateMipmaps( texture, encoder ); + + } + + } + /** * Checks if the given compatibility is supported by the backend. * @@ -89145,4 +89913,4 @@ class ClippingGroup extends Group { } -export { ACESFilmicToneMapping, AONode, AddEquation, AddOperation, AdditiveBlending, AgXToneMapping, AlphaFormat, AlwaysCompare, AlwaysDepth, AlwaysStencilFunc, AmbientLight, AmbientLightNode, AnalyticLightNode, ArrayCamera, ArrayElementNode, ArrayNode, AssignNode, AtomicFunctionNode, AttributeNode, BackSide, Backend, BarrierNode, BasicEnvironmentNode, BasicLightMapNode, BasicNodeLibrary, BasicShadowMap, BitcastNode, BitcountNode, BlendMode, BoxGeometry, BufferAttribute, BufferAttributeNode, BufferGeometry, BufferNode, BuiltinNode, BumpMapNode, BundleGroup, BypassNode, ByteType, CanvasTarget, CineonToneMapping, ClampToEdgeWrapping, ClippingGroup, ClippingNode, CodeNode, Color, ColorManagement, ColorSpaceNode, Compatibility, ComputeBuiltinNode, ComputeNode, ConditionalNode, ConstNode, ContextNode, ConvertNode, CubeCamera, CubeDepthTexture, CubeMapNode, CubeReflectionMapping, CubeRefractionMapping, CubeRenderTarget, CubeTexture, CubeTextureNode, CubeUVReflectionMapping, CullFaceBack, CullFaceFront, CullFaceNone, CustomBlending, CylinderGeometry, DataArrayTexture, DataTexture, DebugNode, DecrementStencilOp, DecrementWrapStencilOp, DepthFormat, DepthStencilFormat, DepthTexture, DirectionalLight, DirectionalLightNode, DoubleSide, DstAlphaFactor, DstColorFactor, DynamicDrawUsage, EnvironmentNode, EqualCompare, EqualDepth, EqualStencilFunc, EquirectangularReflectionMapping, EquirectangularRefractionMapping, EventDispatcher, EventNode, ExpressionNode, FileLoader, FlipNode, Float16BufferAttribute, Float32BufferAttribute, FloatType, FramebufferTexture, FrontFacingNode, FrontSide, Frustum, FrustumArray, FunctionCallNode, FunctionNode, FunctionOverloadingNode, GLSLNodeBuilder, GLSLNodeParser, GreaterCompare, GreaterDepth, GreaterEqualCompare, GreaterEqualDepth, GreaterEqualStencilFunc, GreaterStencilFunc, Group, HalfFloatType, HemisphereLight, HemisphereLightNode, IESSpotLight, IESSpotLightNode, IncrementStencilOp, IncrementWrapStencilOp, IndexNode, IndirectStorageBufferAttribute, InputNode, InspectorBase, InspectorNode, InstancedBufferAttribute, InstancedInterleavedBuffer, IntType, InterleavedBuffer, InterleavedBufferAttribute, InvertStencilOp, IrradianceNode, IsolateNode, JoinNode, KeepStencilOp, LessCompare, LessDepth, LessEqualCompare, LessEqualDepth, LessEqualStencilFunc, LessStencilFunc, LightProbe, LightProbeNode, Lighting, LightingContextNode, LightingModel, LightingNode, LightsNode, Line2NodeMaterial, LineBasicMaterial, LineBasicNodeMaterial, LineDashedMaterial, LineDashedNodeMaterial, LinearFilter, LinearMipMapLinearFilter, LinearMipmapLinearFilter, LinearMipmapNearestFilter, LinearSRGBColorSpace, LinearToneMapping, LinearTransfer, Loader, LoopNode, MRTNode, Material, MaterialBlending, MaterialLoader, MaterialNode, MaterialReferenceNode, MathNode, MathUtils, Matrix2, Matrix3, Matrix4, MaxEquation, MaxMipLevelNode, MemberNode, Mesh, MeshBasicMaterial, MeshBasicNodeMaterial, MeshLambertMaterial, MeshLambertNodeMaterial, MeshMatcapMaterial, MeshMatcapNodeMaterial, MeshNormalMaterial, MeshNormalNodeMaterial, MeshPhongMaterial, MeshPhongNodeMaterial, MeshPhysicalMaterial, MeshPhysicalNodeMaterial, MeshSSSNodeMaterial, MeshStandardMaterial, MeshStandardNodeMaterial, MeshToonMaterial, MeshToonNodeMaterial, MinEquation, MirroredRepeatWrapping, MixOperation, ModelNode, MultiplyBlending, MultiplyOperation, NearestFilter, NearestMipmapLinearFilter, NearestMipmapNearestFilter, NeutralToneMapping, NeverCompare, NeverDepth, NeverStencilFunc, NoBlending, NoColorSpace, NoNormalPacking, NoToneMapping, Node, NodeAccess, NodeAttribute, NodeBuilder, NodeCache, NodeCode, NodeError, NodeFrame, NodeFunctionInput, NodeLoader, NodeMaterial, NodeMaterialLoader, NodeMaterialObserver, NodeObjectLoader, NodeShaderStage, NodeType, NodeUniform, NodeUpdateType, NodeUtils, NodeVar, NodeVarying, NormalBlending, NormalGAPacking, NormalMapNode, NormalRGPacking, NotEqualCompare, NotEqualDepth, NotEqualStencilFunc, Object3D, Object3DNode, ObjectLoader, ObjectSpaceNormalMap, OneFactor, OneMinusDstAlphaFactor, OneMinusDstColorFactor, OneMinusSrcAlphaFactor, OneMinusSrcColorFactor, OperatorNode, OrthographicCamera, OutputStructNode, OverrideContextNode, PCFShadowMap, PCFSoftShadowMap, PMREMGenerator, PMREMNode, PackFloatNode, ParameterNode, PassNode, PerspectiveCamera, PhongLightingModel, PhysicalLightingModel, Plane, PlaneGeometry, PointLight, PointLightNode, PointShadowNode, PointUVNode, PointsMaterial, PointsNodeMaterial, PostProcessing, ProjectorLight, ProjectorLightNode, PropertyNode, QuadMesh, Quaternion, R11_EAC_Format, RED_GREEN_RGTC2_Format, RED_RGTC1_Format, REVISION, RG11_EAC_Format, RGBAFormat, RGBAIntegerFormat, RGBA_ASTC_10x10_Format, RGBA_ASTC_10x5_Format, RGBA_ASTC_10x6_Format, RGBA_ASTC_10x8_Format, RGBA_ASTC_12x10_Format, RGBA_ASTC_12x12_Format, RGBA_ASTC_4x4_Format, RGBA_ASTC_5x4_Format, RGBA_ASTC_5x5_Format, RGBA_ASTC_6x5_Format, RGBA_ASTC_6x6_Format, RGBA_ASTC_8x5_Format, RGBA_ASTC_8x6_Format, RGBA_ASTC_8x8_Format, RGBA_BPTC_Format, RGBA_ETC2_EAC_Format, RGBA_PVRTC_2BPPV1_Format, RGBA_PVRTC_4BPPV1_Format, RGBA_S3TC_DXT1_Format, RGBA_S3TC_DXT3_Format, RGBA_S3TC_DXT5_Format, RGBFormat, RGBIntegerFormat, RGB_BPTC_SIGNED_Format, RGB_BPTC_UNSIGNED_Format, RGB_ETC1_Format, RGB_ETC2_Format, RGB_PVRTC_2BPPV1_Format, RGB_PVRTC_4BPPV1_Format, RGB_S3TC_DXT1_Format, RGFormat, RGIntegerFormat, RTTNode, RangeNode, ReadbackBuffer, RectAreaLight, RectAreaLightNode, RedFormat, RedIntegerFormat, ReferenceBaseNode, ReferenceNode, ReflectorNode, ReinhardToneMapping, RenderOutputNode, RenderPipeline, RenderTarget, Renderer, RendererReferenceNode, RendererUtils, RepeatWrapping, ReplaceStencilOp, ReverseSubtractEquation, RotateNode, SIGNED_R11_EAC_Format, SIGNED_RED_GREEN_RGTC2_Format, SIGNED_RED_RGTC1_Format, SIGNED_RG11_EAC_Format, SRGBColorSpace, SRGBTransfer, SampleNode, Scene, ScreenNode, SetNode, ShadowBaseNode, ShadowMaterial, ShadowNode, ShadowNodeMaterial, ShortType, Sphere, SphereGeometry, SplitNode, SpotLight, SpotLightNode, SpriteMaterial, SpriteNodeMaterial, SrcAlphaFactor, SrcAlphaSaturateFactor, SrcColorFactor, StackNode, StackTrace, StandardNodeLibrary, StaticDrawUsage, Storage3DTexture, StorageArrayElementNode, StorageArrayTexture, StorageBufferAttribute, StorageBufferNode, StorageInstancedBufferAttribute, StorageTexture, StorageTexture3DNode, StorageTextureNode, StructNode, StructTypeNode, SubBuildNode, SubgroupFunctionNode, SubtractEquation, SubtractiveBlending, TSL, TangentSpaceNormalMap, TempNode, Texture, Texture3DNode, TextureNode, TextureSizeNode, TimestampQuery, ToneMappingNode, ToonOutlinePassNode, UVMapping, Uint16BufferAttribute, Uint32BufferAttribute, UniformArrayNode, UniformGroupNode, UniformNode, UnpackFloatNode, UnsignedByteType, UnsignedInt101111Type, UnsignedInt248Type, UnsignedInt5999Type, UnsignedIntType, UnsignedShort4444Type, UnsignedShort5551Type, UnsignedShortType, UserDataNode, VSMShadowMap, VarNode, VaryingNode, Vector2, Vector3, Vector4, VelocityNode, VertexColorNode, ViewportDepthNode, ViewportDepthTextureNode, ViewportSharedTextureNode, ViewportTextureNode, VolumeNodeMaterial, WGSLNodeBuilder, WebGLBackend, WebGLCapabilities, WebGLCoordinateSystem, WebGPUBackend, WebGPUCoordinateSystem, WebGPURenderer, WebXRController, WorkgroupInfoNode, ZeroFactor, ZeroStencilOp, createCanvasElement, defaultBuildStages, defaultShaderStages, error, log$1 as log, shaderStages, vectorComponents, warn, warnOnce }; +export { ACESFilmicToneMapping, AONode, AddEquation, AddOperation, AdditiveBlending, AgXToneMapping, AlphaFormat, AlwaysCompare, AlwaysDepth, AlwaysStencilFunc, AmbientLight, AmbientLightNode, AnalyticLightNode, ArrayCamera, ArrayElementNode, ArrayNode, AssignNode, AtomicFunctionNode, AttributeNode, BackSide, Backend, BarrierNode, BasicEnvironmentNode, BasicLightMapNode, BasicNodeLibrary, BasicShadowMap, BitcastNode, BitcountNode, BlendMode, BoxGeometry, BufferAttribute, BufferAttributeNode, BufferGeometry, BufferNode, BuiltinNode, BumpMapNode, BundleGroup, BypassNode, ByteType, CanvasTarget, CineonToneMapping, ClampToEdgeWrapping, ClippingGroup, ClippingNode, CodeNode, Color, ColorManagement, ColorSpaceNode, Compatibility, ComputeBuiltinNode, ComputeNode, ConditionalNode, ConstNode, ConstantAlphaFactor, ConstantColorFactor, ContextNode, ConvertNode, CubeCamera, CubeDepthTexture, CubeMapNode, CubeReflectionMapping, CubeRefractionMapping, CubeRenderTarget, CubeTexture, CubeTextureNode, CubeUVReflectionMapping, CullFaceBack, CullFaceFront, CullFaceNone, CustomBlending, CylinderGeometry, DataArrayTexture, DataTexture, DebugNode, DecrementStencilOp, DecrementWrapStencilOp, DepthFormat, DepthStencilFormat, DepthTexture, DirectionalLight, DirectionalLightNode, DoubleSide, DstAlphaFactor, DstColorFactor, DynamicDrawUsage, EnvironmentNode, EqualCompare, EqualDepth, EqualStencilFunc, EquirectangularReflectionMapping, EquirectangularRefractionMapping, EventDispatcher, EventNode, ExpressionNode, FileLoader, FlipNode, Float16BufferAttribute, Float32BufferAttribute, FloatType, FramebufferTexture, FrontFacingNode, FrontSide, Frustum, FrustumArray, FunctionCallNode, FunctionNode, FunctionOverloadingNode, GLSLNodeBuilder, GLSLNodeParser, GreaterCompare, GreaterDepth, GreaterEqualCompare, GreaterEqualDepth, GreaterEqualStencilFunc, GreaterStencilFunc, Group, HalfFloatType, HemisphereLight, HemisphereLightNode, IESSpotLight, IESSpotLightNode, IncrementStencilOp, IncrementWrapStencilOp, IndexNode, IndirectStorageBufferAttribute, InputNode, InspectorBase, InspectorNode, InstancedBufferAttribute, InstancedInterleavedBuffer, IntType, InterleavedBuffer, InterleavedBufferAttribute, InvertStencilOp, IrradianceNode, IsolateNode, JoinNode, KeepStencilOp, LessCompare, LessDepth, LessEqualCompare, LessEqualDepth, LessEqualStencilFunc, LessStencilFunc, LightProbe, LightProbeNode, Lighting, LightingContextNode, LightingModel, LightingNode, LightsNode, Line2NodeMaterial, LineBasicMaterial, LineBasicNodeMaterial, LineDashedMaterial, LineDashedNodeMaterial, LinearFilter, LinearMipMapLinearFilter, LinearMipmapLinearFilter, LinearMipmapNearestFilter, LinearSRGBColorSpace, LinearToneMapping, LinearTransfer, Loader, LoopNode, MRTNode, Material, MaterialBlending, MaterialLoader, MaterialNode, MaterialReferenceNode, MathNode, MathUtils, Matrix2, Matrix3, Matrix4, MaxEquation, MaxMipLevelNode, MemberNode, Mesh, MeshBasicMaterial, MeshBasicNodeMaterial, MeshLambertMaterial, MeshLambertNodeMaterial, MeshMatcapMaterial, MeshMatcapNodeMaterial, MeshNormalMaterial, MeshNormalNodeMaterial, MeshPhongMaterial, MeshPhongNodeMaterial, MeshPhysicalMaterial, MeshPhysicalNodeMaterial, MeshSSSNodeMaterial, MeshStandardMaterial, MeshStandardNodeMaterial, MeshToonMaterial, MeshToonNodeMaterial, MinEquation, MirroredRepeatWrapping, MixOperation, ModelNode, MultiplyBlending, MultiplyOperation, NearestFilter, NearestMipmapLinearFilter, NearestMipmapNearestFilter, NeutralToneMapping, NeverCompare, NeverDepth, NeverStencilFunc, NoBlending, NoColorSpace, NoNormalPacking, NoToneMapping, Node, NodeAccess, NodeAttribute, NodeBuilder, NodeCache, NodeCode, NodeError, NodeFrame, NodeFunctionInput, NodeLoader, NodeMaterial, NodeMaterialLoader, NodeMaterialObserver, NodeObjectLoader, NodeShaderStage, NodeType, NodeUniform, NodeUpdateType, NodeUtils, NodeVar, NodeVarying, NormalBlending, NormalGAPacking, NormalMapNode, NormalRGPacking, NotEqualCompare, NotEqualDepth, NotEqualStencilFunc, Object3D, Object3DNode, ObjectLoader, ObjectSpaceNormalMap, OneFactor, OneMinusConstantAlphaFactor, OneMinusConstantColorFactor, OneMinusDstAlphaFactor, OneMinusDstColorFactor, OneMinusSrcAlphaFactor, OneMinusSrcColorFactor, OperatorNode, OrthographicCamera, OutputStructNode, OverrideContextNode, PCFShadowMap, PCFSoftShadowMap, PMREMGenerator, PMREMNode, PackFloatNode, ParameterNode, PassNode, PerspectiveCamera, PhongLightingModel, PhysicalLightingModel, Plane, PlaneGeometry, PointLight, PointLightNode, PointShadowNode, PointUVNode, PointsMaterial, PointsNodeMaterial, PostProcessing, ProjectorLight, ProjectorLightNode, PropertyNode, QuadMesh, Quaternion, R11_EAC_Format, RED_GREEN_RGTC2_Format, RED_RGTC1_Format, REVISION, RG11_EAC_Format, RGBAFormat, RGBAIntegerFormat, RGBA_ASTC_10x10_Format, RGBA_ASTC_10x5_Format, RGBA_ASTC_10x6_Format, RGBA_ASTC_10x8_Format, RGBA_ASTC_12x10_Format, RGBA_ASTC_12x12_Format, RGBA_ASTC_4x4_Format, RGBA_ASTC_5x4_Format, RGBA_ASTC_5x5_Format, RGBA_ASTC_6x5_Format, RGBA_ASTC_6x6_Format, RGBA_ASTC_8x5_Format, RGBA_ASTC_8x6_Format, RGBA_ASTC_8x8_Format, RGBA_BPTC_Format, RGBA_ETC2_EAC_Format, RGBA_PVRTC_2BPPV1_Format, RGBA_PVRTC_4BPPV1_Format, RGBA_S3TC_DXT1_Format, RGBA_S3TC_DXT3_Format, RGBA_S3TC_DXT5_Format, RGBFormat, RGBIntegerFormat, RGB_BPTC_SIGNED_Format, RGB_BPTC_UNSIGNED_Format, RGB_ETC1_Format, RGB_ETC2_Format, RGB_PVRTC_2BPPV1_Format, RGB_PVRTC_4BPPV1_Format, RGB_S3TC_DXT1_Format, RGFormat, RGIntegerFormat, RTTNode, RangeNode, ReadbackBuffer, RectAreaLight, RectAreaLightNode, RedFormat, RedIntegerFormat, ReferenceBaseNode, ReferenceNode, ReflectorNode, ReinhardToneMapping, RenderOutputNode, RenderPipeline, RenderTarget, Renderer, RendererReferenceNode, RendererUtils, RepeatWrapping, ReplaceStencilOp, ReverseSubtractEquation, RotateNode, SIGNED_R11_EAC_Format, SIGNED_RED_GREEN_RGTC2_Format, SIGNED_RED_RGTC1_Format, SIGNED_RG11_EAC_Format, SRGBColorSpace, SRGBTransfer, SampleNode, Scene, ScreenNode, SetNode, ShadowBaseNode, ShadowMaterial, ShadowNode, ShadowNodeMaterial, ShortType, Sphere, SphereGeometry, SplitNode, SpotLight, SpotLightNode, SpriteMaterial, SpriteNodeMaterial, SrcAlphaFactor, SrcAlphaSaturateFactor, SrcColorFactor, StackNode, StackTrace, StandardNodeLibrary, StaticDrawUsage, Storage3DTexture, StorageArrayElementNode, StorageArrayTexture, StorageBufferAttribute, StorageBufferNode, StorageInstancedBufferAttribute, StorageTexture, StorageTexture3DNode, StorageTextureNode, StructNode, StructTypeNode, SubBuildNode, SubgroupFunctionNode, SubtractEquation, SubtractiveBlending, TSL, TangentSpaceNormalMap, TempNode, Texture, Texture3DNode, TextureNode, TextureSizeNode, TimestampQuery, ToneMappingNode, ToonOutlinePassNode, UVMapping, Uint16BufferAttribute, Uint32BufferAttribute, UniformArrayNode, UniformGroupNode, UniformNode, UnpackFloatNode, UnsignedByteType, UnsignedInt101111Type, UnsignedInt248Type, UnsignedInt5999Type, UnsignedIntType, UnsignedShort4444Type, UnsignedShort5551Type, UnsignedShortType, UserDataNode, VSMShadowMap, VarNode, VaryingNode, Vector2, Vector3, Vector4, VelocityNode, VertexColorNode, ViewportDepthNode, ViewportDepthTextureNode, ViewportSharedTextureNode, ViewportTextureNode, VolumeNodeMaterial, WGSLNodeBuilder, WebGLBackend, WebGLCapabilities, WebGLCoordinateSystem, WebGPUBackend, WebGPUCoordinateSystem, WebGPURenderer, WebXRController, WorkgroupInfoNode, ZeroFactor, ZeroStencilOp, createCanvasElement, defaultBuildStages, defaultShaderStages, error, log$1 as log, shaderStages, vectorComponents, warn, warnOnce }; diff --git a/build/three.webgpu.nodes.js b/build/three.webgpu.nodes.js index 9afc24ec85acdb..ed7a708140ac8c 100644 --- a/build/three.webgpu.nodes.js +++ b/build/three.webgpu.nodes.js @@ -3,8 +3,8 @@ * Copyright 2010-2026 Three.js Authors * SPDX-License-Identifier: MIT */ -import { Color, Vector2, Vector3, Vector4, Matrix2, Matrix3, Matrix4, UnsignedIntType, IntType, error, RedFormat, RedIntegerFormat, DepthFormat, DepthStencilFormat, AlphaFormat, RGFormat, RGIntegerFormat, RGBFormat, RGBIntegerFormat, EventDispatcher, MathUtils, warn, WebGLCoordinateSystem, WebGPUCoordinateSystem, ColorManagement, SRGBTransfer, NoToneMapping, StaticDrawUsage, InterleavedBufferAttribute, InterleavedBuffer, DynamicDrawUsage, NoColorSpace, log as log$1, warnOnce, Texture, Compatibility, LessCompare, LessEqualCompare, GreaterCompare, GreaterEqualCompare, NearestFilter, Sphere, BackSide, DoubleSide, CubeTexture, CubeReflectionMapping, CubeRefractionMapping, TangentSpaceNormalMap, NoNormalPacking, NormalRGPacking, NormalGAPacking, ObjectSpaceNormalMap, RED_GREEN_RGTC2_Format, RG11_EAC_Format, InstancedBufferAttribute, InstancedInterleavedBuffer, DataArrayTexture, FloatType, FramebufferTexture, LinearMipmapLinearFilter, DepthTexture, Material, LineBasicMaterial, LineDashedMaterial, NoBlending, MeshNormalMaterial, SRGBColorSpace, RenderTarget, BoxGeometry, Mesh, Scene, LinearFilter, CubeCamera, EquirectangularReflectionMapping, EquirectangularRefractionMapping, AddOperation, MixOperation, MultiplyOperation, MeshBasicMaterial, MeshLambertMaterial, MeshPhongMaterial, DataTexture, HalfFloatType, ClampToEdgeWrapping, BufferGeometry, OrthographicCamera, PerspectiveCamera, LinearSRGBColorSpace, RGBAFormat, CubeUVReflectionMapping, BufferAttribute, MeshStandardMaterial, MeshPhysicalMaterial, MeshToonMaterial, MeshMatcapMaterial, SpriteMaterial, PointsMaterial, ShadowMaterial, Uint32BufferAttribute, Uint16BufferAttribute, ByteType, UnsignedByteType, ShortType, UnsignedShortType, UnsignedShort4444Type, UnsignedShort5551Type, UnsignedInt248Type, UnsignedInt5999Type, UnsignedInt101111Type, NormalBlending, SrcAlphaFactor, OneMinusSrcAlphaFactor, AddEquation, MaterialBlending, Object3D, LinearMipMapLinearFilter, Plane, Float32BufferAttribute, UVMapping, PCFShadowMap, VSMShadowMap, BasicShadowMap, CubeDepthTexture, SphereGeometry, LinearMipmapNearestFilter, NearestMipmapLinearFilter, Float16BufferAttribute, yieldToMain, REVISION, ArrayCamera, PlaneGeometry, FrontSide, CustomBlending, ZeroFactor, CylinderGeometry, Quaternion, WebXRController, RAD2DEG, PCFSoftShadowMap, FrustumArray, Frustum, RGBAIntegerFormat, TimestampQuery, createCanvasElement, ReverseSubtractEquation, SubtractEquation, OneMinusDstAlphaFactor, OneMinusDstColorFactor, OneMinusSrcColorFactor, DstAlphaFactor, DstColorFactor, SrcAlphaSaturateFactor, SrcColorFactor, OneFactor, CullFaceNone, CullFaceBack, CullFaceFront, MultiplyBlending, SubtractiveBlending, AdditiveBlending, NotEqualDepth, GreaterDepth, GreaterEqualDepth, EqualDepth, LessEqualDepth, LessDepth, AlwaysDepth, NeverDepth, ReversedDepthFuncs, RGB_S3TC_DXT1_Format, RGBA_S3TC_DXT1_Format, RGBA_S3TC_DXT3_Format, RGBA_S3TC_DXT5_Format, RGB_PVRTC_4BPPV1_Format, RGB_PVRTC_2BPPV1_Format, RGBA_PVRTC_4BPPV1_Format, RGBA_PVRTC_2BPPV1_Format, RGB_ETC1_Format, RGB_ETC2_Format, RGBA_ETC2_EAC_Format, R11_EAC_Format, SIGNED_R11_EAC_Format, SIGNED_RG11_EAC_Format, RGBA_ASTC_4x4_Format, RGBA_ASTC_5x4_Format, RGBA_ASTC_5x5_Format, RGBA_ASTC_6x5_Format, RGBA_ASTC_6x6_Format, RGBA_ASTC_8x5_Format, RGBA_ASTC_8x6_Format, RGBA_ASTC_8x8_Format, RGBA_ASTC_10x5_Format, RGBA_ASTC_10x6_Format, RGBA_ASTC_10x8_Format, RGBA_ASTC_10x10_Format, RGBA_ASTC_12x10_Format, RGBA_ASTC_12x12_Format, RGBA_BPTC_Format, RGB_BPTC_SIGNED_Format, RGB_BPTC_UNSIGNED_Format, RED_RGTC1_Format, SIGNED_RED_RGTC1_Format, SIGNED_RED_GREEN_RGTC2_Format, MirroredRepeatWrapping, RepeatWrapping, NearestMipmapNearestFilter, NotEqualCompare, EqualCompare, AlwaysCompare, NeverCompare, LinearTransfer, getByteLength, isTypedArray, NotEqualStencilFunc, GreaterStencilFunc, GreaterEqualStencilFunc, EqualStencilFunc, LessEqualStencilFunc, LessStencilFunc, AlwaysStencilFunc, NeverStencilFunc, DecrementWrapStencilOp, IncrementWrapStencilOp, DecrementStencilOp, IncrementStencilOp, InvertStencilOp, ReplaceStencilOp, ZeroStencilOp, KeepStencilOp, MaxEquation, MinEquation, SpotLight, PointLight, DirectionalLight, RectAreaLight, AmbientLight, HemisphereLight, LightProbe, LinearToneMapping, ReinhardToneMapping, CineonToneMapping, ACESFilmicToneMapping, AgXToneMapping, NeutralToneMapping, Group, Loader, FileLoader, MaterialLoader, ObjectLoader } from './three.core.js'; -export { AdditiveAnimationBlendMode, AnimationAction, AnimationClip, AnimationLoader, AnimationMixer, AnimationObjectGroup, AnimationUtils, ArcCurve, ArrowHelper, AttachedBindMode, Audio, AudioAnalyser, AudioContext, AudioListener, AudioLoader, AxesHelper, BasicDepthPacking, BatchedMesh, BezierInterpolant, Bone, BooleanKeyframeTrack, Box2, Box3, Box3Helper, BoxHelper, BufferGeometryLoader, Cache, Camera, CameraHelper, CanvasTexture, CapsuleGeometry, CatmullRomCurve3, CircleGeometry, Clock, ColorKeyframeTrack, CompressedArrayTexture, CompressedCubeTexture, CompressedTexture, CompressedTextureLoader, ConeGeometry, ConstantAlphaFactor, ConstantColorFactor, Controls, CubeTextureLoader, CubicBezierCurve, CubicBezierCurve3, CubicInterpolant, CullFaceFrontBack, Curve, CurvePath, CustomToneMapping, Cylindrical, Data3DTexture, DataTextureLoader, DataUtils, DefaultLoadingManager, DetachedBindMode, DirectionalLightHelper, DiscreteInterpolant, DodecahedronGeometry, DynamicCopyUsage, DynamicReadUsage, EdgesGeometry, EllipseCurve, Euler, ExternalTexture, ExtrudeGeometry, Fog, FogExp2, GLBufferAttribute, GLSL1, GLSL3, GridHelper, HTMLTexture, HemisphereLightHelper, IcosahedronGeometry, ImageBitmapLoader, ImageLoader, ImageUtils, InstancedBufferGeometry, InstancedMesh, Int16BufferAttribute, Int32BufferAttribute, Int8BufferAttribute, Interpolant, InterpolateBezier, InterpolateDiscrete, InterpolateLinear, InterpolateSmooth, InterpolationSamplingMode, InterpolationSamplingType, KeyframeTrack, LOD, LatheGeometry, Layers, Light, Line, Line3, LineCurve, LineCurve3, LineLoop, LineSegments, LinearInterpolant, LinearMipMapNearestFilter, LoaderUtils, LoadingManager, LoopOnce, LoopPingPong, LoopRepeat, MOUSE, MeshDepthMaterial, MeshDistanceMaterial, NearestMipMapLinearFilter, NearestMipMapNearestFilter, NormalAnimationBlendMode, NumberKeyframeTrack, OctahedronGeometry, OneMinusConstantAlphaFactor, OneMinusConstantColorFactor, Path, PlaneHelper, PointLightHelper, Points, PolarGridHelper, PolyhedronGeometry, PositionalAudio, PropertyBinding, PropertyMixer, QuadraticBezierCurve, QuadraticBezierCurve3, QuaternionKeyframeTrack, QuaternionLinearInterpolant, RGBADepthPacking, RGBDepthPacking, RGDepthPacking, RawShaderMaterial, Ray, Raycaster, RenderTarget3D, RingGeometry, ShaderMaterial, Shape, ShapeGeometry, ShapePath, ShapeUtils, Skeleton, SkeletonHelper, SkinnedMesh, Source, Spherical, SphericalHarmonics3, SplineCurve, SpotLightHelper, Sprite, StaticCopyUsage, StaticReadUsage, StereoCamera, StreamCopyUsage, StreamDrawUsage, StreamReadUsage, StringKeyframeTrack, TOUCH, TetrahedronGeometry, TextureLoader, TextureUtils, Timer, TorusGeometry, TorusKnotGeometry, Triangle, TriangleFanDrawMode, TriangleStripDrawMode, TrianglesDrawMode, TubeGeometry, Uint8BufferAttribute, Uint8ClampedBufferAttribute, Uniform, UniformsGroup, VectorKeyframeTrack, VideoFrameTexture, VideoTexture, WebGL3DRenderTarget, WebGLArrayRenderTarget, WebGLRenderTarget, WireframeGeometry, WrapAroundEnding, ZeroCurvatureEnding, ZeroSlopeEnding, getConsoleFunction, setConsoleFunction } from './three.core.js'; +import { Color, Vector2, Vector3, Vector4, Matrix2, Matrix3, Matrix4, UnsignedIntType, IntType, error, RedFormat, RedIntegerFormat, DepthFormat, DepthStencilFormat, AlphaFormat, RGFormat, RGIntegerFormat, RGBFormat, RGBIntegerFormat, EventDispatcher, MathUtils, warn, WebGLCoordinateSystem, WebGPUCoordinateSystem, ColorManagement, SRGBTransfer, NoToneMapping, StaticDrawUsage, InterleavedBufferAttribute, InterleavedBuffer, DynamicDrawUsage, NoColorSpace, log as log$1, warnOnce, Texture, Compatibility, LessCompare, LessEqualCompare, GreaterCompare, GreaterEqualCompare, NearestFilter, Sphere, BackSide, DoubleSide, CubeTexture, CubeReflectionMapping, CubeRefractionMapping, TangentSpaceNormalMap, NoNormalPacking, NormalRGPacking, NormalGAPacking, ObjectSpaceNormalMap, RED_GREEN_RGTC2_Format, RG11_EAC_Format, InstancedBufferAttribute, InstancedInterleavedBuffer, DataTexture, DataArrayTexture, FloatType, FramebufferTexture, LinearMipmapLinearFilter, DepthTexture, Material, LineBasicMaterial, LineDashedMaterial, NoBlending, MeshNormalMaterial, SRGBColorSpace, RenderTarget, BoxGeometry, Mesh, Scene, LinearFilter, CubeCamera, EquirectangularReflectionMapping, EquirectangularRefractionMapping, AddOperation, MixOperation, MultiplyOperation, MeshBasicMaterial, MeshLambertMaterial, MeshPhongMaterial, HalfFloatType, ClampToEdgeWrapping, BufferGeometry, OrthographicCamera, PerspectiveCamera, LinearSRGBColorSpace, RGBAFormat, CubeUVReflectionMapping, BufferAttribute, MeshStandardMaterial, MeshPhysicalMaterial, MeshToonMaterial, MeshMatcapMaterial, SpriteMaterial, PointsMaterial, ShadowMaterial, Uint32BufferAttribute, Uint16BufferAttribute, ByteType, UnsignedByteType, ShortType, UnsignedShortType, UnsignedShort4444Type, UnsignedShort5551Type, UnsignedInt248Type, UnsignedInt5999Type, UnsignedInt101111Type, NormalBlending, SrcAlphaFactor, OneMinusSrcAlphaFactor, AddEquation, MaterialBlending, Object3D, LinearMipMapLinearFilter, Plane, Float32BufferAttribute, UVMapping, PCFShadowMap, VSMShadowMap, BasicShadowMap, CubeDepthTexture, SphereGeometry, LinearMipmapNearestFilter, NearestMipmapLinearFilter, Float16BufferAttribute, yieldToMain, REVISION, ArrayCamera, PlaneGeometry, FrontSide, CustomBlending, ZeroFactor, CylinderGeometry, Quaternion, WebXRController, RAD2DEG, PCFSoftShadowMap, FrustumArray, Frustum, RGBAIntegerFormat, TimestampQuery, createCanvasElement, MaxEquation, MinEquation, ReverseSubtractEquation, SubtractEquation, OneMinusConstantAlphaFactor, ConstantAlphaFactor, OneMinusConstantColorFactor, ConstantColorFactor, OneMinusDstAlphaFactor, OneMinusDstColorFactor, OneMinusSrcColorFactor, DstAlphaFactor, DstColorFactor, SrcAlphaSaturateFactor, SrcColorFactor, OneFactor, CullFaceNone, CullFaceBack, CullFaceFront, MultiplyBlending, SubtractiveBlending, AdditiveBlending, NotEqualDepth, GreaterDepth, GreaterEqualDepth, EqualDepth, LessEqualDepth, LessDepth, AlwaysDepth, NeverDepth, ReversedDepthFuncs, RGB_S3TC_DXT1_Format, RGBA_S3TC_DXT1_Format, RGBA_S3TC_DXT3_Format, RGBA_S3TC_DXT5_Format, RGB_PVRTC_4BPPV1_Format, RGB_PVRTC_2BPPV1_Format, RGBA_PVRTC_4BPPV1_Format, RGBA_PVRTC_2BPPV1_Format, RGB_ETC1_Format, RGB_ETC2_Format, RGBA_ETC2_EAC_Format, R11_EAC_Format, SIGNED_R11_EAC_Format, SIGNED_RG11_EAC_Format, RGBA_ASTC_4x4_Format, RGBA_ASTC_5x4_Format, RGBA_ASTC_5x5_Format, RGBA_ASTC_6x5_Format, RGBA_ASTC_6x6_Format, RGBA_ASTC_8x5_Format, RGBA_ASTC_8x6_Format, RGBA_ASTC_8x8_Format, RGBA_ASTC_10x5_Format, RGBA_ASTC_10x6_Format, RGBA_ASTC_10x8_Format, RGBA_ASTC_10x10_Format, RGBA_ASTC_12x10_Format, RGBA_ASTC_12x12_Format, RGBA_BPTC_Format, RGB_BPTC_SIGNED_Format, RGB_BPTC_UNSIGNED_Format, RED_RGTC1_Format, SIGNED_RED_RGTC1_Format, SIGNED_RED_GREEN_RGTC2_Format, MirroredRepeatWrapping, RepeatWrapping, NearestMipmapNearestFilter, NotEqualCompare, EqualCompare, AlwaysCompare, NeverCompare, LinearTransfer, getByteLength, isTypedArray, NotEqualStencilFunc, GreaterStencilFunc, GreaterEqualStencilFunc, EqualStencilFunc, LessEqualStencilFunc, LessStencilFunc, AlwaysStencilFunc, NeverStencilFunc, DecrementWrapStencilOp, IncrementWrapStencilOp, DecrementStencilOp, IncrementStencilOp, InvertStencilOp, ReplaceStencilOp, ZeroStencilOp, KeepStencilOp, SpotLight, PointLight, DirectionalLight, RectAreaLight, AmbientLight, HemisphereLight, LightProbe, LinearToneMapping, ReinhardToneMapping, CineonToneMapping, ACESFilmicToneMapping, AgXToneMapping, NeutralToneMapping, Group, Loader, FileLoader, MaterialLoader, ObjectLoader } from './three.core.js'; +export { AdditiveAnimationBlendMode, AnimationAction, AnimationClip, AnimationLoader, AnimationMixer, AnimationObjectGroup, AnimationUtils, ArcCurve, ArrowHelper, AttachedBindMode, Audio, AudioAnalyser, AudioContext, AudioListener, AudioLoader, AxesHelper, BasicDepthPacking, BatchedMesh, BezierInterpolant, Bone, BooleanKeyframeTrack, Box2, Box3, Box3Helper, BoxHelper, BufferGeometryLoader, Cache, Camera, CameraHelper, CanvasTexture, CapsuleGeometry, CatmullRomCurve3, CircleGeometry, Clock, ColorKeyframeTrack, CompressedArrayTexture, CompressedCubeTexture, CompressedTexture, CompressedTextureLoader, ConeGeometry, Controls, CubeTextureLoader, CubicBezierCurve, CubicBezierCurve3, CubicInterpolant, CullFaceFrontBack, Curve, CurvePath, CustomToneMapping, Cylindrical, Data3DTexture, DataTextureLoader, DataUtils, DefaultLoadingManager, DetachedBindMode, DirectionalLightHelper, DiscreteInterpolant, DodecahedronGeometry, DynamicCopyUsage, DynamicReadUsage, EdgesGeometry, EllipseCurve, Euler, ExternalTexture, ExtrudeGeometry, Fog, FogExp2, GLBufferAttribute, GLSL1, GLSL3, GridHelper, HTMLTexture, HemisphereLightHelper, IcosahedronGeometry, ImageBitmapLoader, ImageLoader, ImageUtils, InstancedBufferGeometry, InstancedMesh, Int16BufferAttribute, Int32BufferAttribute, Int8BufferAttribute, Interpolant, InterpolateBezier, InterpolateDiscrete, InterpolateLinear, InterpolateSmooth, InterpolationSamplingMode, InterpolationSamplingType, KeyframeTrack, LOD, LatheGeometry, Layers, Light, Line, Line3, LineCurve, LineCurve3, LineLoop, LineSegments, LinearInterpolant, LinearMipMapNearestFilter, LoaderUtils, LoadingManager, LoopOnce, LoopPingPong, LoopRepeat, MOUSE, MeshDepthMaterial, MeshDistanceMaterial, NearestMipMapLinearFilter, NearestMipMapNearestFilter, NormalAnimationBlendMode, NumberKeyframeTrack, OctahedronGeometry, Path, PlaneHelper, PointLightHelper, Points, PolarGridHelper, PolyhedronGeometry, PositionalAudio, PropertyBinding, PropertyMixer, QuadraticBezierCurve, QuadraticBezierCurve3, QuaternionKeyframeTrack, QuaternionLinearInterpolant, RGBADepthPacking, RGBDepthPacking, RGDepthPacking, RawShaderMaterial, Ray, Raycaster, RenderTarget3D, RingGeometry, ShaderMaterial, Shape, ShapeGeometry, ShapePath, ShapeUtils, Skeleton, SkeletonHelper, SkinnedMesh, Source, Spherical, SphericalHarmonics3, SplineCurve, SpotLightHelper, Sprite, StaticCopyUsage, StaticReadUsage, StereoCamera, StreamCopyUsage, StreamDrawUsage, StreamReadUsage, StringKeyframeTrack, TOUCH, TetrahedronGeometry, TextureLoader, TextureUtils, Timer, TorusGeometry, TorusKnotGeometry, Triangle, TriangleFanDrawMode, TriangleStripDrawMode, TrianglesDrawMode, TubeGeometry, Uint8BufferAttribute, Uint8ClampedBufferAttribute, Uniform, UniformsGroup, VectorKeyframeTrack, VideoFrameTexture, VideoTexture, WebGL3DRenderTarget, WebGLArrayRenderTarget, WebGLRenderTarget, WireframeGeometry, WrapAroundEnding, ZeroCurvatureEnding, ZeroSlopeEnding, getConsoleFunction, setConsoleFunction } from './three.core.js'; const refreshUniforms = [ 'alphaMap', @@ -1372,6 +1372,12 @@ function base64ToArrayBuffer( base64 ) { } +function isArrayAsParameter( params ) { + + return ( params[ 0 ] !== undefined && params[ 0 ] !== null ) && ( params[ 0 ].isNode || Object.getPrototypeOf( params[ 0 ] ) !== Object.prototype ); + +} + var NodeUtils = /*#__PURE__*/Object.freeze({ __proto__: null, arrayBufferToBase64: arrayBufferToBase64, @@ -1387,7 +1393,8 @@ var NodeUtils = /*#__PURE__*/Object.freeze({ getValueType: getValueType, hash: hash$1, hashArray: hashArray, - hashString: hashString + hashString: hashString, + isArrayAsParameter: isArrayAsParameter }); /** @@ -4432,12 +4439,6 @@ class ShaderCallNodeInternal extends Node { } -function isArrayAsParameter( params ) { - - return params[ 0 ] && ( params[ 0 ].isNode || Object.getPrototypeOf( params[ 0 ] ) !== Object.prototype ); - -} - function getLayoutParameters( params ) { let output; @@ -13246,6 +13247,18 @@ class TextureNode extends UniformNode { } + /** + * Returns `true` if the texture is sampled with a plain gather (`textureGather`), + * meaning a gather without a compare value. + * + * @return {boolean} Whether a plain gather is used or not. + */ + isPlainGather() { + + return this.gatherNode !== null && this.compareNode === null; + + } + /** * Samples the texture by defining a depth node. * @@ -17740,6 +17753,10 @@ class EventNode extends Node { this.updateType = NodeUpdateType.FRAME; + } else if ( eventType === EventNode.AFTER_OBJECT ) { + + this.updateAfterType = NodeUpdateType.OBJECT; + } else if ( eventType === EventNode.BEFORE_OBJECT ) { this.updateBeforeType = NodeUpdateType.OBJECT; @@ -17798,11 +17815,18 @@ class EventNode extends Node { } + updateAfter( frame ) { + + this.callback( frame ); + + } + } EventNode.OBJECT = 'object'; EventNode.MATERIAL = 'material'; EventNode.FRAME = 'frame'; +EventNode.AFTER_OBJECT = 'afterObject'; EventNode.BEFORE_OBJECT = 'beforeObject'; EventNode.BEFORE_MATERIAL = 'beforeMaterial'; EventNode.BEFORE_FRAME = 'beforeFrame'; @@ -17848,6 +17872,16 @@ const OnMaterialUpdate = ( callback ) => createEvent( EventNode.MATERIAL, callba */ const OnFrameUpdate = ( callback ) => createEvent( EventNode.FRAME, callback ); +/** + * Creates an event that triggers a function every time an object (Mesh|Sprite) has been rendered. + * + * The event will be bound to the declared TSL function `Fn()`; it must be declared within a `Fn()` or the JS function call must be inherited from one. + * + * @param {Function} callback - The callback function. + * @returns {EventNode} + */ +const OnAfterObjectUpdate = ( callback ) => createEvent( EventNode.AFTER_OBJECT, callback ); + /** * Creates an event that triggers a function before an object (Mesh|Sprite) is updated. * @@ -18633,11 +18667,18 @@ const instance = /*@__PURE__*/ Fn( ( [ matrices, colors = null ], builder ) => { const instancedMesh = builder.object; - OnObjectUpdate( ( { object } ) => { + OnAfterObjectUpdate( ( { object } ) => { - const previousInstanceData = _previousInstanceMatrices.get( object ); + const { previousInstanceMatrix } = _previousInstanceMatrices.get( object ); - previousInstanceData.previousInstanceMatrix.array.set( matrices.array ); + previousInstanceMatrix.array.set( matrices.array ); + previousInstanceMatrix.version = matrices.version; + + // handle interleaved path + + const previousInterleavedMatrix = _matrixBuffers.get( previousInstanceMatrix ); + + if ( previousInterleavedMatrix !== undefined ) previousInterleavedMatrix.version = matrices.version; } ); @@ -18680,6 +18721,8 @@ const instancedMesh = /*@__PURE__*/ Fn( ( [ instancedMesh ] ) => { }, 'void' ); +const _previousBatchingMatrices = /*@__PURE__*/ new WeakMap(); + /** * TSL function that retrieves the batching color for a given instance ID from a colors texture. * @@ -18713,6 +18756,61 @@ const getIndirectIndex = /*@__PURE__*/ Fn( ( [ indirectTexture, id ] ) => { } ); +/** + * Creates the node that reads a batching matrix from the given matrices texture. + * + * @param {Texture} matricesTexture - The matrices texture. + * @param {Node} id - The indirect instance ID. + * @returns {Node} The matrix node. + */ +function createBatchingMatrixNode( matricesTexture, id ) { + + const size = int( textureSize( textureLoad( matricesTexture ), 0 ).x ).toConst(); + const j = float( id ).mul( 4 ).toInt().toConst(); + + const x = j.mod( size ).toConst(); + const y = j.div( size ).toConst(); + + return mat4( + textureLoad( matricesTexture, ivec2( x, y ) ), + textureLoad( matricesTexture, ivec2( x.add( 1 ), y ) ), + textureLoad( matricesTexture, ivec2( x.add( 2 ), y ) ), + textureLoad( matricesTexture, ivec2( x.add( 3 ), y ) ) + ); + +} + +/** + * Retrieves or initializes the previous frame batching matrix node for motion vectors. + * Uses a WeakMap to cache previous frame matrices textures and their TSL nodes. + * + * @param {BatchedMesh} batchMesh - The batched mesh. + * @param {Node} id - The indirect instance ID. + * @returns {Node} The previous frame batching matrix node. + */ +function getPreviousNode( batchMesh, id ) { + + let data = _previousBatchingMatrices.get( batchMesh ); + + if ( data === undefined ) { + + const { image, format, type } = batchMesh._matricesTexture; + + const previousMatricesTexture = new DataTexture( image.data.slice(), image.width, image.height, format, type ); + + data = { + previousMatricesTexture, + node: createBatchingMatrixNode( previousMatricesTexture, id ) + }; + + _previousBatchingMatrices.set( batchMesh, data ); + + } + + return data.node; + +} + /** * TSL object representing a varying property for the batching color vector. * @@ -18720,6 +18818,13 @@ const getIndirectIndex = /*@__PURE__*/ Fn( ( [ indirectTexture, id ] ) => { */ const batchColor = /*@__PURE__*/ varyingProperty( 'vec4', 'vBatchColor' ); +/** + * TSL object representing a varying property for the batch indirect index (instance ID). + * + * @type {VaryingNode} + */ +const batchIndirectIndex = /*@__PURE__*/ varyingProperty( 'uint', 'vBatchIndirectId' ); + /** * TSL function representing the vertex shader batching setup. * Applies the batch transformation matrix to positionLocal, normalLocal, and tangentLocal. @@ -18735,19 +18840,9 @@ const batch = /*@__PURE__*/ Fn( ( [ batchMesh ], builder ) => { const indirectId = getIndirectIndex( batchMesh._indirectTexture, int( batchingIdNode ) ); - const matricesTexture = batchMesh._matricesTexture; + batchIndirectIndex.assign( indirectId ); - const size = int( textureSize( textureLoad( matricesTexture ), 0 ).x ).toConst(); - const j = float( indirectId ).mul( 4 ).toInt().toConst(); - - const x = j.mod( size ).toConst(); - const y = j.div( size ).toConst(); - const batchingMatrix = mat4( - textureLoad( matricesTexture, ivec2( x, y ) ), - textureLoad( matricesTexture, ivec2( x.add( 1 ), y ) ), - textureLoad( matricesTexture, ivec2( x.add( 2 ), y ) ), - textureLoad( matricesTexture, ivec2( x.add( 3 ), y ) ) - ); + const batchingMatrix = createBatchingMatrixNode( batchMesh._matricesTexture, indirectId ); const colorsTexture = batchMesh._colorsTexture; @@ -18763,6 +18858,22 @@ const batch = /*@__PURE__*/ Fn( ( [ batchMesh ], builder ) => { positionLocal.assign( batchingMatrix.mul( positionLocal ) ); + if ( builder.needsPreviousData() ) { + + OnAfterObjectUpdate( ( { object } ) => { + + const previousBatchData = _previousBatchingMatrices.get( object ); + + previousBatchData.previousMatricesTexture.image.data.set( object._matricesTexture.image.data ); + previousBatchData.previousMatricesTexture.needsUpdate = true; + + } ); + + const previousBatchingMatrixNode = getPreviousNode( batchMesh, indirectId ); + positionPrevious.assign( previousBatchingMatrixNode.mul( positionPrevious ).xyz ); + + } + const transformedNormal = normalLocal.div( vec3( bm[ 0 ].dot( bm[ 0 ] ), bm[ 1 ].dot( bm[ 1 ] ), bm[ 2 ].dot( bm[ 2 ] ) ) ); const batchingNormal = bm.mul( transformedNormal ).xyz; @@ -24808,10 +24919,10 @@ const getTransmissionSample = /*@__PURE__*/ Fn( ( [ fragCoord, roughness, ior ], const vTexture = material.side === BackSide ? viewportBackSideTexture : viewportFrontSideTexture; - const transmissionSample = vTexture.sample( fragCoord ); + const transmissionSample = vTexture.sample( fragCoord.mul( cameraViewport.zw ).add( cameraViewport.xy ).div( screenSize ) ); //const transmissionSample = viewportMipTexture( fragCoord ); - const lod = log2( screenSize.x ).mul( applyIorToRoughness( roughness, ior ) ); + const lod = log2( cameraViewport.z ).mul( applyIorToRoughness( roughness, ior ) ); return textureBicubicLevel( transmissionSample, lod ); @@ -28042,11 +28153,13 @@ class MeshPhysicalNodeMaterial extends MeshStandardNodeMaterial { setupSpecular() { const iorNode = this.iorNode ? float( this.iorNode ) : materialIOR; + const specularColorNode = this.specularColorNode ? vec3( this.specularColorNode ) : materialSpecularColor; + const specularIntensityNode = this.specularIntensityNode ? float( this.specularIntensityNode ) : materialSpecularIntensity; ior.assign( iorNode ); - specularColor.assign( min$1( pow2( ior.sub( 1.0 ).div( ior.add( 1.0 ) ) ).mul( materialSpecularColor ), vec3( 1.0 ) ).mul( materialSpecularIntensity ) ); + specularColor.assign( min$1( pow2( ior.sub( 1.0 ).div( ior.add( 1.0 ) ) ).mul( specularColorNode ), vec3( 1.0 ) ).mul( specularIntensityNode ) ); specularColorBlended.assign( mix( specularColor, diffuseColor.rgb, metalness ) ); - specularF90.assign( mix( materialSpecularIntensity, 1.0, metalness ) ); + specularF90.assign( mix( specularIntensityNode, 1.0, metalness ) ); } @@ -30040,6 +30153,19 @@ class RenderObject { }; + /** + * An event listener which is executed when `dispose()` is called on + * the 3D object of this render object. + * + * @method + */ + this.onObjectDispose = () => { + + this.dispose(); + + }; + + this.object.addEventListener( 'dispose', this.onObjectDispose ); this.material.addEventListener( 'dispose', this.onMaterialDispose ); this.geometry.addEventListener( 'dispose', this.onGeometryDispose ); @@ -30654,6 +30780,7 @@ class RenderObject { */ dispose() { + this.object.removeEventListener( 'dispose', this.onObjectDispose ); this.material.removeEventListener( 'dispose', this.onMaterialDispose ); this.geometry.removeEventListener( 'dispose', this.onGeometryDispose ); @@ -30983,11 +31110,6 @@ const AttributeType = { const GPU_CHUNK_BYTES = 16; -// @TODO: Move to src/constants.js - -const BlendColorFactor = 211; -const OneMinusBlendColorFactor = 212; - /** * This renderer module manages geometry attributes. * @@ -32319,9 +32441,10 @@ class Pipelines extends DataMap { * * @param {Node} computeNode - The compute node. * @param {Array} bindings - The bindings. + * @param {?Array} [promises=null] - An array of compilation promises which is only relevant in context of `Renderer.compileComputeAsync()`. * @return {ComputePipeline} The compute pipeline. */ - getForCompute( computeNode, bindings ) { + getForCompute( computeNode, bindings, promises = null ) { const { backend } = this; @@ -32368,7 +32491,7 @@ class Pipelines extends DataMap { if ( previousPipeline && previousPipeline.usedTimes === 0 ) this._releasePipeline( previousPipeline ); - pipeline = this._getComputePipeline( computeNode, stageCompute, cacheKey, bindings ); + pipeline = this._getComputePipeline( computeNode, stageCompute, cacheKey, bindings, promises ); } @@ -32580,9 +32703,10 @@ class Pipelines extends DataMap { * @param {ProgrammableStage} stageCompute - The programmable stage representing the compute shader. * @param {string} cacheKey - The cache key. * @param {Array} bindings - The bindings. + * @param {?Array} promises - An array of compilation promises which is only relevant in context of `Renderer.compileComputeAsync()`. * @return {ComputePipeline} The compute pipeline. */ - _getComputePipeline( computeNode, stageCompute, cacheKey, bindings ) { + _getComputePipeline( computeNode, stageCompute, cacheKey, bindings, promises ) { // check for existing pipeline @@ -32596,7 +32720,7 @@ class Pipelines extends DataMap { this.caches.set( cacheKey, pipeline ); - this.backend.createComputePipeline( pipeline, bindings ); + this.backend.createComputePipeline( pipeline, bindings, promises ); } @@ -35816,7 +35940,7 @@ const struct = ( membersLayout, name = null ) => { if ( params.length > 0 ) { - if ( params[ 0 ].isNode ) { + if ( isArrayAsParameter( params ) ) { values = {}; @@ -35824,7 +35948,7 @@ const struct = ( membersLayout, name = null ) => { for ( let i = 0; i < params.length; i ++ ) { - values[ names[ i ] ] = params[ i ]; + values[ names[ i ] ] = nodeObject( params[ i ] ); } @@ -42021,7 +42145,7 @@ class CodeNode extends Node { for ( const include of includes ) { - include.build( builder ); + include.build( builder, 'void' ); } @@ -48717,6 +48841,7 @@ var TSL = /*#__PURE__*/Object.freeze({ NodeShaderStage: NodeShaderStage, NodeType: NodeType, NodeUpdateType: NodeUpdateType, + OnAfterObjectUpdate: OnAfterObjectUpdate, OnAfterRenderPipeline: OnAfterRenderPipeline, OnBeforeFrameUpdate: OnBeforeFrameUpdate, OnBeforeMaterialUpdate: OnBeforeMaterialUpdate, @@ -48781,6 +48906,7 @@ var TSL = /*#__PURE__*/Object.freeze({ backgroundRotation: backgroundRotation, batch: batch, batchColor: batchColor, + batchIndirectIndex: batchIndirectIndex, bentNormalView: bentNormalView, billboarding: billboarding, bitAnd: bitAnd, @@ -56102,9 +56228,10 @@ class NodeManager extends DataMap { * Returns a node builder state for the given compute node. * * @param {Node} computeNode - The compute node. - * @return {NodeBuilderState} The node builder state. + * @param {boolean} [useAsync=false] - Whether to use async build with yielding. + * @return {NodeBuilderState|Promise} The node builder state (or Promise if async). */ - getForCompute( computeNode ) { + getForCompute( computeNode, useAsync = false ) { const computeData = this.get( computeNode ); @@ -56117,6 +56244,21 @@ class NodeManager extends DataMap { if ( onNodeBuilderCreated !== null ) onNodeBuilderCreated( nodeBuilder, computeNode ); + if ( useAsync ) { + + return nodeBuilder.buildAsync().then( () => { + + nodeBuilderState = this._createNodeBuilderState( nodeBuilder ); + + computeData.nodeBuilderState = nodeBuilderState; + computeData.version = computeNode.version; + + return nodeBuilderState; + + } ); + + } + nodeBuilder.build(); nodeBuilderState = this._createNodeBuilderState( nodeBuilder ); @@ -56130,6 +56272,27 @@ class NodeManager extends DataMap { } + /** + * Async version of getForCompute() that yields to main thread during build. + * Use this in compileComputeAsync() to prevent blocking the main thread. + * + * @param {Node} computeNode - The compute node. + * @return {Promise} A promise that resolves to the node builder state. + */ + getForComputeAsync( computeNode ) { + + const result = this.getForCompute( computeNode, true ); + + if ( result.then ) { + + return result; + + } + + return Promise.resolve( result ); + + } + /** * Creates a node builder state for the given node builder. * @@ -56392,6 +56555,27 @@ class NodeManager extends DataMap { if ( node === undefined || forceUpdate ) { + if ( node === undefined && object.isTexture === true ) { + + const onTextureDispose = () => { + + object.removeEventListener( 'dispose', onTextureDispose ); + + const node = nodeCache.get( object ); + + if ( node !== undefined ) { + + nodeCache.delete( object ); + node.dispose(); + + } + + }; + + object.addEventListener( 'dispose', onTextureDispose ); + + } + node = callback(); nodeCache.set( object, node ); @@ -57647,22 +57831,22 @@ class XRManager extends EventDispatcher { this._currentPixelRatio = null; /** - * The renderer's sample count before XR temporarily overrides it. + * The current size of the renderer's canvas + * in logical pixel unit. * * @private - * @type {?number} - * @default null + * @type {Vector2} */ - this._currentSamples = null; + this._currentSize = new Vector2(); /** - * The current size of the renderer's canvas - * in logical pixel unit. + * Holds a reference to the user camera and its current settings. * * @private - * @type {Vector2} + * @type {?Object} + * @default null */ - this._currentSize = new Vector2(); + this._currentCameraSettings = null; /** * The default event listener for handling events inside a XR session. @@ -58065,11 +58249,11 @@ class XRManager extends EventDispatcher { * Browser-side `XRWebGLBinding.foveateBoundTexture()` failures are treated as * non-fatal so they do not interrupt rendering. * - * @param {RenderTarget} renderTarget - The internal render target. + * @param {?RenderTarget} renderTarget - The internal render target. */ foveateBoundTexture( renderTarget ) { - if ( renderTarget.isPostProcessingRenderTarget !== true ) return; + if ( renderTarget === null || renderTarget.isPostProcessingRenderTarget !== true ) return; if ( this.isPresenting !== true ) return; if ( this._glProjLayer === null ) return; @@ -58154,9 +58338,7 @@ class XRManager extends EventDispatcher { */ _validateWebGPUSession() { - const renderer = this._renderer; - - if ( renderer.backend.isWebGPUBackend !== true ) return; + if ( this._renderer.backend.isWebGPUBackend !== true ) return; if ( this._session.enabledFeatures.includes( 'webgpu' ) === false ) { @@ -58164,15 +58346,6 @@ class XRManager extends EventDispatcher { } - if ( renderer.samples > 0 ) { - - warnOnce( 'THREE.XRManager: WebGPU XR does not support MSAA yet. Disabling MSAA for this XR session.' ); - - if ( this._currentSamples === null ) this._currentSamples = renderer.samples; - renderer._samples = 0; - - } - } /** @@ -58187,8 +58360,7 @@ class XRManager extends EventDispatcher { const webgpuBinding = this.getWebGPUBinding(); const glProjLayer = webgpuBinding.createProjectionLayer( { - colorFormat: webgpuBinding.getPreferredColorFormat(), - depthStencilFormat: 'depth24plus' + colorFormat: webgpuBinding.getPreferredColorFormat() } ); this._glProjLayer = glProjLayer; @@ -58204,7 +58376,10 @@ class XRManager extends EventDispatcher { depthBuffer: true, multiview: false, useArrayDepthTexture: true, - samples: 0 + storeMultisampledColorBuffer: false, + storeMultisampledDepthBuffer: false, + storeMultisampledStencilBuffer: false, + samples: this._renderer.samples } ); this._xrRenderTarget.texture.isArrayTexture = true; @@ -58227,46 +58402,27 @@ class XRManager extends EventDispatcher { _disposeWebGPUSession() { const renderer = this._renderer; - const xrRenderTarget = this._xrRenderTarget; - - if ( xrRenderTarget === null || renderer.backend.isWebGPUBackend !== true ) return; - - // XR textures are external (from XRGPUBinding), so clear cached state before disposal. const backend = renderer.backend; - const texturesModule = renderer._textures; - - const renderTargetData = backend.get ? backend.get( xrRenderTarget ) : null; - if ( renderTargetData ) { - - renderTargetData.descriptors = undefined; - - } - - const deleteResource = ( resource ) => { - - if ( resource === null || resource === undefined ) return; + const xrRenderTarget = this._xrRenderTarget; - if ( backend.delete ) backend.delete( resource ); - if ( texturesModule.delete ) texturesModule.delete( resource ); + if ( xrRenderTarget === null || backend.isWebGPUBackend !== true ) return; - }; - - for ( let i = 0; i < xrRenderTarget.textures.length; i ++ ) { + if ( renderer._renderContexts && renderer._renderContexts.dispose ) { - deleteResource( xrRenderTarget.textures[ i ] ); + renderer._renderContexts.dispose(); } - deleteResource( xrRenderTarget.depthTexture ); - deleteResource( xrRenderTarget ); + xrRenderTarget.dispose(); - if ( renderer._renderContexts && renderer._renderContexts.dispose ) { + // The external texture can be registered before the render target is initialized. + for ( const texture of xrRenderTarget.textures ) { - renderer._renderContexts.dispose(); + if ( backend.has( texture ) ) backend.destroyTexture( texture ); } - xrRenderTarget.dispose(); + backend.delete( xrRenderTarget ); } @@ -58345,6 +58501,7 @@ class XRManager extends EventDispatcher { * @param {Function} rendercall - A callback function that renders the layer. Similar to code in * the default animation loop, this method can be used to update/transform 3D object in the layer's scene. * @param {Object} [attributes={}] - Allows to configure the layer's render target. + * @param {number} [attributes.samples] - The scene MSAA sample count. Defaults to the renderer's sample count. * @return {Mesh} A mesh representing the quadratic XR layer. This mesh should be added to the XR scene. */ createQuadLayer( width, height, translation, quaternion, pixelwidth, pixelheight, rendercall, attributes = {} ) { @@ -58369,14 +58526,14 @@ class XRManager extends EventDispatcher { attributes.stencil ? DepthStencilFormat : DepthFormat ), stencilBuffer: attributes.stencil, + samples: attributes.samples ?? this._renderer.samples, resolveDepthBuffer: false, resolveStencilBuffer: false, + storeMultisampledColorBuffer: false, storeMultisampledDepthBuffer: false, storeMultisampledStencilBuffer: false } ); - renderTarget._autoAllocateDepthBuffer = true; - const material = new MeshBasicMaterial( { color: 0xffffff, side: FrontSide } ); material.map = renderTarget.texture; material.map.offset.y = 1; @@ -58393,6 +58550,7 @@ class XRManager extends EventDispatcher { quaternion: quaternion, pixelwidth: pixelwidth, pixelheight: pixelheight, + samples: renderTarget.samples, plane: plane, material: material, rendercall: rendercall, @@ -58438,6 +58596,7 @@ class XRManager extends EventDispatcher { * @param {Function} rendercall - A callback function that renders the layer. Similar to code in * the default animation loop, this method can be used to update/transform 3D object in the layer's scene. * @param {Object} [attributes={}] - Allows to configure the layer's render target. + * @param {number} [attributes.samples] - The scene MSAA sample count. Defaults to the renderer's sample count. * @return {Mesh} A mesh representing the cylindrical XR layer. This mesh should be added to the XR scene. */ createCylinderLayer( radius, centralAngle, aspectratio, translation, quaternion, pixelwidth, pixelheight, rendercall, attributes = {} ) { @@ -58462,14 +58621,14 @@ class XRManager extends EventDispatcher { attributes.stencil ? DepthStencilFormat : DepthFormat ), stencilBuffer: attributes.stencil, + samples: attributes.samples ?? this._renderer.samples, resolveDepthBuffer: false, resolveStencilBuffer: false, + storeMultisampledColorBuffer: false, storeMultisampledDepthBuffer: false, storeMultisampledStencilBuffer: false } ); - renderTarget._autoAllocateDepthBuffer = true; - const material = new MeshBasicMaterial( { color: 0xffffff, side: BackSide } ); material.map = renderTarget.texture; material.map.offset.y = 1; @@ -58487,6 +58646,7 @@ class XRManager extends EventDispatcher { quaternion: quaternion, pixelwidth: pixelwidth, pixelheight: pixelheight, + samples: renderTarget.samples, plane: plane, material: material, rendercall: rendercall, @@ -58784,11 +58944,7 @@ class XRManager extends EventDispatcher { format: RGBAFormat, type: UnsignedByteType, colorSpace: renderer.outputColorSpace, - stencilBuffer: renderer.stencil, - resolveDepthBuffer: ( glBaseLayer.ignoreDepthValues === false ), - resolveStencilBuffer: ( glBaseLayer.ignoreDepthValues === false ), - storeMultisampledDepthBuffer: ( glBaseLayer.ignoreDepthValues === false ), - storeMultisampledStencilBuffer: ( glBaseLayer.ignoreDepthValues === false ), + stencilBuffer: renderer.stencil } ); @@ -58882,6 +59038,12 @@ class XRManager extends EventDispatcher { // update user camera and its children + if ( this._currentCameraSettings === null && camera.isPerspectiveCamera ) { + + this._currentCameraSettings = { camera: camera, fov: camera.fov, zoom: camera.zoom }; + + } + updateUserCamera( camera, cameraXR, parent ); @@ -59096,13 +59258,6 @@ function onSessionEnd() { this._currentDepthNear = null; this._currentDepthFar = null; - if ( this._currentSamples !== null ) { - - renderer._samples = this._currentSamples; - this._currentSamples = null; - - } - // restore framebuffer/rendering state renderer._resetXRState(); @@ -59141,8 +59296,10 @@ function onSessionEnd() { layer.stencilBuffer ? DepthStencilFormat : DepthFormat ), stencilBuffer: layer.stencilBuffer, + samples: layer.samples, resolveDepthBuffer: false, resolveStencilBuffer: false, + storeMultisampledColorBuffer: false, storeMultisampledDepthBuffer: false, storeMultisampledStencilBuffer: false } ); @@ -59172,6 +59329,18 @@ function onSessionEnd() { renderer.setPixelRatio( this._currentPixelRatio ); renderer.setSize( this._currentSize.width, this._currentSize.height, false ); + if ( this._currentCameraSettings !== null ) { + + const camera = this._currentCameraSettings.camera; + + camera.fov = this._currentCameraSettings.fov; + camera.zoom = this._currentCameraSettings.zoom; + camera.updateProjectionMatrix(); + + this._currentCameraSettings = null; + + } + this.dispatchEvent( { type: 'sessionend' } ); } @@ -59396,6 +59565,14 @@ function onAnimationFrame( time, frame ) { renderer.setOutputRenderTarget( this._xrRenderTarget ); const frameBufferTarget = renderer._getFrameBufferTarget(); + + if ( webgpuViewData !== null ) { + + this._xrRenderTarget.samples = frameBufferTarget === null ? renderer.samples : 0; + this._xrRenderTarget.depthBuffer = frameBufferTarget === null; + + } + renderer.xr.foveateBoundTexture( frameBufferTarget ); } @@ -60620,9 +60797,10 @@ class Renderer { * @param {Object3D} scene - The scene or 3D object to precompile. * @param {Camera} camera - The camera that is used to render the scene. * @param {?Scene} targetScene - If the first argument is a 3D object, this parameter must represent the scene the 3D object is going to be added. + * @param {onProgressCallback} [onProgress] - Executed while the compilation is in progress. * @return {Promise} A Promise that resolves when the compile has been finished. */ - async compileAsync( scene, camera, targetScene = null ) { + async compileAsync( scene, camera, targetScene = null, onProgress = null ) { if ( this._isDeviceLost === true ) return; @@ -60656,7 +60834,9 @@ class Renderer { // Match render()'s logic: use frameBufferTarget when needsFrameBufferTarget is true const useFrameBufferTarget = this.needsFrameBufferTarget && this._renderTarget === null; - const renderTarget = useFrameBufferTarget ? this._getFrameBufferTarget() : ( this._renderTarget || this._outputRenderTarget ); + const outputRenderTarget = this._renderTarget || this._outputRenderTarget; + const useXRCamera = this.xr.isPresenting === true && this.isOutputTarget; + const renderTarget = useFrameBufferTarget ? this._getFrameBufferTarget() : outputRenderTarget; const renderContext = this._renderContexts.get( renderTarget, this._mrt ); const activeMipmapLevel = this._activeMipmapLevel; @@ -60687,7 +60867,7 @@ class Renderer { if ( scene.matrixWorldAutoUpdate === true ) scene.updateMatrixWorld(); - camera = this._updateCamera( camera ); + camera = this._updateCamera( camera, useXRCamera ); // @@ -60782,6 +60962,9 @@ class Renderer { // Process compilation work items sequentially to avoid freezing // Yields between objects to keep animation smooth + const total = compilationPromises.length; + let loaded = 0; + for ( const item of compilationPromises ) { const renderObject = this._objects.get( item.object, item.material, item.scene, item.camera, item.lightsNode, item.renderContext, item.clippingContext, item.passId ); @@ -60811,6 +60994,14 @@ class Renderer { this._nodes.updateAfter( renderObject ); this._isPreCompiling = false; + loaded ++; + + if ( onProgress !== null ) { + + onProgress( new ProgressEvent( 'progress', { lengthComputable: true, loaded, total } ) ); + + } + // Yield between objects to allow animation frames await yieldToMain(); @@ -60818,6 +61009,90 @@ class Renderer { } + /** + * Compile compute programs. This can be useful to avoid a + * phenomenon which is called "shader compilation stutter", which occurs when + * rendering an object with a new shader for the first time. + * + * @async + * @param {Node|Array} computeNodes - The compute node(s). + * @param {onProgressCallback} [onProgress] - Executed while the compilation is in progress. + * @return {Promise} A Promise that resolves when the compile has been finished. + */ + async compileComputeAsync( computeNodes, onProgress = null ) { + + if ( this._isDeviceLost === true ) return; + + if ( this._initialized === false ) await this.init(); + + const computeList = Array.isArray( computeNodes ) ? computeNodes : [ computeNodes ]; + + if ( computeList.length === 0 || computeList.some( ( computeNode ) => computeNode === undefined || computeNode === null || computeNode.isComputeNode !== true ) ) { + + throw new Error( 'THREE.Renderer: .compileComputeAsync() expects a ComputeNode.' ); + + } + + const total = computeList.length; + let loaded = 0; + + // + + const pipelines = this._pipelines; + const bindings = this._bindings; + const nodes = this._nodes; + + for ( const computeNode of computeList ) { + + if ( pipelines.has( computeNode ) === false ) { + + const dispose = () => { + + computeNode.removeEventListener( 'dispose', dispose ); + + pipelines.delete( computeNode ); + bindings.deleteForCompute( computeNode ); + nodes.delete( computeNode ); + + }; + + computeNode.addEventListener( 'dispose', dispose ); + + const onInitFn = computeNode.onInitFunction; + + if ( onInitFn !== null ) { + + onInitFn.call( computeNode, { renderer: this } ); + + } + + } + + await nodes.getForComputeAsync( computeNode ); + + nodes.updateForCompute( computeNode ); + bindings.updateForCompute( computeNode ); + + const computeBindings = bindings.getForCompute( computeNode ); + const compilationPromises = []; + + pipelines.getForCompute( computeNode, computeBindings, compilationPromises ); + await Promise.all( compilationPromises ); + + loaded ++; + + if ( onProgress !== null ) { + + onProgress( new ProgressEvent( 'progress', { lengthComputable: true, loaded, total } ) ); + + } + + if ( loaded < total ) await yieldToMain(); + + } + + } + /** * Renders the scene in an async fashion. * @@ -61137,7 +61412,9 @@ class Renderer { _renderOutputLayers( quad, renderTarget ) { - if ( renderTarget.texture.isArrayTexture !== true || renderTarget.texture.image.depth <= 1 ) { + const useMultiview = this.backend.isWebGLBackend === true && renderTarget.multiview === true; + + if ( useMultiview || renderTarget.texture.isArrayTexture !== true || renderTarget.texture.image.depth <= 1 ) { this._renderScene( quad, quad.camera, false ); return; @@ -61176,12 +61453,7 @@ class Renderer { */ _getFrameBufferTarget() { - const { currentToneMapping, currentColorSpace } = this; - - const useToneMapping = currentToneMapping !== NoToneMapping; - const useColorSpace = currentColorSpace !== ColorManagement.workingColorSpace; - - if ( useToneMapping === false && useColorSpace === false ) return null; + if ( this.needsFrameBufferTarget === false ) return null; const { width, height } = this.getDrawingBufferSize( _drawingBufferSize ); const { depth, stencil } = this; @@ -61306,6 +61578,7 @@ class Renderer { const sceneRef = ( scene.isScene === true ) ? scene : _scene; const outputRenderTarget = this._renderTarget || this._outputRenderTarget; + const useXRCamera = this.xr.isPresenting === true && this.isOutputTarget; const activeCubeFace = this._activeCubeFace; const activeMipmapLevel = this._activeMipmapLevel; @@ -61374,7 +61647,7 @@ class Renderer { if ( scene.matrixWorldAutoUpdate === true ) scene.updateMatrixWorld(); - camera = this._updateCamera( camera ); + camera = this._updateCamera( camera, useXRCamera ); // @@ -62224,6 +62497,7 @@ class Renderer { * Returns `true` if a framebuffer target is needed to perform tone mapping or color space conversion. * If this is the case, the renderer allocates an internal render target for that purpose. * + * @type {boolean} */ get needsFrameBufferTarget() { @@ -62839,7 +63113,7 @@ class Renderer { * @param {number} width - The width of the copy region. * @param {number} height - The height of the copy region. * @param {number} [textureIndex=0] - The texture index of a MRT render target. - * @param {number} [faceIndex=0] - The active cube face index. + * @param {number} [faceIndex=0] - The cube face, depth slice or array layer index. * @return {Promise} A Promise that resolves when the read has been finished. The resolve provides the read data as a typed array. */ async readRenderTargetPixelsAsync( renderTarget, x, y, width, height, textureIndex = 0, faceIndex = 0 ) { @@ -63221,13 +63495,14 @@ class Renderer { * * @private * @param {Camera} camera - The camera to update. + * @param {boolean} useXRCamera - Whether the XR camera should be used when presenting. * @return {Camera} The returned camera might be different depending on whether XR is used or not. */ - _updateCamera( camera ) { + _updateCamera( camera, useXRCamera ) { const xr = this.xr; - if ( xr.isPresenting === false ) { + if ( xr.isPresenting === false || useXRCamera === false ) { let projectionMatrixNeedsUpdate = false; @@ -63297,7 +63572,7 @@ class Renderer { // handle XR - if ( xr.enabled === true && xr.isPresenting === true ) { + if ( useXRCamera === true && xr.enabled === true && xr.isPresenting === true ) { if ( xr.cameraAutoUpdate === true ) xr.updateCamera( camera ); camera = xr.getCamera(); // use XR camera for rendering @@ -63588,7 +63863,8 @@ class Renderer { * @param {Object3D} scene - The scene or 3D object to precompile. * @param {Camera} camera - The camera that is used to render the scene. * @param {Scene} targetScene - If the first argument is a 3D object, this parameter must represent the scene the 3D object is going to be added. - * @return {function(Object3D, Camera, ?Scene): Promise|undefined} A Promise that resolves when the compile has been finished. + * @param {onProgressCallback} [onProgress] - Executed while the compilation is in progress. + * @return {function(Object3D, Camera, ?Scene, ?onProgressCallback): Promise|undefined} A Promise that resolves when the compile has been finished. */ get compile() { @@ -65773,7 +66049,7 @@ ${ flowData.code } snippet = `${typePrefix}sampler3D ${ uniform.name };`; - } else if ( texture.compareFunction && textureNode.compareNode !== null ) { + } else if ( texture.compareFunction && textureNode.isPlainGather() === false ) { if ( texture.isArrayTexture === true ) { @@ -66982,8 +67258,9 @@ class Backend { * @abstract * @param {ComputePipeline} computePipeline - The compute pipeline. * @param {Array} bindings - The bindings. + * @param {?Array} [promises=null] - Optional compilation promises. */ - createComputePipeline( /*computePipeline, bindings*/ ) { } + createComputePipeline( /*computePipeline, bindings, promises*/ ) { } // cache key @@ -67090,7 +67367,7 @@ class Backend { * @param {number} y - The y coordinate of the copy origin. * @param {number} width - The width of the copy. * @param {number} height - The height of the copy. - * @param {number} faceIndex - The face index. + * @param {number} faceIndex - The cube face, depth slice or array layer index. * @return {Promise} A Promise that resolves with a typed array when the copy operation has finished. */ async copyTextureToBuffer( /*texture, x, y, width, height, faceIndex*/ ) {} @@ -67964,6 +68241,8 @@ class WebGLState { this.currentBlendDst = null; this.currentBlendSrcAlpha = null; this.currentBlendDstAlpha = null; + this.currentBlendColor = new Color( 0, 0, 0 ); + this.currentBlendAlpha = 0; this.currentPremultipledAlpha = null; this.currentPolygonOffsetFactor = null; this.currentPolygonOffsetUnits = null; @@ -68010,7 +68289,9 @@ class WebGLState { equationToGL = { [ AddEquation ]: gl.FUNC_ADD, [ SubtractEquation ]: gl.FUNC_SUBTRACT, - [ ReverseSubtractEquation ]: gl.FUNC_REVERSE_SUBTRACT + [ ReverseSubtractEquation ]: gl.FUNC_REVERSE_SUBTRACT, + [ MinEquation ]: gl.MIN, + [ MaxEquation ]: gl.MAX }; factorToGL = { @@ -68024,7 +68305,11 @@ class WebGLState { [ OneMinusSrcColorFactor ]: gl.ONE_MINUS_SRC_COLOR, [ OneMinusSrcAlphaFactor ]: gl.ONE_MINUS_SRC_ALPHA, [ OneMinusDstColorFactor ]: gl.ONE_MINUS_DST_COLOR, - [ OneMinusDstAlphaFactor ]: gl.ONE_MINUS_DST_ALPHA + [ 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 }; const scissorParam = gl.getParameter( gl.SCISSOR_BOX ); @@ -68326,7 +68611,7 @@ class WebGLState { * Defines the blending. * * This method caches the state so `gl.blendEquation()`, `gl.blendEquationSeparate()`, - * `gl.blendFunc()` and `gl.blendFuncSeparate()` are only called when necessary. + * `gl.blendFunc()`, `gl.blendFuncSeparate()` and `gl.blendColor()` are only called when necessary. * * @param {number} blending - The blending type. * @param {number} blendEquation - The blending equation. @@ -68335,9 +68620,11 @@ class WebGLState { * @param {number} blendEquationAlpha - Only relevant for custom blending. The blending equation for alpha. * @param {number} blendSrcAlpha - Only relevant for custom blending. The alpha source blending factor. * @param {number} blendDstAlpha - Only relevant for custom blending. The alpha destination blending factor. + * @param {Color} blendColor - Only relevant for custom blending. The RGB values of the constant blend color. + * @param {number} blendAlpha - Only relevant for custom blending. The alpha value of the constant blend color. * @param {boolean} premultipliedAlpha - Whether premultiplied alpha is enabled or not. */ - setBlending( blending, blendEquation, blendSrc, blendDst, blendEquationAlpha, blendSrcAlpha, blendDstAlpha, premultipliedAlpha ) { + setBlending( blending, blendEquation, blendSrc, blendDst, blendEquationAlpha, blendSrcAlpha, blendDstAlpha, blendColor, blendAlpha, premultipliedAlpha ) { const { gl } = this; @@ -68468,6 +68755,15 @@ class WebGLState { } + if ( blendColor.equals( this.currentBlendColor ) === false || blendAlpha !== this.currentBlendAlpha ) { + + gl.blendColor( blendColor.r, blendColor.g, blendColor.b, blendAlpha ); + + this.currentBlendColor.copy( blendColor ); + this.currentBlendAlpha = blendAlpha; + + } + this.currentBlending = blending; this.currentPremultipledAlpha = false; @@ -68817,7 +69113,7 @@ class WebGLState { ( material.blending === NormalBlending && material.transparent === false ) ? this.setBlending( NoBlending ) - : this.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.premultipliedAlpha ); + : this.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.blendColor, material.blendAlpha, material.premultipliedAlpha ); this.setDepthFunc( material.depthFunc ); this.setDepthTest( material.depthTest ); @@ -69344,6 +69640,8 @@ class WebGLState { this.currentBlendDst = null; this.currentBlendSrcAlpha = null; this.currentBlendDstAlpha = null; + this.currentBlendColor.set( 0, 0, 0 ); + this.currentBlendAlpha = 0; this.currentPremultipledAlpha = null; this.currentPolygonOffsetFactor = null; this.currentPolygonOffsetUnits = null; @@ -70929,7 +71227,7 @@ class WebGLTextureUtils { * @param {number} y - The y coordinate of the copy origin. * @param {number} width - The width of the copy. * @param {number} height - The height of the copy. - * @param {number} faceIndex - The face index. + * @param {number} faceIndex - The cube face, depth slice or array layer index. * @return {Promise} A Promise that resolves with a typed array when the copy operation has finished. */ async copyTextureToBuffer( texture, x, y, width, height, faceIndex ) { @@ -70942,9 +71240,17 @@ class WebGLTextureUtils { backend.state.bindFramebuffer( gl.READ_FRAMEBUFFER, fb ); - const target = texture.isCubeTexture ? gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex : gl.TEXTURE_2D; + if ( texture.isData3DTexture || texture.isDataArrayTexture || texture.isArrayTexture ) { + + gl.framebufferTextureLayer( gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, textureGPU, 0, faceIndex ); + + } else { + + const target = texture.isCubeTexture ? gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex : gl.TEXTURE_2D; - gl.framebufferTexture2D( gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, target, textureGPU, 0 ); + gl.framebufferTexture2D( gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, target, textureGPU, 0 ); + + } const typedArrayType = this._getTypedArrayType( glType ); const bytesPerTexel = this._getBytesPerTexel( glType, glFormat ); @@ -73321,7 +73627,7 @@ class WebGLBackend extends Backend { * @param {number} y - The y coordinate of the copy origin. * @param {number} width - The width of the copy. * @param {number} height - The height of the copy. - * @param {number} faceIndex - The face index. + * @param {number} faceIndex - The cube face, depth slice or array layer index. * @return {Promise} A Promise that resolves with a typed array when the copy operation has finished. */ async copyTextureToBuffer( texture, x, y, width, height, faceIndex ) { @@ -73605,10 +73911,11 @@ class WebGLBackend extends Backend { * * @param {ComputePipeline} computePipeline - The compute pipeline. * @param {Array} bindings - The bindings. + * @param {?Array} [promises=null] - Optional compilation promises. */ - createComputePipeline( computePipeline, bindings ) { + createComputePipeline( computePipeline, bindings, promises = null ) { - const { state, gl } = this; + const { gl } = this; // Program @@ -73651,19 +73958,6 @@ class WebGLBackend extends Backend { gl.linkProgram( programGPU ); - if ( gl.getProgramParameter( programGPU, gl.LINK_STATUS ) === false ) { - - this._logProgramError( programGPU, fragmentShader, vertexShader ); - - - } - - state.useProgram( programGPU ); - - // Bindings - - this._setupBindings( bindings, programGPU ); - const attributeNodes = computeProgram.attributes; const attributes = []; const transformBuffers = []; @@ -73690,14 +73984,73 @@ class WebGLBackend extends Backend { } - // + // Store pipeline data this.set( computePipeline, { programGPU, + fragmentShader, + vertexShader, transformBuffers, attributes } ); + if ( promises !== null && this.parallel ) { + + const parallel = this.parallel; + + const p = new Promise( ( resolve ) => { + + const checkStatus = () => { + + if ( gl.getProgramParameter( programGPU, parallel.COMPLETION_STATUS_KHR ) ) { + + this._completeComputeCompile( computePipeline, bindings ); + resolve(); + + } else { + + requestAnimationFrame( checkStatus ); + + } + + }; + + checkStatus(); + + } ); + + promises.push( p ); + return; + + } + + // Sync fallback + this._completeComputeCompile( computePipeline, bindings ); + + } + + /** + * Completes the compute pipeline setup for the given compute pipeline. + * + * @param {ComputePipeline} computePipeline - The compute pipeline. + * @param {Array} bindings - Array of bind groups. + */ + _completeComputeCompile( computePipeline, bindings ) { + + const { state, gl } = this; + const { programGPU, fragmentShader, vertexShader } = this.get( computePipeline ); + + if ( gl.getProgramParameter( programGPU, gl.LINK_STATUS ) === false ) { + + this._logProgramError( programGPU, fragmentShader, vertexShader ); + + } + + state.useProgram( programGPU ); + + // Bindings (must be after link completion) + this._setupBindings( bindings, programGPU ); + } /** @@ -74722,7 +75075,8 @@ class WebGLBackend extends Backend { } - } else if ( renderTarget.storeMultisampledDepthBuffer === false && renderTargetContextData.framebuffers ) { + } else if ( this._supportsInvalidateFramebuffer === true && renderTargetContextData.framebuffers && + ( renderTarget._autoAllocateDepthBuffer === true || ( renderTarget.samples > 0 && renderTarget.storeMultisampledDepthBuffer === false ) ) ) { const fb = renderTargetContextData.framebuffers[ renderContext.getCacheKey() ]; state.bindFramebuffer( gl.DRAW_FRAMEBUFFER, fb ); @@ -75363,10 +75717,21 @@ class WebGPUUtils { } else if ( texture.isDepthTexture && ! texture.renderTarget ) { - const renderer = this.backend.renderer; - const renderTarget = renderer.getRenderTarget(); + const textureData = this.backend.get( texture ); + + if ( textureData.texture !== undefined ) { + + // use the effective sample count of the allocated texture + + samples = textureData.texture.sampleCount; + + } else { - samples = renderTarget ? renderTarget.samples : renderer.currentSamples; + // otherwise use the current samples of the renderer + + samples = this.backend.renderer.currentSamples; + + } } else if ( texture.renderTarget ) { @@ -75377,7 +75742,8 @@ class WebGPUUtils { samples = this.getSampleCount( samples || 1 ); const isMSAA = samples > 1 && texture.renderTarget !== null && ( texture.isDepthTexture !== true && texture.isFramebufferTexture !== true ); - const primarySamples = isMSAA ? 1 : samples; + const isMSAAArrayDepthTexture = samples > 1 && texture.renderTarget !== null && texture.isDepthTexture === true && texture.isArrayTexture === true; + const primarySamples = isMSAA || isMSAAArrayDepthTexture ? 1 : samples; return { samples, primarySamples, isMSAA }; @@ -76287,7 +76653,7 @@ const _renderPassDescriptor = new GPURenderPassDescriptor(); const _renderPipelineDescriptor$1 = new GPURenderPipelineDescriptor(); const _colorAttachment = new GPURenderPassColorAttachment(); const _shaderModuleDescriptor$1 = new GPUShaderModuleDescriptor(); -const _textureDescriptor$1 = new GPUTextureDescriptor(); +const _textureDescriptor$2 = new GPUTextureDescriptor(); const _viewDescriptor$2 = new GPUTextureViewDescriptor(); /** @@ -76498,14 +76864,14 @@ fn main_cube( Varys: VarysStruct ) -> @location( 0 ) vec4 { const format = textureGPUDescriptor.format; const { width, height } = textureGPUDescriptor.size; - _textureDescriptor$1.size.width = width; - _textureDescriptor$1.size.height = height; - _textureDescriptor$1.format = format; - _textureDescriptor$1.usage = GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING; + _textureDescriptor$2.size.width = width; + _textureDescriptor$2.size.height = height; + _textureDescriptor$2.format = format; + _textureDescriptor$2.usage = GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING; - const tempTexture = this.device.createTexture( _textureDescriptor$1 ); + const tempTexture = this.device.createTexture( _textureDescriptor$2 ); - _textureDescriptor$1.reset(); + _textureDescriptor$2.reset(); const copyTransferPipeline = this.getTransferPipeline( format, textureGPU.textureBindingViewDimension ); const flipTransferPipeline = this.getTransferPipeline( format, tempTexture.textureBindingViewDimension ); @@ -77148,7 +77514,7 @@ const _texelCopyBufferInfo = new GPUTexelCopyBufferInfo(); const _texelCopyBufferLayout = new GPUTexelCopyBufferLayout(); const _copyExternalImageSourceInfo = new GPUCopyExternalImageSourceInfo(); const _copyExternalImageDestInfo = new GPUCopyExternalImageDestInfo(); -const _textureDescriptor = new GPUTextureDescriptor(); +const _textureDescriptor$1 = new GPUTextureDescriptor(); const _extent3D$1 = new GPUExtent3D(); const _compareToWebGPU = { @@ -77264,10 +77630,12 @@ class WebGPUTextureUtils { const texture = binding.texture; const textureNode = binding.textureNode; + const isComparison = texture.isDepthTexture === true && texture.compareFunction !== null && textureNode.isPlainGather() === false && backend.hasCompatibility( Compatibility.TEXTURE_COMPARE ); + const samplerKey = texture.minFilter + '-' + texture.magFilter + '-' + texture.wrapS + '-' + texture.wrapT + '-' + ( texture.wrapR || '0' ) + '-' + texture.anisotropy + '-' + ( texture.isDepthTexture === true ? 1 : 0 ) + '-' + - ( texture.compareFunction !== null && textureNode.compareNode !== null ? texture.compareFunction : 0 ); + ( isComparison ? texture.compareFunction : 0 ); let samplerData = this._samplerCache.get( samplerKey ); @@ -77281,7 +77649,7 @@ class WebGPUTextureUtils { _samplerDescriptor.mipmapFilter = this._convertMipmapFilterMode( texture.minFilter ); // Depth textures without compare function must use non-filtering (nearest) sampling - if ( texture.isDepthTexture && ( texture.compareFunction === null || textureNode.compareNode === null ) ) { + if ( texture.isDepthTexture && isComparison === false ) { _samplerDescriptor.magFilter = GPUFilterMode.Nearest; _samplerDescriptor.minFilter = GPUFilterMode.Nearest; @@ -77297,7 +77665,7 @@ class WebGPUTextureUtils { } - if ( texture.isDepthTexture && texture.compareFunction !== null && textureNode.compareNode !== null && backend.hasCompatibility( Compatibility.TEXTURE_COMPARE ) ) { + if ( isComparison ) { _samplerDescriptor.compare = _compareToWebGPU[ texture.compareFunction ]; @@ -77457,6 +77825,20 @@ class WebGPUTextureUtils { textureData.format = format; const { samples, primarySamples, isMSAA } = backend.utils.getTextureSampleData( texture ); + const renderTarget = texture.renderTarget; + + // WebGPU multisampled 2D textures can only have a single array layer. + const useSeparateMSAATextures = samples > 1 && renderTarget !== null && depth > 1 && dimension === GPUTextureDimension.TwoD; + const supportsTransientAttachments = GPUTextureUsage.TRANSIENT_ATTACHMENT !== undefined; + // Layered rendering can resume after a framebuffer copy, so its attachments must support loading. + const useTransientAttachments = supportsTransientAttachments && useSeparateMSAATextures === false; + const useTransientDepthAttachment = texture.isDepthTexture === true && + useTransientAttachments && + renderTarget?.storeMultisampledDepthBuffer === false && + ( renderTarget.stencilBuffer === false || renderTarget.storeMultisampledStencilBuffer === false ); + const useTransientColorAttachment = texture.isDepthTexture !== true && + useTransientAttachments && + renderTarget?.storeMultisampledColorBuffer === false; let usage = GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.COPY_SRC; @@ -77472,17 +77854,11 @@ class WebGPUTextureUtils { } - const renderTarget = texture.renderTarget; - // when the multisampled data are discarded, try to use a transient attachment if possible - if ( texture.isDepthTexture === true && primarySamples > 1 && GPUTextureUsage.TRANSIENT_ATTACHMENT !== undefined ) { - - if ( renderTarget?.storeMultisampledDepthBuffer === false && ( renderTarget.stencilBuffer === false || renderTarget.storeMultisampledStencilBuffer === false ) ) { + if ( primarySamples > 1 && useTransientDepthAttachment ) { - usage = GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TRANSIENT_ATTACHMENT; - - } + usage = GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TRANSIENT_ATTACHMENT; } @@ -77526,7 +77902,7 @@ class WebGPUTextureUtils { } - if ( isMSAA ) { + if ( isMSAA || useSeparateMSAATextures ) { const msaaTextureDescriptorGPU = Object.assign( {}, textureDescriptorGPU ); @@ -77536,13 +77912,30 @@ class WebGPUTextureUtils { // when the multisampled data are discarded, try to use a transient attachment if possible - if ( renderTarget?.storeMultisampledColorBuffer === false && GPUTextureUsage.TRANSIENT_ATTACHMENT !== undefined ) { + if ( useTransientDepthAttachment || useTransientColorAttachment ) { msaaTextureDescriptorGPU.usage = GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TRANSIENT_ATTACHMENT; } - textureData.msaaTexture = backend.device.createTexture( msaaTextureDescriptorGPU ); + if ( useSeparateMSAATextures ) { + + msaaTextureDescriptorGPU.size = Object.assign( {}, msaaTextureDescriptorGPU.size, { depthOrArrayLayers: 1 } ); + + textureData.msaaTextures = []; + + for ( let i = 0; i < depth; i ++ ) { + + msaaTextureDescriptorGPU.label = textureDescriptorGPU.label + '-msaa-' + i; + textureData.msaaTextures.push( backend.device.createTexture( msaaTextureDescriptorGPU ) ); + + } + + } else { + + textureData.msaaTexture = backend.device.createTexture( msaaTextureDescriptorGPU ); + + } } @@ -77563,10 +77956,16 @@ class WebGPUTextureUtils { const backend = this.backend; const textureData = backend.get( texture ); - if ( textureData.texture !== undefined && isDefaultTexture === false && texture.isExternalTexture !== true ) textureData.texture.destroy(); + if ( textureData.texture !== undefined && isDefaultTexture === false && texture.isExternalTexture !== true && textureData.externalTexture !== true ) textureData.texture.destroy(); if ( textureData.msaaTexture !== undefined ) textureData.msaaTexture.destroy(); + if ( textureData.msaaTextures !== undefined ) { + + for ( const msaaTexture of textureData.msaaTextures ) msaaTexture.destroy(); + + } + backend.delete( texture ); } @@ -77613,16 +78012,16 @@ class WebGPUTextureUtils { if ( colorBuffer ) colorBuffer.destroy(); - _textureDescriptor.label = 'colorBuffer'; - _textureDescriptor.size.width = width; - _textureDescriptor.size.height = height; - _textureDescriptor.sampleCount = backend.utils.getSampleCount( backend.renderer.currentSamples ); - _textureDescriptor.format = backend.utils.getPreferredCanvasFormat(); - _textureDescriptor.usage = GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.COPY_SRC; + _textureDescriptor$1.label = 'colorBuffer'; + _textureDescriptor$1.size.width = width; + _textureDescriptor$1.size.height = height; + _textureDescriptor$1.sampleCount = backend.utils.getSampleCount( backend.renderer.currentSamples ); + _textureDescriptor$1.format = backend.utils.getPreferredCanvasFormat(); + _textureDescriptor$1.usage = GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.COPY_SRC; - colorBuffer = backend.device.createTexture( _textureDescriptor ); + colorBuffer = backend.device.createTexture( _textureDescriptor$1 ); - _textureDescriptor.reset(); + _textureDescriptor$1.reset(); // @@ -77871,7 +78270,7 @@ class WebGPUTextureUtils { * @param {number} y - The y coordinate of the copy origin. * @param {number} width - The width of the copy. * @param {number} height - The height of the copy. - * @param {number} faceIndex - The face index. + * @param {number} faceIndex - The cube face, depth slice or array layer index. * @return {Promise} A Promise that resolves with a typed array when the copy operation has finished. */ async copyTextureToBuffer( texture, x, y, width, height, faceIndex ) { @@ -79004,6 +79403,7 @@ const wgslTypeLib$1 = { 'mat4x4f': 'mat4', 'sampler': 'sampler', + 'sampler_comparison': 'samplerComparison', 'texture_1d': 'texture', @@ -81280,7 +81680,7 @@ ${ flowData.code } if ( needsSampler ) { - if ( this.isSampleCompare( texture ) && textureNode.compareNode !== null ) { + if ( this.isSampleCompare( texture ) && textureNode.isPlainGather() === false ) { bindingSnippets.push( `@binding( ${ uniformIndexes.binding ++ } ) @group( ${ uniformIndexes.group } ) var ${ uniform.name }_sampler : sampler_comparison;` ); @@ -81893,8 +82293,8 @@ const typedArraysToVertexFormatPrefix = new Map( [ [ Uint8Array, [ 'uint8', 'unorm8' ]], [ Int16Array, [ 'sint16', 'snorm16' ]], [ Uint16Array, [ 'uint16', 'unorm16' ]], - [ Int32Array, [ 'sint32', 'snorm32' ]], - [ Uint32Array, [ 'uint32', 'unorm32' ]], + [ Int32Array, [ 'sint32' ]], + [ Uint32Array, [ 'uint32' ]], [ Float32Array, [ 'float32', ]], ] ); @@ -81910,9 +82310,7 @@ const typedAttributeToVertexFormatPrefix = new Map( [ const typeArraysToVertexFormatPrefixForItemSize1 = new Map( [ [ Int32Array, 'sint32' ], - [ Int16Array, 'sint32' ], // patch for INT16 [ Uint32Array, 'uint32' ], - [ Uint16Array, 'uint32' ], // patch for UINT16 [ Float32Array, 'float32' ] ] ); @@ -81961,7 +82359,7 @@ class WebGPUAttributeUtils { let array = bufferAttribute.array; // patch for INT16 and UINT16 - if ( attribute.normalized === false ) { + if ( attribute.normalized === false && attribute.isInterleavedBufferAttribute !== true ) { if ( array.constructor === Int16Array || array.constructor === Int8Array ) { @@ -82200,13 +82598,6 @@ class WebGPUAttributeUtils { } - // patch for INT16 and UINT16 - if ( geometryAttribute.normalized === false && ( geometryAttribute.array.constructor === Int16Array || geometryAttribute.array.constructor === Uint16Array ) ) { - - arrayStride = 4; - - } - vertexBufferLayout = { arrayStride, attributes: [], @@ -83030,7 +83421,7 @@ class WebGPUBindingUtils { if ( binding.texture.isDepthTexture ) { - if ( binding.texture.compareFunction !== null && binding.textureNode.compareNode !== null && backend.hasCompatibility( Compatibility.TEXTURE_COMPARE ) ) { + if ( binding.texture.compareFunction !== null && binding.textureNode.isPlainGather() === false && backend.hasCompatibility( Compatibility.TEXTURE_COMPARE ) ) { sampler.type = GPUSamplerBindingType.Comparison; @@ -83585,8 +83976,9 @@ class WebGPUPipelineUtils { * * @param {ComputePipeline} pipeline - The compute pipeline. * @param {Array} bindings - The bindings. + * @param {?Array} [promises=null] - Optional compilation promises. */ - createComputePipeline( pipeline, bindings ) { + createComputePipeline( pipeline, bindings, promises = null ) { const backend = this.backend; const device = backend.device; @@ -83623,23 +84015,87 @@ class WebGPUPipelineUtils { _computePipelineDescriptor.compute = computeProgram; _computePipelineDescriptor.layout = pipelineLayout; - pipelineGPU.pipeline = device.createComputePipeline( _computePipelineDescriptor ); + if ( promises === null ) { - _computePipelineDescriptor.reset(); + pipelineGPU.pipeline = device.createComputePipeline( _computePipelineDescriptor ); - device.popErrorScope().then( ( err ) => { + _computePipelineDescriptor.reset(); - if ( err !== null ) { + device.popErrorScope().then( ( err ) => { - pipelineGPU.error = true; + if ( err !== null ) { - error( `WebGPURenderer: Compute pipeline creation failed (${ pipelineLabel }): ${ err.message }` ); + pipelineGPU.error = true; - this._reportShaderDiagnostics( [ { program: computeStage, module: computeProgram.module } ], pipelineLabel ); + error( `WebGPURenderer: Compute pipeline creation failed (${ pipelineLabel }): ${ err.message }` ); - } + this._reportShaderDiagnostics( [ { program: computeStage, module: computeProgram.module } ], pipelineLabel ); - } ); + } + + } ); + + } else { + + const promise = new Promise( async ( resolve /*, reject*/ ) => { + + try { + + let asyncError = null; + let pipelinePromise = null; + + try { + + pipelinePromise = device.createComputePipelineAsync( _computePipelineDescriptor ); + + } catch ( err ) { + + asyncError = err; + + } + + _computePipelineDescriptor.reset(); + + if ( pipelinePromise !== null ) { + + try { + + pipelineGPU.pipeline = await pipelinePromise; + + } catch ( err ) { + + asyncError = err; + + } + + } + + const errorScope = await device.popErrorScope(); + + if ( errorScope !== null || asyncError !== null ) { + + pipelineGPU.error = true; + + const reason = ( errorScope && errorScope.message ) || ( asyncError && asyncError.message ) || 'unknown'; + error( `WebGPURenderer: Async compute pipeline creation failed (${ pipelineLabel }): ${ reason }` ); + + await this._reportShaderDiagnostics( [ { program: computeStage, module: computeProgram.module } ], pipelineLabel ); + + } + + } finally { + + // Guarantee resolution so `compileComputeAsync`'s Promise.all cannot hang on an + // unexpected throw from any await above. + resolve(); + + } + + } ); + + promises.push( promise ); + + } } @@ -83858,11 +84314,13 @@ class WebGPUPipelineUtils { blendFactor = GPUBlendFactor.SrcAlphaSaturated; break; - case BlendColorFactor: + case ConstantColorFactor: + case ConstantAlphaFactor: // WebGPU has no dedicated constant alpha blend factors blendFactor = GPUBlendFactor.Constant; break; - case OneMinusBlendColorFactor: + case OneMinusConstantColorFactor: + case OneMinusConstantAlphaFactor: // WebGPU has no dedicated constant alpha blend factors blendFactor = GPUBlendFactor.OneMinusConstant; break; @@ -84698,6 +85156,7 @@ class GPURenderPassTimestampWrites { const _clearValue = { r: 0, g: 0, b: 0, a: 1 }; +const _blendConstant = { r: 0, g: 0, b: 0, a: 0 }; const _bufferDescriptor = new GPUBufferDescriptor(); const _commandEncoderDescriptor = new GPUCommandEncoderDescriptor(); const _computePassDescriptor = new GPUComputePassDescriptor(); @@ -84706,6 +85165,7 @@ const _shaderModuleDescriptor = new GPUShaderModuleDescriptor(); const _renderPassTimestampWrites = new GPURenderPassTimestampWrites(); const _texelCopyTextureInfoSrc = new GPUTexelCopyTextureInfo(); const _texelCopyTextureInfoDst = new GPUTexelCopyTextureInfo(); +const _textureDescriptor = new GPUTextureDescriptor(); const _viewDescriptor = new GPUTextureViewDescriptor(); const _extent3D = new GPUExtent3D(); @@ -84973,13 +85433,14 @@ class WebGPUBackend extends Backend { */ setXRRenderTargetTextures( renderTarget, colorTexture, viewDescriptors = null ) { - this.set( renderTarget.texture, { - texture: colorTexture, - format: colorTexture.format, - externalTexture: true, - xrViewDescriptors: viewDescriptors, - initialized: true - } ); + // Update the external XR texture without replacing the cached MSAA attachments. + const textureData = this.get( renderTarget.texture ); + + textureData.texture = colorTexture; + textureData.format = colorTexture.format; + textureData.externalTexture = true; + textureData.xrViewDescriptors = viewDescriptors; + textureData.initialized = true; } @@ -85195,6 +85656,81 @@ class WebGPUBackend extends Backend { } + /** + * Returns multisampled color textures for an external render target. + * + * @private + * @param {RenderContext} renderContext - The render context. + * @param {Object} textureData - The backend data for the external texture. + * @param {number} count - The number of textures to create. + * @return {?Array} The multisampled textures. + */ + _getExternalMSAATextures( renderContext, textureData, count ) { + + const samples = this.utils.getSampleCount( renderContext.sampleCount ); + + if ( samples === 1 ) { + + if ( textureData.msaaTextures !== undefined ) { + + for ( const texture of textureData.msaaTextures ) texture.destroy(); + + textureData.msaaTextures = undefined; + + } + + return null; + + } + + const renderTarget = renderContext.renderTarget; + const width = renderTarget.width; + const height = renderTarget.height; + const format = textureData.format; + + if ( textureData.msaaTextures === undefined || + textureData.msaaTextures.length !== count || + textureData.msaaWidth !== width || + textureData.msaaHeight !== height || + textureData.msaaSamples !== samples || + textureData.msaaFormat !== format ) { + + if ( textureData.msaaTextures !== undefined ) { + + for ( const texture of textureData.msaaTextures ) texture.destroy(); + + } + + _textureDescriptor.size.width = width; + _textureDescriptor.size.height = height; + _textureDescriptor.sampleCount = samples; + _textureDescriptor.format = format; + // Layered rendering can resume after a framebuffer copy, + // so these attachments must support loading. + _textureDescriptor.usage = GPUTextureUsage.RENDER_ATTACHMENT; + + textureData.msaaTextures = []; + + for ( let i = 0; i < count; i ++ ) { + + _textureDescriptor.label = renderTarget.texture.name + '-msaa-' + i; + textureData.msaaTextures.push( this.device.createTexture( _textureDescriptor ) ); + + } + + _textureDescriptor.reset(); + + textureData.msaaWidth = width; + textureData.msaaHeight = height; + textureData.msaaSamples = samples; + textureData.msaaFormat = format; + + } + + return textureData.msaaTextures; + + } + /** * Creates attachment views for an external texture render target. * @@ -85207,14 +85743,19 @@ class WebGPUBackend extends Backend { const textureViews = []; const camera = renderContext.camera; + const viewDescriptors = textureData.xrViewDescriptors; + const viewCount = Math.max( viewDescriptors?.length || 0, renderContext.activeCubeFace + 1, 1 ); + const msaaTextures = this._getExternalMSAATextures( renderContext, textureData, viewCount ); - if ( textureData.xrViewDescriptors && camera !== null && camera.isArrayCamera === true ) { + if ( viewDescriptors && camera !== null && camera.isArrayCamera === true ) { - for ( let i = 0; i < textureData.xrViewDescriptors.length; i ++ ) { + for ( let i = 0; i < viewDescriptors.length; i ++ ) { + + const textureView = textureData.texture.createView( viewDescriptors[ i ] ); textureViews.push( { - view: textureData.texture.createView( textureData.xrViewDescriptors[ i ] ), - resolveTarget: undefined, + view: msaaTextures !== null ? msaaTextures[ i ].createView() : textureView, + resolveTarget: msaaTextures !== null && renderContext.renderTarget.resolveColorBuffer === true ? textureView : undefined, depthSlice: undefined } ); @@ -85222,13 +85763,16 @@ class WebGPUBackend extends Backend { } else { + const layer = renderContext.activeCubeFace; + const textureView = textureData.texture.createView( { + dimension: GPUTextureViewDimension.TwoD, + baseArrayLayer: layer, + arrayLayerCount: 1 + } ); + textureViews.push( { - view: textureData.texture.createView( { - dimension: GPUTextureViewDimension.TwoD, - baseArrayLayer: renderContext.activeCubeFace, - arrayLayerCount: 1 - } ), - resolveTarget: undefined, + view: msaaTextures !== null ? msaaTextures[ layer ].createView() : textureView, + resolveTarget: msaaTextures !== null && renderContext.renderTarget.resolveColorBuffer === true ? textureView : undefined, depthSlice: undefined } ); @@ -85316,9 +85860,10 @@ class WebGPUBackend extends Backend { _viewDescriptor.dimension = GPUTextureViewDimension.TwoD; const textureView = textureData.texture.createView( _viewDescriptor ); + const msaaTexture = textureData.msaaTextures?.[ layer ]; textureViews.push( { - view: textureView, - resolveTarget: undefined, + view: msaaTexture !== undefined ? msaaTexture.createView() : textureView, + resolveTarget: msaaTexture !== undefined && renderTarget.resolveColorBuffer === true ? textureView : undefined, depthSlice: undefined } ); @@ -85343,6 +85888,11 @@ class WebGPUBackend extends Backend { view = textureData.msaaTexture.createView(); resolveTarget = renderTarget.resolveColorBuffer === true ? textureView : undefined; + } else if ( textureData.msaaTextures !== undefined ) { + + view = textureData.msaaTextures[ renderContext.activeCubeFace ].createView(); + resolveTarget = renderTarget.resolveColorBuffer === true ? textureView : undefined; + } else { view = textureView; @@ -85394,7 +85944,8 @@ class WebGPUBackend extends Backend { } const depthStencilAttachment = new GPURenderPassDepthStencilAttachment(); - depthStencilAttachment.view = depthTextureData.texture.createView( _viewDescriptor ); + const msaaDepthTexture = depthTextureData.msaaTextures?.[ renderContext.activeCubeFace ]; + depthStencilAttachment.view = msaaDepthTexture !== undefined ? msaaDepthTexture.createView() : depthTextureData.texture.createView( _viewDescriptor ); descriptorBase.depthStencilAttachment = depthStencilAttachment; _viewDescriptor.reset(); @@ -85518,6 +86069,12 @@ class WebGPUBackend extends Backend { const depthStencilAttachment = descriptor.depthStencilAttachment; const renderTarget = renderContext.renderTarget; + const discardColor = renderContext.sampleCount > 1 && renderTarget?.storeMultisampledColorBuffer === false; + const discardDepth = renderContext.sampleCount > 1 && renderTarget?.storeMultisampledDepthBuffer === false; + const discardStencil = renderContext.sampleCount > 1 && renderTarget?.storeMultisampledStencilBuffer === false; + + // A fullscreen pass overwrites the external texture, so its previous contents do not need to be loaded. + const clearExternalColor = renderContext.fullscreenPass === true && this._hasExternalTexture( renderContext ); if ( renderContext.textures !== null ) { @@ -85527,7 +86084,7 @@ class WebGPUBackend extends Backend { const colorAttachment = colorAttachments[ i ]; - if ( renderContext.clearColor ) { + if ( renderContext.clearColor || discardColor || clearExternalColor ) { if ( i === 0 ) { @@ -85552,7 +86109,7 @@ class WebGPUBackend extends Backend { } - if ( renderContext.sampleCount > 1 && renderTarget?.storeMultisampledColorBuffer === false ) { + if ( discardColor ) { colorAttachment.storeOp = GPUStoreOp.Discard; @@ -85587,7 +86144,7 @@ class WebGPUBackend extends Backend { if ( renderContext.depth ) { - if ( renderContext.clearDepth ) { + if ( renderContext.clearDepth || discardDepth ) { depthStencilAttachment.depthClearValue = renderContext.clearDepthValue; depthStencilAttachment.depthLoadOp = GPULoadOp.Clear; @@ -85598,7 +86155,7 @@ class WebGPUBackend extends Backend { } - if ( renderContext.sampleCount > 1 && renderTarget?.storeMultisampledDepthBuffer === false ) { + if ( discardDepth ) { depthStencilAttachment.depthStoreOp = GPUStoreOp.Discard; @@ -85612,7 +86169,7 @@ class WebGPUBackend extends Backend { if ( renderContext.stencil ) { - if ( renderContext.clearStencil ) { + if ( renderContext.clearStencil || discardStencil ) { depthStencilAttachment.stencilClearValue = renderContext.clearStencilValue; depthStencilAttachment.stencilLoadOp = GPULoadOp.Clear; @@ -85623,7 +86180,7 @@ class WebGPUBackend extends Backend { } - if ( renderContext.sampleCount > 1 && renderTarget?.storeMultisampledStencilBuffer === false ) { + if ( discardStencil ) { depthStencilAttachment.stencilStoreOp = GPUStoreOp.Discard; @@ -85653,40 +86210,22 @@ class WebGPUBackend extends Backend { } else { - this._updateArrayCameraLayerDescriptors( renderContext, renderContextData, cameras ); + this._updateArrayCameraLayerDescriptors( renderContext, renderContextData, descriptor, cameras ); } - // Create bundle encoders for each layer - renderContextData.bundleEncoders = []; - renderContextData.bundleSets = []; - - // Create separate bundle encoders for each camera in the array - for ( let i = 0; i < cameras.length; i ++ ) { - - const bundleEncoder = this.pipelineUtils.createBundleEncoder( - renderContext, - 'renderBundleArrayCamera_' + i - ); - - // Initialize state tracking for this bundle - const bundleSets = { - attributes: {}, - bindingGroups: [], - pipeline: null, - index: null - }; - - renderContextData.bundleEncoders.push( bundleEncoder ); - renderContextData.bundleSets.push( bundleSets ); - - } + this._createArrayCameraBundleEncoders( renderContext, renderContextData ); + renderContextData.arrayCameraRenderStages = []; // We'll complete the bundles in finishRender renderContextData.currentPass = null; } else { + renderContextData.bundleEncoders = undefined; + renderContextData.bundleSets = undefined; + renderContextData.arrayCameraRenderStages = undefined; + const currentPass = encoder.beginRenderPass( descriptor ); renderContextData.currentPass = currentPass; @@ -85708,9 +86247,87 @@ class WebGPUBackend extends Backend { renderContextData.descriptor = descriptor; renderContextData.encoder = encoder; - renderContextData.currentSets = { attributes: {}, bindingGroups: [], pipeline: null, index: null }; renderContextData.renderBundles = []; + this._resetRenderContextData( renderContextData ); + + } + + /** + * Resets the state cache of the given render context data. + * + * A new render pass encoder starts with a blend constant and a stencil reference + * of zero so the cached values must be reset as well. + * + * @private + * @param {Object} renderContextData - The render context data. + */ + _resetRenderContextData( renderContextData ) { + + renderContextData.currentSets = { attributes: {}, bindingGroups: [], pipeline: null, index: null }; + + if ( renderContextData.currentBlendColor === undefined ) renderContextData.currentBlendColor = new Color(); + + renderContextData.currentBlendColor.setRGB( 0, 0, 0 ); + renderContextData.currentBlendAlpha = 0; + renderContextData.currentStencilRef = 0; + + } + + /** + * Creates a render bundle encoder and state cache for each camera layer. + * + * @param {RenderContext} renderContext - The render context. + * @param {Object} renderContextData - The render context data. + * @private + */ + _createArrayCameraBundleEncoders( renderContext, renderContextData ) { + + const cameras = renderContext.camera.cameras; + + renderContextData.bundleEncoders = []; + renderContextData.bundleSets = []; + + for ( let i = 0; i < cameras.length; i ++ ) { + + const bundleEncoder = this.pipelineUtils.createBundleEncoder( + renderContext, + 'renderBundleArrayCamera_' + i + ); + + const bundleSets = { + attributes: {}, + bindingGroups: [], + pipeline: null, + index: null + }; + + renderContextData.bundleEncoders.push( bundleEncoder ); + renderContextData.bundleSets.push( bundleSets ); + + } + + } + + /** + * Finishes the render bundle encoders for all camera layers. + * + * @param {Object} renderContextData - The render context data. + * @return {Array} The completed render bundles. + * @private + */ + _finishArrayCameraBundleEncoders( renderContextData ) { + + const bundles = []; + + for ( const bundleEncoder of renderContextData.bundleEncoders ) { + + bundles.push( bundleEncoder.finish() ); + + } + + return bundles; + } /** @@ -85738,11 +86355,12 @@ class WebGPUBackend extends Backend { for ( let i = 0; i < cameras.length; i ++ ) { const sourceAttachment = descriptor.colorAttachments[ 0 ]; + const layerAttachment = descriptor.colorAttachments[ i ]; const layerColorAttachment = new GPURenderPassColorAttachment(); - layerColorAttachment.view = descriptor.colorAttachments[ i ].view; - layerColorAttachment.depthSlice = sourceAttachment.depthSlice; - layerColorAttachment.resolveTarget = sourceAttachment.resolveTarget; + layerColorAttachment.view = layerAttachment.view; + layerColorAttachment.depthSlice = layerAttachment.depthSlice; + layerColorAttachment.resolveTarget = layerAttachment.resolveTarget; layerColorAttachment.loadOp = sourceAttachment.loadOp; layerColorAttachment.storeOp = sourceAttachment.storeOp; layerColorAttachment.clearValue = sourceAttachment.clearValue; @@ -85759,11 +86377,21 @@ class WebGPUBackend extends Backend { if ( ! depthTextureData.viewCache[ layerIndex ] ) { - _viewDescriptor.dimension = GPUTextureViewDimension.TwoD; - _viewDescriptor.baseArrayLayer = i; - _viewDescriptor.arrayLayerCount = 1; + const msaaTexture = depthTextureData.msaaTextures?.[ layerIndex ]; - depthTextureData.viewCache[ layerIndex ] = depthTextureData.texture.createView( _viewDescriptor ); + if ( msaaTexture !== undefined ) { + + depthTextureData.viewCache[ layerIndex ] = msaaTexture.createView(); + + } else { + + _viewDescriptor.dimension = GPUTextureViewDimension.TwoD; + _viewDescriptor.baseArrayLayer = i; + _viewDescriptor.arrayLayerCount = 1; + + depthTextureData.viewCache[ layerIndex ] = depthTextureData.texture.createView( _viewDescriptor ); + + } _viewDescriptor.reset(); @@ -85812,14 +86440,29 @@ class WebGPUBackend extends Backend { * * @param {RenderContext} renderContext - The render context. * @param {Object} renderContextData - The render context data. + * @param {Object} descriptor - The render pass descriptor. * @param {ArrayCamera} cameras - The array camera. * */ - _updateArrayCameraLayerDescriptors( renderContext, renderContextData, cameras ) { + _updateArrayCameraLayerDescriptors( renderContext, renderContextData, descriptor, cameras ) { + + const renderTarget = renderContext.renderTarget; + const discardDepth = renderContext.sampleCount > 1 && renderTarget?.storeMultisampledDepthBuffer === false; + const discardStencil = renderContext.sampleCount > 1 && renderTarget?.storeMultisampledStencilBuffer === false; for ( let i = 0; i < cameras.length; i ++ ) { const layerDescriptor = renderContextData.layerDescriptors[ i ]; + const sourceColorAttachment = descriptor.colorAttachments[ 0 ]; + const layerColorAttachment = descriptor.colorAttachments[ i ]; + const colorAttachment = layerDescriptor.colorAttachments[ 0 ]; + + colorAttachment.view = layerColorAttachment.view; + colorAttachment.resolveTarget = layerColorAttachment.resolveTarget; + colorAttachment.depthSlice = layerColorAttachment.depthSlice; + colorAttachment.loadOp = sourceColorAttachment.loadOp; + colorAttachment.storeOp = sourceColorAttachment.storeOp; + colorAttachment.clearValue = sourceColorAttachment.clearValue; if ( layerDescriptor.depthStencilAttachment ) { @@ -85827,7 +86470,7 @@ class WebGPUBackend extends Backend { if ( renderContext.depth ) { - if ( renderContext.clearDepth ) { + if ( renderContext.clearDepth || discardDepth ) { depthAttachment.depthClearValue = renderContext.clearDepthValue; depthAttachment.depthLoadOp = GPULoadOp.Clear; @@ -85842,7 +86485,7 @@ class WebGPUBackend extends Backend { if ( renderContext.stencil ) { - if ( renderContext.clearStencil ) { + if ( renderContext.clearStencil || discardStencil ) { depthAttachment.stencilClearValue = renderContext.clearStencilValue; depthAttachment.stencilLoadOp = GPULoadOp.Clear; @@ -85892,20 +86535,49 @@ class WebGPUBackend extends Backend { if ( this._isRenderCameraDepthArray( renderContext ) === true ) { - const bundles = []; + const bundles = this._finishArrayCameraBundleEncoders( renderContextData ); + const renderStages = renderContextData.arrayCameraRenderStages; + renderStages.push( { bundles } ); - for ( let i = 0; i < renderContextData.bundleEncoders.length; i ++ ) { + // A viewport texture is 2D, so each layer must be captured immediately before that layer samples it. + for ( let i = 0; i < renderContextData.layerDescriptors.length; i ++ ) { - const bundleEncoder = renderContextData.bundleEncoders[ i ]; - bundles.push( bundleEncoder.finish() ); + const layerDescriptor = renderContextData.layerDescriptors[ i ]; + const colorLoadOps = layerDescriptor.colorAttachments.map( attachment => attachment.loadOp ); + const colorStoreOps = layerDescriptor.colorAttachments.map( attachment => attachment.storeOp ); + const depthLoadOp = layerDescriptor.depthStencilAttachment?.depthLoadOp; + const depthStoreOp = layerDescriptor.depthStencilAttachment?.depthStoreOp; + const stencilLoadOp = layerDescriptor.depthStencilAttachment?.stencilLoadOp; + const stencilStoreOp = layerDescriptor.depthStencilAttachment?.stencilStoreOp; - } + for ( let stageIndex = 0; stageIndex < renderStages.length; stageIndex ++ ) { + + const renderStage = renderStages[ stageIndex ]; + const bundle = renderStage.bundles[ i ]; + const isLastStage = stageIndex === renderStages.length - 1; + + for ( let j = 0; j < layerDescriptor.colorAttachments.length; j ++ ) { + + const attachment = layerDescriptor.colorAttachments[ j ]; + attachment.loadOp = stageIndex === 0 ? colorLoadOps[ j ] : GPULoadOp.Load; + attachment.storeOp = isLastStage ? colorStoreOps[ j ] : GPUStoreOp.Store; + + } + + if ( renderContext.depth ) { - for ( let i = 0; i < renderContextData.layerDescriptors.length; i ++ ) { + layerDescriptor.depthStencilAttachment.depthLoadOp = stageIndex === 0 ? depthLoadOp : GPULoadOp.Load; + layerDescriptor.depthStencilAttachment.depthStoreOp = isLastStage ? depthStoreOp : GPUStoreOp.Store; + + } - if ( i < bundles.length ) { + if ( renderContext.stencil ) { + + layerDescriptor.depthStencilAttachment.stencilLoadOp = stageIndex === 0 ? stencilLoadOp : GPULoadOp.Load; + layerDescriptor.depthStencilAttachment.stencilStoreOp = isLastStage ? stencilStoreOp : GPUStoreOp.Store; + + } - const layerDescriptor = renderContextData.layerDescriptors[ i ]; const renderPass = encoder.beginRenderPass( layerDescriptor ); if ( renderContext.viewport ) { @@ -85922,10 +86594,39 @@ class WebGPUBackend extends Backend { } - renderPass.executeBundles( [ bundles[ i ] ] ); + renderPass.executeBundles( [ bundle ] ); renderPass.end(); + if ( renderStage.framebufferCopy !== undefined ) { + + const { texture, sourceGPU, destinationGPU, rectangle, generateMipmaps } = renderStage.framebufferCopy; + + this._copyFramebufferToTexture( encoder, texture, sourceGPU, destinationGPU, rectangle, i, generateMipmaps ); + + } + + } + + for ( let j = 0; j < layerDescriptor.colorAttachments.length; j ++ ) { + + layerDescriptor.colorAttachments[ j ].loadOp = colorLoadOps[ j ]; + layerDescriptor.colorAttachments[ j ].storeOp = colorStoreOps[ j ]; + + } + + if ( renderContext.depth ) { + + layerDescriptor.depthStencilAttachment.depthLoadOp = depthLoadOp; + layerDescriptor.depthStencilAttachment.depthStoreOp = depthStoreOp; + + } + + if ( renderContext.stencil ) { + + layerDescriptor.depthStencilAttachment.stencilLoadOp = stencilLoadOp; + layerDescriptor.depthStencilAttachment.stencilStoreOp = stencilStoreOp; + } } @@ -86508,6 +87209,29 @@ class WebGPUBackend extends Backend { } + // blend constant + + if ( material.blending === CustomBlending && passEncoderGPU.setBlendConstant !== undefined ) { + + const blendColor = material.blendColor; + const blendAlpha = material.blendAlpha; + + if ( blendColor.equals( renderContextData.currentBlendColor ) === false || blendAlpha !== renderContextData.currentBlendAlpha ) { + + _blendConstant.r = blendColor.r; + _blendConstant.g = blendColor.g; + _blendConstant.b = blendColor.b; + _blendConstant.a = blendAlpha; + + passEncoderGPU.setBlendConstant( _blendConstant ); + + renderContextData.currentBlendColor.copy( blendColor ); + renderContextData.currentBlendAlpha = blendAlpha; + + } + + } + if ( object.isBatchedMesh === true ) { const starts = object._multiDrawStarts; @@ -86941,7 +87665,7 @@ class WebGPUBackend extends Backend { * @param {number} y - The y coordinate of the copy origin. * @param {number} width - The width of the copy. * @param {number} height - The height of the copy. - * @param {number} faceIndex - The face index. + * @param {number} faceIndex - The cube face, depth slice or array layer index. * @return {Promise} A Promise that resolves with a typed array when the copy operation has finished. */ async copyTextureToBuffer( texture, x, y, width, height, faceIndex ) { @@ -87049,10 +87773,11 @@ class WebGPUBackend extends Backend { * * @param {ComputePipeline} computePipeline - The compute pipeline. * @param {Array} bindings - The bindings. + * @param {?Array} [promises=null] - Optional compilation promises. */ - createComputePipeline( computePipeline, bindings ) { + createComputePipeline( computePipeline, bindings, promises = null ) { - this.pipelineUtils.createComputePipeline( computePipeline, bindings ); + this.pipelineUtils.createComputePipeline( computePipeline, bindings, promises ); } @@ -87482,6 +88207,29 @@ class WebGPUBackend extends Backend { } + if ( this._isRenderCameraDepthArray( renderContext ) === true ) { + + // Layered draws are only executed in finishRender(), so preserve this copy as a render-stage boundary. + const bundles = this._finishArrayCameraBundleEncoders( renderContextData ); + + renderContextData.arrayCameraRenderStages.push( { + bundles, + framebufferCopy: { + texture, + sourceGPU, + destinationGPU, + rectangle: { x: rectangle.x, y: rectangle.y, z: rectangle.z, w: rectangle.w }, + // ViewportTextureNode restores this flag before the deferred copy executes. + generateMipmaps: texture.generateMipmaps + } + } ); + + this._createArrayCameraBundleEncoders( renderContext, renderContextData ); + + return; + + } + let encoder; if ( renderContextData.currentPass ) { @@ -87498,33 +88246,10 @@ class WebGPUBackend extends Backend { } - _texelCopyTextureInfoSrc.texture = sourceGPU; - _texelCopyTextureInfoSrc.origin.x = rectangle.x; - _texelCopyTextureInfoSrc.origin.y = rectangle.y; - - _texelCopyTextureInfoDst.texture = destinationGPU; - - _extent3D.width = rectangle.z; - _extent3D.height = rectangle.w; - - encoder.copyTextureToTexture( - _texelCopyTextureInfoSrc, - _texelCopyTextureInfoDst, - _extent3D - ); - - _texelCopyTextureInfoSrc.reset(); - _texelCopyTextureInfoDst.reset(); - _extent3D.reset(); - // mipmaps must be genereated with the same encoder otherwise the copied texture data // might be out-of-sync, see #31768 - if ( texture.generateMipmaps ) { - - this.textureUtils.generateMipmaps( texture, encoder ); - - } + this._copyFramebufferToTexture( encoder, texture, sourceGPU, destinationGPU, rectangle ); if ( renderContextData.currentPass ) { @@ -87540,7 +88265,8 @@ class WebGPUBackend extends Backend { if ( renderContext.stencil ) descriptor.depthStencilAttachment.stencilLoadOp = GPULoadOp.Load; renderContextData.currentPass = encoder.beginRenderPass( descriptor ); - renderContextData.currentSets = { attributes: {}, bindingGroups: [], pipeline: null, index: null }; + + this._resetRenderContextData( renderContextData ); if ( renderContext.viewport ) { @@ -87562,6 +88288,48 @@ class WebGPUBackend extends Backend { } + /** + * Encodes a framebuffer copy from a specific texture-array layer. + * + * @param {GPUCommandEncoder} encoder - The command encoder. + * @param {Texture} texture - The destination texture. + * @param {GPUTexture} sourceGPU - The source GPU texture. + * @param {GPUTexture} destinationGPU - The destination GPU texture. + * @param {Object} rectangle - The source rectangle. + * @param {number} [sourceLayer=0] - The source array layer. + * @param {boolean} [generateMipmaps=texture.generateMipmaps] - Whether mipmaps should be generated. + * @private + */ + _copyFramebufferToTexture( encoder, texture, sourceGPU, destinationGPU, rectangle, sourceLayer = 0, generateMipmaps = texture.generateMipmaps ) { + + _texelCopyTextureInfoSrc.texture = sourceGPU; + _texelCopyTextureInfoSrc.origin.x = rectangle.x; + _texelCopyTextureInfoSrc.origin.y = rectangle.y; + _texelCopyTextureInfoSrc.origin.z = sourceLayer; + + _texelCopyTextureInfoDst.texture = destinationGPU; + + _extent3D.width = rectangle.z; + _extent3D.height = rectangle.w; + + encoder.copyTextureToTexture( + _texelCopyTextureInfoSrc, + _texelCopyTextureInfoDst, + _extent3D + ); + + _texelCopyTextureInfoSrc.reset(); + _texelCopyTextureInfoDst.reset(); + _extent3D.reset(); + + if ( generateMipmaps ) { + + this.textureUtils.generateMipmaps( texture, encoder ); + + } + + } + /** * Checks if the given compatibility is supported by the backend. * @@ -88863,4 +89631,4 @@ class ClippingGroup extends Group { } -export { ACESFilmicToneMapping, AONode, AddEquation, AddOperation, AdditiveBlending, AgXToneMapping, AlphaFormat, AlwaysCompare, AlwaysDepth, AlwaysStencilFunc, AmbientLight, AmbientLightNode, AnalyticLightNode, ArrayCamera, ArrayElementNode, ArrayNode, AssignNode, AtomicFunctionNode, AttributeNode, BackSide, BarrierNode, BasicEnvironmentNode, BasicLightMapNode, BasicShadowMap, BitcastNode, BitcountNode, BlendMode, BoxGeometry, BufferAttribute, BufferAttributeNode, BufferGeometry, BufferNode, BuiltinNode, BumpMapNode, BundleGroup, BypassNode, ByteType, CanvasTarget, CineonToneMapping, ClampToEdgeWrapping, ClippingGroup, ClippingNode, CodeNode, Color, ColorManagement, ColorSpaceNode, Compatibility, ComputeBuiltinNode, ComputeNode, ConditionalNode, ConstNode, ContextNode, ConvertNode, CubeCamera, CubeDepthTexture, CubeMapNode, CubeReflectionMapping, CubeRefractionMapping, CubeTexture, CubeTextureNode, CubeUVReflectionMapping, CullFaceBack, CullFaceFront, CullFaceNone, CustomBlending, CylinderGeometry, DataArrayTexture, DataTexture, DebugNode, DecrementStencilOp, DecrementWrapStencilOp, DepthFormat, DepthStencilFormat, DepthTexture, DirectionalLight, DirectionalLightNode, DoubleSide, DstAlphaFactor, DstColorFactor, DynamicDrawUsage, EnvironmentNode, EqualCompare, EqualDepth, EqualStencilFunc, EquirectangularReflectionMapping, EquirectangularRefractionMapping, EventDispatcher, EventNode, ExpressionNode, FileLoader, FlipNode, Float16BufferAttribute, Float32BufferAttribute, FloatType, FramebufferTexture, FrontFacingNode, FrontSide, Frustum, FrustumArray, FunctionCallNode, FunctionNode, FunctionOverloadingNode, GLSLNodeParser, GreaterCompare, GreaterDepth, GreaterEqualCompare, GreaterEqualDepth, GreaterEqualStencilFunc, GreaterStencilFunc, Group, HalfFloatType, HemisphereLight, HemisphereLightNode, IESSpotLight, IESSpotLightNode, IncrementStencilOp, IncrementWrapStencilOp, IndexNode, IndirectStorageBufferAttribute, InputNode, InspectorBase, InspectorNode, InstancedBufferAttribute, InstancedInterleavedBuffer, IntType, InterleavedBuffer, InterleavedBufferAttribute, InvertStencilOp, IrradianceNode, IsolateNode, JoinNode, KeepStencilOp, LessCompare, LessDepth, LessEqualCompare, LessEqualDepth, LessEqualStencilFunc, LessStencilFunc, LightProbe, LightProbeNode, Lighting, LightingContextNode, LightingModel, LightingNode, LightsNode, Line2NodeMaterial, LineBasicMaterial, LineBasicNodeMaterial, LineDashedMaterial, LineDashedNodeMaterial, LinearFilter, LinearMipMapLinearFilter, LinearMipmapLinearFilter, LinearMipmapNearestFilter, LinearSRGBColorSpace, LinearToneMapping, LinearTransfer, Loader, LoopNode, MRTNode, Material, MaterialBlending, MaterialLoader, MaterialNode, MaterialReferenceNode, MathNode, MathUtils, Matrix2, Matrix3, Matrix4, MaxEquation, MaxMipLevelNode, MemberNode, Mesh, MeshBasicMaterial, MeshBasicNodeMaterial, MeshLambertMaterial, MeshLambertNodeMaterial, MeshMatcapMaterial, MeshMatcapNodeMaterial, MeshNormalMaterial, MeshNormalNodeMaterial, MeshPhongMaterial, MeshPhongNodeMaterial, MeshPhysicalMaterial, MeshPhysicalNodeMaterial, MeshSSSNodeMaterial, MeshStandardMaterial, MeshStandardNodeMaterial, MeshToonMaterial, MeshToonNodeMaterial, MinEquation, MirroredRepeatWrapping, MixOperation, ModelNode, MultiplyBlending, MultiplyOperation, NearestFilter, NearestMipmapLinearFilter, NearestMipmapNearestFilter, NeutralToneMapping, NeverCompare, NeverDepth, NeverStencilFunc, NoBlending, NoColorSpace, NoNormalPacking, NoToneMapping, Node, NodeAccess, NodeAttribute, NodeBuilder, NodeCache, NodeCode, NodeError, NodeFrame, NodeFunctionInput, NodeLoader, NodeMaterial, NodeMaterialLoader, NodeMaterialObserver, NodeObjectLoader, NodeShaderStage, NodeType, NodeUniform, NodeUpdateType, NodeUtils, NodeVar, NodeVarying, NormalBlending, NormalGAPacking, NormalMapNode, NormalRGPacking, NotEqualCompare, NotEqualDepth, NotEqualStencilFunc, Object3D, Object3DNode, ObjectLoader, ObjectSpaceNormalMap, OneFactor, OneMinusDstAlphaFactor, OneMinusDstColorFactor, OneMinusSrcAlphaFactor, OneMinusSrcColorFactor, OperatorNode, OrthographicCamera, OutputStructNode, OverrideContextNode, PCFShadowMap, PCFSoftShadowMap, PMREMGenerator, PMREMNode, PackFloatNode, ParameterNode, PassNode, PerspectiveCamera, PhongLightingModel, PhysicalLightingModel, Plane, PlaneGeometry, PointLight, PointLightNode, PointShadowNode, PointUVNode, PointsMaterial, PointsNodeMaterial, PostProcessing, ProjectorLight, ProjectorLightNode, PropertyNode, QuadMesh, Quaternion, R11_EAC_Format, RED_GREEN_RGTC2_Format, RED_RGTC1_Format, REVISION, RG11_EAC_Format, RGBAFormat, RGBAIntegerFormat, RGBA_ASTC_10x10_Format, RGBA_ASTC_10x5_Format, RGBA_ASTC_10x6_Format, RGBA_ASTC_10x8_Format, RGBA_ASTC_12x10_Format, RGBA_ASTC_12x12_Format, RGBA_ASTC_4x4_Format, RGBA_ASTC_5x4_Format, RGBA_ASTC_5x5_Format, RGBA_ASTC_6x5_Format, RGBA_ASTC_6x6_Format, RGBA_ASTC_8x5_Format, RGBA_ASTC_8x6_Format, RGBA_ASTC_8x8_Format, RGBA_BPTC_Format, RGBA_ETC2_EAC_Format, RGBA_PVRTC_2BPPV1_Format, RGBA_PVRTC_4BPPV1_Format, RGBA_S3TC_DXT1_Format, RGBA_S3TC_DXT3_Format, RGBA_S3TC_DXT5_Format, RGBFormat, RGBIntegerFormat, RGB_BPTC_SIGNED_Format, RGB_BPTC_UNSIGNED_Format, RGB_ETC1_Format, RGB_ETC2_Format, RGB_PVRTC_2BPPV1_Format, RGB_PVRTC_4BPPV1_Format, RGB_S3TC_DXT1_Format, RGFormat, RGIntegerFormat, RTTNode, RangeNode, ReadbackBuffer, RectAreaLight, RectAreaLightNode, RedFormat, RedIntegerFormat, ReferenceBaseNode, ReferenceNode, ReflectorNode, ReinhardToneMapping, RenderOutputNode, RenderPipeline, RenderTarget, RendererReferenceNode, RendererUtils, RepeatWrapping, ReplaceStencilOp, ReverseSubtractEquation, RotateNode, SIGNED_R11_EAC_Format, SIGNED_RED_GREEN_RGTC2_Format, SIGNED_RED_RGTC1_Format, SIGNED_RG11_EAC_Format, SRGBColorSpace, SRGBTransfer, SampleNode, Scene, ScreenNode, SetNode, ShadowBaseNode, ShadowMaterial, ShadowNode, ShadowNodeMaterial, ShortType, Sphere, SphereGeometry, SplitNode, SpotLight, SpotLightNode, SpriteMaterial, SpriteNodeMaterial, SrcAlphaFactor, SrcAlphaSaturateFactor, SrcColorFactor, StackNode, StackTrace, StaticDrawUsage, StorageArrayElementNode, StorageBufferAttribute, StorageBufferNode, StorageInstancedBufferAttribute, StorageTexture, StorageTexture3DNode, StorageTextureNode, StructNode, StructTypeNode, SubBuildNode, SubgroupFunctionNode, SubtractEquation, SubtractiveBlending, TSL, TangentSpaceNormalMap, TempNode, Texture, Texture3DNode, TextureNode, TextureSizeNode, TimestampQuery, ToneMappingNode, ToonOutlinePassNode, UVMapping, Uint16BufferAttribute, Uint32BufferAttribute, UniformArrayNode, UniformGroupNode, UniformNode, UnpackFloatNode, UnsignedByteType, UnsignedInt101111Type, UnsignedInt248Type, UnsignedInt5999Type, UnsignedIntType, UnsignedShort4444Type, UnsignedShort5551Type, UnsignedShortType, UserDataNode, VSMShadowMap, VarNode, VaryingNode, Vector2, Vector3, Vector4, VelocityNode, VertexColorNode, ViewportDepthNode, ViewportDepthTextureNode, ViewportSharedTextureNode, ViewportTextureNode, VolumeNodeMaterial, WebGLBackend, WebGLCoordinateSystem, WebGPUBackend, WebGPUCoordinateSystem, WebGPURenderer, WebXRController, WorkgroupInfoNode, ZeroFactor, ZeroStencilOp, createCanvasElement, defaultBuildStages, defaultShaderStages, error, log$1 as log, shaderStages, vectorComponents, warn, warnOnce }; +export { ACESFilmicToneMapping, AONode, AddEquation, AddOperation, AdditiveBlending, AgXToneMapping, AlphaFormat, AlwaysCompare, AlwaysDepth, AlwaysStencilFunc, AmbientLight, AmbientLightNode, AnalyticLightNode, ArrayCamera, ArrayElementNode, ArrayNode, AssignNode, AtomicFunctionNode, AttributeNode, BackSide, BarrierNode, BasicEnvironmentNode, BasicLightMapNode, BasicShadowMap, BitcastNode, BitcountNode, BlendMode, BoxGeometry, BufferAttribute, BufferAttributeNode, BufferGeometry, BufferNode, BuiltinNode, BumpMapNode, BundleGroup, BypassNode, ByteType, CanvasTarget, CineonToneMapping, ClampToEdgeWrapping, ClippingGroup, ClippingNode, CodeNode, Color, ColorManagement, ColorSpaceNode, Compatibility, ComputeBuiltinNode, ComputeNode, ConditionalNode, ConstNode, ConstantAlphaFactor, ConstantColorFactor, ContextNode, ConvertNode, CubeCamera, CubeDepthTexture, CubeMapNode, CubeReflectionMapping, CubeRefractionMapping, CubeTexture, CubeTextureNode, CubeUVReflectionMapping, CullFaceBack, CullFaceFront, CullFaceNone, CustomBlending, CylinderGeometry, DataArrayTexture, DataTexture, DebugNode, DecrementStencilOp, DecrementWrapStencilOp, DepthFormat, DepthStencilFormat, DepthTexture, DirectionalLight, DirectionalLightNode, DoubleSide, DstAlphaFactor, DstColorFactor, DynamicDrawUsage, EnvironmentNode, EqualCompare, EqualDepth, EqualStencilFunc, EquirectangularReflectionMapping, EquirectangularRefractionMapping, EventDispatcher, EventNode, ExpressionNode, FileLoader, FlipNode, Float16BufferAttribute, Float32BufferAttribute, FloatType, FramebufferTexture, FrontFacingNode, FrontSide, Frustum, FrustumArray, FunctionCallNode, FunctionNode, FunctionOverloadingNode, GLSLNodeParser, GreaterCompare, GreaterDepth, GreaterEqualCompare, GreaterEqualDepth, GreaterEqualStencilFunc, GreaterStencilFunc, Group, HalfFloatType, HemisphereLight, HemisphereLightNode, IESSpotLight, IESSpotLightNode, IncrementStencilOp, IncrementWrapStencilOp, IndexNode, IndirectStorageBufferAttribute, InputNode, InspectorBase, InspectorNode, InstancedBufferAttribute, InstancedInterleavedBuffer, IntType, InterleavedBuffer, InterleavedBufferAttribute, InvertStencilOp, IrradianceNode, IsolateNode, JoinNode, KeepStencilOp, LessCompare, LessDepth, LessEqualCompare, LessEqualDepth, LessEqualStencilFunc, LessStencilFunc, LightProbe, LightProbeNode, Lighting, LightingContextNode, LightingModel, LightingNode, LightsNode, Line2NodeMaterial, LineBasicMaterial, LineBasicNodeMaterial, LineDashedMaterial, LineDashedNodeMaterial, LinearFilter, LinearMipMapLinearFilter, LinearMipmapLinearFilter, LinearMipmapNearestFilter, LinearSRGBColorSpace, LinearToneMapping, LinearTransfer, Loader, LoopNode, MRTNode, Material, MaterialBlending, MaterialLoader, MaterialNode, MaterialReferenceNode, MathNode, MathUtils, Matrix2, Matrix3, Matrix4, MaxEquation, MaxMipLevelNode, MemberNode, Mesh, MeshBasicMaterial, MeshBasicNodeMaterial, MeshLambertMaterial, MeshLambertNodeMaterial, MeshMatcapMaterial, MeshMatcapNodeMaterial, MeshNormalMaterial, MeshNormalNodeMaterial, MeshPhongMaterial, MeshPhongNodeMaterial, MeshPhysicalMaterial, MeshPhysicalNodeMaterial, MeshSSSNodeMaterial, MeshStandardMaterial, MeshStandardNodeMaterial, MeshToonMaterial, MeshToonNodeMaterial, MinEquation, MirroredRepeatWrapping, MixOperation, ModelNode, MultiplyBlending, MultiplyOperation, NearestFilter, NearestMipmapLinearFilter, NearestMipmapNearestFilter, NeutralToneMapping, NeverCompare, NeverDepth, NeverStencilFunc, NoBlending, NoColorSpace, NoNormalPacking, NoToneMapping, Node, NodeAccess, NodeAttribute, NodeBuilder, NodeCache, NodeCode, NodeError, NodeFrame, NodeFunctionInput, NodeLoader, NodeMaterial, NodeMaterialLoader, NodeMaterialObserver, NodeObjectLoader, NodeShaderStage, NodeType, NodeUniform, NodeUpdateType, NodeUtils, NodeVar, NodeVarying, NormalBlending, NormalGAPacking, NormalMapNode, NormalRGPacking, NotEqualCompare, NotEqualDepth, NotEqualStencilFunc, Object3D, Object3DNode, ObjectLoader, ObjectSpaceNormalMap, OneFactor, OneMinusConstantAlphaFactor, OneMinusConstantColorFactor, OneMinusDstAlphaFactor, OneMinusDstColorFactor, OneMinusSrcAlphaFactor, OneMinusSrcColorFactor, OperatorNode, OrthographicCamera, OutputStructNode, OverrideContextNode, PCFShadowMap, PCFSoftShadowMap, PMREMGenerator, PMREMNode, PackFloatNode, ParameterNode, PassNode, PerspectiveCamera, PhongLightingModel, PhysicalLightingModel, Plane, PlaneGeometry, PointLight, PointLightNode, PointShadowNode, PointUVNode, PointsMaterial, PointsNodeMaterial, PostProcessing, ProjectorLight, ProjectorLightNode, PropertyNode, QuadMesh, Quaternion, R11_EAC_Format, RED_GREEN_RGTC2_Format, RED_RGTC1_Format, REVISION, RG11_EAC_Format, RGBAFormat, RGBAIntegerFormat, RGBA_ASTC_10x10_Format, RGBA_ASTC_10x5_Format, RGBA_ASTC_10x6_Format, RGBA_ASTC_10x8_Format, RGBA_ASTC_12x10_Format, RGBA_ASTC_12x12_Format, RGBA_ASTC_4x4_Format, RGBA_ASTC_5x4_Format, RGBA_ASTC_5x5_Format, RGBA_ASTC_6x5_Format, RGBA_ASTC_6x6_Format, RGBA_ASTC_8x5_Format, RGBA_ASTC_8x6_Format, RGBA_ASTC_8x8_Format, RGBA_BPTC_Format, RGBA_ETC2_EAC_Format, RGBA_PVRTC_2BPPV1_Format, RGBA_PVRTC_4BPPV1_Format, RGBA_S3TC_DXT1_Format, RGBA_S3TC_DXT3_Format, RGBA_S3TC_DXT5_Format, RGBFormat, RGBIntegerFormat, RGB_BPTC_SIGNED_Format, RGB_BPTC_UNSIGNED_Format, RGB_ETC1_Format, RGB_ETC2_Format, RGB_PVRTC_2BPPV1_Format, RGB_PVRTC_4BPPV1_Format, RGB_S3TC_DXT1_Format, RGFormat, RGIntegerFormat, RTTNode, RangeNode, ReadbackBuffer, RectAreaLight, RectAreaLightNode, RedFormat, RedIntegerFormat, ReferenceBaseNode, ReferenceNode, ReflectorNode, ReinhardToneMapping, RenderOutputNode, RenderPipeline, RenderTarget, RendererReferenceNode, RendererUtils, RepeatWrapping, ReplaceStencilOp, ReverseSubtractEquation, RotateNode, SIGNED_R11_EAC_Format, SIGNED_RED_GREEN_RGTC2_Format, SIGNED_RED_RGTC1_Format, SIGNED_RG11_EAC_Format, SRGBColorSpace, SRGBTransfer, SampleNode, Scene, ScreenNode, SetNode, ShadowBaseNode, ShadowMaterial, ShadowNode, ShadowNodeMaterial, ShortType, Sphere, SphereGeometry, SplitNode, SpotLight, SpotLightNode, SpriteMaterial, SpriteNodeMaterial, SrcAlphaFactor, SrcAlphaSaturateFactor, SrcColorFactor, StackNode, StackTrace, StaticDrawUsage, StorageArrayElementNode, StorageBufferAttribute, StorageBufferNode, StorageInstancedBufferAttribute, StorageTexture, StorageTexture3DNode, StorageTextureNode, StructNode, StructTypeNode, SubBuildNode, SubgroupFunctionNode, SubtractEquation, SubtractiveBlending, TSL, TangentSpaceNormalMap, TempNode, Texture, Texture3DNode, TextureNode, TextureSizeNode, TimestampQuery, ToneMappingNode, ToonOutlinePassNode, UVMapping, Uint16BufferAttribute, Uint32BufferAttribute, UniformArrayNode, UniformGroupNode, UniformNode, UnpackFloatNode, UnsignedByteType, UnsignedInt101111Type, UnsignedInt248Type, UnsignedInt5999Type, UnsignedIntType, UnsignedShort4444Type, UnsignedShort5551Type, UnsignedShortType, UserDataNode, VSMShadowMap, VarNode, VaryingNode, Vector2, Vector3, Vector4, VelocityNode, VertexColorNode, ViewportDepthNode, ViewportDepthTextureNode, ViewportSharedTextureNode, ViewportTextureNode, VolumeNodeMaterial, WebGLBackend, WebGLCoordinateSystem, WebGPUBackend, WebGPUCoordinateSystem, WebGPURenderer, WebXRController, WorkgroupInfoNode, ZeroFactor, ZeroStencilOp, createCanvasElement, defaultBuildStages, defaultShaderStages, error, log$1 as log, shaderStages, vectorComponents, warn, warnOnce }; diff --git a/examples/screenshots/webgpu_loader_materialx.jpg b/examples/screenshots/webgpu_loader_materialx.jpg index a9d673b5c779cc..4be4781b12107f 100644 Binary files a/examples/screenshots/webgpu_loader_materialx.jpg and b/examples/screenshots/webgpu_loader_materialx.jpg differ diff --git a/src/materials/nodes/MeshPhysicalNodeMaterial.js b/src/materials/nodes/MeshPhysicalNodeMaterial.js index bd0b92411317ea..3293ff37d4b222 100644 --- a/src/materials/nodes/MeshPhysicalNodeMaterial.js +++ b/src/materials/nodes/MeshPhysicalNodeMaterial.js @@ -373,11 +373,13 @@ class MeshPhysicalNodeMaterial extends MeshStandardNodeMaterial { setupSpecular() { const iorNode = this.iorNode ? float( this.iorNode ) : materialIOR; + const specularColorNode = this.specularColorNode ? vec3( this.specularColorNode ) : materialSpecularColor; + const specularIntensityNode = this.specularIntensityNode ? float( this.specularIntensityNode ) : materialSpecularIntensity; ior.assign( iorNode ); - specularColor.assign( min( pow2( ior.sub( 1.0 ).div( ior.add( 1.0 ) ) ).mul( materialSpecularColor ), vec3( 1.0 ) ).mul( materialSpecularIntensity ) ); + specularColor.assign( min( pow2( ior.sub( 1.0 ).div( ior.add( 1.0 ) ) ).mul( specularColorNode ), vec3( 1.0 ) ).mul( specularIntensityNode ) ); specularColorBlended.assign( mix( specularColor, diffuseColor.rgb, metalness ) ); - specularF90.assign( mix( materialSpecularIntensity, 1.0, metalness ) ); + specularF90.assign( mix( specularIntensityNode, 1.0, metalness ) ); }