@vincentt-xr/sdk 2.0.0-alpha.7 → 2.0.0-alpha.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/GROUNDING.md +5651 -82
- package/README.md +1 -0
- package/dist/CanonicalHeadFrame-BHcWyaiK.js +1506 -0
- package/dist/CanonicalHeadFrame-D-_T1OMU.cjs +1 -0
- package/dist/DebuggerUI-7ngnJsBe.js +275 -0
- package/dist/DebuggerUI-CoglgKdO.cjs +1 -0
- package/dist/FaceRetouch-CLoTfrcs.js +1071 -0
- package/dist/FaceRetouch-J1lC1WbS.cjs +134 -0
- package/dist/FaceSurface-CHAMEeG1.cjs +1 -0
- package/dist/FaceSurface-DmP9AEeC.js +27 -0
- package/dist/SegmentationOverlay-D_FWkcyP.cjs +35 -0
- package/dist/SegmentationOverlay-vn5x_knv.js +6237 -0
- package/dist/SkeletonUtils-C2r90MtN.js +21 -0
- package/dist/SkeletonUtils-CddIup1F.cjs +1 -0
- package/dist/TextLabel-XE0rQSDn.cjs +2 -0
- package/dist/TextLabel-c9BCucOI.js +961 -0
- package/dist/assets/cache.d.ts +99 -0
- package/dist/assets/estimate.d.ts +11 -0
- package/dist/assets/gltfLoader.d.ts +16 -0
- package/dist/assets/index.d.ts +7 -0
- package/dist/assets/loaders.d.ts +43 -0
- package/dist/assets/react.d.ts +33 -0
- package/dist/body-pose/index.d.ts +521 -0
- package/dist/body-trigger/__fixtures__/syntheticBody.d.ts +83 -0
- package/dist/body-trigger/frame.d.ts +88 -0
- package/dist/body-trigger/index.d.ts +6 -0
- package/dist/body-trigger/moves.d.ts +235 -0
- package/dist/body-trigger/trigger.d.ts +75 -0
- package/dist/calibration/calibration.d.ts +75 -0
- package/dist/calibration/index.d.ts +6 -0
- package/dist/calibration/storage.d.ts +13 -0
- package/dist/calibration/types.d.ts +53 -0
- package/dist/calibration/useXRCalibration.d.ts +46 -0
- package/dist/camera/CameraPermissionGate.d.ts +26 -0
- package/dist/camera/devices.d.ts +26 -0
- package/dist/camera/index.d.ts +8 -0
- package/dist/camera/permission.d.ts +86 -0
- package/dist/camera/useCameraPermission.d.ts +35 -0
- package/dist/canonicalFace-BHwyCx1c.js +9 -0
- package/dist/canonicalFace-C83I225R.cjs +1 -0
- package/dist/capabilities/detect.d.ts +45 -0
- package/dist/capabilities/index.d.ts +5 -0
- package/dist/capabilities/types.d.ts +120 -0
- package/dist/capabilities/useXRCapabilities.d.ts +18 -0
- package/dist/compat/environment.d.ts +5 -0
- package/dist/compat/index.d.ts +4 -0
- package/dist/compat/run.d.ts +18 -0
- package/dist/compat/scenarios.d.ts +10 -0
- package/dist/compat/types.d.ts +101 -0
- package/dist/components/BodyInstruction/BodyPoseHint.d.ts +63 -0
- package/dist/components/BodyInstruction/index.d.ts +69 -0
- package/dist/components/BodyInstruction/useBodyPose.d.ts +23 -0
- package/dist/components/BodyTracker/index.d.ts +17 -0
- package/dist/components/BodyTrigger/index.d.ts +49 -0
- package/dist/components/Debugger/DebuggerProvider.d.ts +14 -1
- package/dist/components/Debugger/DebuggerUI.d.ts +3 -1
- package/dist/components/FaceAtlas/FaceAtlasLayer.d.ts +114 -0
- package/dist/components/FaceAtlas/MadeUpCamera.d.ts +80 -0
- package/dist/components/FaceAtlas/constants.d.ts +8 -0
- package/dist/components/FaceAtlas/index.d.ts +7 -0
- package/dist/components/FaceAtlas/useFaceAtlasSurface.d.ts +84 -0
- package/dist/components/FaceAtlas/useFaceSkin.d.ts +84 -0
- package/dist/components/FaceCharacter/ExternalFaceMesh.d.ts +109 -0
- package/dist/components/FaceCharacter/FaceExpressionController.d.ts +53 -0
- package/dist/components/FaceCharacter/FaceMorph.d.ts +71 -0
- package/dist/components/FaceCharacter/FacePiercing.d.ts +65 -0
- package/dist/components/FaceCharacter/FaceReprojection.d.ts +85 -0
- package/dist/components/FaceCharacter/FaceRig.d.ts +38 -0
- package/dist/components/FaceCharacter/FaceSurface.d.ts +49 -0
- package/dist/components/FaceCharacter/FaceSurfaceOccluder.d.ts +39 -0
- package/dist/components/FaceCharacter/PinToFaceMesh.d.ts +68 -0
- package/dist/components/FaceCharacter/index.d.ts +18 -0
- package/dist/components/FaceCharacter/useFaceReprojector.d.ts +10 -0
- package/dist/components/FaceInset/FaceInset.d.ts +68 -0
- package/dist/components/FaceInset/frame.d.ts +94 -0
- package/dist/components/FaceInset/index.d.ts +6 -0
- package/dist/components/FaceInset/material.d.ts +40 -0
- package/dist/components/FaceInset/useFaceInsetTexture.d.ts +37 -0
- package/dist/components/FaceInstruction/FaceExpressionHint.d.ts +43 -0
- package/dist/components/FaceInstruction/index.d.ts +56 -0
- package/dist/components/FaceInstruction/useFaceExpression.d.ts +20 -0
- package/dist/components/FaceLiquify/FaceLiquify.d.ts +49 -0
- package/dist/components/FaceLiquify/debug.d.ts +37 -0
- package/dist/components/FaceLiquify/frame.d.ts +55 -0
- package/dist/components/FaceLiquify/index.d.ts +10 -0
- package/dist/components/FaceLiquify/material.d.ts +39 -0
- package/dist/components/FaceLiquify/pass.d.ts +49 -0
- package/dist/components/FaceLiquify/presence.d.ts +25 -0
- package/dist/components/FaceLiquify/presets.d.ts +82 -0
- package/dist/components/FaceLiquify/selfTest.d.ts +66 -0
- package/dist/components/FaceLiquify/target.d.ts +85 -0
- package/dist/components/FaceLiquify/warp.d.ts +72 -0
- package/dist/components/FaceMesh/canonical/CanonicalFaceMeshRenderer.d.ts +37 -5
- package/dist/components/FaceMesh/canonical/geometryGroups.d.ts +21 -0
- package/dist/components/FaceMesh/canonical/parseCanonicalFaceModel.d.ts +21 -0
- package/dist/components/FaceMesh/canonical/shaders.d.ts +1 -1
- package/dist/components/FaceMesh/index.d.ts +2 -2
- package/dist/components/FaceRetouch/Background.d.ts +3 -1
- package/dist/components/FaceRetouch/FaceRetouch.d.ts +5 -0
- package/dist/components/FaceRetouch/renderState.d.ts +19 -0
- package/dist/components/FaceSwap/FaceMirror.d.ts +46 -0
- package/dist/components/FaceSwap/FaceSwap.d.ts +58 -0
- package/dist/components/FaceSwap/FaceTextureLayer.d.ts +72 -0
- package/dist/components/FaceSwap/faceSwapPlan.d.ts +91 -0
- package/dist/components/FaceSwap/index.d.ts +13 -0
- package/dist/components/FaceSwap/settings.d.ts +300 -0
- package/dist/components/FaceSwap/useFaceTexture.d.ts +35 -0
- package/dist/components/FaceSwap/useLiveFace.d.ts +38 -0
- package/dist/components/FaceSwap/useLiveFaceTexture.d.ts +31 -0
- package/dist/components/FaceWarp3D/FaceWarp3D.d.ts +50 -0
- package/dist/components/FaceWarp3D/index.d.ts +2 -3
- package/dist/components/Faceless/Faceless.d.ts +51 -0
- package/dist/components/Faceless/index.d.ts +2 -0
- package/dist/components/GestureListener/index.d.ts +11 -0
- package/dist/components/HairLock/HairLock.d.ts +39 -0
- package/dist/components/HairLock/index.d.ts +2 -0
- package/dist/components/HairLock/lockGeometry.d.ts +15 -0
- package/dist/components/HandCutout/index.d.ts +35 -0
- package/dist/components/HandInstruction/HandGestureHint.d.ts +70 -0
- package/dist/components/HandInstruction/index.d.ts +74 -0
- package/dist/components/HandInstruction/useHandGesture.d.ts +22 -0
- package/dist/components/HandRig/ForearmOccluder.d.ts +29 -0
- package/dist/components/HandRig/HandAttachment.d.ts +34 -0
- package/dist/components/HandRig/HandOccluder.d.ts +55 -0
- package/dist/components/HandRig/HandTattoo.d.ts +61 -0
- package/dist/components/HandRig/WristAttachment.d.ts +34 -0
- package/dist/components/HandRig/index.d.ts +101 -0
- package/dist/components/HandRig/useArmMask.d.ts +29 -0
- package/dist/components/HandRig/wristSolve.d.ts +69 -0
- package/dist/components/HandTouch/HandTouch.d.ts +62 -0
- package/dist/components/HandTouch/Touchable.d.ts +36 -0
- package/dist/components/HandTouch/index.d.ts +2 -0
- package/dist/components/HandTracker/index.d.ts +10 -0
- package/dist/components/HeadBinding/index.d.ts +14 -0
- package/dist/components/HeadOccluder/CanonicalHeadFrame.d.ts +22 -0
- package/dist/components/HeadOccluder/Earrings.d.ts +55 -0
- package/dist/components/HeadOccluder/HeadAttachment.d.ts +38 -0
- package/dist/components/HeadOccluder/NeckOccluder.d.ts +64 -0
- package/dist/components/HeadOccluder/earringPlacement.d.ts +31 -0
- package/dist/components/HeadOccluder/headAttachmentPoints.d.ts +69 -0
- package/dist/components/HeadOccluder/index.d.ts +57 -3
- package/dist/components/HeadOccluder/useCanonicalHeadFit.d.ts +36 -0
- package/dist/components/HeadOccluder/useLandmarkPoseFit.d.ts +80 -0
- package/dist/components/HolisticTracker/index.d.ts +69 -0
- package/dist/components/HolisticTracker/settings.d.ts +58 -0
- package/dist/components/HolisticTracker/signals.d.ts +49 -0
- package/dist/components/Instruction/HintStage.d.ts +29 -0
- package/dist/components/Instruction/InstructionCue.d.ts +126 -0
- package/dist/components/Instruction/gestureHold.d.ts +20 -0
- package/dist/components/Instruction/ghost.d.ts +129 -0
- package/dist/components/Instruction/hintBlend.d.ts +19 -0
- package/dist/components/Instruction/hintLook.d.ts +81 -0
- package/dist/components/Instruction/hintLoop.d.ts +36 -0
- package/dist/components/Instruction/index.d.ts +41 -0
- package/dist/components/Instruction/useGhostModel.d.ts +33 -0
- package/dist/components/Instruction/useInstructionHold.d.ts +72 -0
- package/dist/components/IrisEffect/IrisMaterial.d.ts +73 -0
- package/dist/components/IrisEffect/index.d.ts +51 -0
- package/dist/components/IrisEffect/settings.d.ts +117 -0
- package/dist/components/LipEffect/LipEffect.d.ts +27 -1
- package/dist/components/LipEffect/LipEffectMaterial.d.ts +95 -7
- package/dist/components/LipEffect/LipEffects.d.ts +12 -0
- package/dist/components/LipEffect/defaults.d.ts +46 -4
- package/dist/components/LipEffect/index.d.ts +11 -3
- package/dist/components/LipEffect/lipShading.d.ts +73 -0
- package/dist/components/LipEffect/settings.d.ts +375 -0
- package/dist/components/LipEffect/shader.d.ts +39 -0
- package/dist/components/LipEffect/types.d.ts +128 -9
- package/dist/components/LipEffect/useLipDesignTextures.d.ts +17 -0
- package/dist/components/LipEffect/uvGuide.d.ts +74 -0
- package/dist/components/Makeup/Blush.d.ts +18 -0
- package/dist/components/Makeup/Brows.d.ts +20 -0
- package/dist/components/Makeup/Contour.d.ts +17 -0
- package/dist/components/Makeup/Eyeliner.d.ts +20 -0
- package/dist/components/Makeup/Eyeshadow.d.ts +20 -0
- package/dist/components/Makeup/Highlighter.d.ts +18 -0
- package/dist/components/Makeup/MakeupDesign.d.ts +37 -0
- package/dist/components/Makeup/MakeupRegion.d.ts +132 -0
- package/dist/components/Makeup/constants.d.ts +44 -0
- package/dist/components/Makeup/design.d.ts +106 -0
- package/dist/components/Makeup/designSamples.d.ts +42 -0
- package/dist/components/Makeup/eyes.d.ts +114 -0
- package/dist/components/Makeup/fields.d.ts +10 -0
- package/dist/components/Makeup/geometry.d.ts +106 -0
- package/dist/components/Makeup/index.d.ts +26 -0
- package/dist/components/Makeup/looks.d.ts +28 -0
- package/dist/components/Makeup/material.d.ts +239 -0
- package/dist/components/Makeup/settings.d.ts +54 -0
- package/dist/components/Makeup/shades.d.ts +143 -0
- package/dist/components/Makeup/shapes.d.ts +27 -0
- package/dist/components/Makeup/skinTone.d.ts +135 -0
- package/dist/components/Makeup/types.d.ts +110 -0
- package/dist/components/Makeup/useMakeupSkinTone.d.ts +40 -0
- package/dist/components/Necklace/Necklace.d.ts +44 -0
- package/dist/components/Necklace/index.d.ts +1 -0
- package/dist/components/ParticleEmitter/ParticleEmitter.d.ts +69 -0
- package/dist/components/ParticleEmitter/index.d.ts +1 -0
- package/dist/components/PersonCutout/index.d.ts +50 -0
- package/dist/components/PersonCutout/personCutout.d.ts +16 -0
- package/dist/components/ScreenImage/components/ScreenImageBody.d.ts +1 -1
- package/dist/components/ScreenImage/index.d.ts +3 -1
- package/dist/components/ScreenImage/materials/ScreenImageBlendMaterial.d.ts +1 -1
- package/dist/components/ScreenImage/materials/ScreenImageMaskMaterial.d.ts +11 -0
- package/dist/components/ScreenImage/source.d.ts +6 -0
- package/dist/components/ScreenImage/types.d.ts +18 -0
- package/dist/components/SegmentationOverlay/SegmentationOverlay.d.ts +37 -0
- package/dist/components/SegmentationOverlay/SegmentationOverlayMaterial.d.ts +31 -0
- package/dist/components/SegmentationOverlay/index.d.ts +9 -0
- package/dist/components/SegmentationOverlay/maskTexture.d.ts +23 -0
- package/dist/components/SegmentationOverlay/providers.d.ts +72 -0
- package/dist/components/SegmentationOverlay/settings.d.ts +65 -0
- package/dist/components/ShoulderOccluder/index.d.ts +43 -0
- package/dist/components/ShoulderOccluder/useCanonicalTorsoFit.d.ts +24 -0
- package/dist/components/SpringSwing/SpringSwing.d.ts +22 -0
- package/dist/components/SpringSwing/index.d.ts +1 -0
- package/dist/components/XRProvider/index.d.ts +16 -2
- package/dist/components/XRScene/renderOutputTarget.d.ts +12 -0
- package/dist/components/XRViewport/hooks/useViewportExternalFaces.d.ts +1 -1
- package/dist/components/XRViewport/hooks/useViewportMediaSource.d.ts +1 -1
- package/dist/components/XRViewport/hooks/useViewportPipeline.d.ts +1 -1
- package/dist/components/index.d.ts +11 -0
- package/dist/config/index.d.ts +0 -1
- package/dist/constants/index.d.ts +4 -1
- package/dist/context-DTxSQvp4.js +13 -0
- package/dist/context-hA0Rb2Xa.cjs +1 -0
- package/dist/contexts-BH7PdKFS.cjs +1 -0
- package/dist/contexts-jak8-tND.js +667 -0
- package/dist/coordinates/feed.d.ts +52 -0
- package/dist/coordinates/index.d.ts +7 -0
- package/dist/coordinates/side.d.ts +40 -0
- package/dist/coordinates/spaces.d.ts +49 -0
- package/dist/coordinates/viewport.d.ts +22 -0
- package/dist/coordinates/world.d.ts +15 -0
- package/dist/debug-ui/default-setting.cjs +2 -2
- package/dist/debug-ui/face-swap-settings/index.d.ts +22 -0
- package/dist/debug-ui/gesture-settings/index.d.ts +14 -0
- package/dist/debug-ui/hierarchy-panel/index.d.ts +3 -2
- package/dist/debug-ui/holistic-tracker-settings/index.d.ts +16 -0
- package/dist/debug-ui/index.d.ts +18 -3
- package/dist/debug-ui/iris-effect-settings/index.d.ts +12 -0
- package/dist/debug-ui/lip-effect-settings/index.d.ts +15 -0
- package/dist/debug-ui/media-source/index.d.ts +1 -1
- package/dist/debug-ui/media-source/session.d.ts +30 -2
- package/dist/debug-ui/media-source.cjs +1 -1
- package/dist/debug-ui/media-source.js +1 -1
- package/dist/debug-ui/object-inspector-panel/index.d.ts +3 -2
- package/dist/debug-ui/product-hotspots/index.d.ts +25 -0
- package/dist/debug-ui/scene-editor/hierarchy-panel.d.ts +3 -1
- package/dist/debug-ui/scene-editor/inspector-panel.d.ts +3 -1
- package/dist/debug-ui/screen-image-settings/index.d.ts +3 -1
- package/dist/debug-ui/screen-text-settings/ScreenTextSettingsPanel.d.ts +1 -1
- package/dist/debug-ui/screen-text-settings/types.d.ts +2 -0
- package/dist/debug-ui/segmentation-overlay-settings/index.d.ts +12 -0
- package/dist/debug-ui/settings-panel/index.d.ts +6 -1
- package/dist/debug-ui/shared/debugWindow.d.ts +51 -0
- package/dist/debug-ui/xr-diagnostics/index.d.ts +26 -0
- package/dist/debug-ui.cjs +3 -3
- package/dist/debug-ui.js +2695 -2547
- package/dist/detector-K8aej4MB.js +59 -0
- package/dist/detector-ijypGtse.cjs +1 -0
- package/dist/entries/all.d.ts +3 -1
- package/dist/entries/core.d.ts +20 -2
- package/dist/entries/face-effects.d.ts +123 -9
- package/dist/entries/instructions.d.ts +48 -0
- package/dist/entries/internal.d.ts +2 -1
- package/dist/entries/low-level.d.ts +49 -3
- package/dist/entries/particles.d.ts +11 -0
- package/dist/entries/product.d.ts +11 -0
- package/dist/entries/tracking.d.ts +60 -2
- package/dist/face-atlas/attributes.d.ts +30 -0
- package/dist/face-atlas/eyes.d.ts +272 -0
- package/dist/face-atlas/faceAtlas.generated.d.ts +46 -0
- package/dist/face-atlas/glsl/atlasVertex.d.ts +46 -0
- package/dist/face-atlas/glsl/common.d.ts +55 -0
- package/dist/face-atlas/glsl/design.d.ts +49 -0
- package/dist/face-atlas/glsl/eyes.d.ts +73 -0
- package/dist/face-atlas/glsl/finish.d.ts +24 -0
- package/dist/face-atlas/glsl/format.d.ts +4 -0
- package/dist/face-atlas/glsl/index.d.ts +59 -0
- package/dist/face-atlas/glsl/shading.d.ts +15 -0
- package/dist/face-atlas/glsl/shapes.d.ts +66 -0
- package/dist/face-atlas/glsl/sparkle.d.ts +19 -0
- package/dist/face-atlas/glsl/uniforms.d.ts +106 -0
- package/dist/face-atlas/guide.d.ts +51 -0
- package/dist/face-atlas/index.d.ts +25 -0
- package/dist/face-atlas/lead.d.ts +117 -0
- package/dist/face-atlas/madeUpCamera.d.ts +125 -0
- package/dist/face-atlas/masks.d.ts +53 -0
- package/dist/face-atlas/obj.d.ts +69 -0
- package/dist/face-atlas/polylines.d.ts +63 -0
- package/dist/face-atlas/probe/FaceSkinProbe.d.ts +208 -0
- package/dist/face-atlas/probe/__fixtures__/emulate.d.ts +9 -0
- package/dist/face-atlas/probe/__fixtures__/face.d.ts +24 -0
- package/dist/face-atlas/probe/constants.d.ts +137 -0
- package/dist/face-atlas/probe/glsl.d.ts +43 -0
- package/dist/face-atlas/probe/lightFit.d.ts +108 -0
- package/dist/face-atlas/probe/schedule.d.ts +44 -0
- package/dist/face-atlas/probe/selfTest.d.ts +87 -0
- package/dist/face-atlas/probe/stats.d.ts +143 -0
- package/dist/face-atlas/probe/targets.d.ts +70 -0
- package/dist/face-atlas/probe/unwrap.d.ts +76 -0
- package/dist/face-atlas/quality.d.ts +28 -0
- package/dist/face-atlas/regions.d.ts +31 -0
- package/dist/face-atlas/registry.d.ts +252 -0
- package/dist/face-atlas/renderState.d.ts +86 -0
- package/dist/face-atlas/selfOcclusion.d.ts +62 -0
- package/dist/face-atlas/shading.d.ts +406 -0
- package/dist/face-atlas/shapes.d.ts +86 -0
- package/dist/face-atlas/sides.d.ts +41 -0
- package/dist/face-atlas/skinMask.d.ts +35 -0
- package/dist/face-atlas/surface.d.ts +155 -0
- package/dist/face-atlas/topology.d.ts +44 -0
- package/dist/face-character/__fixtures__/faceImageDetections.d.ts +25 -0
- package/dist/face-character/__fixtures__/faceNode.d.ts +22 -0
- package/dist/face-character/bindFaceModel.d.ts +106 -0
- package/dist/face-character/canonicalFace.d.ts +17 -0
- package/dist/face-character/canonicalFaceGeometry.d.ts +11 -0
- package/dist/face-character/canonicalFacePositions.d.ts +7 -0
- package/dist/face-character/driveFaceModel.d.ts +57 -0
- package/dist/face-character/expressionOutputs.d.ts +45 -0
- package/dist/face-character/faceExpressions.d.ts +104 -0
- package/dist/face-character/faceImageLandmarker.d.ts +93 -0
- package/dist/face-character/faceMeshBinding.d.ts +62 -0
- package/dist/face-character/faceMorph.d.ts +77 -0
- package/dist/face-character/faceMorphs.d.ts +46 -0
- package/dist/face-character/facePhoto.d.ts +138 -0
- package/dist/face-character/facePiercings.d.ts +116 -0
- package/dist/face-character/facePin.d.ts +131 -0
- package/dist/face-character/faceReprojection.d.ts +273 -0
- package/dist/face-character/faceReprojector.d.ts +171 -0
- package/dist/face-character/faceRig.d.ts +176 -0
- package/dist/face-character/faceSwapPresence.d.ts +85 -0
- package/dist/face-character/faceTexture.d.ts +169 -0
- package/dist/face-character/faceTextureBaker.d.ts +86 -0
- package/dist/face-character/faceTextureGuide.d.ts +106 -0
- package/dist/face-character/faceTextureStats.d.ts +298 -0
- package/dist/face-character/faceTransfer.d.ts +396 -0
- package/dist/face-character/faceTransferGeometry.d.ts +109 -0
- package/dist/face-character/faceTransferSelfTest.d.ts +94 -0
- package/dist/face-character/faceWarp3D.d.ts +101 -0
- package/dist/face-character/faceless.d.ts +79 -0
- package/dist/face-character/featureWarp.d.ts +28 -0
- package/dist/face-character/liveFaceRegistry.d.ts +370 -0
- package/dist/face-character/liveValue.d.ts +12 -0
- package/dist/face-character/memo.d.ts +15 -0
- package/dist/face-effects.cjs +2324 -1
- package/dist/face-effects.js +14208 -2268
- package/dist/face-expression/index.d.ts +182 -0
- package/dist/face-info/landmarks.d.ts +17 -3
- package/dist/face-info/types.d.ts +20 -3
- package/dist/gestures/definitions.d.ts +98 -0
- package/dist/gestures/detector.d.ts +87 -0
- package/dist/gestures/index.d.ts +8 -0
- package/dist/gestures/measures.d.ts +114 -0
- package/dist/gestures/settings.d.ts +49 -0
- package/dist/getFaceInfo-B1otSDMX.cjs +1 -0
- package/dist/getFaceInfo-Cu4xDWiL.js +62 -0
- package/dist/hand/armFit.d.ts +46 -0
- package/dist/hand/armMask.d.ts +178 -0
- package/dist/hand/handCutout.d.ts +23 -0
- package/dist/hand/handCutoutRegistry.d.ts +7 -0
- package/dist/hand/handGestures.d.ts +524 -0
- package/dist/hand/handPose.d.ts +98 -0
- package/dist/hand/handRigSolver.d.ts +159 -0
- package/dist/hand/handTattoo.d.ts +81 -0
- package/dist/hand/handTouch.d.ts +240 -0
- package/dist/hand/wrist.d.ts +44 -0
- package/dist/hand/wristFilter.d.ts +44 -0
- package/dist/hooks/selectors.d.ts +76 -1
- package/dist/hooks/useCalibrationFaceTracker.d.ts +1 -1
- package/dist/hooks/useFaceInfo.d.ts +13 -1
- package/dist/hooks/useFaceInfos.d.ts +1 -1
- package/dist/hooks/useFaceModelAcquisition.d.ts +38 -0
- package/dist/hooks/useGesture.d.ts +32 -0
- package/dist/hooks/useIrisTracking.d.ts +45 -0
- package/dist/hooks/useTrackerContext.d.ts +6 -0
- package/dist/hooks/useXRDiagnostics.d.ts +81 -0
- package/dist/hooks/useXRModel.d.ts +7 -0
- package/dist/hooks/useXRSession/facade.d.ts +42 -2
- package/dist/hooks/useXRSession/index.d.ts +2 -2
- package/dist/hooks/useXRSession/reason.d.ts +3 -1
- package/dist/hooks/useXRSession/registry.d.ts +14 -0
- package/dist/hooks/useXRSession/store.d.ts +52 -3
- package/dist/index-B1_TzJaI.js +1104 -0
- package/dist/index-BavF06C6.js +190 -0
- package/dist/index-BfFmpddl.cjs +21 -0
- package/dist/index-BuBzneeW.cjs +46 -0
- package/dist/index-CGsQWodV.cjs +1 -0
- package/dist/index-CIe7eCMH.js +3200 -0
- package/dist/index-CfSF8LXa.cjs +1 -0
- package/dist/index-D5GTzOzD.cjs +1 -0
- package/dist/index-DBhQzvVa.js +314 -0
- package/dist/index-DE17y0ZI.cjs +1 -0
- package/dist/index-JII7huPk.js +442 -0
- package/dist/index-tpCr9CLj.cjs +1 -0
- package/dist/index-w1S7fI2B.js +1432 -0
- package/dist/index-zGaqrz_K.js +188 -0
- package/dist/instructions.cjs +30 -0
- package/dist/instructions.js +1507 -0
- package/dist/{internal-Dmk1cTXq.js → internal-B90P-clC.js} +138 -119
- package/dist/internal-Cjinca64.cjs +1 -0
- package/dist/internal.cjs +1 -1
- package/dist/internal.js +15 -10
- package/dist/iris/compute.d.ts +27 -0
- package/dist/iris/index.d.ts +4 -0
- package/dist/iris/lead.d.ts +19 -0
- package/dist/iris/types.d.ts +89 -0
- package/dist/landmarkMask-BFDyBnKM.js +224 -0
- package/dist/landmarkMask-u7es2k4X.cjs +1 -0
- package/dist/landmarks-BlUqf5MZ.cjs +1 -0
- package/dist/landmarks-bftdwq6Z.js +76 -0
- package/dist/loaders-BGAUACsd.js +363 -0
- package/dist/loaders-BJ1_QCHt.cjs +1 -0
- package/dist/low-level.cjs +1 -1
- package/dist/low-level.js +1190 -675
- package/dist/main.cjs +1 -1
- package/dist/main.js +1190 -452
- package/dist/models/Base/index.d.ts +49 -0
- package/dist/models/Body/index.d.ts +3 -1
- package/dist/models/Face/constants.d.ts +8 -0
- package/dist/models/Face/index.d.ts +4 -12
- package/dist/models/Face/rotation.d.ts +18 -3
- package/dist/models/Hand/GestureTracking.d.ts +1 -1
- package/dist/models/Hand/HandTracking.d.ts +17 -1
- package/dist/models/Holistic/index.d.ts +49 -0
- package/dist/models/Holistic/result.d.ts +68 -0
- package/dist/models/Segmentation/index.d.ts +2 -0
- package/dist/models/SemanticSegmentation/index.d.ts +31 -0
- package/dist/models/SemanticSegmentation/presets.d.ts +28 -0
- package/dist/models/index.d.ts +2 -0
- package/dist/models/nodeSource.d.ts +9 -0
- package/dist/particles/emission.d.ts +24 -0
- package/dist/particles/eyes.d.ts +24 -0
- package/dist/particles/glsl.d.ts +14 -0
- package/dist/particles/index.d.ts +10 -0
- package/dist/particles/motion.d.ts +42 -0
- package/dist/particles/presets.d.ts +12 -0
- package/dist/particles/ring.d.ts +58 -0
- package/dist/particles/selfTest.d.ts +53 -0
- package/dist/particles/settings.d.ts +127 -0
- package/dist/particles/shapes.d.ts +29 -0
- package/dist/particles/spawner.d.ts +60 -0
- package/dist/particles/system.d.ts +64 -0
- package/dist/particles.cjs +122 -0
- package/dist/particles.js +774 -0
- package/dist/product/ProductDimensions.d.ts +16 -0
- package/dist/product/ProductHotspot.d.ts +16 -0
- package/dist/product/ProductViewer.d.ts +9 -0
- package/dist/product/details.d.ts +53 -0
- package/dist/product/index.d.ts +14 -0
- package/dist/product/loadModelViewer.d.ts +4 -0
- package/dist/product/types.d.ts +71 -0
- package/dist/product/useProductAr.d.ts +37 -0
- package/dist/product/useProductDetails.d.ts +60 -0
- package/dist/product.cjs +1 -0
- package/dist/product.js +414 -0
- package/dist/providers-C8rE26Uf.js +366 -0
- package/dist/providers-DHsrhDI2.cjs +62 -0
- package/dist/quality/XRQualityController.d.ts +25 -0
- package/dist/quality/controller.d.ts +33 -0
- package/dist/quality/index.d.ts +6 -0
- package/dist/quality/types.d.ts +100 -0
- package/dist/quality/useXRQuality.d.ts +28 -0
- package/dist/render/renderPasses.d.ts +8 -0
- package/dist/render/sceneBeforeRender.d.ts +12 -0
- package/dist/{renderGroups-KZk6eRiY.js → renderGroups-B38pUaX2.js} +1 -1
- package/dist/{renderGroups-80H3DpTl.cjs → renderGroups-Cb_4Ar1Q.cjs} +1 -1
- package/dist/renderPasses-B6l8IpJv.js +1290 -0
- package/dist/renderPasses-dqmkft4P.cjs +158 -0
- package/dist/renderState-CJNmj5jz.js +39 -0
- package/dist/renderState-apSfg4eR.cjs +1 -0
- package/dist/scene-object.cjs +1 -1
- package/dist/scene-object.js +2 -2
- package/dist/segmentation-Cb3ouK6Z.js +1758 -0
- package/dist/segmentation-D9pYO6aR.cjs +1 -0
- package/dist/segmentation2d/faceMemory.d.ts +28 -0
- package/dist/segmentation2d/faceRegions.d.ts +24 -0
- package/dist/segmentation2d/index.d.ts +9 -0
- package/dist/segmentation2d/maskUv.d.ts +23 -0
- package/dist/segmentation2d/rasterize.d.ts +14 -0
- package/dist/segmentation2d/types.d.ts +52 -0
- package/dist/select-Ck5LGz-J.cjs +1 -0
- package/dist/select-pYRo_win.js +233 -0
- package/dist/selectors-C4X71aoD.cjs +1 -0
- package/dist/selectors-DmNaKIwE.js +196 -0
- package/dist/session-BrH8G7iJ.cjs +31 -0
- package/dist/session-DgA_z6O1.js +418 -0
- package/dist/settings-BJ7FMBsO.js +111 -0
- package/dist/settings-C63FMBlF.cjs +1 -0
- package/dist/similarityFit-BFqHND2e.cjs +1 -0
- package/dist/similarityFit-Bbz-R8AY.js +91 -0
- package/dist/spring/index.d.ts +2 -0
- package/dist/spring/spring.d.ts +69 -0
- package/dist/spring/swing.d.ts +54 -0
- package/dist/subjects/index.d.ts +2 -0
- package/dist/subjects/select.d.ts +62 -0
- package/dist/subjects/types.d.ts +55 -0
- package/dist/tracking-config/apply.d.ts +57 -0
- package/dist/tracking-config/index.d.ts +7 -0
- package/dist/tracking-config/resolve.d.ts +25 -0
- package/dist/tracking-config/storage.d.ts +8 -0
- package/dist/tracking-config/types.d.ts +106 -0
- package/dist/tracking-config/useXRTrackingConfig.d.ts +38 -0
- package/dist/tracking.cjs +10 -1
- package/dist/tracking.js +1326 -506
- package/dist/trigger-D0Pm9noT.cjs +49 -0
- package/dist/trigger-IQeys0oS.js +2128 -0
- package/dist/types/compositor.d.ts +21 -0
- package/dist/types/face.d.ts +20 -1
- package/dist/types/hand-tracking.d.ts +9 -0
- package/dist/types/holistic.d.ts +121 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/model.d.ts +22 -2
- package/dist/types/nodes.d.ts +47 -3
- package/dist/types/segmentation.d.ts +24 -0
- package/dist/types/session.d.ts +41 -3
- package/dist/updateThrottle-BseecYag.js +4 -0
- package/dist/updateThrottle-Of5Y4SVa.cjs +1 -0
- package/dist/useFaceInfo-BHDNCvsJ.cjs +1 -0
- package/dist/useFaceInfo-J4x7LsqL.js +76 -0
- package/dist/useFaceResultReader-BvEo5REG.js +61 -0
- package/dist/useFaceResultReader-DuaL1KJG.cjs +1 -0
- package/dist/useInstructionHold-DOu-RpCM.js +53 -0
- package/dist/useInstructionHold-DwJY1Alr.cjs +1 -0
- package/dist/useLandmarkPoseFit-Bg-h9BPb.cjs +1 -0
- package/dist/useLandmarkPoseFit-Bmb3h6Mw.js +87 -0
- package/dist/useXRCapabilities-Cr3RzuAW.cjs +1 -0
- package/dist/useXRCapabilities-Cxmlmpbd.js +30 -0
- package/dist/utils/canonicalRigidLandmarks.d.ts +8 -0
- package/dist/utils/fns.d.ts +6 -3
- package/dist/utils/headOccluderFit.d.ts +42 -0
- package/dist/utils/integrity.d.ts +21 -1
- package/dist/utils/resolveNumFaces.d.ts +13 -0
- package/dist/utils/shoulderOccluderFit.d.ts +38 -0
- package/dist/utils/similarityFit.d.ts +23 -0
- package/dist/utils/updateThrottle.d.ts +2 -0
- package/dist/utils/useStableUniforms.d.ts +18 -0
- package/dist/uv-BMFt19bg.cjs +1 -0
- package/dist/{index-ByoNj0QP.js → uv-DJU_XfmN.js} +15 -247
- package/docs/SDK_DOCUMENTATION.md +1 -2
- package/docs/api/adaptive-quality.mdx +104 -0
- package/docs/api/asset-lifecycle.mdx +78 -0
- package/docs/api/body-instructions.mdx +285 -0
- package/docs/api/body-triggers.mdx +234 -0
- package/docs/api/camera-permission.mdx +142 -0
- package/docs/api/coordinate-spaces.mdx +168 -0
- package/docs/api/cross-camera.mdx +89 -0
- package/docs/api/debug-ui-scene-editor.mdx +23 -2
- package/docs/api/diagnostics-calibration.mdx +97 -0
- package/docs/api/external-face-mesh.mdx +231 -0
- package/docs/api/face-actions.mdx +20 -16
- package/docs/api/face-attribute-expression.mdx +1 -1
- package/docs/api/face-binding-anchors.mdx +4 -2
- package/docs/api/face-character.mdx +157 -0
- package/docs/api/face-effects.mdx +9 -0
- package/docs/api/face-expression-controller.mdx +153 -0
- package/docs/api/face-info.mdx +17 -11
- package/docs/api/face-inset.mdx +204 -0
- package/docs/api/face-instructions.mdx +183 -0
- package/docs/api/face-liquify.mdx +196 -0
- package/docs/api/face-mesh.mdx +8 -9
- package/docs/api/face-morph.mdx +117 -0
- package/docs/api/face-painting.mdx +7 -0
- package/docs/api/face-reprojection.mdx +154 -0
- package/docs/api/face-retouching.mdx +18 -10
- package/docs/api/face-swap.mdx +350 -0
- package/docs/api/face-warp-3d.mdx +166 -0
- package/docs/api/faceless.mdx +143 -0
- package/docs/api/gestures.mdx +209 -0
- package/docs/api/hair.mdx +97 -0
- package/docs/api/hand-instructions.mdx +222 -0
- package/docs/api/hand-rig.mdx +535 -0
- package/docs/api/hand-touch.mdx +162 -0
- package/docs/api/head-occluder.mdx +563 -0
- package/docs/api/holistic-tracker.mdx +164 -0
- package/docs/api/instructions.mdx +323 -0
- package/docs/api/iris-tracking.mdx +247 -0
- package/docs/api/made-up-camera.mdx +131 -0
- package/docs/api/makeup-skin-tone.mdx +135 -0
- package/docs/api/makeup.mdx +353 -0
- package/docs/api/multi-subject.mdx +98 -0
- package/docs/api/particles.mdx +155 -0
- package/docs/api/person-cutout.mdx +136 -0
- package/docs/api/pin-to-face-mesh.mdx +274 -0
- package/docs/api/product-ar.mdx +114 -0
- package/docs/api/product-details.mdx +78 -0
- package/docs/api/screen-space-coordinates.mdx +4 -1
- package/docs/api/segmentation-overlay.mdx +301 -0
- package/docs/api/session-lifecycle.mdx +136 -0
- package/docs/api/trackers.mdx +5 -0
- package/docs/api/tracking-config.mdx +108 -0
- package/docs/docs.json +51 -1
- package/docs/examples/lip-shaders.mdx +273 -0
- package/docs/guides/face-atlas-template.svg +1 -0
- package/docs/guides/face-atlas-textures.mdx +186 -0
- package/docs/guides/face-texture-template.svg +1 -0
- package/docs/guides/harness-debug-ui.mdx +4 -4
- package/docs/guides/lip-effect-textures.mdx +368 -0
- package/docs/guides/lip-uv-template.png +0 -0
- package/docs/guides/lip-uv-template.svg +1 -0
- package/docs/guides/makeup-design-textures.mdx +109 -0
- package/docs/introduction.mdx +1 -2
- package/package.json +23 -1
- package/dist/DebuggerUI-B6bP6P9r.cjs +0 -1
- package/dist/DebuggerUI-BjOMr8q_.js +0 -269
- package/dist/FaceMeshRenderer-C5l6VLdO.cjs +0 -155
- package/dist/FaceMeshRenderer-wjAHrJzP.js +0 -1270
- package/dist/FaceRetouch-BkJzoA79.cjs +0 -134
- package/dist/FaceRetouch-DwbKQJAN.js +0 -551
- package/dist/components/FaceWarp3D/FaceWarp3DHead.d.ts +0 -15
- package/dist/components/FaceWarp3D/defaults.d.ts +0 -37
- package/dist/components/FaceWarp3D/warp.d.ts +0 -13
- package/dist/contexts-ByhzppYl.js +0 -663
- package/dist/contexts-Dr62It_K.cjs +0 -1
- package/dist/debug-ui/face-warp-3d/index.d.ts +0 -6
- package/dist/getFaceInfo-C4QpCQIY.js +0 -118
- package/dist/getFaceInfo-fA1bFBub.cjs +0 -1
- package/dist/index-9dlAQAhy.js +0 -1462
- package/dist/index-BjmTe9eM.cjs +0 -1
- package/dist/index-BpEf2BBb.cjs +0 -1
- package/dist/index-CyUUurQT.cjs +0 -1
- package/dist/index-DCiMbxC3.cjs +0 -1
- package/dist/index-DXT3WccE.js +0 -2089
- package/dist/index-DpI-qo5X.cjs +0 -17
- package/dist/index-DyVF4vEW.js +0 -111
- package/dist/index-VJ0SJwmG.js +0 -214
- package/dist/internal-Cq-TEQ5Y.cjs +0 -1
- package/dist/renderLayers-lDtL0_43.cjs +0 -1
- package/dist/renderLayers-zrK2pv5O.js +0 -13
- package/dist/renderPasses-BOoBSr8z.cjs +0 -21
- package/dist/renderPasses-BcquyVtu.js +0 -1500
- package/dist/selectors-B8H97CKA.js +0 -59
- package/dist/selectors-CZLKT2Iv.cjs +0 -1
- package/dist/session-CpkiK5YA.cjs +0 -31
- package/dist/session-DLFN_VII.js +0 -363
- package/dist/useFaceInfo-BJ8-_MOs.cjs +0 -1
- package/dist/useFaceInfo-Dk426LTu.js +0 -62
- package/dist/useFaceResults-CtetsO9M.js +0 -19
- package/dist/useFaceResults-wBJF3zyp.cjs +0 -1
package/dist/face-effects.cjs
CHANGED
|
@@ -1 +1,2324 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const A=require("react/jsx-runtime"),K=require("react"),d=require("three"),me=require("./index-CyUUurQT.cjs"),re=require("./index-DCiMbxC3.cjs"),J=require("@react-three/drei"),S=require("./FaceMeshRenderer-C5l6VLdO.cjs"),F=require("./FaceRetouch-BkJzoA79.cjs"),Me=require("@react-three/fiber");function Ie(l){const t=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(l){for(const e in l)if(e!=="default"){const s=Object.getOwnPropertyDescriptor(l,e);Object.defineProperty(t,e,s.get?s:{enumerable:!0,get:()=>l[e]})}}return t.default=l,Object.freeze(t)}const C=Ie(d),k={color:"#e85d75",opacity:.8,intensity:1,maskMode:"outer-and-inner-lips",shading:!0,renderOrder:30},Re=({context:l,color:t,opacity:e,intensity:s,shading:n,subtractMouth:i=!1})=>{const r=Me.useLoader(C.TextureLoader,S.TRANSPARENT_TEXTURE_DATA_URL),a=l.designTexture??r,o={cameraTexture:{value:l.cameraTexture},designTexture:{value:a},tint:{value:new C.Color(t)},opacity:{value:e},intensity:{value:s},shading:{value:n?1:0}};return A.jsx("shaderMaterial",{uniforms:o,vertexShader:"attribute vec2 faceUv; varying vec2 vFaceUv; varying vec2 vUv; void main() { vUv = uv; vFaceUv = faceUv; gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); }",fragmentShader:"uniform sampler2D cameraTexture; uniform sampler2D designTexture; uniform vec3 tint; uniform float opacity; uniform float intensity; uniform float shading; varying vec2 vFaceUv; varying vec2 vUv; void main() { vec3 base = texture2D(cameraTexture, vFaceUv).rgb; vec4 design = texture2D(designTexture, vUv); vec3 painted = mix(design.rgb, design.rgb * tint, intensity); vec3 color = mix(base, painted, design.a * opacity); gl_FragColor = vec4(color, opacity * design.a); }",transparent:!0,side:C.DoubleSide,stencilWrite:!1,stencilRef:1,stencilFunc:i?C.NotEqualStencilFunc:C.AlwaysStencilFunc,depthWrite:!1,toneMapped:!1})},Ne=({faceIndex:l=0,designTexture:t,color:e=k.color,opacity:s=k.opacity,intensity:n=k.intensity,maskMode:i=k.maskMode,shading:r=k.shading,material:a,renderOrder:o=k.renderOrder})=>{const c=Me.useLoader(C.TextureLoader,typeof t=="string"?t:S.TRANSPARENT_TEXTURE_DATA_URL),h=typeof t=="string"?c:t??null,u=({cameraTexture:f,geometryKey:m})=>{if(m==="mouth")return A.jsx("meshBasicMaterial",{color:"#ffffff",colorWrite:!1,depthWrite:!1,depthTest:!1,stencilWrite:!0,stencilRef:1,stencilFunc:C.AlwaysStencilFunc,stencilZPass:C.ReplaceStencilOp});const T={cameraTexture:f,designTexture:h,lipMask:null,faceUv:null,faceIndex:l};return a?typeof a=="function"?a(T):a:A.jsx(Re,{context:T,color:e,opacity:s,intensity:n,shading:r,subtractMouth:!0})};return A.jsx(S.CanonicalFaceMeshRenderer,{faceIndex:l,showMouthGeometry:!0,showLipsGeometry:!0,showBaseGeometry:!1,showMouthMask:i==="outer-lips",showEyeGeometry:!1,showNoseGeometry:!1,showLeftEyeGeometry:!1,showRightEyeGeometry:!1,showEyeMask:!1,showNoseMask:!1,renderOrder:o,materialOverride:u})};function ge(l,t){if(t===d.TrianglesDrawMode)return console.warn("THREE.BufferGeometryUtils.toTrianglesDrawMode(): Geometry already defined as triangles."),l;if(t===d.TriangleFanDrawMode||t===d.TriangleStripDrawMode){let e=l.getIndex();if(e===null){const r=[],a=l.getAttribute("position");if(a!==void 0){for(let o=0;o<a.count;o++)r.push(o);l.setIndex(r),e=l.getIndex()}else return console.error("THREE.BufferGeometryUtils.toTrianglesDrawMode(): Undefined position attribute. Processing not possible."),l}const s=e.count-2,n=[];if(t===d.TriangleFanDrawMode)for(let r=1;r<=s;r++)n.push(e.getX(0)),n.push(e.getX(r)),n.push(e.getX(r+1));else for(let r=0;r<s;r++)r%2===0?(n.push(e.getX(r)),n.push(e.getX(r+1)),n.push(e.getX(r+2))):(n.push(e.getX(r+2)),n.push(e.getX(r+1)),n.push(e.getX(r)));n.length/3!==s&&console.error("THREE.BufferGeometryUtils.toTrianglesDrawMode(): Unable to generate correct amount of triangles.");const i=l.clone();return i.setIndex(n),i.clearGroups(),i}else return console.error("THREE.BufferGeometryUtils.toTrianglesDrawMode(): Unknown draw mode:",t),l}class Oe extends d.Loader{constructor(t){super(t),this.dracoLoader=null,this.ktx2Loader=null,this.meshoptDecoder=null,this.pluginCallbacks=[],this.register(function(e){return new Be(e)}),this.register(function(e){return new Ge(e)}),this.register(function(e){return new qe(e)}),this.register(function(e){return new Ze(e)}),this.register(function(e){return new Qe(e)}),this.register(function(e){return new je(e)}),this.register(function(e){return new Ke(e)}),this.register(function(e){return new Xe(e)}),this.register(function(e){return new Ve(e)}),this.register(function(e){return new ve(e)}),this.register(function(e){return new Ye(e)}),this.register(function(e){return new ke(e)}),this.register(function(e){return new ze(e)}),this.register(function(e){return new We(e)}),this.register(function(e){return new He(e)}),this.register(function(e){return new Je(e)}),this.register(function(e){return new $e(e)})}load(t,e,s,n){const i=this;let r;if(this.resourcePath!=="")r=this.resourcePath;else if(this.path!==""){const c=d.LoaderUtils.extractUrlBase(t);r=d.LoaderUtils.resolveURL(c,this.path)}else r=d.LoaderUtils.extractUrlBase(t);this.manager.itemStart(t);const a=function(c){n?n(c):console.error(c),i.manager.itemError(t),i.manager.itemEnd(t)},o=new d.FileLoader(this.manager);o.setPath(this.path),o.setResponseType("arraybuffer"),o.setRequestHeader(this.requestHeader),o.setWithCredentials(this.withCredentials),o.load(t,function(c){try{i.parse(c,r,function(h){e(h),i.manager.itemEnd(t)},a)}catch(h){a(h)}},s,a)}setDRACOLoader(t){return this.dracoLoader=t,this}setKTX2Loader(t){return this.ktx2Loader=t,this}setMeshoptDecoder(t){return this.meshoptDecoder=t,this}register(t){return this.pluginCallbacks.indexOf(t)===-1&&this.pluginCallbacks.push(t),this}unregister(t){return this.pluginCallbacks.indexOf(t)!==-1&&this.pluginCallbacks.splice(this.pluginCallbacks.indexOf(t),1),this}parse(t,e,s,n){let i;const r={},a={},o=new TextDecoder;if(typeof t=="string")i=JSON.parse(t);else if(t instanceof ArrayBuffer)if(o.decode(new Uint8Array(t,0,4))===_e){try{r[x.KHR_BINARY_GLTF]=new et(t)}catch(u){n&&n(u);return}i=JSON.parse(r[x.KHR_BINARY_GLTF].content)}else i=JSON.parse(o.decode(t));else i=t;if(i.asset===void 0||i.asset.version[0]<2){n&&n(new Error("THREE.GLTFLoader: Unsupported asset. glTF versions >=2.0 are supported."));return}const c=new ft(i,{path:e||this.resourcePath||"",crossOrigin:this.crossOrigin,requestHeader:this.requestHeader,manager:this.manager,ktx2Loader:this.ktx2Loader,meshoptDecoder:this.meshoptDecoder});c.fileLoader.setRequestHeader(this.requestHeader);for(let h=0;h<this.pluginCallbacks.length;h++){const u=this.pluginCallbacks[h](c);u.name||console.error("THREE.GLTFLoader: Invalid plugin found: missing name"),a[u.name]=u,r[u.name]=!0}if(i.extensionsUsed)for(let h=0;h<i.extensionsUsed.length;++h){const u=i.extensionsUsed[h],f=i.extensionsRequired||[];switch(u){case x.KHR_MATERIALS_UNLIT:r[u]=new Ue;break;case x.KHR_DRACO_MESH_COMPRESSION:r[u]=new tt(i,this.dracoLoader);break;case x.KHR_TEXTURE_TRANSFORM:r[u]=new nt;break;case x.KHR_MESH_QUANTIZATION:r[u]=new st;break;default:f.indexOf(u)>=0&&a[u]===void 0&&console.warn('THREE.GLTFLoader: Unknown extension "'+u+'".')}}c.setExtensions(r),c.setPlugins(a),c.parse(s,n)}parseAsync(t,e){const s=this;return new Promise(function(n,i){s.parse(t,e,n,i)})}}function De(){let l={};return{get:function(t){return l[t]},add:function(t,e){l[t]=e},remove:function(t){delete l[t]},removeAll:function(){l={}}}}const x={KHR_BINARY_GLTF:"KHR_binary_glTF",KHR_DRACO_MESH_COMPRESSION:"KHR_draco_mesh_compression",KHR_LIGHTS_PUNCTUAL:"KHR_lights_punctual",KHR_MATERIALS_CLEARCOAT:"KHR_materials_clearcoat",KHR_MATERIALS_DISPERSION:"KHR_materials_dispersion",KHR_MATERIALS_IOR:"KHR_materials_ior",KHR_MATERIALS_SHEEN:"KHR_materials_sheen",KHR_MATERIALS_SPECULAR:"KHR_materials_specular",KHR_MATERIALS_TRANSMISSION:"KHR_materials_transmission",KHR_MATERIALS_IRIDESCENCE:"KHR_materials_iridescence",KHR_MATERIALS_ANISOTROPY:"KHR_materials_anisotropy",KHR_MATERIALS_UNLIT:"KHR_materials_unlit",KHR_MATERIALS_VOLUME:"KHR_materials_volume",KHR_TEXTURE_BASISU:"KHR_texture_basisu",KHR_TEXTURE_TRANSFORM:"KHR_texture_transform",KHR_MESH_QUANTIZATION:"KHR_mesh_quantization",KHR_MATERIALS_EMISSIVE_STRENGTH:"KHR_materials_emissive_strength",EXT_MATERIALS_BUMP:"EXT_materials_bump",EXT_TEXTURE_WEBP:"EXT_texture_webp",EXT_TEXTURE_AVIF:"EXT_texture_avif",EXT_MESHOPT_COMPRESSION:"EXT_meshopt_compression",EXT_MESH_GPU_INSTANCING:"EXT_mesh_gpu_instancing"};class He{constructor(t){this.parser=t,this.name=x.KHR_LIGHTS_PUNCTUAL,this.cache={refs:{},uses:{}}}_markDefs(){const t=this.parser,e=this.parser.json.nodes||[];for(let s=0,n=e.length;s<n;s++){const i=e[s];i.extensions&&i.extensions[this.name]&&i.extensions[this.name].light!==void 0&&t._addNodeRef(this.cache,i.extensions[this.name].light)}}_loadLight(t){const e=this.parser,s="light:"+t;let n=e.cache.get(s);if(n)return n;const i=e.json,o=((i.extensions&&i.extensions[this.name]||{}).lights||[])[t];let c;const h=new d.Color(16777215);o.color!==void 0&&h.setRGB(o.color[0],o.color[1],o.color[2],d.LinearSRGBColorSpace);const u=o.range!==void 0?o.range:0;switch(o.type){case"directional":c=new d.DirectionalLight(h),c.target.position.set(0,0,-1),c.add(c.target);break;case"point":c=new d.PointLight(h),c.distance=u;break;case"spot":c=new d.SpotLight(h),c.distance=u,o.spot=o.spot||{},o.spot.innerConeAngle=o.spot.innerConeAngle!==void 0?o.spot.innerConeAngle:0,o.spot.outerConeAngle=o.spot.outerConeAngle!==void 0?o.spot.outerConeAngle:Math.PI/4,c.angle=o.spot.outerConeAngle,c.penumbra=1-o.spot.innerConeAngle/o.spot.outerConeAngle,c.target.position.set(0,0,-1),c.add(c.target);break;default:throw new Error("THREE.GLTFLoader: Unexpected light type: "+o.type)}return c.position.set(0,0,0),D(c,o),o.intensity!==void 0&&(c.intensity=o.intensity),c.name=e.createUniqueName(o.name||"light_"+t),n=Promise.resolve(c),e.cache.add(s,n),n}getDependency(t,e){if(t==="light")return this._loadLight(e)}createNodeAttachment(t){const e=this,s=this.parser,i=s.json.nodes[t],a=(i.extensions&&i.extensions[this.name]||{}).light;return a===void 0?null:this._loadLight(a).then(function(o){return s._getNodeRef(e.cache,a,o)})}}class Ue{constructor(){this.name=x.KHR_MATERIALS_UNLIT}getMaterialType(){return d.MeshBasicMaterial}extendParams(t,e,s){const n=[];t.color=new d.Color(1,1,1),t.opacity=1;const i=e.pbrMetallicRoughness;if(i){if(Array.isArray(i.baseColorFactor)){const r=i.baseColorFactor;t.color.setRGB(r[0],r[1],r[2],d.LinearSRGBColorSpace),t.opacity=r[3]}i.baseColorTexture!==void 0&&n.push(s.assignTexture(t,"map",i.baseColorTexture,d.SRGBColorSpace))}return Promise.all(n)}}class ve{constructor(t){this.parser=t,this.name=x.KHR_MATERIALS_EMISSIVE_STRENGTH}extendMaterialParams(t,e){const n=this.parser.json.materials[t];if(!n.extensions||!n.extensions[this.name])return Promise.resolve();const i=n.extensions[this.name].emissiveStrength;return i!==void 0&&(e.emissiveIntensity=i),Promise.resolve()}}class Be{constructor(t){this.parser=t,this.name=x.KHR_MATERIALS_CLEARCOAT}getMaterialType(t){const s=this.parser.json.materials[t];return!s.extensions||!s.extensions[this.name]?null:d.MeshPhysicalMaterial}extendMaterialParams(t,e){const s=this.parser,n=s.json.materials[t];if(!n.extensions||!n.extensions[this.name])return Promise.resolve();const i=[],r=n.extensions[this.name];if(r.clearcoatFactor!==void 0&&(e.clearcoat=r.clearcoatFactor),r.clearcoatTexture!==void 0&&i.push(s.assignTexture(e,"clearcoatMap",r.clearcoatTexture)),r.clearcoatRoughnessFactor!==void 0&&(e.clearcoatRoughness=r.clearcoatRoughnessFactor),r.clearcoatRoughnessTexture!==void 0&&i.push(s.assignTexture(e,"clearcoatRoughnessMap",r.clearcoatRoughnessTexture)),r.clearcoatNormalTexture!==void 0&&(i.push(s.assignTexture(e,"clearcoatNormalMap",r.clearcoatNormalTexture)),r.clearcoatNormalTexture.scale!==void 0)){const a=r.clearcoatNormalTexture.scale;e.clearcoatNormalScale=new d.Vector2(a,a)}return Promise.all(i)}}class Ge{constructor(t){this.parser=t,this.name=x.KHR_MATERIALS_DISPERSION}getMaterialType(t){const s=this.parser.json.materials[t];return!s.extensions||!s.extensions[this.name]?null:d.MeshPhysicalMaterial}extendMaterialParams(t,e){const n=this.parser.json.materials[t];if(!n.extensions||!n.extensions[this.name])return Promise.resolve();const i=n.extensions[this.name];return e.dispersion=i.dispersion!==void 0?i.dispersion:0,Promise.resolve()}}class ke{constructor(t){this.parser=t,this.name=x.KHR_MATERIALS_IRIDESCENCE}getMaterialType(t){const s=this.parser.json.materials[t];return!s.extensions||!s.extensions[this.name]?null:d.MeshPhysicalMaterial}extendMaterialParams(t,e){const s=this.parser,n=s.json.materials[t];if(!n.extensions||!n.extensions[this.name])return Promise.resolve();const i=[],r=n.extensions[this.name];return r.iridescenceFactor!==void 0&&(e.iridescence=r.iridescenceFactor),r.iridescenceTexture!==void 0&&i.push(s.assignTexture(e,"iridescenceMap",r.iridescenceTexture)),r.iridescenceIor!==void 0&&(e.iridescenceIOR=r.iridescenceIor),e.iridescenceThicknessRange===void 0&&(e.iridescenceThicknessRange=[100,400]),r.iridescenceThicknessMinimum!==void 0&&(e.iridescenceThicknessRange[0]=r.iridescenceThicknessMinimum),r.iridescenceThicknessMaximum!==void 0&&(e.iridescenceThicknessRange[1]=r.iridescenceThicknessMaximum),r.iridescenceThicknessTexture!==void 0&&i.push(s.assignTexture(e,"iridescenceThicknessMap",r.iridescenceThicknessTexture)),Promise.all(i)}}class je{constructor(t){this.parser=t,this.name=x.KHR_MATERIALS_SHEEN}getMaterialType(t){const s=this.parser.json.materials[t];return!s.extensions||!s.extensions[this.name]?null:d.MeshPhysicalMaterial}extendMaterialParams(t,e){const s=this.parser,n=s.json.materials[t];if(!n.extensions||!n.extensions[this.name])return Promise.resolve();const i=[];e.sheenColor=new d.Color(0,0,0),e.sheenRoughness=0,e.sheen=1;const r=n.extensions[this.name];if(r.sheenColorFactor!==void 0){const a=r.sheenColorFactor;e.sheenColor.setRGB(a[0],a[1],a[2],d.LinearSRGBColorSpace)}return r.sheenRoughnessFactor!==void 0&&(e.sheenRoughness=r.sheenRoughnessFactor),r.sheenColorTexture!==void 0&&i.push(s.assignTexture(e,"sheenColorMap",r.sheenColorTexture,d.SRGBColorSpace)),r.sheenRoughnessTexture!==void 0&&i.push(s.assignTexture(e,"sheenRoughnessMap",r.sheenRoughnessTexture)),Promise.all(i)}}class Ke{constructor(t){this.parser=t,this.name=x.KHR_MATERIALS_TRANSMISSION}getMaterialType(t){const s=this.parser.json.materials[t];return!s.extensions||!s.extensions[this.name]?null:d.MeshPhysicalMaterial}extendMaterialParams(t,e){const s=this.parser,n=s.json.materials[t];if(!n.extensions||!n.extensions[this.name])return Promise.resolve();const i=[],r=n.extensions[this.name];return r.transmissionFactor!==void 0&&(e.transmission=r.transmissionFactor),r.transmissionTexture!==void 0&&i.push(s.assignTexture(e,"transmissionMap",r.transmissionTexture)),Promise.all(i)}}class Xe{constructor(t){this.parser=t,this.name=x.KHR_MATERIALS_VOLUME}getMaterialType(t){const s=this.parser.json.materials[t];return!s.extensions||!s.extensions[this.name]?null:d.MeshPhysicalMaterial}extendMaterialParams(t,e){const s=this.parser,n=s.json.materials[t];if(!n.extensions||!n.extensions[this.name])return Promise.resolve();const i=[],r=n.extensions[this.name];e.thickness=r.thicknessFactor!==void 0?r.thicknessFactor:0,r.thicknessTexture!==void 0&&i.push(s.assignTexture(e,"thicknessMap",r.thicknessTexture)),e.attenuationDistance=r.attenuationDistance||1/0;const a=r.attenuationColor||[1,1,1];return e.attenuationColor=new d.Color().setRGB(a[0],a[1],a[2],d.LinearSRGBColorSpace),Promise.all(i)}}class Ve{constructor(t){this.parser=t,this.name=x.KHR_MATERIALS_IOR}getMaterialType(t){const s=this.parser.json.materials[t];return!s.extensions||!s.extensions[this.name]?null:d.MeshPhysicalMaterial}extendMaterialParams(t,e){const n=this.parser.json.materials[t];if(!n.extensions||!n.extensions[this.name])return Promise.resolve();const i=n.extensions[this.name];return e.ior=i.ior!==void 0?i.ior:1.5,Promise.resolve()}}class Ye{constructor(t){this.parser=t,this.name=x.KHR_MATERIALS_SPECULAR}getMaterialType(t){const s=this.parser.json.materials[t];return!s.extensions||!s.extensions[this.name]?null:d.MeshPhysicalMaterial}extendMaterialParams(t,e){const s=this.parser,n=s.json.materials[t];if(!n.extensions||!n.extensions[this.name])return Promise.resolve();const i=[],r=n.extensions[this.name];e.specularIntensity=r.specularFactor!==void 0?r.specularFactor:1,r.specularTexture!==void 0&&i.push(s.assignTexture(e,"specularIntensityMap",r.specularTexture));const a=r.specularColorFactor||[1,1,1];return e.specularColor=new d.Color().setRGB(a[0],a[1],a[2],d.LinearSRGBColorSpace),r.specularColorTexture!==void 0&&i.push(s.assignTexture(e,"specularColorMap",r.specularColorTexture,d.SRGBColorSpace)),Promise.all(i)}}class We{constructor(t){this.parser=t,this.name=x.EXT_MATERIALS_BUMP}getMaterialType(t){const s=this.parser.json.materials[t];return!s.extensions||!s.extensions[this.name]?null:d.MeshPhysicalMaterial}extendMaterialParams(t,e){const s=this.parser,n=s.json.materials[t];if(!n.extensions||!n.extensions[this.name])return Promise.resolve();const i=[],r=n.extensions[this.name];return e.bumpScale=r.bumpFactor!==void 0?r.bumpFactor:1,r.bumpTexture!==void 0&&i.push(s.assignTexture(e,"bumpMap",r.bumpTexture)),Promise.all(i)}}class ze{constructor(t){this.parser=t,this.name=x.KHR_MATERIALS_ANISOTROPY}getMaterialType(t){const s=this.parser.json.materials[t];return!s.extensions||!s.extensions[this.name]?null:d.MeshPhysicalMaterial}extendMaterialParams(t,e){const s=this.parser,n=s.json.materials[t];if(!n.extensions||!n.extensions[this.name])return Promise.resolve();const i=[],r=n.extensions[this.name];return r.anisotropyStrength!==void 0&&(e.anisotropy=r.anisotropyStrength),r.anisotropyRotation!==void 0&&(e.anisotropyRotation=r.anisotropyRotation),r.anisotropyTexture!==void 0&&i.push(s.assignTexture(e,"anisotropyMap",r.anisotropyTexture)),Promise.all(i)}}class qe{constructor(t){this.parser=t,this.name=x.KHR_TEXTURE_BASISU}loadTexture(t){const e=this.parser,s=e.json,n=s.textures[t];if(!n.extensions||!n.extensions[this.name])return null;const i=n.extensions[this.name],r=e.options.ktx2Loader;if(!r){if(s.extensionsRequired&&s.extensionsRequired.indexOf(this.name)>=0)throw new Error("THREE.GLTFLoader: setKTX2Loader must be called before loading KTX2 textures");return null}return e.loadTextureImage(t,i.source,r)}}class Ze{constructor(t){this.parser=t,this.name=x.EXT_TEXTURE_WEBP,this.isSupported=null}loadTexture(t){const e=this.name,s=this.parser,n=s.json,i=n.textures[t];if(!i.extensions||!i.extensions[e])return null;const r=i.extensions[e],a=n.images[r.source];let o=s.textureLoader;if(a.uri){const c=s.options.manager.getHandler(a.uri);c!==null&&(o=c)}return this.detectSupport().then(function(c){if(c)return s.loadTextureImage(t,r.source,o);if(n.extensionsRequired&&n.extensionsRequired.indexOf(e)>=0)throw new Error("THREE.GLTFLoader: WebP required by asset but unsupported.");return s.loadTexture(t)})}detectSupport(){return this.isSupported||(this.isSupported=new Promise(function(t){const e=new Image;e.src="data:image/webp;base64,UklGRiIAAABXRUJQVlA4IBYAAAAwAQCdASoBAAEADsD+JaQAA3AAAAAA",e.onload=e.onerror=function(){t(e.height===1)}})),this.isSupported}}class Qe{constructor(t){this.parser=t,this.name=x.EXT_TEXTURE_AVIF,this.isSupported=null}loadTexture(t){const e=this.name,s=this.parser,n=s.json,i=n.textures[t];if(!i.extensions||!i.extensions[e])return null;const r=i.extensions[e],a=n.images[r.source];let o=s.textureLoader;if(a.uri){const c=s.options.manager.getHandler(a.uri);c!==null&&(o=c)}return this.detectSupport().then(function(c){if(c)return s.loadTextureImage(t,r.source,o);if(n.extensionsRequired&&n.extensionsRequired.indexOf(e)>=0)throw new Error("THREE.GLTFLoader: AVIF required by asset but unsupported.");return s.loadTexture(t)})}detectSupport(){return this.isSupported||(this.isSupported=new Promise(function(t){const e=new Image;e.src="data:image/avif;base64,AAAAIGZ0eXBhdmlmAAAAAGF2aWZtaWYxbWlhZk1BMUIAAADybWV0YQAAAAAAAAAoaGRscgAAAAAAAAAAcGljdAAAAAAAAAAAAAAAAGxpYmF2aWYAAAAADnBpdG0AAAAAAAEAAAAeaWxvYwAAAABEAAABAAEAAAABAAABGgAAABcAAAAoaWluZgAAAAAAAQAAABppbmZlAgAAAAABAABhdjAxQ29sb3IAAAAAamlwcnAAAABLaXBjbwAAABRpc3BlAAAAAAAAAAEAAAABAAAAEHBpeGkAAAAAAwgICAAAAAxhdjFDgQAMAAAAABNjb2xybmNseAACAAIABoAAAAAXaXBtYQAAAAAAAAABAAEEAQKDBAAAAB9tZGF0EgAKCBgABogQEDQgMgkQAAAAB8dSLfI=",e.onload=e.onerror=function(){t(e.height===1)}})),this.isSupported}}class Je{constructor(t){this.name=x.EXT_MESHOPT_COMPRESSION,this.parser=t}loadBufferView(t){const e=this.parser.json,s=e.bufferViews[t];if(s.extensions&&s.extensions[this.name]){const n=s.extensions[this.name],i=this.parser.getDependency("buffer",n.buffer),r=this.parser.options.meshoptDecoder;if(!r||!r.supported){if(e.extensionsRequired&&e.extensionsRequired.indexOf(this.name)>=0)throw new Error("THREE.GLTFLoader: setMeshoptDecoder must be called before loading compressed files");return null}return i.then(function(a){const o=n.byteOffset||0,c=n.byteLength||0,h=n.count,u=n.byteStride,f=new Uint8Array(a,o,c);return r.decodeGltfBufferAsync?r.decodeGltfBufferAsync(h,u,f,n.mode,n.filter).then(function(m){return m.buffer}):r.ready.then(function(){const m=new ArrayBuffer(h*u);return r.decodeGltfBuffer(new Uint8Array(m),h,u,f,n.mode,n.filter),m})})}else return null}}class $e{constructor(t){this.name=x.EXT_MESH_GPU_INSTANCING,this.parser=t}createNodeMesh(t){const e=this.parser.json,s=e.nodes[t];if(!s.extensions||!s.extensions[this.name]||s.mesh===void 0)return null;const n=e.meshes[s.mesh];for(const c of n.primitives)if(c.mode!==I.TRIANGLES&&c.mode!==I.TRIANGLE_STRIP&&c.mode!==I.TRIANGLE_FAN&&c.mode!==void 0)return null;const r=s.extensions[this.name].attributes,a=[],o={};for(const c in r)a.push(this.parser.getDependency("accessor",r[c]).then(h=>(o[c]=h,o[c])));return a.length<1?null:(a.push(this.parser.createNodeMesh(t)),Promise.all(a).then(c=>{const h=c.pop(),u=h.isGroup?h.children:[h],f=c[0].count,m=[];for(const T of u){const E=new d.Matrix4,g=new d.Vector3,p=new d.Quaternion,M=new d.Vector3(1,1,1),_=new d.InstancedMesh(T.geometry,T.material,f);for(let R=0;R<f;R++)o.TRANSLATION&&g.fromBufferAttribute(o.TRANSLATION,R),o.ROTATION&&p.fromBufferAttribute(o.ROTATION,R),o.SCALE&&M.fromBufferAttribute(o.SCALE,R),_.setMatrixAt(R,E.compose(g,p,M));for(const R in o)if(R==="_COLOR_0"){const L=o[R];_.instanceColor=new d.InstancedBufferAttribute(L.array,L.itemSize,L.normalized)}else R!=="TRANSLATION"&&R!=="ROTATION"&&R!=="SCALE"&&T.geometry.setAttribute(R,o[R]);d.Object3D.prototype.copy.call(_,T),this.parser.assignFinalMaterial(_),m.push(_)}return h.isGroup?(h.clear(),h.add(...m),h):m[0]}))}}const _e="glTF",W=12,Ae={JSON:1313821514,BIN:5130562};class et{constructor(t){this.name=x.KHR_BINARY_GLTF,this.content=null,this.body=null;const e=new DataView(t,0,W),s=new TextDecoder;if(this.header={magic:s.decode(new Uint8Array(t.slice(0,4))),version:e.getUint32(4,!0),length:e.getUint32(8,!0)},this.header.magic!==_e)throw new Error("THREE.GLTFLoader: Unsupported glTF-Binary header.");if(this.header.version<2)throw new Error("THREE.GLTFLoader: Legacy binary file detected.");const n=this.header.length-W,i=new DataView(t,W);let r=0;for(;r<n;){const a=i.getUint32(r,!0);r+=4;const o=i.getUint32(r,!0);if(r+=4,o===Ae.JSON){const c=new Uint8Array(t,W+r,a);this.content=s.decode(c)}else if(o===Ae.BIN){const c=W+r;this.body=t.slice(c,c+a)}r+=a}if(this.content===null)throw new Error("THREE.GLTFLoader: JSON content not found.")}}class tt{constructor(t,e){if(!e)throw new Error("THREE.GLTFLoader: No DRACOLoader instance provided.");this.name=x.KHR_DRACO_MESH_COMPRESSION,this.json=t,this.dracoLoader=e,this.dracoLoader.preload()}decodePrimitive(t,e){const s=this.json,n=this.dracoLoader,i=t.extensions[this.name].bufferView,r=t.extensions[this.name].attributes,a={},o={},c={};for(const h in r){const u=ie[h]||h.toLowerCase();a[u]=r[h]}for(const h in t.attributes){const u=ie[h]||h.toLowerCase();if(r[h]!==void 0){const f=s.accessors[t.attributes[h]],m=X[f.componentType];c[u]=m.name,o[u]=f.normalized===!0}}return e.getDependency("bufferView",i).then(function(h){return new Promise(function(u,f){n.decodeDracoFile(h,function(m){for(const T in m.attributes){const E=m.attributes[T],g=o[T];g!==void 0&&(E.normalized=g)}u(m)},a,c,d.LinearSRGBColorSpace,f)})})}}class nt{constructor(){this.name=x.KHR_TEXTURE_TRANSFORM}extendTexture(t,e){return(e.texCoord===void 0||e.texCoord===t.channel)&&e.offset===void 0&&e.rotation===void 0&&e.scale===void 0||(t=t.clone(),e.texCoord!==void 0&&(t.channel=e.texCoord),e.offset!==void 0&&t.offset.fromArray(e.offset),e.rotation!==void 0&&(t.rotation=e.rotation),e.scale!==void 0&&t.repeat.fromArray(e.scale),t.needsUpdate=!0),t}}class st{constructor(){this.name=x.KHR_MESH_QUANTIZATION}}class Se extends d.Interpolant{constructor(t,e,s,n){super(t,e,s,n)}copySampleValue_(t){const e=this.resultBuffer,s=this.sampleValues,n=this.valueSize,i=t*n*3+n;for(let r=0;r!==n;r++)e[r]=s[i+r];return e}interpolate_(t,e,s,n){const i=this.resultBuffer,r=this.sampleValues,a=this.valueSize,o=a*2,c=a*3,h=n-e,u=(s-e)/h,f=u*u,m=f*u,T=t*c,E=T-c,g=-2*m+3*f,p=m-f,M=1-g,_=p-f+u;for(let R=0;R!==a;R++){const L=r[E+R+a],P=r[E+R+o]*h,w=r[T+R+a],N=r[T+R]*h;i[R]=M*L+_*P+g*w+p*N}return i}}const rt=new d.Quaternion;class it extends Se{interpolate_(t,e,s,n){const i=super.interpolate_(t,e,s,n);return rt.fromArray(i).normalize().toArray(i),i}}const I={POINTS:0,LINES:1,LINE_LOOP:2,LINE_STRIP:3,TRIANGLES:4,TRIANGLE_STRIP:5,TRIANGLE_FAN:6},X={5120:Int8Array,5121:Uint8Array,5122:Int16Array,5123:Uint16Array,5125:Uint32Array,5126:Float32Array},Te={9728:d.NearestFilter,9729:d.LinearFilter,9984:d.NearestMipmapNearestFilter,9985:d.LinearMipmapNearestFilter,9986:d.NearestMipmapLinearFilter,9987:d.LinearMipmapLinearFilter},Ee={33071:d.ClampToEdgeWrapping,33648:d.MirroredRepeatWrapping,10497:d.RepeatWrapping},$={SCALAR:1,VEC2:2,VEC3:3,VEC4:4,MAT2:4,MAT3:9,MAT4:16},ie={POSITION:"position",NORMAL:"normal",TANGENT:"tangent",TEXCOORD_0:"uv",TEXCOORD_1:"uv1",TEXCOORD_2:"uv2",TEXCOORD_3:"uv3",COLOR_0:"color",WEIGHTS_0:"skinWeight",JOINTS_0:"skinIndex"},v={scale:"scale",translation:"position",rotation:"quaternion",weights:"morphTargetInfluences"},ot={CUBICSPLINE:void 0,LINEAR:d.InterpolateLinear,STEP:d.InterpolateDiscrete},ee={OPAQUE:"OPAQUE",MASK:"MASK",BLEND:"BLEND"};function at(l){return l.DefaultMaterial===void 0&&(l.DefaultMaterial=new d.MeshStandardMaterial({color:16777215,emissive:0,metalness:1,roughness:1,transparent:!1,depthTest:!0,side:d.FrontSide})),l.DefaultMaterial}function G(l,t,e){for(const s in e.extensions)l[s]===void 0&&(t.userData.gltfExtensions=t.userData.gltfExtensions||{},t.userData.gltfExtensions[s]=e.extensions[s])}function D(l,t){t.extras!==void 0&&(typeof t.extras=="object"?Object.assign(l.userData,t.extras):console.warn("THREE.GLTFLoader: Ignoring primitive type .extras, "+t.extras))}function ct(l,t,e){let s=!1,n=!1,i=!1;for(let c=0,h=t.length;c<h;c++){const u=t[c];if(u.POSITION!==void 0&&(s=!0),u.NORMAL!==void 0&&(n=!0),u.COLOR_0!==void 0&&(i=!0),s&&n&&i)break}if(!s&&!n&&!i)return Promise.resolve(l);const r=[],a=[],o=[];for(let c=0,h=t.length;c<h;c++){const u=t[c];if(s){const f=u.POSITION!==void 0?e.getDependency("accessor",u.POSITION):l.attributes.position;r.push(f)}if(n){const f=u.NORMAL!==void 0?e.getDependency("accessor",u.NORMAL):l.attributes.normal;a.push(f)}if(i){const f=u.COLOR_0!==void 0?e.getDependency("accessor",u.COLOR_0):l.attributes.color;o.push(f)}}return Promise.all([Promise.all(r),Promise.all(a),Promise.all(o)]).then(function(c){const h=c[0],u=c[1],f=c[2];return s&&(l.morphAttributes.position=h),n&&(l.morphAttributes.normal=u),i&&(l.morphAttributes.color=f),l.morphTargetsRelative=!0,l})}function lt(l,t){if(l.updateMorphTargets(),t.weights!==void 0)for(let e=0,s=t.weights.length;e<s;e++)l.morphTargetInfluences[e]=t.weights[e];if(t.extras&&Array.isArray(t.extras.targetNames)){const e=t.extras.targetNames;if(l.morphTargetInfluences.length===e.length){l.morphTargetDictionary={};for(let s=0,n=e.length;s<n;s++)l.morphTargetDictionary[e[s]]=s}else console.warn("THREE.GLTFLoader: Invalid extras.targetNames length. Ignoring names.")}}function ut(l){let t;const e=l.extensions&&l.extensions[x.KHR_DRACO_MESH_COMPRESSION];if(e?t="draco:"+e.bufferView+":"+e.indices+":"+te(e.attributes):t=l.indices+":"+te(l.attributes)+":"+l.mode,l.targets!==void 0)for(let s=0,n=l.targets.length;s<n;s++)t+=":"+te(l.targets[s]);return t}function te(l){let t="";const e=Object.keys(l).sort();for(let s=0,n=e.length;s<n;s++)t+=e[s]+":"+l[e[s]]+";";return t}function oe(l){switch(l){case Int8Array:return 1/127;case Uint8Array:return 1/255;case Int16Array:return 1/32767;case Uint16Array:return 1/65535;default:throw new Error("THREE.GLTFLoader: Unsupported normalized accessor component type.")}}function ht(l){return l.search(/\.jpe?g($|\?)/i)>0||l.search(/^data\:image\/jpeg/)===0?"image/jpeg":l.search(/\.webp($|\?)/i)>0||l.search(/^data\:image\/webp/)===0?"image/webp":l.search(/\.ktx2($|\?)/i)>0||l.search(/^data\:image\/ktx2/)===0?"image/ktx2":"image/png"}const dt=new d.Matrix4;class ft{constructor(t={},e={}){this.json=t,this.extensions={},this.plugins={},this.options=e,this.cache=new De,this.associations=new Map,this.primitiveCache={},this.nodeCache={},this.meshCache={refs:{},uses:{}},this.cameraCache={refs:{},uses:{}},this.lightCache={refs:{},uses:{}},this.sourceCache={},this.textureCache={},this.nodeNamesUsed={};let s=!1,n=-1,i=!1,r=-1;if(typeof navigator<"u"){const a=navigator.userAgent;s=/^((?!chrome|android).)*safari/i.test(a)===!0;const o=a.match(/Version\/(\d+)/);n=s&&o?parseInt(o[1],10):-1,i=a.indexOf("Firefox")>-1,r=i?a.match(/Firefox\/([0-9]+)\./)[1]:-1}typeof createImageBitmap>"u"||s&&n<17||i&&r<98?this.textureLoader=new d.TextureLoader(this.options.manager):this.textureLoader=new d.ImageBitmapLoader(this.options.manager),this.textureLoader.setCrossOrigin(this.options.crossOrigin),this.textureLoader.setRequestHeader(this.options.requestHeader),this.fileLoader=new d.FileLoader(this.options.manager),this.fileLoader.setResponseType("arraybuffer"),this.options.crossOrigin==="use-credentials"&&this.fileLoader.setWithCredentials(!0)}setExtensions(t){this.extensions=t}setPlugins(t){this.plugins=t}parse(t,e){const s=this,n=this.json,i=this.extensions;this.cache.removeAll(),this.nodeCache={},this._invokeAll(function(r){return r._markDefs&&r._markDefs()}),Promise.all(this._invokeAll(function(r){return r.beforeRoot&&r.beforeRoot()})).then(function(){return Promise.all([s.getDependencies("scene"),s.getDependencies("animation"),s.getDependencies("camera")])}).then(function(r){const a={scene:r[0][n.scene||0],scenes:r[0],animations:r[1],cameras:r[2],asset:n.asset,parser:s,userData:{}};return G(i,a,n),D(a,n),Promise.all(s._invokeAll(function(o){return o.afterRoot&&o.afterRoot(a)})).then(function(){for(const o of a.scenes)o.updateMatrixWorld();t(a)})}).catch(e)}_markDefs(){const t=this.json.nodes||[],e=this.json.skins||[],s=this.json.meshes||[];for(let n=0,i=e.length;n<i;n++){const r=e[n].joints;for(let a=0,o=r.length;a<o;a++)t[r[a]].isBone=!0}for(let n=0,i=t.length;n<i;n++){const r=t[n];r.mesh!==void 0&&(this._addNodeRef(this.meshCache,r.mesh),r.skin!==void 0&&(s[r.mesh].isSkinnedMesh=!0)),r.camera!==void 0&&this._addNodeRef(this.cameraCache,r.camera)}}_addNodeRef(t,e){e!==void 0&&(t.refs[e]===void 0&&(t.refs[e]=t.uses[e]=0),t.refs[e]++)}_getNodeRef(t,e,s){if(t.refs[e]<=1)return s;const n=s.clone(),i=(r,a)=>{const o=this.associations.get(r);o!=null&&this.associations.set(a,o);for(const[c,h]of r.children.entries())i(h,a.children[c])};return i(s,n),n.name+="_instance_"+t.uses[e]++,n}_invokeOne(t){const e=Object.values(this.plugins);e.push(this);for(let s=0;s<e.length;s++){const n=t(e[s]);if(n)return n}return null}_invokeAll(t){const e=Object.values(this.plugins);e.unshift(this);const s=[];for(let n=0;n<e.length;n++){const i=t(e[n]);i&&s.push(i)}return s}getDependency(t,e){const s=t+":"+e;let n=this.cache.get(s);if(!n){switch(t){case"scene":n=this.loadScene(e);break;case"node":n=this._invokeOne(function(i){return i.loadNode&&i.loadNode(e)});break;case"mesh":n=this._invokeOne(function(i){return i.loadMesh&&i.loadMesh(e)});break;case"accessor":n=this.loadAccessor(e);break;case"bufferView":n=this._invokeOne(function(i){return i.loadBufferView&&i.loadBufferView(e)});break;case"buffer":n=this.loadBuffer(e);break;case"material":n=this._invokeOne(function(i){return i.loadMaterial&&i.loadMaterial(e)});break;case"texture":n=this._invokeOne(function(i){return i.loadTexture&&i.loadTexture(e)});break;case"skin":n=this.loadSkin(e);break;case"animation":n=this._invokeOne(function(i){return i.loadAnimation&&i.loadAnimation(e)});break;case"camera":n=this.loadCamera(e);break;default:if(n=this._invokeOne(function(i){return i!=this&&i.getDependency&&i.getDependency(t,e)}),!n)throw new Error("Unknown type: "+t);break}this.cache.add(s,n)}return n}getDependencies(t){let e=this.cache.get(t);if(!e){const s=this,n=this.json[t+(t==="mesh"?"es":"s")]||[];e=Promise.all(n.map(function(i,r){return s.getDependency(t,r)})),this.cache.add(t,e)}return e}loadBuffer(t){const e=this.json.buffers[t],s=this.fileLoader;if(e.type&&e.type!=="arraybuffer")throw new Error("THREE.GLTFLoader: "+e.type+" buffer type is not supported.");if(e.uri===void 0&&t===0)return Promise.resolve(this.extensions[x.KHR_BINARY_GLTF].body);const n=this.options;return new Promise(function(i,r){s.load(d.LoaderUtils.resolveURL(e.uri,n.path),i,void 0,function(){r(new Error('THREE.GLTFLoader: Failed to load buffer "'+e.uri+'".'))})})}loadBufferView(t){const e=this.json.bufferViews[t];return this.getDependency("buffer",e.buffer).then(function(s){const n=e.byteLength||0,i=e.byteOffset||0;return s.slice(i,i+n)})}loadAccessor(t){const e=this,s=this.json,n=this.json.accessors[t];if(n.bufferView===void 0&&n.sparse===void 0){const r=$[n.type],a=X[n.componentType],o=n.normalized===!0,c=new a(n.count*r);return Promise.resolve(new d.BufferAttribute(c,r,o))}const i=[];return n.bufferView!==void 0?i.push(this.getDependency("bufferView",n.bufferView)):i.push(null),n.sparse!==void 0&&(i.push(this.getDependency("bufferView",n.sparse.indices.bufferView)),i.push(this.getDependency("bufferView",n.sparse.values.bufferView))),Promise.all(i).then(function(r){const a=r[0],o=$[n.type],c=X[n.componentType],h=c.BYTES_PER_ELEMENT,u=h*o,f=n.byteOffset||0,m=n.bufferView!==void 0?s.bufferViews[n.bufferView].byteStride:void 0,T=n.normalized===!0;let E,g;if(m&&m!==u){const p=Math.floor(f/m),M="InterleavedBuffer:"+n.bufferView+":"+n.componentType+":"+p+":"+n.count;let _=e.cache.get(M);_||(E=new c(a,p*m,n.count*m/h),_=new d.InterleavedBuffer(E,m/h),e.cache.add(M,_)),g=new d.InterleavedBufferAttribute(_,o,f%m/h,T)}else a===null?E=new c(n.count*o):E=new c(a,f,n.count*o),g=new d.BufferAttribute(E,o,T);if(n.sparse!==void 0){const p=$.SCALAR,M=X[n.sparse.indices.componentType],_=n.sparse.indices.byteOffset||0,R=n.sparse.values.byteOffset||0,L=new M(r[1],_,n.sparse.count*p),P=new c(r[2],R,n.sparse.count*o);a!==null&&(g=new d.BufferAttribute(g.array.slice(),g.itemSize,g.normalized)),g.normalized=!1;for(let w=0,N=L.length;w<N;w++){const b=L[w];if(g.setX(b,P[w*o]),o>=2&&g.setY(b,P[w*o+1]),o>=3&&g.setZ(b,P[w*o+2]),o>=4&&g.setW(b,P[w*o+3]),o>=5)throw new Error("THREE.GLTFLoader: Unsupported itemSize in sparse BufferAttribute.")}g.normalized=T}return g})}loadTexture(t){const e=this.json,s=this.options,i=e.textures[t].source,r=e.images[i];let a=this.textureLoader;if(r.uri){const o=s.manager.getHandler(r.uri);o!==null&&(a=o)}return this.loadTextureImage(t,i,a)}loadTextureImage(t,e,s){const n=this,i=this.json,r=i.textures[t],a=i.images[e],o=(a.uri||a.bufferView)+":"+r.sampler;if(this.textureCache[o])return this.textureCache[o];const c=this.loadImageSource(e,s).then(function(h){h.flipY=!1,h.name=r.name||a.name||"",h.name===""&&typeof a.uri=="string"&&a.uri.startsWith("data:image/")===!1&&(h.name=a.uri);const f=(i.samplers||{})[r.sampler]||{};return h.magFilter=Te[f.magFilter]||d.LinearFilter,h.minFilter=Te[f.minFilter]||d.LinearMipmapLinearFilter,h.wrapS=Ee[f.wrapS]||d.RepeatWrapping,h.wrapT=Ee[f.wrapT]||d.RepeatWrapping,h.generateMipmaps=!h.isCompressedTexture&&h.minFilter!==d.NearestFilter&&h.minFilter!==d.LinearFilter,n.associations.set(h,{textures:t}),h}).catch(function(){return null});return this.textureCache[o]=c,c}loadImageSource(t,e){const s=this,n=this.json,i=this.options;if(this.sourceCache[t]!==void 0)return this.sourceCache[t].then(u=>u.clone());const r=n.images[t],a=self.URL||self.webkitURL;let o=r.uri||"",c=!1;if(r.bufferView!==void 0)o=s.getDependency("bufferView",r.bufferView).then(function(u){c=!0;const f=new Blob([u],{type:r.mimeType});return o=a.createObjectURL(f),o});else if(r.uri===void 0)throw new Error("THREE.GLTFLoader: Image "+t+" is missing URI and bufferView");const h=Promise.resolve(o).then(function(u){return new Promise(function(f,m){let T=f;e.isImageBitmapLoader===!0&&(T=function(E){const g=new d.Texture(E);g.needsUpdate=!0,f(g)}),e.load(d.LoaderUtils.resolveURL(u,i.path),T,void 0,m)})}).then(function(u){return c===!0&&a.revokeObjectURL(o),D(u,r),u.userData.mimeType=r.mimeType||ht(r.uri),u}).catch(function(u){throw console.error("THREE.GLTFLoader: Couldn't load texture",o),u});return this.sourceCache[t]=h,h}assignTexture(t,e,s,n){const i=this;return this.getDependency("texture",s.index).then(function(r){if(!r)return null;if(s.texCoord!==void 0&&s.texCoord>0&&(r=r.clone(),r.channel=s.texCoord),i.extensions[x.KHR_TEXTURE_TRANSFORM]){const a=s.extensions!==void 0?s.extensions[x.KHR_TEXTURE_TRANSFORM]:void 0;if(a){const o=i.associations.get(r);r=i.extensions[x.KHR_TEXTURE_TRANSFORM].extendTexture(r,a),i.associations.set(r,o)}}return n!==void 0&&(r.colorSpace=n),t[e]=r,r})}assignFinalMaterial(t){const e=t.geometry;let s=t.material;const n=e.attributes.tangent===void 0,i=e.attributes.color!==void 0,r=e.attributes.normal===void 0;if(t.isPoints){const a="PointsMaterial:"+s.uuid;let o=this.cache.get(a);o||(o=new d.PointsMaterial,d.Material.prototype.copy.call(o,s),o.color.copy(s.color),o.map=s.map,o.sizeAttenuation=!1,this.cache.add(a,o)),s=o}else if(t.isLine){const a="LineBasicMaterial:"+s.uuid;let o=this.cache.get(a);o||(o=new d.LineBasicMaterial,d.Material.prototype.copy.call(o,s),o.color.copy(s.color),o.map=s.map,this.cache.add(a,o)),s=o}if(n||i||r){let a="ClonedMaterial:"+s.uuid+":";n&&(a+="derivative-tangents:"),i&&(a+="vertex-colors:"),r&&(a+="flat-shading:");let o=this.cache.get(a);o||(o=s.clone(),i&&(o.vertexColors=!0),r&&(o.flatShading=!0),n&&(o.normalScale&&(o.normalScale.y*=-1),o.clearcoatNormalScale&&(o.clearcoatNormalScale.y*=-1)),this.cache.add(a,o),this.associations.set(o,this.associations.get(s))),s=o}t.material=s}getMaterialType(){return d.MeshStandardMaterial}loadMaterial(t){const e=this,s=this.json,n=this.extensions,i=s.materials[t];let r;const a={},o=i.extensions||{},c=[];if(o[x.KHR_MATERIALS_UNLIT]){const u=n[x.KHR_MATERIALS_UNLIT];r=u.getMaterialType(),c.push(u.extendParams(a,i,e))}else{const u=i.pbrMetallicRoughness||{};if(a.color=new d.Color(1,1,1),a.opacity=1,Array.isArray(u.baseColorFactor)){const f=u.baseColorFactor;a.color.setRGB(f[0],f[1],f[2],d.LinearSRGBColorSpace),a.opacity=f[3]}u.baseColorTexture!==void 0&&c.push(e.assignTexture(a,"map",u.baseColorTexture,d.SRGBColorSpace)),a.metalness=u.metallicFactor!==void 0?u.metallicFactor:1,a.roughness=u.roughnessFactor!==void 0?u.roughnessFactor:1,u.metallicRoughnessTexture!==void 0&&(c.push(e.assignTexture(a,"metalnessMap",u.metallicRoughnessTexture)),c.push(e.assignTexture(a,"roughnessMap",u.metallicRoughnessTexture))),r=this._invokeOne(function(f){return f.getMaterialType&&f.getMaterialType(t)}),c.push(Promise.all(this._invokeAll(function(f){return f.extendMaterialParams&&f.extendMaterialParams(t,a)})))}i.doubleSided===!0&&(a.side=d.DoubleSide);const h=i.alphaMode||ee.OPAQUE;if(h===ee.BLEND?(a.transparent=!0,a.depthWrite=!1):(a.transparent=!1,h===ee.MASK&&(a.alphaTest=i.alphaCutoff!==void 0?i.alphaCutoff:.5)),i.normalTexture!==void 0&&r!==d.MeshBasicMaterial&&(c.push(e.assignTexture(a,"normalMap",i.normalTexture)),a.normalScale=new d.Vector2(1,1),i.normalTexture.scale!==void 0)){const u=i.normalTexture.scale;a.normalScale.set(u,u)}if(i.occlusionTexture!==void 0&&r!==d.MeshBasicMaterial&&(c.push(e.assignTexture(a,"aoMap",i.occlusionTexture)),i.occlusionTexture.strength!==void 0&&(a.aoMapIntensity=i.occlusionTexture.strength)),i.emissiveFactor!==void 0&&r!==d.MeshBasicMaterial){const u=i.emissiveFactor;a.emissive=new d.Color().setRGB(u[0],u[1],u[2],d.LinearSRGBColorSpace)}return i.emissiveTexture!==void 0&&r!==d.MeshBasicMaterial&&c.push(e.assignTexture(a,"emissiveMap",i.emissiveTexture,d.SRGBColorSpace)),Promise.all(c).then(function(){const u=new r(a);return i.name&&(u.name=i.name),D(u,i),e.associations.set(u,{materials:t}),i.extensions&&G(n,u,i),u})}createUniqueName(t){const e=d.PropertyBinding.sanitizeNodeName(t||"");return e in this.nodeNamesUsed?e+"_"+ ++this.nodeNamesUsed[e]:(this.nodeNamesUsed[e]=0,e)}loadGeometries(t){const e=this,s=this.extensions,n=this.primitiveCache;function i(a){return s[x.KHR_DRACO_MESH_COMPRESSION].decodePrimitive(a,e).then(function(o){return xe(o,a,e)})}const r=[];for(let a=0,o=t.length;a<o;a++){const c=t[a],h=ut(c),u=n[h];if(u)r.push(u.promise);else{let f;c.extensions&&c.extensions[x.KHR_DRACO_MESH_COMPRESSION]?f=i(c):f=xe(new d.BufferGeometry,c,e),n[h]={primitive:c,promise:f},r.push(f)}}return Promise.all(r)}loadMesh(t){const e=this,s=this.json,n=this.extensions,i=s.meshes[t],r=i.primitives,a=[];for(let o=0,c=r.length;o<c;o++){const h=r[o].material===void 0?at(this.cache):this.getDependency("material",r[o].material);a.push(h)}return a.push(e.loadGeometries(r)),Promise.all(a).then(function(o){const c=o.slice(0,o.length-1),h=o[o.length-1],u=[];for(let m=0,T=h.length;m<T;m++){const E=h[m],g=r[m];let p;const M=c[m];if(g.mode===I.TRIANGLES||g.mode===I.TRIANGLE_STRIP||g.mode===I.TRIANGLE_FAN||g.mode===void 0)p=i.isSkinnedMesh===!0?new d.SkinnedMesh(E,M):new d.Mesh(E,M),p.isSkinnedMesh===!0&&p.normalizeSkinWeights(),g.mode===I.TRIANGLE_STRIP?p.geometry=ge(p.geometry,d.TriangleStripDrawMode):g.mode===I.TRIANGLE_FAN&&(p.geometry=ge(p.geometry,d.TriangleFanDrawMode));else if(g.mode===I.LINES)p=new d.LineSegments(E,M);else if(g.mode===I.LINE_STRIP)p=new d.Line(E,M);else if(g.mode===I.LINE_LOOP)p=new d.LineLoop(E,M);else if(g.mode===I.POINTS)p=new d.Points(E,M);else throw new Error("THREE.GLTFLoader: Primitive mode unsupported: "+g.mode);Object.keys(p.geometry.morphAttributes).length>0&<(p,i),p.name=e.createUniqueName(i.name||"mesh_"+t),D(p,i),g.extensions&&G(n,p,g),e.assignFinalMaterial(p),u.push(p)}for(let m=0,T=u.length;m<T;m++)e.associations.set(u[m],{meshes:t,primitives:m});if(u.length===1)return i.extensions&&G(n,u[0],i),u[0];const f=new d.Group;i.extensions&&G(n,f,i),e.associations.set(f,{meshes:t});for(let m=0,T=u.length;m<T;m++)f.add(u[m]);return f})}loadCamera(t){let e;const s=this.json.cameras[t],n=s[s.type];if(!n){console.warn("THREE.GLTFLoader: Missing camera parameters.");return}return s.type==="perspective"?e=new d.PerspectiveCamera(d.MathUtils.radToDeg(n.yfov),n.aspectRatio||1,n.znear||1,n.zfar||2e6):s.type==="orthographic"&&(e=new d.OrthographicCamera(-n.xmag,n.xmag,n.ymag,-n.ymag,n.znear,n.zfar)),s.name&&(e.name=this.createUniqueName(s.name)),D(e,s),Promise.resolve(e)}loadSkin(t){const e=this.json.skins[t],s=[];for(let n=0,i=e.joints.length;n<i;n++)s.push(this._loadNodeShallow(e.joints[n]));return e.inverseBindMatrices!==void 0?s.push(this.getDependency("accessor",e.inverseBindMatrices)):s.push(null),Promise.all(s).then(function(n){const i=n.pop(),r=n,a=[],o=[];for(let c=0,h=r.length;c<h;c++){const u=r[c];if(u){a.push(u);const f=new d.Matrix4;i!==null&&f.fromArray(i.array,c*16),o.push(f)}else console.warn('THREE.GLTFLoader: Joint "%s" could not be found.',e.joints[c])}return new d.Skeleton(a,o)})}loadAnimation(t){const e=this.json,s=this,n=e.animations[t],i=n.name?n.name:"animation_"+t,r=[],a=[],o=[],c=[],h=[];for(let u=0,f=n.channels.length;u<f;u++){const m=n.channels[u],T=n.samplers[m.sampler],E=m.target,g=E.node,p=n.parameters!==void 0?n.parameters[T.input]:T.input,M=n.parameters!==void 0?n.parameters[T.output]:T.output;E.node!==void 0&&(r.push(this.getDependency("node",g)),a.push(this.getDependency("accessor",p)),o.push(this.getDependency("accessor",M)),c.push(T),h.push(E))}return Promise.all([Promise.all(r),Promise.all(a),Promise.all(o),Promise.all(c),Promise.all(h)]).then(function(u){const f=u[0],m=u[1],T=u[2],E=u[3],g=u[4],p=[];for(let M=0,_=f.length;M<_;M++){const R=f[M],L=m[M],P=T[M],w=E[M],N=g[M];if(R===void 0)continue;R.updateMatrix&&R.updateMatrix();const b=s._createAnimationTracks(R,L,P,w,N);if(b)for(let O=0;O<b.length;O++)p.push(b[O])}return new d.AnimationClip(i,void 0,p)})}createNodeMesh(t){const e=this.json,s=this,n=e.nodes[t];return n.mesh===void 0?null:s.getDependency("mesh",n.mesh).then(function(i){const r=s._getNodeRef(s.meshCache,n.mesh,i);return n.weights!==void 0&&r.traverse(function(a){if(a.isMesh)for(let o=0,c=n.weights.length;o<c;o++)a.morphTargetInfluences[o]=n.weights[o]}),r})}loadNode(t){const e=this.json,s=this,n=e.nodes[t],i=s._loadNodeShallow(t),r=[],a=n.children||[];for(let c=0,h=a.length;c<h;c++)r.push(s.getDependency("node",a[c]));const o=n.skin===void 0?Promise.resolve(null):s.getDependency("skin",n.skin);return Promise.all([i,Promise.all(r),o]).then(function(c){const h=c[0],u=c[1],f=c[2];f!==null&&h.traverse(function(m){m.isSkinnedMesh&&m.bind(f,dt)});for(let m=0,T=u.length;m<T;m++)h.add(u[m]);return h})}_loadNodeShallow(t){const e=this.json,s=this.extensions,n=this;if(this.nodeCache[t]!==void 0)return this.nodeCache[t];const i=e.nodes[t],r=i.name?n.createUniqueName(i.name):"",a=[],o=n._invokeOne(function(c){return c.createNodeMesh&&c.createNodeMesh(t)});return o&&a.push(o),i.camera!==void 0&&a.push(n.getDependency("camera",i.camera).then(function(c){return n._getNodeRef(n.cameraCache,i.camera,c)})),n._invokeAll(function(c){return c.createNodeAttachment&&c.createNodeAttachment(t)}).forEach(function(c){a.push(c)}),this.nodeCache[t]=Promise.all(a).then(function(c){let h;if(i.isBone===!0?h=new d.Bone:c.length>1?h=new d.Group:c.length===1?h=c[0]:h=new d.Object3D,h!==c[0])for(let u=0,f=c.length;u<f;u++)h.add(c[u]);if(i.name&&(h.userData.name=i.name,h.name=r),D(h,i),i.extensions&&G(s,h,i),i.matrix!==void 0){const u=new d.Matrix4;u.fromArray(i.matrix),h.applyMatrix4(u)}else i.translation!==void 0&&h.position.fromArray(i.translation),i.rotation!==void 0&&h.quaternion.fromArray(i.rotation),i.scale!==void 0&&h.scale.fromArray(i.scale);return n.associations.has(h)||n.associations.set(h,{}),n.associations.get(h).nodes=t,h}),this.nodeCache[t]}loadScene(t){const e=this.extensions,s=this.json.scenes[t],n=this,i=new d.Group;s.name&&(i.name=n.createUniqueName(s.name)),D(i,s),s.extensions&&G(e,i,s);const r=s.nodes||[],a=[];for(let o=0,c=r.length;o<c;o++)a.push(n.getDependency("node",r[o]));return Promise.all(a).then(function(o){for(let h=0,u=o.length;h<u;h++)i.add(o[h]);const c=h=>{const u=new Map;for(const[f,m]of n.associations)(f instanceof d.Material||f instanceof d.Texture)&&u.set(f,m);return h.traverse(f=>{const m=n.associations.get(f);m!=null&&u.set(f,m)}),u};return n.associations=c(i),i})}_createAnimationTracks(t,e,s,n,i){const r=[],a=t.name?t.name:t.uuid,o=[];v[i.path]===v.weights?t.traverse(function(f){f.morphTargetInfluences&&o.push(f.name?f.name:f.uuid)}):o.push(a);let c;switch(v[i.path]){case v.weights:c=d.NumberKeyframeTrack;break;case v.rotation:c=d.QuaternionKeyframeTrack;break;case v.position:case v.scale:c=d.VectorKeyframeTrack;break;default:switch(s.itemSize){case 1:c=d.NumberKeyframeTrack;break;case 2:case 3:default:c=d.VectorKeyframeTrack;break}break}const h=n.interpolation!==void 0?ot[n.interpolation]:d.InterpolateLinear,u=this._getArrayFromAccessor(s);for(let f=0,m=o.length;f<m;f++){const T=new c(o[f]+"."+v[i.path],e.array,u,h);n.interpolation==="CUBICSPLINE"&&this._createCubicSplineTrackInterpolant(T),r.push(T)}return r}_getArrayFromAccessor(t){let e=t.array;if(t.normalized){const s=oe(e.constructor),n=new Float32Array(e.length);for(let i=0,r=e.length;i<r;i++)n[i]=e[i]*s;e=n}return e}_createCubicSplineTrackInterpolant(t){t.createInterpolant=function(s){const n=this instanceof d.QuaternionKeyframeTrack?it:Se;return new n(this.times,this.values,this.getValueSize()/3,s)},t.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline=!0}}function pt(l,t,e){const s=t.attributes,n=new d.Box3;if(s.POSITION!==void 0){const a=e.json.accessors[s.POSITION],o=a.min,c=a.max;if(o!==void 0&&c!==void 0){if(n.set(new d.Vector3(o[0],o[1],o[2]),new d.Vector3(c[0],c[1],c[2])),a.normalized){const h=oe(X[a.componentType]);n.min.multiplyScalar(h),n.max.multiplyScalar(h)}}else{console.warn("THREE.GLTFLoader: Missing min/max properties for accessor POSITION.");return}}else return;const i=t.targets;if(i!==void 0){const a=new d.Vector3,o=new d.Vector3;for(let c=0,h=i.length;c<h;c++){const u=i[c];if(u.POSITION!==void 0){const f=e.json.accessors[u.POSITION],m=f.min,T=f.max;if(m!==void 0&&T!==void 0){if(o.setX(Math.max(Math.abs(m[0]),Math.abs(T[0]))),o.setY(Math.max(Math.abs(m[1]),Math.abs(T[1]))),o.setZ(Math.max(Math.abs(m[2]),Math.abs(T[2]))),f.normalized){const E=oe(X[f.componentType]);o.multiplyScalar(E)}a.max(o)}else console.warn("THREE.GLTFLoader: Missing min/max properties for accessor POSITION.")}}n.expandByVector(a)}l.boundingBox=n;const r=new d.Sphere;n.getCenter(r.center),r.radius=n.min.distanceTo(n.max)/2,l.boundingSphere=r}function xe(l,t,e){const s=t.attributes,n=[];function i(r,a){return e.getDependency("accessor",r).then(function(o){l.setAttribute(a,o)})}for(const r in s){const a=ie[r]||r.toLowerCase();a in l.attributes||n.push(i(s[r],a))}if(t.indices!==void 0&&!l.index){const r=e.getDependency("accessor",t.indices).then(function(a){l.setIndex(a)});n.push(r)}return d.ColorManagement.workingColorSpace!==d.LinearSRGBColorSpace&&"COLOR_0"in s&&console.warn(`THREE.GLTFLoader: Converting vertex colors from "srgb-linear" to "${d.ColorManagement.workingColorSpace}" not supported.`),D(l,t),pt(l,t,e),Promise.all(n).then(function(){return t.targets!==void 0?ct(l,t.targets,e):l})}const z=[0,0,-10],B=[.5,.5,.5],ae=1,ne=new Map,mt=l=>{const t=ne.get(l);if(t)return t;const e=new Oe,s=re.fetchAndVerify(l).then(n=>new Promise((i,r)=>{e.parse(n,"",i,r)})).catch(n=>{throw ne.delete(l),n});return ne.set(l,s),s},ce=({position:l,rotation:t,scale:e,url:s,showDebugMaterial:n=!1,opacity:i=ae})=>{const r=s??new URL("/assets/xr/3d-models/head-occluder-v2.glb",re.libConfig.assetStorageEndpoint).toString(),[a,o]=K.useState(null);K.useEffect(()=>{let h=!1;return mt(r).then(u=>{h||o(u.scene)}).catch(u=>{h||console.error(`${re.libConfig.loggerPrefix} head occluder load failed`,u)}),()=>{h=!0}},[r]);const c=K.useMemo(()=>{if(!a)return null;const h=a.clone();return h.traverse(u=>{u instanceof C.Mesh&&(u.material=new C.MeshStandardMaterial({color:15132390,colorWrite:n,depthWrite:!0,opacity:n?i:1,side:C.DoubleSide,transparent:n}))}),h},[a,n,i]);return K.useEffect(()=>{if(c)return()=>{c.traverse(h=>{h instanceof C.Mesh&&h.material.dispose()})}},[c]),c?(l?c.position.set(l[0],l[1],l[2]):c.position.set(z[0],z[1],z[2]),t&&c.rotation.set(t[0],t[1],t[2]),e?c.scale.set(e[0],e[1],e[2]):c.scale.set(B[0],B[1],B[2]),c.renderOrder=-1,A.jsx("primitive",{object:c})):null},gt=4,At=({children:l,faceIndex:t=0,numFaces:e=gt,scaleWithFace:s=!0,occluder:n=!0,showFaceMesh:i=!1,faceMeshMaterial:r})=>{const a=K.useMemo(()=>new C.MeshBasicMaterial({color:"#22c55e",side:C.BackSide,transparent:!0,opacity:.35,depthWrite:!1}),[]),o=n===!1?null:n===!0?{}:n;return A.jsxs(me.FaceTracker,{faceIndex:t,numFaces:e,scaleWithFace:s,children:[o&&A.jsx(ce,{position:o.position??z,rotation:o.rotation,scale:o.scale??B,url:o.url,showDebugMaterial:o.showDebugMaterial,opacity:o.opacity??ae}),l,i&&A.jsx(me.FaceMesh,{faceIndex:t,numFaces:e,material:r??a})]})},Tt=57,Et=15.5,se=Tt/Math.PI/Et,xt=-.134,Mt=-.024,H=(l,t,e)=>Math.min(e,Math.max(t,l)),ye=(l,t)=>l*t-t/2,Le=(l,t)=>-(l*t-t/2),Rt=({eyeMidX:l,noseX:t,offsetX:e,rawYaw:s,sideMidX:n})=>{const i=H((Math.abs(s)-.18)/.42,0,1),r=n*.75+l*.25,a=l*.7+t*.3;return r*(1-i)+a*i+e},_t=({baseScale:l,pitchRadians:t})=>{const e=t*180/Math.PI,n=1+H((e-6)/22,0,1)*.22;return[l[0]*n,l[1]*n,l[2]*n]},St=({yawRadians:l})=>{const t=Math.abs(l*180/Math.PI),s=.066*H((t-8)/12,0,1);return Math.sign(l)*s},yt=({pitchRadians:l})=>{const t=l*180/Math.PI;return-.026*H((-t-6)/18,0,1)},Lt=({baseOffset:l,yawRadians:t})=>{const e=Math.abs(t*180/Math.PI),s=H((e-8)/24,0,1);return l+s*.25},wt=({baseOffsetY:l,baseScaleY:t,face:e})=>{if(!e||e.bounds.width<=0)return{aspectRatio:0,normalizedAspect:0,scaleY:t,offsetY:l};const s=e.bounds.height/e.bounds.width,n=H((s-1.55)/.35,-1,1);return{aspectRatio:s,normalizedAspect:n,scaleY:t+n*.06,offsetY:l+n*.005}},we=({face:l,offsetX:t,offsetY:e,scaleX:s,scaleY:n})=>{const i=l.bounds.width*s,r=l.bounds.height*n,a=l.bounds.centerX+t,o=l.bounds.centerY+e;return{x:a-i*.5,y:o-r*.5,width:i,height:r,centerX:a,centerY:o}},bt=({face:l,height:t,lockDepth:e,lockRotation:s,model:n,offsetX:i,offsetY:r,scaleX:a,scaleY:o,scaleZ:c,width:h})=>{const u=we({face:l,offsetX:i,offsetY:r,scaleX:a,scaleY:o}),f=l.landmarks[33],m=l.landmarks[263],T=l.landmarks[234],E=l.landmarks[454],g=l.landmarks[1],p=l.landmarks[10],M=l.landmarks[152],_=u.width*h,R=u.height*t,L=f&&m?(f.x+m.x)*.5:l.bounds.centerX,P=f&&m?(f.y+m.y)*.5:l.bounds.centerY-l.bounds.height*.15,w=T&&E?(T.x+E.x)*.5:L,N=(p==null?void 0:p.y)??l.bounds.minY,b=(M==null?void 0:M.y)??l.bounds.maxY,O=(N+b)*.5,q=f&&m?Math.atan2(m.y-f.y,m.x-f.x):0,U=g&&l.bounds.width>0?H((g.x-l.bounds.centerX)/(l.bounds.width*.5),-1,1)*.75:0,j=Rt({eyeMidX:L,noseX:(g==null?void 0:g.x)??L,offsetX:i,rawYaw:U,sideMidX:w}),y=O*.75+P*.25+r,Z=n==="v2"?ye(j,h):u.centerX*h-h/2,V=n==="v2"?Le(l.bounds.centerY+r*.75,t):-(u.centerY*t-t/2),Y=p&&g?Math.max(1e-4,g.y-p.y):l.bounds.height*.42,ue=g&&M?Math.max(1e-4,M.y-g.y):l.bounds.height*.58,he=(ue-Y)/(ue+Y),de=H((he-xt)/.28,-1,1)*.58,fe=g&&l.bounds.height>0?H((l.bounds.centerY-g.y)/(l.bounds.height*.5)-Mt,-1,1)*.18:0,Q=de*.82+fe*.18,pe=s?0:n==="v2"?U*.72:U,Ce=s?0:n==="v2"?-Q*.78:-Q,Fe=s?0:-q,Pe=e?_*se:n==="v2"?_*(se+Math.abs(pe)*.18):_*se;return{centerXPx:Z,centerYPx:V,depthPx:Pe*c,heightPx:R,pitch:Ce,rawPitch:Q,rawPitchFromBalance:de,rawPitchFromCenter:fe,rawYaw:U,rotationZ:Fe,roll:q,shape:u,skullAnchorX:j,skullAnchorY:y,verticalBalance:he,widthPx:_,yaw:pe}},be=({lockDepth:l,lockRotation:t,model:e,face:s,height:n,headDepthOffset:i,offsetX:r,offsetY:a,rotationOffsetX:o,rotationOffsetY:c,rotationOffsetZ:h,scaleX:u,scaleY:f,scaleZ:m,skullCenterMode:T,skullVerticalBias:E,width:g})=>le({lockDepth:l,lockRotation:t,model:e,face:s,height:n,headDepthOffset:i,offsetX:r,offsetY:a,rotationOffsetX:o,rotationOffsetY:c,rotationOffsetZ:h,scaleX:u,scaleY:f,scaleZ:m,skullCenterMode:T,skullVerticalBias:E,width:g}).pose,le=({lockDepth:l,lockRotation:t,model:e,face:s,height:n,headDepthOffset:i,offsetX:r,offsetY:a,rotationOffsetX:o,rotationOffsetY:c,rotationOffsetZ:h,scaleX:u,scaleY:f,scaleZ:m,skullCenterMode:T,skullVerticalBias:E,width:g})=>{const p=bt({face:s,height:n,lockDepth:l,lockRotation:t,model:e,offsetX:r,offsetY:a,scaleX:u,scaleY:f,scaleZ:m,width:g});if(T){const _=new d.Vector3(0,p.heightPx*E,-p.depthPx*i).applyEuler(new d.Euler(p.pitch,p.yaw,p.rotationZ,"XYZ")),R=ye(p.skullAnchorX,g),L=Le(p.skullAnchorY,n);return{pose:{boxCenterZ:_.z,centerX:R+_.x,centerY:L+_.y,width:p.widthPx,height:p.heightPx,depth:p.depthPx,rotationX:p.pitch+o,rotationY:p.yaw+c,rotationZ:p.rotationZ+h},debugMetrics:{face:{centerX:p.shape.centerX,centerY:p.shape.centerY,width:p.shape.width,height:p.shape.height},normalized:{rawPitch:p.rawPitch,rawPitchFromBalance:p.rawPitchFromBalance,rawPitchFromCenter:p.rawPitchFromCenter,rawYaw:p.rawYaw,roll:p.roll,verticalBalance:p.verticalBalance},pose:{pitch:p.pitch,yaw:p.yaw,rotationX:p.pitch+o,rotationY:p.yaw+c,rotationZ:p.rotationZ+h},skullAnchor:{x:p.skullAnchorX,y:p.skullAnchorY},center:{x:R+_.x,y:L+_.y,z:_.z},depthPx:p.depthPx,screen:{widthPx:p.widthPx,heightPx:p.heightPx}}}}return{pose:{boxCenterZ:-p.depthPx*i,centerX:p.centerXPx,centerY:p.centerYPx,width:p.widthPx,height:p.heightPx,depth:p.depthPx,rotationX:p.pitch+o,rotationY:p.yaw+c,rotationZ:p.rotationZ+h},debugMetrics:{face:{centerX:p.shape.centerX,centerY:p.shape.centerY,width:p.shape.width,height:p.shape.height},normalized:{rawPitch:p.rawPitch,rawPitchFromBalance:p.rawPitchFromBalance,rawPitchFromCenter:p.rawPitchFromCenter,rawYaw:p.rawYaw,roll:p.roll,verticalBalance:p.verticalBalance},pose:{pitch:p.pitch,yaw:p.yaw,rotationX:p.pitch+o,rotationY:p.yaw+c,rotationZ:p.rotationZ+h},skullAnchor:{x:p.skullAnchorX,y:p.skullAnchorY},center:{x:p.centerXPx,y:p.centerYPx,z:-p.depthPx*i},depthPx:p.depthPx,screen:{widthPx:p.widthPx,heightPx:p.heightPx}}}},Ct=({lockDepth:l,lockRotation:t,model:e,face:s,height:n,headDepthOffset:i,offsetX:r,offsetY:a,rotationOffsetX:o,rotationOffsetY:c,rotationOffsetZ:h,scaleX:u,scaleY:f,scaleZ:m,skullCenterMode:T,skullVerticalBias:E,width:g})=>le({lockDepth:l,lockRotation:t,model:e,face:s,height:n,headDepthOffset:i,offsetX:r,offsetY:a,rotationOffsetX:o,rotationOffsetY:c,rotationOffsetZ:h,scaleX:u,scaleY:f,scaleZ:m,skullCenterMode:T,skullVerticalBias:E,width:g}).debugMetrics,Ft=({boxColor:l,boxOpacity:t,face:e,headDepthOffset:s,lockDepth:n,lockRotation:i,model:r,occluderOffset:a,occluderOpacity:o,occluderScale:c,showOccluderProxy:h=!1,offsetX:u,offsetY:f,pose:m,rotationOffsetX:T,rotationOffsetY:E,rotationOffsetZ:g,scaleX:p,scaleY:M,scaleZ:_,show:R,showCenterDot:L,showFacePlaneReference:P,showGizmo:w,showHeadOccluder:N,skullCenterMode:b,skullVerticalBias:O,url:q,viewportHeight:U,viewportWidth:j})=>{const y=K.useMemo(()=>m||(!e||j<=0||U<=0?null:be({face:e,width:j,height:U,headDepthOffset:s,lockDepth:n,lockRotation:i,model:r,offsetX:u,offsetY:f,rotationOffsetX:T,rotationOffsetY:E,rotationOffsetZ:g,scaleX:p,scaleY:M,scaleZ:_,skullCenterMode:b,skullVerticalBias:O})),[e,s,n,i,r,u,f,T,E,g,p,M,_,b,O,m,U,j]);if(!R||!y)return null;const Z=b?[0,-y.height*O,y.depth*s]:[0,0,0],V=y.height,Y=[B[0]*c[0]*V,B[1]*c[1]*V,B[2]*c[2]*V];return A.jsxs(A.Fragment,{children:[A.jsxs("group",{position:[y.centerX,y.centerY,y.boxCenterZ],rotation:[y.rotationX,y.rotationY,y.rotationZ],children:[A.jsx("group",{scale:[y.width,y.height,y.depth],children:t>0&&A.jsxs("mesh",{children:[A.jsx("boxGeometry",{args:[1,1,1]}),A.jsx("meshBasicMaterial",{color:l,wireframe:!0,transparent:!0,opacity:t})]})}),L&&A.jsxs("mesh",{children:[A.jsx("sphereGeometry",{args:[6,20,20]}),A.jsx("meshBasicMaterial",{color:l})]}),P&&A.jsxs("group",{position:Z,children:[A.jsxs("mesh",{rotation:[0,0,Math.PI/4],children:[A.jsx("ringGeometry",{args:[6,8,24]}),A.jsx("meshBasicMaterial",{color:"#f8fafc",side:d.DoubleSide})]}),A.jsxs("mesh",{rotation:[0,0,Math.PI/2],children:[A.jsx("planeGeometry",{args:[3,16]}),A.jsx("meshBasicMaterial",{color:"#f8fafc",transparent:!0,opacity:.9,side:d.DoubleSide})]}),A.jsxs("mesh",{children:[A.jsx("planeGeometry",{args:[16,3]}),A.jsx("meshBasicMaterial",{color:"#f8fafc",transparent:!0,opacity:.9,side:d.DoubleSide})]})]}),N&&A.jsxs(A.Fragment,{children:[h&&A.jsxs("mesh",{position:a,scale:Y,renderOrder:20,children:[A.jsx("sphereGeometry",{args:[1,24,16]}),A.jsx("meshBasicMaterial",{color:"#facc15",wireframe:!0,transparent:!0,opacity:.95,depthTest:!1,depthWrite:!1})]}),A.jsx(ce,{opacity:o,position:a,scale:Y,showDebugMaterial:!0,url:q})]})]}),w&&A.jsx("group",{position:[y.centerX,y.centerY,y.boxCenterZ],rotation:[y.rotationX,y.rotationY,y.rotationZ],renderOrder:10,children:A.jsxs("group",{children:[A.jsxs("mesh",{children:[A.jsx("sphereGeometry",{args:[6,20,20]}),A.jsx("meshBasicMaterial",{color:"#e2e8f0",depthTest:!1,depthWrite:!1})]}),A.jsxs("mesh",{position:[18,0,0],rotation:[0,0,-Math.PI/2],children:[A.jsx("cylinderGeometry",{args:[1.6,1.6,24,12]}),A.jsx("meshBasicMaterial",{color:"#ef4444",depthTest:!1,depthWrite:!1})]}),A.jsxs("mesh",{position:[34,0,0],rotation:[0,0,-Math.PI/2],children:[A.jsx("coneGeometry",{args:[4.2,12,16]}),A.jsx("meshBasicMaterial",{color:"#ef4444",depthTest:!1,depthWrite:!1})]}),A.jsxs("mesh",{position:[0,18,0],children:[A.jsx("cylinderGeometry",{args:[1.6,1.6,24,12]}),A.jsx("meshBasicMaterial",{color:"#22c55e",depthTest:!1,depthWrite:!1})]}),A.jsxs("mesh",{position:[0,34,0],children:[A.jsx("coneGeometry",{args:[4.2,12,16]}),A.jsx("meshBasicMaterial",{color:"#22c55e",depthTest:!1,depthWrite:!1})]}),A.jsxs("mesh",{position:[0,0,18],rotation:[Math.PI/2,0,0],children:[A.jsx("cylinderGeometry",{args:[1.6,1.6,24,12]}),A.jsx("meshBasicMaterial",{color:"#3b82f6",depthTest:!1,depthWrite:!1})]}),A.jsxs("mesh",{position:[0,0,34],rotation:[Math.PI/2,0,0],children:[A.jsx("coneGeometry",{args:[4.2,12,16]}),A.jsx("meshBasicMaterial",{color:"#3b82f6",depthTest:!1,depthWrite:!1})]}),A.jsx(J.Text,{position:[42,0,0],fontSize:10,color:"#ef4444",anchorX:"center",anchorY:"middle",renderOrder:11,"material-depthTest":!1,children:"X"}),A.jsx(J.Text,{position:[0,42,0],fontSize:10,color:"#22c55e",anchorX:"center",anchorY:"middle",renderOrder:11,"material-depthTest":!1,children:"Y"}),A.jsx(J.Text,{position:[0,0,42],fontSize:10,color:"#3b82f6",anchorX:"center",anchorY:"middle",renderOrder:11,"material-depthTest":!1,children:"Z"})]})})]})};exports.CANONICAL_FACE_MESH_GEOMETRY_SPECS=S.CANONICAL_FACE_MESH_GEOMETRY_SPECS;exports.CanonicalFaceMeshRenderer=S.CanonicalFaceMeshRenderer;exports.DEFAULT_APPEARANCE=S.DEFAULT_APPEARANCE;exports.DEFAULT_FACE_MESH_RENDERER=S.DEFAULT_FACE_MESH_RENDERER;exports.DEFAULT_FACE_MESH_TRANSFORM=S.DEFAULT_FACE_MESH_TRANSFORM;exports.DEFAULT_MASKING=S.DEFAULT_MASKING;exports.FACE_MESH_ALPHA_MAPS=S.FACE_MESH_ALPHA_MAPS;exports.FACE_MESH_BLEND_MODES=S.FACE_MESH_BLEND_MODES;exports.FACE_MESH_MASK_TEXTURE_SOURCES=S.FACE_MESH_MASK_TEXTURE_SOURCES;exports.FACE_MESH_MATERIAL_TYPES=S.FACE_MESH_MATERIAL_TYPES;exports.FACE_MESH_SHADER_PRESETS=S.FACE_MESH_SHADER_PRESETS;exports.FACE_MESH_SIDES=S.FACE_MESH_SIDES;exports.FACE_MESH_TEXTURE_MAPS=S.FACE_MESH_TEXTURE_MAPS;exports.FaceMeshMaterial=S.FaceMeshMaterial;exports.FaceMeshRenderer=S.FaceMeshRenderer;exports.blendModeIndices=S.blendModeIndices;exports.canonicalFaceAlphaMaskUrl=S.canonicalFaceAlphaMaskUrl;exports.canonicalFaceTextureStyle2Url=S.canonicalFaceTextureStyle2Url;exports.canonicalFaceTextureUrl=S.canonicalFaceTextureUrl;exports.mapFaceMeshRendererProps=S.mapFaceMeshRendererProps;exports.mapFaceMeshRendererSettingsToProps=S.mapFaceMeshRendererSettingsToProps;exports.parseCanonicalFaceModel=S.parseCanonicalFaceModel;exports.resolveFaceMeshRendererSettings=S.resolveFaceMeshRendererSettings;exports.supportsBlendMode=S.supportsBlendMode;exports.supportsTexturePanel=S.supportsTexturePanel;exports.useCanonicalFaceMesh=S.useCanonicalFaceMesh;exports.DEFAULT_FACE_WARP_3D_SETTINGS=F.DEFAULT_FACE_WARP_3D_SETTINGS;exports.FACE_RETOUCH_DEFAULT_CONTROLS=F.FACE_RETOUCH_DEFAULT_CONTROLS;exports.FACE_RETOUCH_SETTINGS_FIELDS=F.FACE_RETOUCH_SETTINGS_FIELDS;exports.FACE_WARP_3D_PRESET=F.FACE_WARP_3D_PRESET;exports.FaceRetouch=F.FaceRetouch;exports.alphaMapOptions=F.alphaMapOptions;exports.blendModeOptions=F.blendModeOptions;exports.materialTypeOptions=F.materialTypeOptions;exports.patchFaceRetouchControls=F.patchFaceRetouchControls;exports.resolveFaceRetouchControls=F.resolveFaceRetouchControls;exports.shaderPresetOptions=F.shaderPresetOptions;exports.sideOptions=F.sideOptions;exports.textureMapOptions=F.textureMapOptions;exports.DEFAULT_LIP_EFFECT=k;exports.HEAD_OCCLUDER_DEFAULT_OPACITY=ae;exports.HEAD_OCCLUDER_DEFAULT_POSITION=z;exports.HEAD_OCCLUDER_DEFAULT_SCALE=B;exports.HeadBinding=At;exports.HeadBindingOccluder=Ft;exports.HeadOccluder=ce;exports.LipEffect=Ne;exports.LipEffectMaterial=Re;exports.computeAdaptiveVerticalFit=wt;exports.computeHeadBindingCubePose=be;exports.computeHeadBindingDebugMetrics=Ct;exports.computeHeadBindingShape=we;exports.computeUniversalHeadDepthOffset=Lt;exports.computeUniversalOccluderScale=_t;exports.computeUniversalPitchOffsetY=yt;exports.computeUniversalYawOffsetX=St;exports.solveHeadBinding=le;
|
|
1
|
+
"use strict";var ld=Object.defineProperty;var ud=(e,t,n)=>t in e?ld(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n;var C=(e,t,n)=>ud(e,typeof t!="symbol"?t+"":t,n);Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const L=require("react/jsx-runtime"),J=require("@react-three/fiber"),_=require("react"),Ae=require("three"),ou=require("./uv-BMFt19bg.cjs"),T=require("./SegmentationOverlay-D_FWkcyP.cjs"),ee=require("./index-CfSF8LXa.cjs"),O=require("./FaceRetouch-J1lC1WbS.cjs"),V=require("./CanonicalHeadFrame-D-_T1OMU.cjs"),iu=require("./similarityFit-BFqHND2e.cjs"),ae=require("./selectors-C4X71aoD.cjs"),Te=require("./index-DE17y0ZI.cjs"),K=require("./canonicalFace-C83I225R.cjs"),us=require("@react-three/drei"),eo=require("./landmarks-BlUqf5MZ.cjs"),le=require("./FaceSurface-CHAMEeG1.cjs"),Pn=require("./loaders-BJ1_QCHt.cjs"),pi=require("./select-Ck5LGz-J.cjs"),di=require("@mediapipe/tasks-vision"),Gt=require("./useLandmarkPoseFit-Bg-h9BPb.cjs"),hd=require("./segmentation-D9pYO6aR.cjs"),oe=require("./renderPasses-dqmkft4P.cjs"),de=require("./renderState-apSfg4eR.cjs"),mi=require("./index-D5GTzOzD.cjs"),tt=require("./landmarkMask-u7es2k4X.cjs"),cu=require("./SkeletonUtils-CddIup1F.cjs"),pn=require("./providers-DHsrhDI2.cjs");function fd(e){const t=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(e){for(const n in e)if(n!=="default"){const a=Object.getOwnPropertyDescriptor(e,n);Object.defineProperty(t,n,a.get?a:{enumerable:!0,get:()=>e[n]})}}return t.default=e,Object.freeze(t)}const d=fd(Ae),to={headCenter:[0,2.7,-2.2],crown:[0,13.26,-3.76],forehead:[0,6.545,5.027],noseBridge:[0,2.473,5.789],noseTip:[0,-1.127,7.476],chin:[0,-9.403,4.264],leftEar:[8.84,1.37,-3.26],rightEar:[-8.84,1.37,-3.26],leftEarLobe:[9.34,-.73,-3],rightEarLobe:[-9.34,-.73,-3]},pd=Object.keys(to),dd=new Set(["leftEar","rightEar","leftEarLobe","rightEarLobe"]),qn=(e,t=!1)=>{const n=to[ee.feedSidedName(e,t)];return{position:n,mirror:dd.has(e)&&n[0]<0}},md=(e,t=new d.Vector3,n=!1)=>t.fromArray(qn(e,n).position),lu=(e,t,n=!1)=>{const{position:a,mirror:s}=qn(e,n),[r,o,i]=a,[c,u,l]=(t==null?void 0:t.position)??[0,0,0],h=t==null?void 0:t.rotation;return{position:[r+(s?-c:c),o+u,i+l],rotation:h&&s?[h[0],-h[1],-h[2]]:h}},gd=({point:e,offset:t,mirrored:n,children:a,...s})=>{const r=_.useContext(V.CanonicalHeadFrameContext),o=ae.useXRMirrored(),i=(t==null?void 0:t.scale)??1,c={point:e,offset:t,scale:i,mirrored:n??o};return r?L.jsx(Sd,{...c,children:a}):L.jsx(Ed,{...c,fitOptions:s,children:a})},uu=(e,t,n)=>[qn(e,t).mirror?-n:n,n,n],Sd=({point:e,offset:t,scale:n,mirrored:a,children:s})=>{const r=lu(e,t,a);return L.jsx("group",{position:r.position,rotation:r.rotation??[0,0,0],children:L.jsx("group",{scale:uu(e,a,n),children:s})})},Ed=({point:e,offset:t,scale:n,mirrored:a,fitOptions:s,children:r})=>{const o=_.useRef(null),i=_.useMemo(()=>lu(e,t,a),[e,a,...(t==null?void 0:t.position)??[],...(t==null?void 0:t.rotation)??[]]);return V.useCanonicalHeadFit(o,{...s,offset:i}),L.jsx("group",{ref:o,children:L.jsx("group",{scale:uu(e,a,n),children:r})})},no=Object.freeze({frequency:1.8,damping:.25,maxAngle:50}),yr={frequency:[.2,10],damping:[0,1],maxAngle:[1,175]},ao=(e={})=>{const t={...no};return Object.keys(yr).forEach(n=>{const a=e[n],[s,r]=yr[n];typeof a=="number"&&Number.isFinite(a)&&(t[n]=Math.min(r,Math.max(s,a)))}),t},hu=1/120,fu=.25,pu=20,Ad=Math.PI/180,na=new d.Vector3,hs=new d.Vector3,gi=new d.Vector3,aa=new d.Vector3,We=new d.Vector3,Si=new d.Vector3,qe=new d.Vector3,_t=new d.Vector3,Ei=new d.Vector3,En=new d.Vector3;class so{constructor(){C(this,"position",new d.Vector3);C(this,"velocity",new d.Vector3);C(this,"ready",!1);C(this,"lastPivot",new d.Vector3);C(this,"lastRest",new d.Vector3(0,-1,0));C(this,"lastLength",0);C(this,"lastTarget",new d.Vector3)}reset(t,n,a){this.position.copy(n).multiplyScalar(a).add(t),this.velocity.set(0,0,0),this.lastPivot.copy(t),this.lastRest.copy(n),this.lastLength=a,this.lastTarget.copy(this.position),this.ready=!0}step(t,n,a,s,r,o=new d.Vector3){na.copy(n).multiplyScalar(a).add(t);const i=na.distanceTo(this.lastTarget)>pu*Math.max(a,1e-6);if(!this.ready||!(s>0)||s>fu||i||!(a>0))return this.reset(t,n,a),o.copy(n);const c=2*Math.PI*r.frequency,u=c*c,l=2*r.damping*c,h=r.maxAngle*Ad;hs.copy(t).sub(this.lastPivot).divideScalar(s),gi.copy(na).sub(this.lastTarget).divideScalar(s);const f=Math.max(1,Math.ceil(s/hu)),p=s/f;for(let m=1;m<=f;m+=1){const E=m/f;aa.lerpVectors(this.lastPivot,t,E),We.lerpVectors(this.lastRest,n,E),We.lengthSq()<1e-12&&We.copy(n),We.normalize();const S=this.lastLength+(a-this.lastLength)*E;Si.copy(We).multiplyScalar(S).add(aa),Ei.copy(Si).sub(this.position).multiplyScalar(u).addScaledVector(En.copy(gi).sub(this.velocity),l),this.velocity.addScaledVector(Ei,p),this.position.addScaledVector(this.velocity,p),qe.copy(this.position).sub(aa),qe.lengthSq()<1e-12&&qe.copy(We),qe.normalize();const g=d.MathUtils.clamp(qe.dot(We),-1,1);if(Math.acos(g)>h){_t.copy(qe).addScaledVector(We,-g),_t.lengthSq()<1e-12&&_t.set(1,0,0).cross(We),_t.normalize(),qe.copy(We).multiplyScalar(Math.cos(h)).addScaledVector(_t,Math.sin(h)),En.copy(this.velocity).sub(hs);const A=En.dot(_t);A>0&&this.velocity.addScaledVector(_t,-A)}this.position.copy(qe).multiplyScalar(S).add(aa),En.copy(this.velocity).sub(hs),this.velocity.addScaledVector(qe,-En.dot(qe))}return this.lastPivot.copy(t),this.lastRest.copy(n),this.lastLength=a,this.lastTarget.copy(na),o.copy(this.position).sub(t).normalize()}}class du{constructor(t){C(this,"joints");C(this,"pivot",new d.Vector3);this.joints=Array.from({length:Math.max(1,Math.floor(t))},()=>new so)}step(t,n,a,s,r,o){return this.pivot.copy(t),this.joints.forEach((i,c)=>{o[c]??(o[c]=new d.Vector3),i.step(this.pivot,n[c]??n[n.length-1],a[c]??0,s,r,o[c]),this.pivot.copy(i.position)}),o}reset(t,n,a){this.pivot.copy(t),this.joints.forEach((s,r)=>{s.reset(this.pivot,n[r]??n[n.length-1],a[r]??0),this.pivot.copy(s.position)})}}const wr=1.5,Ai=new d.Vector3(0,-1,0),vd=e=>{for(let t=e;t;t=t.parent)if(!t.visible)return!1;return!0};class ro{constructor(t,n,a={}){C(this,"settings",no);C(this,"length",wr);C(this,"joint",new so);C(this,"lastTime",null);C(this,"pivot",new d.Vector3);C(this,"rest",new d.Vector3);C(this,"direction",new d.Vector3);C(this,"linear",new d.Matrix3);this.outer=t,this.inner=n,this.setOptions(a)}setOptions({length:t,...n}){this.settings=ao(n),this.length=typeof t=="number"&&Number.isFinite(t)&&t>0?t:wr}update(t){const{outer:n,inner:a}=this;if(!vd(n)){this.lastTime=null,this.toRest();return}const s=this.lastTime;if(s!==null&&!(t>s))return;this.lastTime=t;const r=n.matrixWorld.elements;this.pivot.set(r[12],r[13],r[14]),this.rest.copy(Ai).transformDirection(n.matrixWorld);const o=(Math.hypot(r[0],r[1],r[2])+Math.hypot(r[4],r[5],r[6])+Math.hypot(r[8],r[9],r[10]))/3,i=this.length*o;if(s===null){this.joint.reset(this.pivot,this.rest,i),this.toRest();return}this.joint.step(this.pivot,this.rest,i,t-s,this.settings,this.direction),this.linear.setFromMatrix4(n.matrixWorld).invert(),this.direction.applyMatrix3(this.linear).normalize(),a.quaternion.setFromUnitVectors(Ai,this.direction),a.updateMatrixWorld(!0)}reset(){this.lastTime=null,this.toRest()}toRest(){this.inner.quaternion.w!==1&&(this.inner.quaternion.identity(),this.inner.updateMatrixWorld(!0))}}const mu=(e,t)=>{const n=t.map(r=>r.toLowerCase()).filter(Boolean),a=[],s=r=>{if(r!==e&&n.some(o=>r.name.toLowerCase().includes(o))){a.push(r);return}r.children.forEach(s)};return s(e),a.map(r=>{const o=r.parent,i=new d.Group;i.name=`${r.name} swing`,i.position.copy(r.position);const c=new d.Group,u=o.children.indexOf(r);return o.remove(r),r.position.set(0,0,0),c.add(r),i.add(c),i.parent=o,o.children.splice(u,0,i),{node:r,outer:i,inner:c}})},gu=({enabled:e=!0,position:t,rotation:n,children:a,...s})=>{const r=J.useThree(f=>f.scene),o=J.useThree(f=>f.get),i=_.useRef(null),c=_.useRef(null),u=_.useRef(null),l=_.useRef({enabled:e});l.current.enabled=e;const h=JSON.stringify(s);return _.useEffect(()=>{if(!i.current||!c.current)return;const f=new ro(i.current,c.current);u.current=f;const p=Gt.addSceneBeforeRender(r,()=>{l.current.enabled?f.update(o().clock.elapsedTime):f.reset()});return()=>{p(),f.reset(),u.current===f&&(u.current=null)}},[r,o]),_.useEffect(()=>{var f;(f=u.current)==null||f.setOptions(JSON.parse(h))},[h]),L.jsx("group",{ref:i,position:t,rotation:n,children:L.jsx("group",{ref:c,children:a})})},Md=5,yd=6,wd=(e,t,n=!1)=>{const a=qn(e==="left"?"leftEarLobe":"rightEarLobe",n),[s,r,o]=a.position,[i,c,u]=(t==null?void 0:t.position)??[0,0,0],[l,h,f]=(t==null?void 0:t.rotation)??[0,0,0],p=(t==null?void 0:t.scale)??1;return a.mirror?{position:[s-i,r+c,o+u],rotation:[l,-h,-f],scale:[-p,p,p]}:{position:[s+i,r+c,o+u],rotation:[l,h,f],scale:[p,p,p]}},Su=e=>{const t=e.clone(!0);return t.traverse(n=>{if(n.frustumCulled=!1,!(n instanceof d.Mesh)||n.renderOrder!==0)return;const a=Array.isArray(n.material)?n.material:[n.material];n.renderOrder=a.some(s=>s.transparent)?yd:Md}),t},_d=({model:e,children:t,left:n=!0,right:a=!0,offset:s,mirrored:r,swing:o=!1,...i})=>{const c=_.useContext(V.CanonicalHeadFrameContext),u=ae.useXRMirrored();if(!n&&!a)return null;const l=r??u,h=L.jsxs(L.Fragment,{children:[a&&L.jsx(vi,{side:"right",model:e,offset:s,mirrored:l,swing:o,children:t}),n&&L.jsx(vi,{side:"left",model:e,offset:s,mirrored:l,swing:o,children:t})]});return c?h:L.jsx(V.CanonicalHeadFrame,{...i,children:h})},vi=({side:e,model:t,offset:n,mirrored:a,swing:s,children:r})=>{const o=_.useMemo(()=>wd(e,n,a),[e,a,...(n==null?void 0:n.position)??[],...(n==null?void 0:n.rotation)??[],n==null?void 0:n.scale]),i=_.useMemo(()=>t?Su(t):null,[t]);return L.jsx("group",{position:o.position,rotation:o.rotation,scale:o.scale,children:L.jsxs(gu,{enabled:s!==!1,...typeof s=="object"?s:{},children:[i&&L.jsx("primitive",{object:i}),typeof r=="function"?r(e):r]})})},Eu=()=>({irisCenter:{value:new d.Vector2},irisRadius:{value:0},irisOffset:{value:new d.Vector2},irisConfidence:{value:0},irisOpenness:{value:0},time:{value:0},color:{value:new d.Color("#4fa3ff")},opacity:{value:1},mirror:{value:0},tintImage:{value:0},map:{value:null}}),Au=(e,t,n)=>(e.irisCenter.value.set(t.center.x,t.center.y),e.irisRadius.value=t.radius,e.irisOffset.value.set(t.offset.x,t.offset.y),e.irisConfidence.value=t.confidence,e.irisOpenness.value=t.openness,e.time.value=n.time,n.color!==void 0&&e.color.value.set(n.color),n.opacity!==void 0&&(e.opacity.value=n.opacity),e.mirror.value=n.mirrored?1:0,n.tintImage!==void 0&&(e.tintImage.value=n.tintImage?1:0),n.map!==void 0&&(e.map.value=n.map),e),oo=`
|
|
2
|
+
varying vec2 vUv;
|
|
3
|
+
void main() {
|
|
4
|
+
vUv = uv;
|
|
5
|
+
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
|
|
6
|
+
}
|
|
7
|
+
`,vu=`
|
|
8
|
+
uniform vec2 irisOffset;
|
|
9
|
+
uniform float irisConfidence;
|
|
10
|
+
uniform float time;
|
|
11
|
+
uniform vec3 color;
|
|
12
|
+
uniform float opacity;
|
|
13
|
+
uniform float mirror;
|
|
14
|
+
varying vec2 vUv;
|
|
15
|
+
|
|
16
|
+
float hash(float n) { return fract(sin(n) * 43758.5453123); }
|
|
17
|
+
|
|
18
|
+
void main() {
|
|
19
|
+
vec2 p = vUv - 0.5;
|
|
20
|
+
p.x = mix(p.x, -p.x, mirror);
|
|
21
|
+
float r = length(p) * 2.0;
|
|
22
|
+
if (r > 1.0) discard;
|
|
23
|
+
float angle = atan(p.y, p.x);
|
|
24
|
+
// Radial fibres: a few overlapping angular frequencies, slowly rotating.
|
|
25
|
+
float fibres = 0.5
|
|
26
|
+
+ 0.25 * sin(angle * 36.0 + time * 0.3)
|
|
27
|
+
+ 0.15 * sin(angle * 91.0 - r * 6.0)
|
|
28
|
+
+ 0.10 * sin(angle * 17.0 + time * 0.7);
|
|
29
|
+
vec3 base = color * (0.55 + 0.6 * fibres) * (1.1 - 0.5 * r);
|
|
30
|
+
// Limbal ring: darken the outer edge.
|
|
31
|
+
base *= 1.0 - smoothstep(0.78, 1.0, r) * 0.7;
|
|
32
|
+
// Pupil: a soft dark disc offset slightly with the iris position in the eye.
|
|
33
|
+
vec2 pupil = p - irisOffset * 0.08;
|
|
34
|
+
float pupilR = length(pupil) * 2.0;
|
|
35
|
+
float pupilMask = 1.0 - smoothstep(0.26, 0.36, pupilR);
|
|
36
|
+
base = mix(base, vec3(0.02), pupilMask);
|
|
37
|
+
// Specular glint.
|
|
38
|
+
float glint = 1.0 - smoothstep(0.0, 0.14, length(p - vec2(-0.18, 0.2)));
|
|
39
|
+
base += glint * 0.8;
|
|
40
|
+
float edge = 1.0 - smoothstep(0.92, 1.0, r);
|
|
41
|
+
gl_FragColor = vec4(base, opacity * edge * irisConfidence);
|
|
42
|
+
#include <colorspace_fragment>
|
|
43
|
+
}
|
|
44
|
+
`,Mu=`
|
|
45
|
+
uniform sampler2D map;
|
|
46
|
+
uniform float irisConfidence;
|
|
47
|
+
uniform vec3 color;
|
|
48
|
+
uniform float opacity;
|
|
49
|
+
uniform float mirror;
|
|
50
|
+
uniform float tintImage;
|
|
51
|
+
varying vec2 vUv;
|
|
52
|
+
void main() {
|
|
53
|
+
vec2 uv = vUv;
|
|
54
|
+
uv.x = mix(uv.x, 1.0 - uv.x, mirror);
|
|
55
|
+
vec4 texel = texture2D(map, uv);
|
|
56
|
+
// Image as authored; multiplied by the tint only when tintImage is on.
|
|
57
|
+
vec3 rgb = texel.rgb * mix(vec3(1.0), color, tintImage);
|
|
58
|
+
gl_FragColor = vec4(rgb, texel.a * opacity * irisConfidence);
|
|
59
|
+
#include <colorspace_fragment>
|
|
60
|
+
}
|
|
61
|
+
`,yu={transparent:!0,depthTest:!1,depthWrite:!1,side:d.DoubleSide},wu=e=>new d.ShaderMaterial({...yu,uniforms:e,vertexShader:oo,fragmentShader:vu}),_u=e=>new d.ShaderMaterial({...yu,uniforms:e,vertexShader:oo,fragmentShader:Mu}),Fu=ou.RENDER_LAYERS.TRACKED,Fd=(e,t)=>{const[n,a]=_.useState(null);return _.useEffect(()=>{if(t!=null){a(null);return}if(!e){a(null);return}let s=!1;const r=new d.TextureLoader;r.setCrossOrigin("anonymous");const o=r.load(e,i=>{s||(i.colorSpace=d.SRGBColorSpace,i.needsUpdate=!0,a(i))});return()=>{s=!0,o.dispose(),a(i=>i===o?null:i)}},[e,t]),t??n},xd=(e,t,n,a,s)=>{const r=_.useMemo(()=>Eu(),[]),o=_.useMemo(()=>t==="image"?_u(r):wu(r),[t,r]);_.useEffect(()=>()=>o.dispose(),[o]);const i=_.useRef(a);i.current=a;const c=_.useMemo(()=>n?typeof n=="function"?n({side:e,uniforms:r,result:s,texture:i.current}):n:null,[n,s,e,r]);return _.useEffect(()=>{if(!(!c||typeof n!="function"))return()=>c.dispose()},[c,n]),{material:c??o,uniforms:r}},Mi=({side:e,eye:t,settings:n,texture:a,override:s,result:r,renderOrder:o,clock:i})=>{const c=_.useRef(null),{camera:u}=J.useThree(),{material:l,uniforms:h}=xd(e,n.mode,s,a,r),f=_.useRef(new d.Vector3),p=_.useRef(new d.Vector3),m=_.useRef({x:0,y:0,z:0,visibility:0});return J.useFrame(()=>{const E=c.current;if(!E)return;const S=t.detected&&t.confidence>0&&(n.mode!=="image"||s!==void 0||a!==null);if(E.visible=S,!S)return;m.current.x=t.center.x,m.current.y=t.center.y,m.current.z=t.center.z,ee.feedToWorld(m.current,u,f.current),m.current.x=t.center.x+t.radius,ee.feedToWorld(m.current,u,p.current);const g=f.current.distanceTo(p.current)*n.scale;E.position.copy(f.current),E.scale.set(g,g,1),Au(h,t,{time:i.current,color:n.color,opacity:n.opacity,mirrored:n.mirrored,tintImage:n.tintImage,map:a})}),L.jsx("mesh",{ref:c,material:l,renderOrder:o,frustumCulled:!1,visible:!1,children:L.jsx("planeGeometry",{args:[2,2]})})},Cd=({numFaces:e,active:t=!0,predictMs:n=0,texture:a,material:s,renderOrder:r=Fu,onTracking:o,...i})=>{const c=O.resolveIrisEffectSettings(i),u=T.useIrisTracking({faceIndex:c.faceIndex,numFaces:e,active:t,targetFps:c.targetFps>0?c.targetFps:void 0,holdMs:c.holdMs,predictMs:n,smoothing:c.smoothing,leadMs:c.leadMs}),l=_.useRef(o);l.current=o;const{result:h,ready:f,status:p,error:m}=u;_.useEffect(()=>{var v;(v=l.current)==null||v.call(l,{result:h,ready:f,status:p,error:m})},[h,f,p,m]);const E=Fd(c.textureUrl,a),S=_.useRef(0);J.useFrame((v,M)=>{S.current+=M});const g=c.eye!=="right",A=c.eye!=="left";return L.jsxs("group",{children:[g&&L.jsx(Mi,{side:"left",eye:h.left,settings:c,texture:E,override:s,result:h,renderOrder:r,clock:S}),A&&L.jsx(Mi,{side:"right",eye:h.right,settings:c,texture:E,override:s,result:h,renderOrder:r,clock:S})]})},yi=Object.freeze({high:{leadCapMs:33,selfOcclusion:!0},medium:{leadCapMs:42,selfOcclusion:!0},low:{leadCapMs:66,selfOcclusion:!1}}),xu=(e,t)=>!(e>0)||t<=1?"high":e>=t-1?"low":"medium",dn=(e,t)=>{var s;const n=((s=ee.useOptionalXRContext())==null?void 0:s.session)??null,a=_.useId();_.useEffect(()=>{if(!e||!n)return;let r=!1,o=!1;return queueMicrotask(()=>{r||(o=!0,n.registry.acquire(ee.XRModel.FACE_TRACKER,a,{numFaces:t}).catch(()=>{}))}),()=>{r=!0,o&&n.registry.release(ee.XRModel.FACE_TRACKER,a)}},[e,t,a,n])},wi=new WeakMap,Td=(e,t)=>typeof(e==null?void 0:e.numFaces)=="number"&&t>=e.numFaces,ja=(e,t,n)=>{if(!e||!Td(e,t))return!1;const a=ee.modelNodeSource(e);let s=wi.get(a);if(s||(s=new Set,wi.set(a,s)),s.has(t))return!1;s.add(t);const r=t+1;return console.warn(`[xr-sdk face] ${n}: face ${t} is never tracked, because the face model was started with numFaces ${String(e.numFaces)}. The first component to start the model sets the count: pass numFaces={${r}} to it (for example <FaceTextureLayer numFaces={${r}}>, useLiveFaceTexture(${t}, { numFaces: ${r} }) or a makeup layer), or mount <FaceTracker numFaces={${r}}> above.`),!0},Cu=(e,t,n,a=!0)=>{_.useEffect(()=>{a&&ja(e,t,n)},[e,t,n,a])},io=_.createContext(null),ge=()=>_.useContext(io),kd=-1,_i=new d.Matrix4,Fi=new d.Matrix4,xi=new d.Matrix4,Ld=new d.Vector3,yt=({children:e,faceIndex:t,onTrackingChange:n,neutralKey:a,...s})=>{const r=Te.useTrackerContext(),o=t??((r==null?void 0:r.type)==="face"?r.faceIndex:void 0)??0,i=ae.useXRModelNode(ee.XRModel.FACE_TRACKER),{camera:c}=J.useThree(),u=_.useRef(null),l=_.useRef(T.createFaceRigState());l.current.faceIndex=o;const h=_.useMemo(()=>T.createFaceRigDriver(l.current),[]),f=_.useRef(s);f.current=s;const p=_.useRef(n);p.current=n;const m=_.useRef(!0);_.useEffect(()=>{if(m.current){m.current=!1;return}T.recalibrateFaceRig(l.current)},[a]);const E=ae.useXRCameraTexture(),S=_.useRef(E);return _.useEffect(()=>{S.current!==E&&(S.current=E,T.resetFaceRigDriver(h))},[E,h]),J.useFrame(()=>{var F;const g=T.stepFaceRigFromModel(h,i,o,c,performance.now(),f.current);g&&((F=p.current)==null||F.call(p,g==="found"));const A=u.current;if(!A)return;const v=l.current;if(A.visible=v.tracking!=="lost",!A.visible||!A.parent)return;const{position:M,quaternion:y,scale:x}=v.pose;_i.compose(M,y,Ld.setScalar(x)),A.parent.updateMatrixWorld(),Fi.copy(A.parent.matrixWorld).invert(),xi.multiplyMatrices(Fi,_i),xi.decompose(A.position,A.quaternion,A.scale)},kd),L.jsx(io.Provider,{value:l,children:L.jsx("group",{ref:u,visible:!1,children:e})})},Rd=-1,bd=-.4,Ze=Object.freeze({matte:0,satin:1,gloss:2,shimmer:3,metallic:4,glitter:5}),Re=Object.freeze({none:0,lips:1,blush:2,contour:3,highlighter:4,brows:5}),Id=(e,t,n)=>{const a=Math.hypot(e,t,n);return[e/a,t/a,n/a]},co=[.2126729,.7151522,.072175],nt=Object.freeze({epsilon:1e-4,maxRatio:4,tintMin:.85,tintMax:1.15,clip:.15,highlightKnee:1.1,lowpassMinWeight:.02,lowpassFullWeight:.1,lowpassTexels:32,lowpassCoarseLods:2,edgeFadeCm:1,maxLightLevel:2,keyLight:Id(.35,.6,1),lightConfidenceMin:.15,lightConfidenceBlend:.03,sideBlendCm:.15,facingMin:0,facingFull:.25,discardBelow:1/255}),Zt=e=>Math.max(0,Math.log2(Math.max(e,1)/nt.lowpassTexels)),Ci=Object.freeze({fast:.25,slow:4}),Tu=Object.freeze({satin:{cameraHighlight:.35,roughness:.6,lobe:.15},gloss:{cameraHighlight:1,cameraHighlightShine:1.5,roughness:.12,lobe:.8,fresnel:.25,f0:.04},metallic:{diffuse:.45,environment:.55,roughness:.35,lobe:.9},maskTermsFullOpacity:.1,sparkleTintMix:.5}),ku=Object.freeze({shimmer:{cellScale:1.5,kappa:20,sharpness:24,gain:8,hueJitter:0},glitter:{cellScale:2,kappa:8,sharpness:60,gain:3,hueJitter:.35,body:.6},resolveStartPx:.75,resolveFullPx:1.5,lowQualityGlitterDensity:.5,cellOffset:32768}),Lu=Object.freeze({lips:{saturation:1.2,value:.7},blush:{rose:[.8,.28,.33],mix:.55,value:.92},contour:{saturation:.85,value:.62},highlighter:{warm:[1,.86,.62],mix:.3,value:1.6}}),fs=(e,t,n)=>e+(t-e)*n,Nd=(e,t)=>e[0]*t[0]+e[1]*t[1]+e[2]*t[2],Ft=(e,t)=>[e[0]*t,e[1]*t,e[2]*t],_r=(e,t,n)=>[fs(e[0],t[0],n),fs(e[1],t[1],n),fs(e[2],t[2],n)],Od=e=>[e,e,e],De=e=>Nd(e,co),ba=(e,t)=>_r(Od(De(e)),e,t),ps=e=>e<=.0031308?e*12.92:1.055*Math.pow(e,.41666)-.055,ds=e=>e<=.04045?e*.0773993808:Math.pow(e*.9478672986+.0521327014,2.4),Pd=e=>[ps(Math.max(e[0],0)),ps(Math.max(e[1],0)),ps(Math.max(e[2],0))],Ud=e=>[ds(e[0]),ds(e[1]),ds(e[2])],ms=(e,t)=>t<=0?1:1-Math.exp(-Math.max(e,0)/t),Ti=(e,t,n)=>{const{epsilon:a}=nt,s=De(e.skinSlow),r=Ft(e.skinLocal,s/Math.max(De(e.skinLocal),a)),{lips:o,blush:i,contour:c,highlighter:u}=Lu;switch(t){case"lips":return Ft(ba(e.lip,o.saturation),o.value);case"blush":{const l=Ft(i.rose,De(r)/De(i.rose));return Ft(_r(r,l,i.mix),i.value)}case"contour":return Ft(ba(r,c.saturation),c.value);case"highlighter":{const l=Ft(u.warm,De(r)),h=Ft(_r(r,l,u.mix),u.value);return[Math.min(h[0],1),Math.min(h[1],1),Math.min(h[2],1)]}case"brows":return[...e.brow];default:return[...n]}},ve=Object.freeze({facingMin:.1,facingFull:.5,inFrameMargin:.01,maskSize:128,maskFeather:.03,maxYawDeg:35,minFacePx:80,minPresence:.5,maxDt:.25,fastTau:Ci.fast,slowTau:Ci.slow,lightTau:.5,snapJump:.4,readySeconds:.3,minCoverage:.05,minLightTaps:6,minFeatureTaps:1,browHairShare:.6,browHairFloor:.5,reacquireSnapMs:1e3,maxConfidence:100}),Dd=["auto","high","medium","low"],bt=Object.freeze({high:{key:"high",size:128,hz:15,lightFit:!0},medium:{key:"medium",size:128,hz:10,lightFit:!0},low:{key:"low",size:64,hz:5,lightFit:!1}}),gs=["high","medium","low"],Gd=(e,t,n)=>e!=="auto"?bt[e]??bt.high:t<=0||n<=1?bt.high:t>=n-1?bt.low:bt.medium,$d=e=>{let t=gs.length-1,n=!1;for(const a of e)n=!0,t=Math.min(t,Math.max(0,gs.indexOf(a)));return n?gs[t]:"high"},Bd=e=>e.presence>=ve.minPresence?Math.abs(e.yawDeg)<=ve.maxYawDeg?e.faceHeightPx>=ve.minFacePx?null:"small":"turned":"absent",ki=(e,t={mapBlend:1,fastBlend:1,slowBlend:1,lightBlend:1,readyStep:1,snap:!0,lightFit:!0})=>{const n=e.snap||e.still,a=Math.min(Math.max(Number.isFinite(e.dt)?e.dt:0,0),ve.maxDt),s=n?1:ms(a,ve.fastTau);return t.mapBlend=e.halfFloat?s:1,t.fastBlend=e.halfFloat?1:s,t.slowBlend=n?1:ms(a,ve.slowTau),t.lightBlend=n?1:ms(a,ve.lightTau),t.readyStep=e.still?1:a/ve.readySeconds,t.snap=n,t.lightFit=e.lightFit,t},xt=2,Li=(e,t,n)=>{n.forEach(a=>{const s=[0,1,2].map(g=>{const A=T.FACE_ATLAS_TRIANGLES[a*3+g];return[T.FACE_ATLAS_UVS[A*2]*t,(1-T.FACE_ATLAS_UVS[A*2+1])*t]}),[[r,o],[i,c],[u,l]]=s,h=(i-r)*(l-o)-(c-o)*(u-r);if(h===0)return;const f=Math.max(0,Math.floor(Math.min(r,i,u))),p=Math.min(t-1,Math.ceil(Math.max(r,i,u))),m=Math.max(0,Math.floor(Math.min(o,c,l))),E=Math.min(t-1,Math.ceil(Math.max(o,c,l))),S=1e-9*Math.abs(h);for(let g=m;g<=E;g+=1){const A=g+.5;for(let v=f;v<=p;v+=1){const M=v+.5,y=((i-M)*(l-A)-(c-A)*(u-M))/h,x=((u-M)*(o-A)-(l-A)*(r-M))/h,F=1-y-x;y>=-S&&x>=-S&&F>=-S&&(e[g*t+v]=1)}}})},Hd=(e,t,n)=>{if(n<1)return;const a=new Float32Array(t),s=(r,o)=>{for(let i=0;i<t;i+=1){const c=i*r;for(let l=0;l<t;l+=1)a[l]=e[c+l*o];let u=0;for(let l=-n;l<=n;l+=1)u+=a[Math.min(t-1,Math.max(0,l))];for(let l=0;l<t;l+=1)e[c+l*o]=u/(n*2+1),u+=a[Math.min(t-1,l+n+1)]-a[Math.max(0,l-n)]}};for(let r=0;r<3;r+=1)s(t,1),s(1,t)},Xn=e=>{const{include:t,exclude:n,size:a=256,feather:s=0,origin:r="top"}=e,o=a*xt,i=new Uint8Array(o*o);Li(i,o,T.getFaceAtlasRegionTriangles(t));const c=new Uint8Array(o*o);n&&Li(c,o,T.getFaceAtlasRegionTriangles(n));const u=new Float32Array(a*a);for(let h=0;h<a;h+=1)for(let f=0;f<a;f+=1){let p=0;for(let m=0;m<xt;m+=1)for(let E=0;E<xt;E+=1){const S=(h*xt+m)*o+f*xt+E;i[S]&&!c[S]&&(p+=1)}u[h*a+f]=p/(xt*xt)}Hd(u,a,Math.round(s*a/2));const l=new Uint8ClampedArray(a*a);for(let h=0;h<a;h+=1){const f=r==="top"?h:a-1-h;for(let p=0;p<a;p+=1)l[f*a+p]=Math.round(u[h*a+p]*255)}return{width:a,height:a,data:l}},Ru=e=>{const t=Xn({...e,origin:"bottom"}),n=new Ae.DataTexture(new Uint8Array(t.data.buffer,t.data.byteOffset,t.data.length),t.width,t.height,Ae.RedFormat,Ae.UnsignedByteType);return n.flipY=!1,n.unpackAlignment=1,n.magFilter=Ae.LinearFilter,n.minFilter=Ae.LinearFilter,n.needsUpdate=!0,n},zd=(e,t=[255,255,255])=>{const n=new Uint8ClampedArray(e.data.length*4);return e.data.forEach((a,s)=>{n[s*4]=t[0],n[s*4+1]=t[1],n[s*4+2]=t[2],n[s*4+3]=a}),n},I=e=>{if(!Number.isFinite(e))throw new Error(`glslFloat: ${e} is not a finite number`);const t=String(e);return/[.eE]/.test(t)?t:`${t}.0`},ln=e=>`vec3(${e.map(I).join(", ")})`,sa=Object.freeze({ridge:.001,iterations:4,tukey:4.685,minScale:.03,maxConfidence:100,confidenceMin:nt.lightConfidenceMin}),In=Object.freeze({forehead:1,jaw:2,plusX:4,minusX:8}),Ri=Object.freeze([0,In.forehead,In.jaw,In.plusX,In.minusX]),bi=Object.freeze([151,9,104,333,197,116,345,50,280,205,425,136,365,148,377,199]),{forehead:ra,jaw:An,plusX:zt,minusX:Kt}=In,Kd=Object.freeze([ra,ra,ra|Kt,ra|zt,0,Kt,zt,Kt,zt,Kt,zt,An|Kt,An|zt,An|Kt,An|zt,An]),dt=(e,t,n)=>({landmarks:e,points:Float32Array.from(e.flatMap(a=>[V.CANONICAL_FACE_POSITIONS[a*3],V.CANONICAL_FACE_POSITIONS[a*3+1],V.CANONICAL_FACE_POSITIONS[a*3+2]])),closed:t,sided:n}),bu=["upperLash","lowerLash","browUpper","browLower","lipOuter","lipInner","oval","noseBridge"],jd=e=>{const t={};return Object.keys(e).forEach(n=>{let a;Object.defineProperty(t,n,{enumerable:!0,get:()=>(a??(a=e[n]()),a)})}),Object.freeze(t)},un=jd({upperLash:()=>dt([33,246,161,160,159,158,157,173,133],!1,!0),lowerLash:()=>dt([33,7,163,144,145,153,154,155,133],!1,!0),browUpper:()=>dt([70,63,105,66,107],!1,!0),browLower:()=>dt([46,53,52,65,55],!1,!0),lipOuter:()=>dt(T.FACE_ATLAS_LIP_RINGS.outer,!0,!1),lipInner:()=>dt(T.FACE_ATLAS_LIP_RINGS.inner,!0,!1),oval:()=>dt(T.FACE_ATLAS_OVAL_RING,!0,!1),noseBridge:()=>dt([168,6,197,195,5,4],!1,!1)}),Fr={outerEyeCorner:33,innerEyeCorner:133,browTail:70,browPeak:105,browHead:107,temple:139,cheekbone:116,cheekApple:205,cheekHollow:187,mouthCorner:61,jawAngle:172,noseBridge:6,noseTip:4,cupidsBow:0,chin:199,foreheadCenter:151},Vd=(e,t="negX")=>{const n=t==="posX"?T.FACE_ATLAS_MIRROR[Fr[e]]:Fr[e];return[V.CANONICAL_FACE_POSITIONS[n*3],V.CANONICAL_FACE_POSITIONS[n*3+1],V.CANONICAL_FACE_POSITIONS[n*3+2]]},Iu=e=>{const t=Float32Array.from(e.points);for(let n=0;n<t.length;n+=3)t[n]=-t[n];return{landmarks:e.landmarks.map(n=>T.FACE_ATLAS_MIRROR[n]),points:t,closed:e.closed,sided:e.sided}},Ss=e=>{const t=Number(e.toFixed(5)).toString();return t.includes(".")||t.includes("e")?t:`${t}.0`},Wd=e=>e.replace(/([a-z0-9])([A-Z])/g,"$1_$2").toUpperCase(),qd=(e=bu,t="FACE_ATLAS_")=>e.map(n=>{const{points:a}=un[n],s=a.length/3,r=`${t}${Wd(n)}`,o=[];for(let i=0;i<a.length;i+=3)o.push(`vec3(${Ss(a[i])}, ${Ss(a[i+1])}, ${Ss(a[i+2])})`);return`const int ${r}_COUNT = ${s};
|
|
62
|
+
const vec3 ${r}[${s}] = vec3[${s}](${o.join(", ")});
|
|
63
|
+
`}).join(""),re=Object.freeze({texels:8,skinSlow:0,skinFast:1,light:2,lip:3,brow:4}),Xd=1,Nu=Object.freeze([1/6,1/2,5/6]),Yd=()=>{const e=f=>[T.FACE_ATLAS_UVS[f*2],T.FACE_ATLAS_UVS[f*2+1]],t=(f,p,m)=>{const[E,S]=e(f),[g,A]=e(p);return[E+(g-E)*m,S+(A-S)*m]},{restNormal:n}=T.getFaceAtlasAttributes(),a={uv:Float32Array.from(bi.flatMap(e)),normal:Float32Array.from(bi.flatMap(f=>[n[f*3],n[f*3+1],n[f*3+2]])),group:Int32Array.from(Kd)},{outer:s,inner:r}=T.FACE_ATLAS_LIP_RINGS,o=[s.indexOf(61),s.indexOf(291)],i=(f,p)=>{const m=Math.abs(f-p);return Math.min(m,s.length-m)},c=[];s.forEach((f,p)=>{o.some(m=>i(p,m)<=Xd)||c.push(...t(f,r[p],.5))});const u=un.browUpper.landmarks,l=un.browLower.landmarks,h=[];return u.forEach((f,p)=>{Nu.forEach(m=>{h.push(...t(f,l[p],m)),h.push(...t(T.FACE_ATLAS_MIRROR[f],T.FACE_ATLAS_MIRROR[l[p]],m))})}),{light:a,lip:Float32Array.from(c),brow:Float32Array.from(h)}};let Ii=null;const Qd=()=>(Ii??(Ii=Yd()),Ii),Jd=(e,t)=>{const n=ve.maxConfidence,a=Math.hypot(e[0],e[1],e[2]);return Math.min(a/Math.max(t,a/n,1e-6),n)},lo=e=>{const t=r=>[e[r*4],e[r*4+1],e[r*4+2]],n=r=>e[r*4+3],a=t(re.light),s=Math.hypot(...a);return{skinSlow:t(re.skinSlow),ready:n(re.skinSlow),skinFast:t(re.skinFast),coverage:n(re.skinFast),light:{gradient:a,ambient:n(re.light),direction:s>0?[a[0]/s,a[1]/s,a[2]/s]:[0,0,1],confidence:Jd(a,n(re.light))},lip:t(re.lip),lipSeen:n(re.lip),brow:t(re.brow),browSeen:n(re.brow)}},Zd=e=>e.extensions.has("EXT_color_buffer_half_float")||e.extensions.has("EXT_color_buffer_float"),em=e=>e.extensions.has("EXT_color_buffer_float"),Ni=(e,t)=>e===!1?"rgba8":e===!0||!t||Zd(t)?"half-float":"rgba8",Oi=(e,t)=>e==="rgba8"?"packed":!t||em(t)?"float":"packed",Pt=8,mn=3,tm=16777215,nm=e=>e==="packed"?Pt*mn:Pt,Es=(e,t)=>{const n=new d.WebGLRenderTarget(e,e,{count:2,type:t==="half-float"?d.HalfFloatType:d.UnsignedByteType,format:d.RGBAFormat,colorSpace:d.NoColorSpace,depthBuffer:!1,stencilBuffer:!1,generateMipmaps:!0,minFilter:d.LinearMipmapLinearFilter,magFilter:d.LinearFilter,wrapS:d.ClampToEdgeWrapping,wrapT:d.ClampToEdgeWrapping});return n.textures[0].name="FaceSkinProbe.skinMap",n.textures[1].name="FaceSkinProbe.featureMap",n},vn=e=>{const t=new d.WebGLRenderTarget(nm(e),1,{type:e==="float"?d.FloatType:d.UnsignedByteType,format:d.RGBAFormat,colorSpace:d.NoColorSpace,depthBuffer:!1,stencilBuffer:!1,generateMipmaps:!1,minFilter:d.NearestFilter,magFilter:d.NearestFilter});return t.texture.name="FaceSkinProbe.lightingMap",t},uo=2,am=(e,t,n)=>((e*256+t)*256+n)/tm,Pi=(e,t,n=new Float32Array(Pt*4))=>{const a=mn*4;for(let s=0;s<Pt;s+=1)for(let r=0;r<4;r+=1){let o;{const i=s*a+r;o=am(e[i],e[i+4],e[i+8]),s===uo&&r<3&&(o=o*2-1)}n[s*4+r]=o}return n},Yn=`
|
|
64
|
+
precision highp float;
|
|
65
|
+
precision highp int;
|
|
66
|
+
precision highp sampler2D;
|
|
67
|
+
`,ho=`
|
|
68
|
+
vec4 faceSkinStatFrom(sampler2D map, int texel, float packed) {
|
|
69
|
+
if (packed < 0.5) return texelFetch(map, ivec2(texel, 0), 0);
|
|
70
|
+
int at = texel * ${mn};
|
|
71
|
+
vec4 hi = floor(texelFetch(map, ivec2(at, 0), 0) * 255.0 + 0.5);
|
|
72
|
+
vec4 mid = floor(texelFetch(map, ivec2(at + 1, 0), 0) * 255.0 + 0.5);
|
|
73
|
+
vec4 lo = floor(texelFetch(map, ivec2(at + 2, 0), 0) * 255.0 + 0.5);
|
|
74
|
+
vec4 v = ((hi * 256.0 + mid) * 256.0 + lo) / 16777215.0;
|
|
75
|
+
return texel == ${uo} ? vec4(v.xyz * 2.0 - 1.0, v.w) : v;
|
|
76
|
+
}
|
|
77
|
+
`,Ou=`
|
|
78
|
+
vec4 faceSkinStatPack(vec4 value, int texel, int physical) {
|
|
79
|
+
if (texel == ${uo}) value.xyz = value.xyz * 0.5 + 0.5;
|
|
80
|
+
vec4 bits = floor(clamp(value, 0.0, 1.0) * 16777215.0 + 0.5);
|
|
81
|
+
vec4 hi = floor(bits / 65536.0);
|
|
82
|
+
vec4 rest = bits - hi * 65536.0;
|
|
83
|
+
vec4 mid = floor(rest / 256.0);
|
|
84
|
+
vec4 lo = rest - mid * 256.0;
|
|
85
|
+
int part = physical - texel * ${mn};
|
|
86
|
+
return (part == 0 ? hi : (part == 1 ? mid : lo)) / 255.0;
|
|
87
|
+
}
|
|
88
|
+
`,Pu=`
|
|
89
|
+
#ifndef VXR_FACE_SKIN_STATS
|
|
90
|
+
#define VXR_FACE_SKIN_STATS
|
|
91
|
+
uniform sampler2D uSkinStats;
|
|
92
|
+
uniform float uSkinStatsPacked;
|
|
93
|
+
${ho}
|
|
94
|
+
vec4 faceSkinStat(int texel) {
|
|
95
|
+
return faceSkinStatFrom(uSkinStats, texel, uSkinStatsPacked);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
vec4 faceSkinLight() {
|
|
99
|
+
vec4 t = faceSkinStat(${re.light});
|
|
100
|
+
float strength = length(t.xyz);
|
|
101
|
+
float k = strength / max(max(t.w, strength / ${I(ve.maxConfidence)}), 1e-6);
|
|
102
|
+
return vec4(t.xyz, min(k, ${I(ve.maxConfidence)}));
|
|
103
|
+
}
|
|
104
|
+
#endif
|
|
105
|
+
`,Uu=`
|
|
106
|
+
${Pu}
|
|
107
|
+
#ifndef VXR_MAKEUP_SKIN_STATS_VERTEX
|
|
108
|
+
#define VXR_MAKEUP_SKIN_STATS_VERTEX
|
|
109
|
+
void makeupWriteSkinStats() {
|
|
110
|
+
vec4 slow = faceSkinStat(${re.skinSlow});
|
|
111
|
+
vMakeupSkinSlow = slow.rgb;
|
|
112
|
+
vMakeupSkinReady = slow.a;
|
|
113
|
+
vMakeupSkinFast = faceSkinStat(${re.skinFast}).rgb;
|
|
114
|
+
vMakeupLight = faceSkinLight();
|
|
115
|
+
vMakeupLipColor = faceSkinStat(${re.lip}).rgb;
|
|
116
|
+
vMakeupBrowColor = faceSkinStat(${re.brow}).rgb;
|
|
117
|
+
}
|
|
118
|
+
#endif
|
|
119
|
+
`,sm=`${Yn}
|
|
120
|
+
in vec3 position;
|
|
121
|
+
in vec2 cameraUv;
|
|
122
|
+
in float weight;
|
|
123
|
+
out vec2 vAtlasUv;
|
|
124
|
+
out vec2 vCameraUv;
|
|
125
|
+
out float vWeight;
|
|
126
|
+
void main() {
|
|
127
|
+
vAtlasUv = position.xy;
|
|
128
|
+
vCameraUv = cameraUv;
|
|
129
|
+
vWeight = weight;
|
|
130
|
+
gl_Position = vec4(position.xy * 2.0 - 1.0, 0.0, 1.0);
|
|
131
|
+
}
|
|
132
|
+
`,rm=`${Yn}
|
|
133
|
+
uniform sampler2D uSource;
|
|
134
|
+
uniform sampler2D uSkinMask;
|
|
135
|
+
uniform float uDecodeSrgb;
|
|
136
|
+
uniform float uSqrt;
|
|
137
|
+
in vec2 vAtlasUv;
|
|
138
|
+
in vec2 vCameraUv;
|
|
139
|
+
in float vWeight;
|
|
140
|
+
layout(location = 0) out highp vec4 outSkin;
|
|
141
|
+
layout(location = 1) out highp vec4 outFeature;
|
|
142
|
+
|
|
143
|
+
vec3 faceSkinSrgbToLinear(vec3 c) {
|
|
144
|
+
vec3 low = c * 0.0773993808;
|
|
145
|
+
vec3 high = pow(c * 0.9478672986 + 0.0521327014, vec3(2.4));
|
|
146
|
+
return mix(high, low, vec3(lessThanEqual(c, vec3(0.04045))));
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
void main() {
|
|
150
|
+
vec3 c = texture(uSource, vCameraUv).rgb;
|
|
151
|
+
if (uDecodeSrgb > 0.5) c = faceSkinSrgbToLinear(c);
|
|
152
|
+
c = max(c, vec3(0.0));
|
|
153
|
+
vec3 e = uSqrt > 0.5 ? sqrt(c) : c;
|
|
154
|
+
float w = clamp(vWeight, 0.0, 1.0);
|
|
155
|
+
float skin = smoothstep(0.5, 1.0, texture(uSkinMask, vAtlasUv).r);
|
|
156
|
+
outSkin = vec4(e * (w * skin), w * skin);
|
|
157
|
+
outFeature = vec4(e * w, w);
|
|
158
|
+
}
|
|
159
|
+
`,Ui=`${Yn}
|
|
160
|
+
in vec3 position;
|
|
161
|
+
void main() {
|
|
162
|
+
gl_Position = vec4(position.xy, 0.0, 1.0);
|
|
163
|
+
}
|
|
164
|
+
`,As=(e,t)=>{const n=t.length/2,a=[];for(let s=0;s<n;s+=1)a.push(`vec2(${I(t[s*2])}, ${I(t[s*2+1])})`);return`const vec2 ${e}[${n}] = vec2[${n}](
|
|
165
|
+
${a.join(`,
|
|
166
|
+
`)}
|
|
167
|
+
);`},om=(e,t)=>{const n=t.length/3,a=[];for(let s=0;s<n;s+=1)a.push(ln([t[s*3],t[s*3+1],t[s*3+2]]));return`const vec3 ${e}[${n}] = vec3[${n}](
|
|
168
|
+
${a.join(`,
|
|
169
|
+
`)}
|
|
170
|
+
);`},Di=(e,t)=>`const int ${e}[${t.length}] = int[${t.length}](${Array.from(t).join(", ")});`,im=()=>{const e=Qd(),t=e.light.group.length,n=e.lip.length/2,a=e.brow.length/2,s=Nu.length,r=nt,o=ve;return`${Yn}
|
|
171
|
+
uniform sampler2D uSkinMap;
|
|
172
|
+
uniform sampler2D uFeatureMap;
|
|
173
|
+
uniform sampler2D uPrevious;
|
|
174
|
+
uniform int uTopLevel;
|
|
175
|
+
uniform float uSkinLod;
|
|
176
|
+
uniform float uSqrt;
|
|
177
|
+
uniform float uPacked;
|
|
178
|
+
uniform float uFastBlend;
|
|
179
|
+
uniform float uSlowBlend;
|
|
180
|
+
uniform float uLightBlend;
|
|
181
|
+
uniform float uReadyStep;
|
|
182
|
+
uniform float uSnap;
|
|
183
|
+
uniform float uLightFit;
|
|
184
|
+
uniform mat3 uRotation;
|
|
185
|
+
layout(location = 0) out highp vec4 outStat;
|
|
186
|
+
|
|
187
|
+
#define FS_EPSILON ${I(r.epsilon)}
|
|
188
|
+
#define FS_FIT_TAPS ${t}
|
|
189
|
+
#define FS_FIT_CANDIDATES ${Ri.length}
|
|
190
|
+
#define FS_LIP_TAPS ${n}
|
|
191
|
+
#define FS_BROW_TAPS ${a}
|
|
192
|
+
|
|
193
|
+
${As("FS_LIGHT_TAP_UV",e.light.uv)}
|
|
194
|
+
${om("FS_LIGHT_TAP_NORMAL",e.light.normal)}
|
|
195
|
+
${Di("FS_LIGHT_TAP_GROUP",e.light.group)}
|
|
196
|
+
${Di("FS_LEAVE_OUT",Ri)}
|
|
197
|
+
${As("FS_LIP_TAP_UV",e.lip)}
|
|
198
|
+
${As("FS_BROW_TAP_UV",e.brow)}
|
|
199
|
+
${ho}${Ou}
|
|
200
|
+
float fsLuma(vec3 c) {
|
|
201
|
+
return dot(c, ${ln(co)});
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// A map texel or mip: rgb / a, squared on RGBA8 (rgb = w * sqrt(c)).
|
|
205
|
+
vec3 fsDecode(vec4 t) {
|
|
206
|
+
vec3 c = t.rgb / max(t.a, FS_EPSILON);
|
|
207
|
+
return uSqrt > 0.5 ? c * c : c;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
float fsWeight(float a) {
|
|
211
|
+
return smoothstep(${I(r.lowpassMinWeight)}, ${I(r.lowpassFullWeight)}, a);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// The local skin: the low-pass, a coarser mip, then the fast skin (makeupSample's rule).
|
|
215
|
+
vec3 fsLocal(vec2 uv, vec3 fast) {
|
|
216
|
+
vec4 lowpass = textureLod(uSkinMap, uv, uSkinLod);
|
|
217
|
+
float fine = fsWeight(lowpass.a);
|
|
218
|
+
vec3 local = fast;
|
|
219
|
+
if (fine < 1.0) {
|
|
220
|
+
vec4 coarse = textureLod(uSkinMap, uv, uSkinLod + ${I(r.lowpassCoarseLods)});
|
|
221
|
+
local = mix(fast, fsDecode(coarse), fsWeight(coarse.a));
|
|
222
|
+
}
|
|
223
|
+
return mix(local, fsDecode(lowpass), fine);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// Caps the brow-hair extrapolation factor g for one channel: the hair stays at
|
|
227
|
+
// least browHairFloor of the measured brow (dense brows read dark, not black)
|
|
228
|
+
// and at most 1.
|
|
229
|
+
float fsHairFactor(float g, float brow, float skin) {
|
|
230
|
+
float d = brow - skin;
|
|
231
|
+
if (d < -FS_EPSILON) return min(g, (skin - ${I(o.browHairFloor)} * brow) / -d);
|
|
232
|
+
if (d > FS_EPSILON) return min(g, (1.0 - skin) / d);
|
|
233
|
+
return g;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// ---- The light fit: a port of fitLight (lightFit.ts) ----
|
|
237
|
+
|
|
238
|
+
float fitLum[FS_FIT_TAPS];
|
|
239
|
+
float fitBase[FS_FIT_TAPS];
|
|
240
|
+
vec3 fitNormal[FS_FIT_TAPS];
|
|
241
|
+
|
|
242
|
+
// Solves M x = y for a symmetric positive-definite 4x4 M by Cholesky; false when M is not SPD.
|
|
243
|
+
bool fsSolveSpd4(mat4 m, vec4 y, out vec4 x) {
|
|
244
|
+
float l[16];
|
|
245
|
+
for (int k = 0; k < 16; k++) l[k] = 0.0;
|
|
246
|
+
x = vec4(0.0);
|
|
247
|
+
for (int i = 0; i < 4; i++) {
|
|
248
|
+
for (int j = 0; j <= i; j++) {
|
|
249
|
+
float sum = m[i][j];
|
|
250
|
+
for (int k = 0; k < j; k++) sum -= l[i * 4 + k] * l[j * 4 + k];
|
|
251
|
+
if (i == j) {
|
|
252
|
+
if (!(sum > 0.0)) return false;
|
|
253
|
+
l[i * 4 + i] = sqrt(sum);
|
|
254
|
+
} else {
|
|
255
|
+
l[i * 4 + j] = sum / l[j * 4 + j];
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
vec4 z = vec4(0.0);
|
|
260
|
+
for (int i = 0; i < 4; i++) {
|
|
261
|
+
float sum = y[i];
|
|
262
|
+
for (int k = 0; k < i; k++) sum -= l[i * 4 + k] * z[k];
|
|
263
|
+
z[i] = sum / l[i * 4 + i];
|
|
264
|
+
}
|
|
265
|
+
for (int i = 3; i >= 0; i--) {
|
|
266
|
+
float sum = z[i];
|
|
267
|
+
for (int k = i + 1; k < 4; k++) sum -= l[k * 4 + i] * x[k];
|
|
268
|
+
x[i] = sum / l[i * 4 + i];
|
|
269
|
+
}
|
|
270
|
+
return true;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// Weighted least squares of lum = a + b . n with a ridge on b; x = (a, b).
|
|
274
|
+
bool fsSolveWeighted(float w[FS_FIT_TAPS], out vec4 x) {
|
|
275
|
+
mat4 m = mat4(0.0);
|
|
276
|
+
vec4 y = vec4(0.0);
|
|
277
|
+
float total = 0.0;
|
|
278
|
+
x = vec4(0.0);
|
|
279
|
+
for (int i = 0; i < FS_FIT_TAPS; i++) {
|
|
280
|
+
if (w[i] <= 0.0) continue;
|
|
281
|
+
vec4 r = vec4(1.0, fitNormal[i]);
|
|
282
|
+
m += w[i] * outerProduct(r, r);
|
|
283
|
+
y += (w[i] * fitLum[i]) * r;
|
|
284
|
+
total += w[i];
|
|
285
|
+
}
|
|
286
|
+
if (!(total > 1e-9)) return false;
|
|
287
|
+
float lambda = ${I(sa.ridge)} * total;
|
|
288
|
+
m[1][1] += lambda;
|
|
289
|
+
m[2][2] += lambda;
|
|
290
|
+
m[3][3] += lambda;
|
|
291
|
+
return fsSolveSpd4(m, y, x);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
float fsResidual(vec4 x, int i) {
|
|
295
|
+
return fitLum[i] - (x.x + dot(x.yzw, fitNormal[i]));
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// A tap brighter than the model while facing away from the light is in attached shadow: 0.
|
|
299
|
+
float fsScoredResidual(vec4 x, int i) {
|
|
300
|
+
float facing = dot(x.yzw, fitNormal[i]);
|
|
301
|
+
float r = fitLum[i] - (x.x + facing);
|
|
302
|
+
return (r > 0.0 && facing < 0.0) ? 0.0 : r;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// The median of v over the taps with mask > 0, by counting ranks.
|
|
306
|
+
float fsMedian(float v[FS_FIT_TAPS], float mask[FS_FIT_TAPS]) {
|
|
307
|
+
int n = 0;
|
|
308
|
+
for (int i = 0; i < FS_FIT_TAPS; i++) {
|
|
309
|
+
if (mask[i] > 0.0) n++;
|
|
310
|
+
}
|
|
311
|
+
if (n == 0) return 0.0;
|
|
312
|
+
int lo = (n - 1) / 2;
|
|
313
|
+
int hi = n / 2;
|
|
314
|
+
float a = 0.0;
|
|
315
|
+
float b = 0.0;
|
|
316
|
+
for (int i = 0; i < FS_FIT_TAPS; i++) {
|
|
317
|
+
if (mask[i] <= 0.0) continue;
|
|
318
|
+
int rank = 0;
|
|
319
|
+
for (int j = 0; j < FS_FIT_TAPS; j++) {
|
|
320
|
+
if (mask[j] <= 0.0) continue;
|
|
321
|
+
if (v[j] < v[i] || (v[j] == v[i] && j < i)) rank++;
|
|
322
|
+
}
|
|
323
|
+
if (rank == lo) a = v[i];
|
|
324
|
+
if (rank == hi) b = v[i];
|
|
325
|
+
}
|
|
326
|
+
return 0.5 * (a + b);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// x = (a, b) of the robust fit over the light taps; false with too little skin.
|
|
330
|
+
bool fsLightFit(out vec4 x) {
|
|
331
|
+
x = vec4(0.0);
|
|
332
|
+
float total = 0.0;
|
|
333
|
+
float mean = 0.0;
|
|
334
|
+
for (int i = 0; i < FS_FIT_TAPS; i++) {
|
|
335
|
+
vec4 t = textureLod(uSkinMap, FS_LIGHT_TAP_UV[i], uSkinLod);
|
|
336
|
+
fitBase[i] = fsWeight(t.a);
|
|
337
|
+
fitLum[i] = fsLuma(fsDecode(t));
|
|
338
|
+
fitNormal[i] = uRotation * FS_LIGHT_TAP_NORMAL[i];
|
|
339
|
+
total += fitBase[i];
|
|
340
|
+
mean += fitBase[i] * fitLum[i];
|
|
341
|
+
}
|
|
342
|
+
if (total < ${I(o.minLightTaps)}) return false;
|
|
343
|
+
mean /= total;
|
|
344
|
+
|
|
345
|
+
// Start from the leave-a-region-out candidate with the least score over every tap.
|
|
346
|
+
float best = 1e30;
|
|
347
|
+
bool found = false;
|
|
348
|
+
for (int c = 0; c < FS_FIT_CANDIDATES; c++) {
|
|
349
|
+
float w[FS_FIT_TAPS];
|
|
350
|
+
for (int i = 0; i < FS_FIT_TAPS; i++) {
|
|
351
|
+
w[i] = (FS_LIGHT_TAP_GROUP[i] & FS_LEAVE_OUT[c]) != 0 ? 0.0 : fitBase[i];
|
|
352
|
+
}
|
|
353
|
+
vec4 trial;
|
|
354
|
+
if (!fsSolveWeighted(w, trial)) continue;
|
|
355
|
+
float absolute[FS_FIT_TAPS];
|
|
356
|
+
float brighter = 0.0;
|
|
357
|
+
float taps = 0.0;
|
|
358
|
+
for (int i = 0; i < FS_FIT_TAPS; i++) {
|
|
359
|
+
absolute[i] = 0.0;
|
|
360
|
+
if (fitBase[i] <= 0.0) continue;
|
|
361
|
+
float r = fsScoredResidual(trial, i);
|
|
362
|
+
absolute[i] = abs(r);
|
|
363
|
+
brighter += max(r, 0.0);
|
|
364
|
+
taps += 1.0;
|
|
365
|
+
}
|
|
366
|
+
float score = fsMedian(absolute, fitBase) + brighter / taps;
|
|
367
|
+
if (score < best) {
|
|
368
|
+
best = score;
|
|
369
|
+
x = trial;
|
|
370
|
+
found = true;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
if (!found) return false;
|
|
374
|
+
|
|
375
|
+
// Tukey reweighting.
|
|
376
|
+
float weights[FS_FIT_TAPS];
|
|
377
|
+
for (int i = 0; i < FS_FIT_TAPS; i++) weights[i] = fitBase[i];
|
|
378
|
+
for (int pass = 0; pass < ${sa.iterations}; pass++) {
|
|
379
|
+
float residual[FS_FIT_TAPS];
|
|
380
|
+
float absolute[FS_FIT_TAPS];
|
|
381
|
+
for (int i = 0; i < FS_FIT_TAPS; i++) {
|
|
382
|
+
residual[i] = 0.0;
|
|
383
|
+
absolute[i] = 0.0;
|
|
384
|
+
if (fitBase[i] <= 0.0) continue;
|
|
385
|
+
residual[i] = fsResidual(x, i);
|
|
386
|
+
absolute[i] = abs(residual[i]);
|
|
387
|
+
}
|
|
388
|
+
float scale = max(max(1.4826 * fsMedian(absolute, fitBase), ${I(sa.minScale)} * abs(mean)), 1e-6);
|
|
389
|
+
for (int i = 0; i < FS_FIT_TAPS; i++) {
|
|
390
|
+
if (fitBase[i] <= 0.0) continue;
|
|
391
|
+
float u = residual[i] / (${I(sa.tukey)} * scale);
|
|
392
|
+
float t = 1.0 - u * u;
|
|
393
|
+
weights[i] = abs(u) < 1.0 ? fitBase[i] * t * t : 0.0;
|
|
394
|
+
}
|
|
395
|
+
vec4 next;
|
|
396
|
+
if (!fsSolveWeighted(weights, next)) break;
|
|
397
|
+
x = next;
|
|
398
|
+
}
|
|
399
|
+
return true;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// ---- One stats texel (stepFaceSkinStats) ----
|
|
403
|
+
|
|
404
|
+
vec4 fsPrevious(int texel) {
|
|
405
|
+
return faceSkinStatFrom(uPrevious, texel, uPacked);
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
vec4 fsStat(int texel) {
|
|
409
|
+
bool snap = uSnap > 0.5;
|
|
410
|
+
vec4 prevSlow = fsPrevious(${re.skinSlow});
|
|
411
|
+
vec4 prevFast = fsPrevious(${re.skinFast});
|
|
412
|
+
|
|
413
|
+
// Fast skin.
|
|
414
|
+
vec4 top = texelFetch(uSkinMap, ivec2(0, 0), uTopLevel);
|
|
415
|
+
float coverage = top.a;
|
|
416
|
+
bool covered = coverage >= ${I(o.minCoverage)};
|
|
417
|
+
float fastBlend = (snap || fsLuma(prevFast.rgb) < FS_EPSILON) ? 1.0 : uFastBlend;
|
|
418
|
+
vec3 rf = covered
|
|
419
|
+
? max(mix(prevFast.rgb, fsDecode(top), fastBlend), vec3(0.0))
|
|
420
|
+
: (snap ? vec3(0.0) : prevFast.rgb);
|
|
421
|
+
float lumRs = fsLuma(prevSlow.rgb);
|
|
422
|
+
bool jump = !snap && covered && lumRs >= FS_EPSILON
|
|
423
|
+
&& abs(fsLuma(rf) - lumRs) > ${I(o.snapJump)} * lumRs;
|
|
424
|
+
bool restart = snap || jump;
|
|
425
|
+
|
|
426
|
+
if (texel == ${re.skinSlow}) {
|
|
427
|
+
if (!covered) return snap ? vec4(0.0) : prevSlow;
|
|
428
|
+
float blend = (restart || lumRs < FS_EPSILON) ? 1.0 : uSlowBlend;
|
|
429
|
+
float ready = min(1.0, (snap ? 0.0 : prevSlow.a) + uReadyStep);
|
|
430
|
+
return vec4(max(mix(prevSlow.rgb, rf, blend), vec3(0.0)), ready);
|
|
431
|
+
}
|
|
432
|
+
if (texel == ${re.skinFast}) return vec4(rf, coverage);
|
|
433
|
+
|
|
434
|
+
if (texel == ${re.light}) {
|
|
435
|
+
if (uLightFit < 0.5) return vec4(0.0, 0.0, 0.0, fsLuma(rf));
|
|
436
|
+
vec4 prev = fsPrevious(${re.light});
|
|
437
|
+
vec4 fit;
|
|
438
|
+
if (fsLightFit(fit)) {
|
|
439
|
+
float blend = (restart || prev.w <= FS_EPSILON) ? 1.0 : uLightBlend;
|
|
440
|
+
return mix(prev, vec4(fit.yzw, fit.x), blend);
|
|
441
|
+
}
|
|
442
|
+
return snap ? vec4(0.0, 0.0, 0.0, fsLuma(rf)) : prev;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
if (texel == ${re.lip}) {
|
|
446
|
+
vec4 prev = fsPrevious(${re.lip});
|
|
447
|
+
float sw = 0.0;
|
|
448
|
+
vec3 sc = vec3(0.0);
|
|
449
|
+
for (int i = 0; i < FS_LIP_TAPS; i++) {
|
|
450
|
+
vec4 t = textureLod(uFeatureMap, FS_LIP_TAP_UV[i], 0.0);
|
|
451
|
+
sw += t.a;
|
|
452
|
+
sc += t.a * fsDecode(t);
|
|
453
|
+
}
|
|
454
|
+
if (!(sw >= ${I(o.minFeatureTaps)})) return snap ? vec4(0.0) : prev;
|
|
455
|
+
float blend = (restart || prev.a <= 0.0) ? 1.0 : uSlowBlend;
|
|
456
|
+
float seen = min(1.0, sw / float(FS_LIP_TAPS));
|
|
457
|
+
return vec4(max(mix(prev.rgb, sc / sw, blend), vec3(0.0)), mix(prev.a, seen, blend));
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
if (texel == ${re.brow}) {
|
|
461
|
+
vec4 prev = fsPrevious(${re.brow});
|
|
462
|
+
float sw = 0.0;
|
|
463
|
+
vec3 sb = vec3(0.0);
|
|
464
|
+
vec3 sl = vec3(0.0);
|
|
465
|
+
for (int i = 0; i < FS_BROW_TAPS; i++) {
|
|
466
|
+
vec4 t = textureLod(uFeatureMap, FS_BROW_TAP_UV[i], 0.0);
|
|
467
|
+
sw += t.a;
|
|
468
|
+
sb += t.a * fsDecode(t);
|
|
469
|
+
sl += t.a * fsLocal(FS_BROW_TAP_UV[i], rf);
|
|
470
|
+
}
|
|
471
|
+
// ${s} taps per brow column: the threshold counts columns.
|
|
472
|
+
if (!(sw >= ${I(o.minFeatureTaps*s)})) return snap ? vec4(0.0) : prev;
|
|
473
|
+
vec3 skin = sl / sw;
|
|
474
|
+
vec3 brow = sb / sw;
|
|
475
|
+
float g = ${I(1/o.browHairShare)};
|
|
476
|
+
g = fsHairFactor(g, brow.r, skin.r);
|
|
477
|
+
g = fsHairFactor(g, brow.g, skin.g);
|
|
478
|
+
g = fsHairFactor(g, brow.b, skin.b);
|
|
479
|
+
vec3 hair = clamp(skin + (brow - skin) * max(g, 1.0), 0.0, 1.0);
|
|
480
|
+
float blend = (restart || prev.a <= 0.0) ? 1.0 : uSlowBlend;
|
|
481
|
+
float seen = min(1.0, sw / float(FS_BROW_TAPS));
|
|
482
|
+
return vec4(max(mix(prev.rgb, hair, blend), vec3(0.0)), mix(prev.a, seen, blend));
|
|
483
|
+
}
|
|
484
|
+
return vec4(0.0);
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
void main() {
|
|
488
|
+
int physical = int(gl_FragCoord.x);
|
|
489
|
+
int texel = uPacked > 0.5 ? physical / ${mn} : physical;
|
|
490
|
+
vec4 value = fsStat(texel);
|
|
491
|
+
outStat = uPacked > 0.5 ? faceSkinStatPack(value, texel, physical) : value;
|
|
492
|
+
}
|
|
493
|
+
`},cm=`${Yn}
|
|
494
|
+
uniform sampler2D uStats;
|
|
495
|
+
uniform float uPacked;
|
|
496
|
+
layout(location = 0) out highp vec4 outByte;
|
|
497
|
+
${ho}${Ou}
|
|
498
|
+
void main() {
|
|
499
|
+
int physical = int(gl_FragCoord.x);
|
|
500
|
+
int texel = physical / ${mn};
|
|
501
|
+
outByte = faceSkinStatPack(faceSkinStatFrom(uStats, texel, uPacked), texel, physical);
|
|
502
|
+
}
|
|
503
|
+
`,Mn=(e,t,n)=>{const a=Math.min(1,Math.max(0,(n-e)/(t-e)));return a*a*(3-2*a)},lm=e=>e.isRenderTargetTexture?!0:e.flipY===!1?!1:!(typeof ImageBitmap<"u"&&e.image instanceof ImageBitmap),Ia=T.FACE_ATLAS_SOURCE.vertexCount,xr=T.FACE_ATLAS_SOURCE.triangleCount,Gi=new Float32Array(xr),vs=new Float32Array(Ia),oa=new Uint8Array(Ia),um=(e,t,n,a)=>{const{aspect:s,flipY:r}=t,o=ve.inFrameMargin;for(let l=0;l<Ia;l+=1){const h=e[l];n[l*2]=h.x,n[l*2+1]=r?1-h.y:h.y}const i=T.FACE_ATLAS_TRIANGLES;let c=0;for(let l=0;l<xr;l+=1){const h=e[i[l*3]],f=e[i[l*3+1]],p=e[i[l*3+2]],m=(f.x-h.x)*s,E=f.y-h.y,S=((f.z??0)-(h.z??0))*s,g=(p.x-h.x)*s,A=p.y-h.y,v=((p.z??0)-(h.z??0))*s,M=m*A-E*g,y=Math.hypot(E*v-S*A,S*g-m*v,M);Gi[l]=y>1e-12?M/y:0,c+=M}const u=c<0?-1:1;vs.fill(0),oa.fill(0);for(let l=0;l<xr;l+=1)for(let h=0;h<3;h+=1){const f=i[l*3+h];vs[f]+=Gi[l]*u,oa[f]+=1}for(let l=0;l<Ia;l+=1){const h=oa[l]?vs[l]/oa[l]:0,{x:f,y:p}=e[l],m=Mn(0,o,f)*Mn(0,o,1-f)*Mn(0,o,p)*Mn(0,o,1-p);a[l]=Mn(ve.facingMin,ve.facingFull,h)*(Number.isFinite(m)?m:0)}},Du=()=>({rotation:new d.Matrix3,yawDeg:0,pitchDeg:0,faceHeightPx:0}),Gu=V.CANONICAL_RIGID_INDICES.length,ia=new Float64Array(Gu*3),$i={scale:1,quaternion:new d.Quaternion,translation:new d.Vector3,rms:0},$u=new d.Matrix4,Bi=180/Math.PI,hm=new d.Vector3(0,0,1),yn=new d.Vector3,Hi=new d.Quaternion,fm=(e,t=new d.Matrix3)=>{if(t.identity(),!e)return t;yn.set(-e.x,-e.y,-e.z);const n=yn.length();return!(n>1e-9)||!Number.isFinite(n)||yn.z<=0?t:(yn.divideScalar(n),Hi.setFromUnitVectors(hm,yn),t.setFromMatrix4($u.makeRotationFromQuaternion(Hi)))},pm=(e,t,n)=>t.isPerspectiveCamera?(n.set((e.x-.5)*2,(.5-e.y)*2,.5).applyMatrix4(t.projectionMatrixInverse),Number.isFinite(n.x)&&Number.isFinite(n.y)&&n.z<0?n:null):null,dm=(e,t,n,a=Du())=>{const s=t/Math.max(n,1);for(let h=0;h<Gu;h+=1){const f=e[V.CANONICAL_RIGID_INDICES[h]];ia[h*3]=f.x*s,ia[h*3+1]=-f.y,ia[h*3+2]=-(f.z??0)*s}iu.solveSimilarity(V.CANONICAL_RIGID_POINTS,ia,$i),a.rotation.setFromMatrix4($u.makeRotationFromQuaternion($i.quaternion));const r=a.rotation.elements,o=r[6],i=r[7],c=r[8];a.yawDeg=Math.atan2(o,c)*Bi,a.pitchDeg=Math.atan2(i,Math.hypot(o,c))*Bi;const u=e[10],l=e[152];return a.faceHeightPx=Math.hypot((l.x-u.x)*t,(l.y-u.y)*n),a},mm=e=>e.isRenderTargetTexture?!1:e.colorSpace===d.NoColorSpace?!0:d.ColorManagement.getTransfer(e.colorSpace)!==d.SRGBTransfer?!1:e.type!==d.UnsignedByteType,Ms=e=>Object.assign(e,{side:d.DoubleSide,depthTest:!1,depthWrite:!1,toneMapped:!1}),gm=e=>{var n;const t=(n=e.getContext)==null?void 0:n.call(e);typeof(t==null?void 0:t.PIXEL_PACK_BUFFER)=="number"&&t.bindBuffer(t.PIXEL_PACK_BUFFER,null)},zi=new d.Color,Sm=new d.Matrix3;class Bu{constructor(t={}){C(this,"mapTarget");C(this,"pendingMapTarget",null);C(this,"stats");C(this,"current",0);C(this,"formatResolved");C(this,"formatValue");C(this,"statsFormatValue");C(this,"size");C(this,"halfFloat");C(this,"mask");C(this,"camera",new d.OrthographicCamera(-1,1,1,-1,0,1));C(this,"unwrapScene",new d.Scene);C(this,"statsScene",new d.Scene);C(this,"unwrapGeometry",new d.BufferGeometry);C(this,"statsGeometry",new d.BufferGeometry);C(this,"unwrapMaterial");C(this,"statsMaterial");C(this,"pose",Du());C(this,"step",ki({dt:0,snap:!0,still:!1,halfFloat:!0,lightFit:!0}));C(this,"stepInput",{dt:0,snap:!0,still:!1,halfFloat:!0,lightFit:!0});C(this,"imageSize",{width:0,height:0});C(this,"gateInput",{presence:1,yawDeg:0,faceHeightPx:0});C(this,"unwrapImage",{aspect:1,flipY:!0});C(this,"readback",null);C(this,"readbackBytes",null);C(this,"pendingRead",null);C(this,"disposed",!1);C(this,"lastTexture",null);C(this,"pendingSnap",!0);C(this,"updates",0);C(this,"unwrapUniforms",{uSource:{value:null},uSkinMask:{value:null},uDecodeSrgb:{value:0},uSqrt:{value:0}});C(this,"statsUniforms",{uSkinMap:{value:null},uFeatureMap:{value:null},uPrevious:{value:null},uTopLevel:{value:7},uSkinLod:{value:Zt(128)},uSqrt:{value:0},uPacked:{value:0},uFastBlend:{value:1},uSlowBlend:{value:1},uLightBlend:{value:1},uReadyStep:{value:0},uSnap:{value:1},uLightFit:{value:1},uRotation:{value:new d.Matrix3}});C(this,"uniforms",{uSkinMap:{value:null},uSkinLod:{value:Zt(128)},uSkinSqrt:{value:0},uSkinStats:{value:null},uSkinStatsPacked:{value:0}});this.halfFloat=t.halfFloat??"auto",this.size=t.resolution===64?64:128,this.formatResolved=!!t.renderer,this.formatValue=Ni(this.halfFloat,t.renderer??null),this.statsFormatValue=Oi(this.formatValue,t.renderer??null),this.mapTarget=Es(this.size,this.formatValue),this.stats=[vn(this.statsFormatValue),vn(this.statsFormatValue)],this.mask=Ru({include:"skin",size:ve.maskSize,feather:ve.maskFeather}),this.unwrapUniforms.uSkinMask.value=this.mask;const n=T.FACE_ATLAS_SOURCE.vertexCount,a=new Float32Array(n*3);for(let i=0;i<n;i+=1)a[i*3]=T.FACE_ATLAS_UVS[i*2],a[i*3+1]=T.FACE_ATLAS_UVS[i*2+1];const s=i=>new d.BufferAttribute(new Float32Array(n*i),i).setUsage(d.DynamicDrawUsage);this.unwrapGeometry.setAttribute("position",new d.BufferAttribute(a,3)),this.unwrapGeometry.setAttribute("cameraUv",s(2)),this.unwrapGeometry.setAttribute("weight",s(1)),this.unwrapGeometry.setIndex(new d.BufferAttribute(T.getFaceAtlasRegionIndices("face"),1)),this.unwrapMaterial=Ms(new d.RawShaderMaterial({name:"FaceSkinProbe.unwrap",glslVersion:d.GLSL3,uniforms:this.unwrapUniforms,vertexShader:sm,fragmentShader:rm,blending:d.CustomBlending,blendEquation:d.AddEquation,blendSrc:d.ConstantAlphaFactor,blendDst:d.OneMinusConstantAlphaFactor,blendEquationAlpha:d.AddEquation,blendSrcAlpha:d.ConstantAlphaFactor,blendDstAlpha:d.OneMinusConstantAlphaFactor}));const r=new d.Mesh(this.unwrapGeometry,this.unwrapMaterial);r.frustumCulled=!1,this.unwrapScene.add(r),this.statsGeometry.setAttribute("position",new d.BufferAttribute(new Float32Array([-1,-1,0,3,-1,0,-1,3,0]),3)),this.statsMaterial=Ms(new d.RawShaderMaterial({name:"FaceSkinProbe.stats",glslVersion:d.GLSL3,uniforms:this.statsUniforms,vertexShader:Ui,fragmentShader:im(),blending:d.NoBlending}));const o=new d.Mesh(this.statsGeometry,this.statsMaterial);o.frustumCulled=!1,this.statsScene.add(o),this.syncUniforms()}get skinMap(){return this.mapTarget.textures[0]}get featureMap(){return this.mapTarget.textures[1]}get lightingMap(){return this.stats[this.current].texture}get format(){return this.formatValue}get statsFormat(){return this.statsFormatValue}get resolution(){return this.pendingMapTarget?this.pendingMapTarget.width:this.size}get updateCount(){return this.updates}get lastPose(){return this.pose}setResolution(t){var a;const n=t===64?64:128;n!==this.resolution&&((a=this.pendingMapTarget)==null||a.dispose(),this.pendingMapTarget=n===this.size?null:Es(n,this.formatValue))}reset(){this.pendingSnap=!0,this.updates=0}render(t,n,a,s={}){return this.update(t,n,a,s,!1)}renderStill(t,n,a,s={}){return this.update(t,n,a,{...s,gate:!1},!0)}update(t,n,a,s,r){if(!a||a.length<T.FACE_ATLAS_SOURCE.vertexCount)return"no-landmarks";this.resolveFormat(t);const{width:o,height:i}=this.readImageSize(n,s),c=o>0&&i>0?o/i:1;if(dm(a,o||1,i||1,this.pose),s.gate!==!1){const w=this.gateInput;w.presence=s.presence??1,w.yawDeg=this.pose.yawDeg,w.faceHeightPx=o>0&&i>0?this.pose.faceHeightPx:1/0;const k=Bd(w);if(k)return k}const u=r||this.pendingSnap||s.snap===!0||n!==this.lastTexture,l=this.pendingMapTarget;l&&(this.mapTarget.dispose(),this.mapTarget=l,this.pendingMapTarget=null,this.size=l.width);const h=this.formatValue==="half-float",f=this.stepInput;f.dt=s.dt??1/15,f.snap=u,f.still=r,f.halfFloat=h,f.lightFit=s.lightFit!==!1,ki(f,this.step);const p=u||l!==null;p&&(this.step.mapBlend=1);const m=this.unwrapGeometry.getAttribute("cameraUv"),E=this.unwrapGeometry.getAttribute("weight");this.unwrapImage.aspect=c,this.unwrapImage.flipY=lm(n),um(a,this.unwrapImage,m.array,E.array),m.needsUpdate=!0,E.needsUpdate=!0,this.unwrapUniforms.uSource.value=n,this.unwrapUniforms.uDecodeSrgb.value=mm(n)?1:0,this.unwrapUniforms.uSqrt.value=h?0:1,this.unwrapMaterial.blendAlpha=this.step.mapBlend;const S=this.statsUniforms,g=this.stats[this.current],A=this.stats[1-this.current],v=this.statsFormatValue==="packed"?1:0;S.uSkinMap.value=this.skinMap,S.uFeatureMap.value=this.featureMap,S.uPrevious.value=g.texture,S.uTopLevel.value=Math.round(Math.log2(this.size)),S.uSkinLod.value=Zt(this.size),S.uSqrt.value=h?0:1,S.uPacked.value=v,S.uFastBlend.value=this.step.fastBlend,S.uSlowBlend.value=this.step.slowBlend,S.uLightBlend.value=this.step.lightBlend,S.uReadyStep.value=this.step.readyStep,S.uSnap.value=this.step.snap?1:0,S.uLightFit.value=this.step.lightFit?1:0,S.uRotation.value.copy(this.pose.rotation).premultiply(fm(s.lineOfSight,Sm));const M=t.getRenderTarget();t.getClearColor(zi);const y=t.getClearAlpha(),x=t.xr.enabled,F=t.autoClear;return t.xr.enabled=!1,t.autoClear=!1,t.setRenderTarget(this.mapTarget),p&&(t.setClearColor(0,0),t.clear(!0,!1,!1)),t.render(this.unwrapScene,this.camera),t.setRenderTarget(A),t.render(this.statsScene,this.camera),t.setRenderTarget(M),t.setClearColor(zi,y),t.xr.enabled=x,t.autoClear=F,this.current=1-this.current,this.lastTexture=n,this.pendingSnap=!1,this.updates=u?1:this.updates+1,this.syncUniforms(),"updated"}readStats(t){const n=this.packStats(t),a=new Uint8Array(n.width*4);return t.readRenderTargetPixels(n,0,0,n.width,1,a),lo(Pi(a))}async readStatsAsync(t,n=new Float32Array(Pt*4)){if(this.disposed)return null;let a=this.pendingRead;if(!a){a=this.readStatsOnce(t),this.pendingRead=a;const r=a;r.then(()=>{this.pendingRead===r&&(this.pendingRead=null)},()=>{})}const s=await a;return!s||this.disposed?null:(n.set(s),n)}async readStatsOnce(t){const n=this.packStats(t);this.readbackBytes??(this.readbackBytes=new Uint8Array(n.width*4));const a=this.readbackBytes;try{const s=t.readRenderTargetPixelsAsync;if(typeof s=="function"){const r=s.call(t,n,0,0,n.width,1,a);gm(t),await r}else t.readRenderTargetPixels(n,0,0,n.width,1,a)}catch{return null}return this.disposed?null:Pi(a,"packed",new Float32Array(Pt*4))}packStats(t){this.readback??(this.readback=this.createReadback());const{target:n,scene:a,uniforms:s}=this.readback;s.uStats.value=this.lightingMap,s.uPacked.value=this.statsFormatValue==="packed"?1:0;const r=t.getRenderTarget(),o=t.xr.enabled,i=t.autoClear;return t.xr.enabled=!1,t.autoClear=!1,t.setRenderTarget(n),t.render(a,this.camera),t.setRenderTarget(r),t.xr.enabled=o,t.autoClear=i,n}dispose(){var t;this.disposed=!0,this.mapTarget.dispose(),(t=this.pendingMapTarget)==null||t.dispose(),this.pendingMapTarget=null,this.stats[0].dispose(),this.stats[1].dispose(),this.mask.dispose(),this.unwrapGeometry.dispose(),this.statsGeometry.dispose(),this.unwrapMaterial.dispose(),this.statsMaterial.dispose(),this.readback&&(this.readback.target.dispose(),this.readback.material.dispose(),this.readback=null)}readImageSize(t,n){const a=t.image;return this.imageSize.width=n.width??((a==null?void 0:a.videoWidth)||(a==null?void 0:a.width)||0),this.imageSize.height=n.height??((a==null?void 0:a.videoHeight)||(a==null?void 0:a.height)||0),this.imageSize}createReadback(){const t=vn("packed"),n={uStats:{value:null},uPacked:{value:0}},a=Ms(new d.RawShaderMaterial({name:"FaceSkinProbe.readback",glslVersion:d.GLSL3,uniforms:n,vertexShader:Ui,fragmentShader:cm,blending:d.NoBlending})),s=new d.Mesh(this.statsGeometry,a);s.frustumCulled=!1;const r=new d.Scene;return r.add(s),{target:t,scene:r,material:a,uniforms:n}}resolveFormat(t){var s;if(this.formatResolved)return;this.formatResolved=!0;const n=Ni(this.halfFloat,t),a=Oi(n,t);if(!(n===this.formatValue&&a===this.statsFormatValue)){if(n!==this.formatValue){this.formatValue=n;const r=this.resolution;this.mapTarget.dispose(),(s=this.pendingMapTarget)==null||s.dispose(),this.pendingMapTarget=null,this.mapTarget=Es(r,n),this.size=r}a!==this.statsFormatValue&&(this.statsFormatValue=a,this.stats[0].dispose(),this.stats[1].dispose(),this.stats=[vn(a),vn(a)],this.current=0),this.reset(),this.syncUniforms()}}syncUniforms(){const t=this.uniforms;t.uSkinMap.value=this.skinMap,t.uSkinLod.value=Zt(this.size),t.uSkinSqrt.value=this.formatValue==="half-float"?0:1,t.uSkinStats.value=this.lightingMap,t.uSkinStatsPacked.value=this.statsFormatValue==="packed"?1:0}}const Em=()=>({lastLandmarks:null,lastUpdateMs:-1/0,lastSeenMs:-1/0,pendingSnap:!1}),Am=(e,t,n={run:!1,snap:!1,dt:0})=>{if(n.run=!1,n.snap=!1,n.dt=0,!t.landmarks||(Number.isFinite(e.lastSeenMs)&&t.nowMs-e.lastSeenMs>ve.reacquireSnapMs&&(e.pendingSnap=!0),e.lastSeenMs=t.nowMs,t.landmarks===e.lastLandmarks))return n;const a=t.hz>0?1e3/t.hz:0;return t.nowMs-e.lastUpdateMs<a-1||(n.run=!0,n.snap=e.pendingSnap,n.dt=Number.isFinite(e.lastUpdateMs)?(t.nowMs-e.lastUpdateMs)/1e3:0),n},vm=(e,t)=>{e.lastLandmarks=t.landmarks,t.updated&&(e.lastUpdateMs=t.nowMs,e.pendingSnap=!1)},Na=new WeakMap,Mm=(e,t)=>{let n=Na.get(e);n||(n=new Map,Na.set(e,n));let a=n.get(t);return a||(a={probe:new Bu({renderer:e}),refs:0,stamp:Number.NaN,schedule:Em(),qualities:new Map,best:"high",ready:!1,listeners:new Set},n.set(t,a)),a.refs+=1,a},ym=(e,t)=>{var n,a;return((a=(n=Na.get(e))==null?void 0:n.get(t))==null?void 0:a.probe)??null},wm=(e,t,n)=>{if(n.refs-=1,n.refs>0)return;n.probe.dispose();const a=Na.get(e);(a==null?void 0:a.get(t))===n&&a.delete(t)},ys=(e,t,n)=>{if(n===null){if(!e.qualities.delete(t))return}else{if(e.qualities.get(t)===n)return;e.qualities.set(t,n)}e.best=$d(e.qualities.values())},ca={run:!1,snap:!1,dt:0},wn={nowMs:0,landmarks:null,hz:0},_n={nowMs:0,landmarks:null,updated:!1},_m=new d.Vector3,Fn={dt:0,snap:!1,lightFit:!0},Va=(e={})=>{const t=Te.useTrackerContext(),n=e.faceIndex??((t==null?void 0:t.type)==="face"?t.faceIndex:void 0)??0,a=e.enabled!==!1,s=e.quality??"auto",r=J.useThree(v=>v.gl),o=ee.useOptionalXRContext(),i=ae.useXRModelNode(ee.XRModel.FACE_TRACKER),c=ae.useXRCameraTexture(),[u,l]=_.useState(null),[h,f]=_.useState(!1),p=_.useMemo(()=>({}),[]),m=_.useMemo(()=>({uSkinMap:{value:null},uSkinLod:{value:Zt(128)},uSkinSqrt:{value:0},uSkinStats:{value:null},uSkinStatsPacked:{value:0}}),[]),E=_.useRef({quality:s,xr:o});E.current.quality=s,E.current.xr=o;const S=()=>{var M,y,x;const v=(M=E.current.xr)==null?void 0:M.session.store.getSnapshot();return Gd(E.current.quality,((y=v==null?void 0:v.quality)==null?void 0:y.index)??-1,((x=v==null?void 0:v.qualityConfig)==null?void 0:x.tiers.length)??0).key},g=_.useRef(S);g.current=S,_.useEffect(()=>{if(!a)return;const v=Mm(r,n);ys(v,p,g.current());const M=y=>f(y);return v.listeners.add(M),l(v),f(v.ready),()=>{v.listeners.delete(M),ys(v,p,null),wm(r,n,v),l(null),f(!1)}},[r,n,a,p]),J.useFrame(v=>{var y,x;if(!u)return;const{probe:M}=u;if(ys(u,p,S()),u.stamp!==v.clock.elapsedTime){u.stamp=v.clock.elapsedTime;const F=bt[u.best];M.setResolution(F.size);const w=((x=(y=i==null?void 0:i.detectionResults)==null?void 0:y.faceLandmarks)==null?void 0:x[n])??null,k=performance.now();if(wn.nowMs=k,wn.landmarks=w,wn.hz=F.hz,Am(u.schedule,wn,ca),wn.landmarks=null,ca.run&&w&&c){Fn.dt=ca.dt,Fn.snap=ca.snap,Fn.lightFit=F.lightFit,Fn.lineOfSight=(w[1]&&pm(w[1],v.camera,_m))??void 0;const R=M.render(r,c,w,Fn);_n.nowMs=k,_n.landmarks=w,_n.updated=R==="updated",vm(u.schedule,_n),_n.landmarks=null;const b=M.updateCount>0;b!==u.ready&&(u.ready=b,u.listeners.forEach(N=>N(b)))}}m.uSkinMap.value=M.uniforms.uSkinMap.value,m.uSkinLod.value=M.uniforms.uSkinLod.value,m.uSkinSqrt.value=M.uniforms.uSkinSqrt.value,m.uSkinStats.value=M.uniforms.uSkinStats.value,m.uSkinStatsPacked.value=M.uniforms.uSkinStatsPacked.value},-.5);const A=(u==null?void 0:u.probe)??null;return _.useMemo(()=>({probe:A,get skinMap(){return(A==null?void 0:A.skinMap)??null},get featureMap(){return(A==null?void 0:A.featureMap)??null},get lightingMap(){return(A==null?void 0:A.lightingMap)??null},uniforms:m,ready:h,format:(A==null?void 0:A.format)??null,faceIndex:n}),[A,m,h,n])},fo=(e={})=>{const{faceIndex:t,numFaces:n,leadMs:a,holdMs:s}=typeof e=="number"?{faceIndex:e}:e,r=ge(),o=le.useFaceSurface(),i=Te.useTrackerContext(),c=J.useThree(w=>w.scene),u=T.resolveFaceAtlasBinding({faceIndex:t,numFaces:n,rigFaceIndex:r?r.current.faceIndex:null,trackerFaceIndex:(i==null?void 0:i.type)==="face"?i.faceIndex??0:null}),{borrow:l,faceIndex:h}=u;dn(u.acquire,u.numFaces);const f=ae.useXRModelNode(ee.XRModel.FACE_TRACKER);Cu(f,h,"useFaceAtlasSurface (makeup and face-atlas layers)");const p=ae.useXRCameraTexture(),{index:m,tiers:E}=Pn.useXRQuality(),S=xu(m,E.length),[g,A]=_.useState(null),v=l?r:null,M=l?o:null;_.useEffect(()=>{const w=T.getFaceAtlasRegistry(c),k=v?{kind:"borrowed",rig:v,offsets:M}:{kind:"owned",faceIndex:h},R=w.get(k);return w.retain(R,c),A(R),()=>{w.release(R),A(b=>b===R?null:b)}},[c,v,M,h]);const y=_.useRef({node:f,cameraTexture:null,quality:S});y.current.node=f,y.current.cameraTexture=p??null,y.current.quality=S;const x=_.useRef({});x.current.leadMs=a??yi[S].leadCapMs,_.useEffect(()=>g&&s!==void 0?g.requestHold(s):void 0,[g,s]);const F=_.useRef({stamp:0,nowMs:0,cameraTexture:null,selfOcclusion:!1,camera:void 0});return J.useFrame(w=>{g!=null&&g.owned&&g.stepRig(w.clock.elapsedTime,y.current.node,w.camera,performance.now(),x.current,y.current.cameraTexture)},Rd),J.useFrame(w=>{var R;if(!g)return;const k=F.current;k.stamp=w.clock.elapsedTime,k.nowMs=performance.now(),k.cameraTexture=y.current.cameraTexture,k.selfOcclusion=yi[y.current.quality].selfOcclusion,k.camera=w.camera,g.update(k)&&g.updateSkin(((R=ym(w.gl,g.faceIndex))==null?void 0:R.uniforms)??null)},bd),_.useMemo(()=>g?{surface:g.surface,geometry:g.surface.geometry,group:g.group,rig:g.rig,uniforms:g.uniforms,faceIndex:h,owned:g.owned,quality:S,requestSelfOcclusion:()=>g.requestSelfOcclusion()}:null,[g,h,S])},Hu=({handle:e,region:t="face",triangles:n,attributes:a,material:s,renderOrder:r=de.MAKEUP_RENDER_ORDER.design,mirrored:o,selfOcclusion:i,faceUv:c=!1,visible:u=!0})=>{const{surface:l,requestSelfOcclusion:h}=e,f=typeof t=="string"?t:t.join(","),p=_.useMemo(()=>n?[]:f.split(","),[f,n]),[m,E]=_.useState(null),S=_.useRef(null);_.useEffect(()=>{if(l.disposed)return;const w=n?{triangles:n}:p,k=l.createGeometry(w,a);return S.current&&(S.current.geometry=k),E(k),()=>{l.releaseGeometry(k),E(R=>R===k?null:R)}},[l,p,n,a]);const g=i??de.faceAtlasLayerSelfOccludes(r,u);_.useEffect(()=>g?h():void 0,[h,g]),_.useEffect(()=>c?l.requestFaceUv():void 0,[l,c]);const A=ae.useXRMirrored(),v=ee.personLeftSign(o??A),M=_.useMemo(()=>({...e.uniforms,uPersonLeftSign:{value:1}}),[e.uniforms]);M.uPersonLeftSign.value=v;const y=ae.useXRCameraTexture()??null,x=_.useMemo(()=>m?typeof s!="function"?s:s({uniforms:M,cameraTexture:y,personLeftSign:v,faceIndex:e.faceIndex,regions:p,geometry:m}):null,[s,M,y,v,e.faceIndex,p,m]);if(!m)return null;const F=x instanceof d.Material?x:null;return J.createPortal(L.jsx("mesh",{ref:S,geometry:m,...F?{material:F}:{},renderOrder:r,frustumCulled:!1,visible:u,children:F?null:x},F?"instance":"node"),e.group)},Cr=({faceIndex:e,numFaces:t,leadMs:n,holdMs:a,...s})=>{const r=fo({faceIndex:e,numFaces:t,leadMs:n,holdMs:a});return r?L.jsx(Hu,{handle:r,...s}):null},Wa=de.MAKEUP_RENDER_ORDER.lips,Fm=.001,xm={...O.DEFAULT_LIP_EFFECT_SETTINGS,renderOrder:Wa},po=`
|
|
504
|
+
varying vec3 vMakeupCamera;
|
|
505
|
+
varying vec2 vMakeupUv;
|
|
506
|
+
varying vec3 vMakeupRest;
|
|
507
|
+
varying vec3 vMakeupNormal;
|
|
508
|
+
varying vec3 vMakeupFlakeNormal;
|
|
509
|
+
varying vec3 vMakeupViewPosition;
|
|
510
|
+
varying float vMakeupEdge;
|
|
511
|
+
varying float vMakeupLipEdge;
|
|
512
|
+
varying float vMakeupEyeRing;
|
|
513
|
+
flat varying vec3 vMakeupSkinSlow;
|
|
514
|
+
flat varying vec3 vMakeupSkinFast;
|
|
515
|
+
flat varying float vMakeupSkinReady;
|
|
516
|
+
flat varying vec4 vMakeupLight;
|
|
517
|
+
flat varying vec3 vMakeupLipColor;
|
|
518
|
+
flat varying vec3 vMakeupBrowColor;
|
|
519
|
+
flat varying vec3 vMakeupHeadUp;
|
|
520
|
+
`,ke=nt,Cm=`
|
|
521
|
+
#define MAKEUP_FINISH_MATTE ${Ze.matte}
|
|
522
|
+
#define MAKEUP_FINISH_SATIN ${Ze.satin}
|
|
523
|
+
#define MAKEUP_FINISH_GLOSS ${Ze.gloss}
|
|
524
|
+
#define MAKEUP_FINISH_SHIMMER ${Ze.shimmer}
|
|
525
|
+
#define MAKEUP_FINISH_METALLIC ${Ze.metallic}
|
|
526
|
+
#define MAKEUP_FINISH_GLITTER ${Ze.glitter}
|
|
527
|
+
#define MAKEUP_AUTO_NONE ${Re.none}
|
|
528
|
+
#define MAKEUP_AUTO_LIPS ${Re.lips}
|
|
529
|
+
#define MAKEUP_AUTO_BLUSH ${Re.blush}
|
|
530
|
+
#define MAKEUP_AUTO_CONTOUR ${Re.contour}
|
|
531
|
+
#define MAKEUP_AUTO_HIGHLIGHTER ${Re.highlighter}
|
|
532
|
+
#define MAKEUP_AUTO_BROWS ${Re.brows}
|
|
533
|
+
#define MAKEUP_PI 3.141592653589793
|
|
534
|
+
#define MAKEUP_EPSILON ${I(ke.epsilon)}
|
|
535
|
+
|
|
536
|
+
#ifndef gl_FragColor
|
|
537
|
+
layout(location = 0) out highp vec4 pc_fragColor;
|
|
538
|
+
#define gl_FragColor pc_fragColor
|
|
539
|
+
#endif
|
|
540
|
+
${po}
|
|
541
|
+
uniform sampler2D uCameraMap;
|
|
542
|
+
uniform sampler2D uSkinMap;
|
|
543
|
+
uniform float uSkinLod;
|
|
544
|
+
uniform float uSkinSqrt;
|
|
545
|
+
uniform vec3 uColor;
|
|
546
|
+
uniform int uAutoShade;
|
|
547
|
+
uniform float uOpacity;
|
|
548
|
+
uniform float uCoverage;
|
|
549
|
+
uniform int uFinish;
|
|
550
|
+
uniform float uShine;
|
|
551
|
+
uniform vec3 uSparkleColor;
|
|
552
|
+
uniform float uSparkleAuto;
|
|
553
|
+
uniform float uSparkleDensity;
|
|
554
|
+
uniform float uSparkleSize;
|
|
555
|
+
uniform float uSparkleQuality;
|
|
556
|
+
uniform vec2 uSide;
|
|
557
|
+
uniform float uPersonLeftSign;
|
|
558
|
+
uniform float uPresence;
|
|
559
|
+
|
|
560
|
+
float makeupLuma(vec3 c) {
|
|
561
|
+
return dot(c, ${ln(co)});
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
// Linear -> the output colour space (sRGB on the canvas, linear into a linear target).
|
|
565
|
+
vec3 makeupEncode(vec3 c) {
|
|
566
|
+
return linearToOutputTexel(vec4(max(c, vec3(0.0)), 1.0)).rgb;
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
// A skin-map texel or mip: rgb / a, squared on the RGBA8 fallback (rgb = w * sqrt(c)).
|
|
570
|
+
vec3 makeupSkinDecode(vec4 texel) {
|
|
571
|
+
vec3 c = texel.rgb / max(texel.a, MAKEUP_EPSILON);
|
|
572
|
+
return uSkinSqrt > 0.5 ? c * c : c;
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
float makeupSkinWeight(float a) {
|
|
576
|
+
return smoothstep(${I(ke.lowpassMinWeight)}, ${I(ke.lowpassFullWeight)}, a);
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
// The fitted light, blended to the key light as the fit's confidence drops.
|
|
580
|
+
vec3 makeupLightDirection(vec4 fit) {
|
|
581
|
+
vec3 key = ${ln(ke.keyLight)};
|
|
582
|
+
float len = length(fit.xyz);
|
|
583
|
+
float w = smoothstep(${I(ke.lightConfidenceMin-ke.lightConfidenceBlend)}, ${I(ke.lightConfidenceMin+ke.lightConfidenceBlend)}, fit.w)
|
|
584
|
+
* step(MAKEUP_EPSILON, len);
|
|
585
|
+
vec3 fitted = len > MAKEUP_EPSILON ? fit.xyz / len : key;
|
|
586
|
+
vec3 d = mix(key, fitted, w);
|
|
587
|
+
return dot(d, d) > 1e-6 ? normalize(d) : key;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
struct MakeupSample {
|
|
591
|
+
vec3 camera; // C: the linear camera at the un-warped point
|
|
592
|
+
vec3 skinSlow; // Rs: the person's skin under the settled light (C until ready)
|
|
593
|
+
vec3 skinFast; // Rf: the skin under the current light (C until ready)
|
|
594
|
+
vec3 skinLocal; // L: the local low-pass skin; a coarser mip, then Rf, where it has no skin (C until ready)
|
|
595
|
+
vec3 lip; // the person's own lip colour (uColor until ready)
|
|
596
|
+
vec3 brow; // the person's own brow-hair colour (uColor until ready)
|
|
597
|
+
float ready; // 0..1
|
|
598
|
+
vec3 rest; // rest position, canonical cm
|
|
599
|
+
vec3 facet; // unit normal of the rest-space facet under the pixel
|
|
600
|
+
float pixelCm; // pixel footprint on the surface, canonical cm
|
|
601
|
+
vec2 uv; // face-atlas uv
|
|
602
|
+
vec3 normal; // live metric normal, view space, unit
|
|
603
|
+
vec3 flakeNormal; // rest normal x pose, view space, unit
|
|
604
|
+
vec3 headUp; // the head's +Y, view space, unit
|
|
605
|
+
vec3 viewDir; // surface -> eye, view space, unit
|
|
606
|
+
vec3 light; // light direction, view space, unit
|
|
607
|
+
float lightConfidence;
|
|
608
|
+
float personLeft; // 1 on the person's own left, 0 on their right
|
|
609
|
+
float side; // uSide weight
|
|
610
|
+
float facing; // facing fade
|
|
611
|
+
float fade; // side x edge x facing x presence
|
|
612
|
+
};
|
|
613
|
+
|
|
614
|
+
// Everything but the colours: derivatives (so call it first, in uniform control flow), the rest
|
|
615
|
+
// point, normals, light, sides and fades. No texture reads.
|
|
616
|
+
MakeupSample makeupSampleGeometry() {
|
|
617
|
+
MakeupSample s;
|
|
618
|
+
vec3 dx = dFdx(vMakeupRest);
|
|
619
|
+
vec3 dy = dFdy(vMakeupRest);
|
|
620
|
+
vec3 facet = cross(dx, dy);
|
|
621
|
+
s.facet = facet / max(length(facet), 1e-12);
|
|
622
|
+
s.pixelCm = max(length(dx), length(dy));
|
|
623
|
+
|
|
624
|
+
s.camera = vec3(0.0);
|
|
625
|
+
s.skinSlow = vec3(0.0);
|
|
626
|
+
s.skinFast = vec3(0.0);
|
|
627
|
+
s.skinLocal = vec3(0.0);
|
|
628
|
+
s.lip = uColor;
|
|
629
|
+
s.brow = uColor;
|
|
630
|
+
s.ready = 0.0;
|
|
631
|
+
|
|
632
|
+
s.rest = vMakeupRest;
|
|
633
|
+
s.uv = vMakeupUv;
|
|
634
|
+
s.normal = normalize(vMakeupNormal);
|
|
635
|
+
s.flakeNormal = normalize(vMakeupFlakeNormal);
|
|
636
|
+
s.headUp = normalize(vMakeupHeadUp);
|
|
637
|
+
s.viewDir = normalize(-vMakeupViewPosition);
|
|
638
|
+
s.light = makeupLightDirection(vMakeupLight);
|
|
639
|
+
s.lightConfidence = vMakeupLight.w;
|
|
640
|
+
|
|
641
|
+
s.personLeft = smoothstep(${I(-ke.sideBlendCm)}, ${I(ke.sideBlendCm)}, vMakeupRest.x * uPersonLeftSign);
|
|
642
|
+
s.side = mix(uSide.y, uSide.x, s.personLeft);
|
|
643
|
+
s.facing = smoothstep(${I(ke.facingMin)}, ${I(ke.facingFull)}, dot(s.normal, s.viewDir));
|
|
644
|
+
s.fade = s.side * smoothstep(0.0, ${I(ke.edgeFadeCm)}, vMakeupEdge) * s.facing * clamp(uPresence, 0.0, 1.0);
|
|
645
|
+
return s;
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
// The colours: the camera and the skin references. Every read has an explicit LOD (the camera has
|
|
649
|
+
// no mips), so this may follow a discard.
|
|
650
|
+
void makeupSampleColor(inout MakeupSample s) {
|
|
651
|
+
vec2 cameraUv = vMakeupCamera.xy / vMakeupCamera.z * 0.5 + 0.5;
|
|
652
|
+
s.camera = textureLod(uCameraMap, cameraUv, 0.0).rgb;
|
|
653
|
+
float ready = clamp(vMakeupSkinReady, 0.0, 1.0) * step(MAKEUP_EPSILON, makeupLuma(vMakeupSkinSlow));
|
|
654
|
+
vec4 lowpass = textureLod(uSkinMap, vMakeupUv, uSkinLod);
|
|
655
|
+
float fine = makeupSkinWeight(lowpass.a);
|
|
656
|
+
vec3 local = vMakeupSkinFast;
|
|
657
|
+
if (fine < 1.0) {
|
|
658
|
+
// No skin in the low-pass here (lips, eyes, brows): a coarser mip keeps the large-scale light.
|
|
659
|
+
vec4 coarse = textureLod(uSkinMap, vMakeupUv, uSkinLod + ${I(ke.lowpassCoarseLods)});
|
|
660
|
+
local = mix(vMakeupSkinFast, makeupSkinDecode(coarse), makeupSkinWeight(coarse.a));
|
|
661
|
+
}
|
|
662
|
+
local = mix(local, makeupSkinDecode(lowpass), fine);
|
|
663
|
+
s.skinSlow = mix(s.camera, vMakeupSkinSlow, ready);
|
|
664
|
+
s.skinFast = mix(s.camera, vMakeupSkinFast, ready);
|
|
665
|
+
s.skinLocal = mix(s.camera, local, ready);
|
|
666
|
+
s.lip = mix(uColor, vMakeupLipColor, ready);
|
|
667
|
+
s.brow = mix(uColor, vMakeupBrowColor, ready);
|
|
668
|
+
s.ready = ready;
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
// The whole sample: geometry, then colours.
|
|
672
|
+
MakeupSample makeupSample() {
|
|
673
|
+
MakeupSample s = makeupSampleGeometry();
|
|
674
|
+
makeupSampleColor(s);
|
|
675
|
+
return s;
|
|
676
|
+
}
|
|
677
|
+
`,Tm=Object.freeze({width:re.texels,skinSlow:re.skinSlow,skinFast:re.skinFast,light:re.light,lip:re.lip,brow:re.brow}),zu=`
|
|
678
|
+
attribute vec3 basePosition;
|
|
679
|
+
attribute vec3 restPosition;
|
|
680
|
+
attribute vec3 restNormal;
|
|
681
|
+
attribute float edge;
|
|
682
|
+
attribute float lipEdge;
|
|
683
|
+
attribute float eyeRing;
|
|
684
|
+
`,km=Tm,Lm=`
|
|
685
|
+
${zu}
|
|
686
|
+
${po}
|
|
687
|
+
${Uu}
|
|
688
|
+
|
|
689
|
+
void main() {
|
|
690
|
+
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
|
|
691
|
+
vec4 viewPosition = modelViewMatrix * vec4(position, 1.0);
|
|
692
|
+
vec4 base = projectionMatrix * modelViewMatrix * vec4(basePosition, 1.0);
|
|
693
|
+
vMakeupCamera = base.xyw;
|
|
694
|
+
vMakeupUv = uv;
|
|
695
|
+
vMakeupRest = restPosition;
|
|
696
|
+
vMakeupNormal = normalMatrix * normal;
|
|
697
|
+
vMakeupFlakeNormal = normalMatrix * restNormal;
|
|
698
|
+
vMakeupViewPosition = viewPosition.xyz;
|
|
699
|
+
vMakeupEdge = edge;
|
|
700
|
+
vMakeupLipEdge = lipEdge;
|
|
701
|
+
vMakeupEyeRing = eyeRing;
|
|
702
|
+
vMakeupHeadUp = normalMatrix * vec3(0.0, 1.0, 0.0);
|
|
703
|
+
|
|
704
|
+
if (textureSize(uSkinStats, 0).x >= ${km.width}) {
|
|
705
|
+
makeupWriteSkinStats();
|
|
706
|
+
} else {
|
|
707
|
+
vMakeupSkinSlow = vec3(0.0);
|
|
708
|
+
vMakeupSkinReady = 0.0;
|
|
709
|
+
vMakeupSkinFast = vec3(0.0);
|
|
710
|
+
vMakeupLight = vec4(0.0);
|
|
711
|
+
vMakeupLipColor = vec3(0.0);
|
|
712
|
+
vMakeupBrowColor = vec3(0.0);
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
`,Rm=`
|
|
716
|
+
uniform sampler2D uDesignMap;
|
|
717
|
+
uniform float uDesignSrgb;
|
|
718
|
+
uniform float uDesignPremultiplied;
|
|
719
|
+
|
|
720
|
+
// The art's uv on this feed: (1 - u, v) on a mirrored feed (uPersonLeftSign < 0).
|
|
721
|
+
vec2 makeupDesignUv(vec2 uv) {
|
|
722
|
+
return vec2(uPersonLeftSign < 0.0 ? 1.0 - uv.x : uv.x, uv.y);
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
vec3 makeupDesignDecode(vec3 c) {
|
|
726
|
+
vec3 low = c / 12.92;
|
|
727
|
+
vec3 high = pow((c + 0.055) / 1.055, vec3(2.4));
|
|
728
|
+
return mix(low, high, step(vec3(0.04045), c));
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
// The art at an atlas uv: linear rgb, straight alpha. Implicit derivatives: call before any discard.
|
|
732
|
+
vec4 makeupDesignSample(vec2 uv) {
|
|
733
|
+
vec4 texel = texture(uDesignMap, makeupDesignUv(uv));
|
|
734
|
+
float a = clamp(texel.a, 0.0, 1.0);
|
|
735
|
+
vec3 c = uDesignPremultiplied > 0.5 ? texel.rgb / max(a, 1e-4) : texel.rgb;
|
|
736
|
+
c = clamp(c, 0.0, 1.0);
|
|
737
|
+
return vec4(uDesignSrgb > 0.5 ? makeupDesignDecode(c) : c, a);
|
|
738
|
+
}
|
|
739
|
+
`,Ku=()=>({uDesignMap:{value:null},uDesignSrgb:{value:0},uDesignPremultiplied:{value:0}}),ht=8,bm=.05,Im=()=>({count:0,start:new Float32Array(ht*4),end:new Float32Array(ht*4),weight:new Float32Array(ht)}),Nm=(e,t=Im())=>{if(e.length>ht)throw new Error(`a makeup shape has at most ${ht} capsules`);return t.start.fill(0),t.end.fill(0),t.weight.fill(0),e.forEach(({a:n,b:a,ra:s,rb:r,weight:o},i)=>{t.start.set([n[0],n[1],n[2],s],i*4),t.end.set([a[0],a[1],a[2],r],i*4),t.weight[i]=o}),t.count=e.length,t},Om=(e,t,n,a,s,r=[0,0])=>{const o=n[0]-t[0],i=n[1]-t[1],c=n[2]-t[2],u=e[0]-t[0],l=e[1]-t[1],h=e[2]-t[2],f=Math.min(1,Math.max(0,(u*o+l*i+h*c)/Math.max(o*o+i*i+c*c,1e-6)));return r[0]=Math.hypot(u-o*f,l-i*f,h-c*f),r[1]=a+(s-a)*f,r},Tr=T.FACE_ATLAS_SOURCE.vertexCount,Pm=T.FACE_ATLAS_SOURCE.triangleCount,Um=(e,t,n=[0,0,0])=>{const a=V.CANONICAL_FACE_POSITIONS;let s=-1/0;for(let r=0;r<Pm;r+=1){const o=T.FACE_ATLAS_TRIANGLES[r*3]*3,i=T.FACE_ATLAS_TRIANGLES[r*3+1]*3,c=T.FACE_ATLAS_TRIANGLES[r*3+2]*3,u=a[o],l=a[o+1],h=a[i]-u,f=a[i+1]-l,p=a[c]-u,m=a[c+1]-l,E=h*m-p*f;if(Math.abs(E)<1e-9)continue;const S=e-u,g=t-l,A=(S*m-p*g)/E,v=(h*g-S*f)/E;if(A<-1e-6||v<-1e-6||A+v>1+1e-6)continue;const y=a[o+2]+A*(a[i+2]-a[o+2])+v*(a[c+2]-a[o+2]);y>s&&(s=y)}if(s===-1/0){let r=1/0;for(let o=0;o<Tr;o+=1){const i=(a[o*3]-e)**2+(a[o*3+1]-t)**2;i<r&&(r=i,s=a[o*3+2])}}return n[0]=e,n[1]=t,n[2]=s,n},Dm=(e,t)=>{const n=new Uint8Array(Tr);for(let s=0;s<Tr;s+=1)n[s]=t(s)?1:0;const a=[];for(let s=0;s<e.length;s+=1){const r=e[s];(n[T.FACE_ATLAS_TRIANGLES[r*3]]||n[T.FACE_ATLAS_TRIANGLES[r*3+1]]||n[T.FACE_ATLAS_TRIANGLES[r*3+2]])&&a.push(r)}return Uint16Array.from(a).sort()},Gm=e=>e==="left"?[1,0]:e==="right"?[0,1]:[1,1],Ki=Object.freeze({negX:"eyeBlinkRight",posX:"eyeBlinkLeft"}),la={keep:.6,width:[.12,.3],fade:[.15,.6]},$m=({keep:e,width:t,fade:n})=>e*(t[0]+t[1])*(n[0]/2+(n[1]-n[0])+(1-n[1])/2),pt=Object.freeze({gateCm:.02,blinkFade:[.35,.75],antialiasPx:1.5,liner:Object.freeze({taperStart:.15,lowerWidth:.6,lowerReach:[.3,.75],lowerReachSoftness:.2,lowerFadeIn:.3,softnessScale:.5,smudgeSoftness:.8,wingTip:.15,wingTipMinCm:.02,wingBelow:.06}),shadow:Object.freeze({minGap:.3,edge:[.06,.3],sharpEdgeCm:.02,top:[.9,1.02],outerReach:[.35,.4],innerReach:.35,outerSlope:.3,innerSlope:.8,creaseCentre:[.2,.9],creaseWidth:[.12,.18],outerBias:.7,lowerWidth:[.15,.35],innerRadius:.45,haloRadius:.45,haloLift:.3,wingLength:1.3,wingAngle:25,wingRadius:[.45,.08]}),brow:Object.freeze({tailTaper:.75,strokeSpacing:.055,strokeLength:.6,strokeKeep:la.keep,strokeWidth:la.width,strokeFade:la.fade,strokeJitter:.4,strokeReach:1.15,strokeMean:$m(la),strokeResolvePx:[1.5,3],strokeAngle:[25,75],strokeHeadBlend:[.7,.95],hairGain:[1.8,3.2],boldnessWidth:[.6,1,1.45]})}),ji=Object.freeze({offset:4096,salt:7919}),ju=5,Bn=ju-1,Bm=[33,246,161,160,159,158,157,173,133],Hm=[33,7,163,144,145,153,154,155,133],zm=[70,63,105,66,107],Vi=[46,53,52,65,55],It=e=>[V.CANONICAL_FACE_POSITIONS[e*3],V.CANONICAL_FACE_POSITIONS[e*3+1]],ws=e=>{const t=new Float32Array((e.length-1)*4);for(let n=1;n<e.length;n+=1)t.set([...It(e[n-1]),...It(e[n])],(n-1)*4);return t},Km=(e,t)=>{const n=Math.hypot(e,t)||1;return[e/n,t/n]},Vu=(e,t)=>{const n=Math.atan2(e[1],e[0])-t*Math.PI/180;return[Math.cos(n),Math.sin(n)]};let ua=null;const Qn=()=>{if(ua)return ua;const e=It(33),t=It(133),n=Math.hypot(e[0]-t[0],e[1]-t[1]),a=Km(e[0]-t[0],e[1]-t[1]),s=[-a[1],a[0]],r=s[1]>=0?s:[a[1],-a[0]],o=[(e[0]+t[0])/2,(e[1]+t[1])/2],i=It(159),c=pt.shadow,u=Vu(a,c.wingAngle),l=zm.map((h,f)=>{const p=It(h),m=It(Vi[f]);return[(p[0]+m[0])/2,(p[1]+m[1])/2,Math.hypot(p[0]-m[0],p[1]-m[1])/2]});return ua={lines:{upper:ws(Bm),lower:ws(Hm),browLower:ws(Vi)},outer:e,inner:t,middle:o,axis:a,axisLength:n,up:r,lidCentre:[i[0]+r[0]*c.haloLift,i[1]+r[1]*c.haloLift],shadowWing:[e,[e[0]+u[0]*c.wingLength,e[1]+u[1]*c.wingLength]],brow:l},ua},jm=e=>Math.min(1,Math.max(0,e)),Vm=(e,t,n)=>e+(t-e)*n,Wm=(e,t,n,a=[0,0])=>{const s=e.length/4;let r=1/0,o=0;for(let i=0;i<s;i+=1){const c=e[i*4],u=e[i*4+1],l=e[i*4+2]-c,h=e[i*4+3]-u,f=jm(((t-c)*l+(n-u)*h)/Math.max(l*l+h*h,1e-8)),p=Math.hypot(t-c-l*f,n-u-h*f);p<r&&(r=p,o=(i+f)/s)}return a[0]=r,a[1]=o,a},Wi=(e,t)=>{let n=0,a=1/0;for(let s=0;s<e.length;s+=4){const r=e[s],o=e[s+2],i=Math.min(Math.max(t,r),o),c=Math.abs(t-i);c<a&&(a=c,n=Vm(e[s+1],e[s+3],(i-r)/Math.max(o-r,1e-6)))}return n},qi=Object.freeze({negX:T.FACE_MORPH_NAMES.indexOf(Ki.negX),posX:T.FACE_MORPH_NAMES.indexOf(Ki.posX)}),Je=pt,Be=Je.liner,he=Je.shadow,ye=Je.brow,mt=e=>`vec2(${I(e[0])}, ${I(e[1])})`,_s=(e,t,n)=>{const a=[];for(let s=0;s<n.length;s+=4)a.push(`vec4(${I(n[s])}, ${I(n[s+1])}, ${I(n[s+2])}, ${I(n[s+3])})`);return`const vec4 ${e}[${t}] = vec4[${t}](
|
|
740
|
+
${a.join(`,
|
|
741
|
+
`)}
|
|
742
|
+
);`},qm=()=>{const e=Qn(),[t,n]=e.shadowWing;return`
|
|
743
|
+
#define MAKEUP_EYE_LASH_SEGMENTS ${e.lines.upper.length/4}
|
|
744
|
+
#define MAKEUP_EYE_BROW_EDGE_SEGMENTS ${e.lines.browLower.length/4}
|
|
745
|
+
#define MAKEUP_BROW_SEGMENTS ${Bn}
|
|
746
|
+
#define MAKEUP_BROW_FIRST 0
|
|
747
|
+
#define MAKEUP_BROW_LAST ${Bn-1}
|
|
748
|
+
#define MAKEUP_EYE_LINE_UPPER 0
|
|
749
|
+
#define MAKEUP_EYE_LINE_LOWER 1
|
|
750
|
+
#define MAKEUP_EYE_LINE_BROW_EDGE 2
|
|
751
|
+
#define MAKEUP_BROW_LANE_OFFSET ${ji.offset}
|
|
752
|
+
#define MAKEUP_BROW_SALT ${ji.salt}u
|
|
753
|
+
${_s("MAKEUP_EYE_UPPER","MAKEUP_EYE_LASH_SEGMENTS",e.lines.upper)}
|
|
754
|
+
${_s("MAKEUP_EYE_LOWER","MAKEUP_EYE_LASH_SEGMENTS",e.lines.lower)}
|
|
755
|
+
${_s("MAKEUP_EYE_BROW_EDGE","MAKEUP_EYE_BROW_EDGE_SEGMENTS",e.lines.browLower)}
|
|
756
|
+
|
|
757
|
+
uniform vec2 uBlink;
|
|
758
|
+
uniform vec4 uLiner;
|
|
759
|
+
uniform vec3 uWingStart;
|
|
760
|
+
uniform vec3 uWingEnd;
|
|
761
|
+
uniform vec4 uShadow;
|
|
762
|
+
uniform vec3 uShadowShape;
|
|
763
|
+
uniform vec2 uShadowCut;
|
|
764
|
+
uniform vec3 uShadowCreaseColor;
|
|
765
|
+
uniform vec3 uShadowInnerColor;
|
|
766
|
+
uniform vec3 uBrowStart[MAKEUP_BROW_SEGMENTS];
|
|
767
|
+
uniform vec3 uBrowEnd[MAKEUP_BROW_SEGMENTS];
|
|
768
|
+
uniform vec3 uBrow;
|
|
769
|
+
|
|
770
|
+
// The rest point folded onto the canonical -X half, frontal (x, y) cm.
|
|
771
|
+
vec2 makeupEyePoint(vec3 rest) {
|
|
772
|
+
return vec2(-abs(rest.x), rest.y);
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
// One segment (xy -> zw) of a line: keeps the nearest as (distance cm, position along the line).
|
|
776
|
+
void makeupEyeSegment(vec2 p, vec4 sg, float index, float count, inout vec2 best) {
|
|
777
|
+
vec2 ab = sg.zw - sg.xy;
|
|
778
|
+
float t = clamp(dot(p - sg.xy, ab) / max(dot(ab, ab), 1e-8), 0.0, 1.0);
|
|
779
|
+
float d = length(p - sg.xy - ab * t);
|
|
780
|
+
if (d < best.x) best = vec2(d, (index + t) / count);
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
// (distance cm, position 0..1 along the line) to the upper (MAKEUP_EYE_LINE_UPPER) or lower lash
|
|
784
|
+
// line, outer corner 0 -> inner corner 1.
|
|
785
|
+
vec2 makeupEyeLine(vec2 p, int line) {
|
|
786
|
+
vec2 best = vec2(1e6, 0.0);
|
|
787
|
+
for (int i = 0; i < MAKEUP_EYE_LASH_SEGMENTS; i++) {
|
|
788
|
+
vec4 sg = line == MAKEUP_EYE_LINE_UPPER ? MAKEUP_EYE_UPPER[i] : MAKEUP_EYE_LOWER[i];
|
|
789
|
+
makeupEyeSegment(p, sg, float(i), float(MAKEUP_EYE_LASH_SEGMENTS), best);
|
|
790
|
+
}
|
|
791
|
+
return best;
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
// One segment of a line that rises in x: keeps the height at x of the segment nearest in x.
|
|
795
|
+
void makeupEyeHeight(vec4 sg, float x, inout float nearest, inout float y) {
|
|
796
|
+
float cx = clamp(x, sg.x, sg.z);
|
|
797
|
+
float gap = abs(x - cx);
|
|
798
|
+
if (gap < nearest) {
|
|
799
|
+
nearest = gap;
|
|
800
|
+
y = mix(sg.y, sg.w, (cx - sg.x) / max(sg.z - sg.x, 1e-6));
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
// The height (y, cm) of the upper lash line (MAKEUP_EYE_LINE_UPPER) or the brow's lower edge
|
|
805
|
+
// (MAKEUP_EYE_LINE_BROW_EDGE) at x: both run left to right in x; past an end, the end's height.
|
|
806
|
+
float makeupEyeLineHeight(float x, int line) {
|
|
807
|
+
float y = 0.0;
|
|
808
|
+
float nearest = 1e6;
|
|
809
|
+
if (line == MAKEUP_EYE_LINE_BROW_EDGE) {
|
|
810
|
+
for (int i = 0; i < MAKEUP_EYE_BROW_EDGE_SEGMENTS; i++) makeupEyeHeight(MAKEUP_EYE_BROW_EDGE[i], x, nearest, y);
|
|
811
|
+
} else {
|
|
812
|
+
for (int i = 0; i < MAKEUP_EYE_LASH_SEGMENTS; i++) makeupEyeHeight(MAKEUP_EYE_UPPER[i], x, nearest, y);
|
|
813
|
+
}
|
|
814
|
+
return y;
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
// 1 on the lid, 0 under the eye: split where the lash lines are equally near, and along the
|
|
818
|
+
// corner-to-corner axis beyond the corners.
|
|
819
|
+
float makeupEyeLidGate(vec2 p, float upperCm, float lowerCm) {
|
|
820
|
+
float height = dot(p - ${mt(e.middle)}, ${mt(e.up)});
|
|
821
|
+
return smoothstep(${I(-Je.gateCm)}, ${I(Je.gateCm)}, lowerCm - upperCm + height);
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
// The lower zones fade out as the eye on this MESH side blinks (atlas +X <-> eyeBlinkLeft).
|
|
825
|
+
float makeupEyeBlinkFade(vec3 rest) {
|
|
826
|
+
float blink = rest.x < 0.0 ? uBlink.x : uBlink.y;
|
|
827
|
+
return 1.0 - smoothstep(${I(Je.blinkFade[0])}, ${I(Je.blinkFade[1])}, blink);
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
// An edge feather of at least ${Je.antialiasPx} px for a shape radiusCm wide.
|
|
831
|
+
float makeupEyeSoftness(float softness, float radiusCm, float pixelCm) {
|
|
832
|
+
return max(softness, ${I(Je.antialiasPx)} * pixelCm / max(radiusCm, 1e-4));
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
// A tapered capsule (xy ends, z radii) in the frontal plane.
|
|
836
|
+
float makeupEyeCapsule(vec2 p, vec3 a, vec3 b, float softness, float pixelCm) {
|
|
837
|
+
vec2 ab = b.xy - a.xy;
|
|
838
|
+
float t = clamp(dot(p - a.xy, ab) / max(dot(ab, ab), 1e-8), 0.0, 1.0);
|
|
839
|
+
float radius = max(mix(a.z, b.z, t), 1e-4);
|
|
840
|
+
float d = length(p - a.xy - ab * t);
|
|
841
|
+
return makeupShapeProfile(d / radius, makeupEyeSoftness(softness, radius, pixelCm));
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
// Eyeliner: the upper lash line (tapering toward the inner corner), the lower one (from the outer
|
|
845
|
+
// corner in, by uLiner.y; fades with blinks) and the wing, antialiased by the pixel footprint.
|
|
846
|
+
float eyelinerShape(vec3 rest, float pixelCm) {
|
|
847
|
+
vec2 p = makeupEyePoint(rest);
|
|
848
|
+
vec2 up = makeupEyeLine(p, MAKEUP_EYE_LINE_UPPER);
|
|
849
|
+
vec2 lo = makeupEyeLine(p, MAKEUP_EYE_LINE_LOWER);
|
|
850
|
+
float gate = makeupEyeLidGate(p, up.x, lo.x);
|
|
851
|
+
float smudge = uLiner.w;
|
|
852
|
+
float width = uLiner.x * (1.0 + smudge);
|
|
853
|
+
float softness = uSoftness * ${I(Be.softnessScale)} + smudge * ${I(Be.smudgeSoftness)};
|
|
854
|
+
float wu = max(width * mix(1.0, uLiner.z, smoothstep(${I(Be.taperStart)}, 1.0, up.y)), 1e-4);
|
|
855
|
+
float upper = makeupShapeProfile(up.x / wu, makeupEyeSoftness(softness, wu, pixelCm)) * gate;
|
|
856
|
+
float wl = max(width * ${I(Be.lowerWidth)} * mix(1.0, uLiner.z, smoothstep(${I(Be.taperStart)}, 1.0, lo.y)), 1e-4);
|
|
857
|
+
float reach = ${I(Be.lowerReach[0])} + ${I(Be.lowerReach[1])} * uLiner.y;
|
|
858
|
+
float lowerOn = smoothstep(0.0, ${I(Be.lowerFadeIn)}, uLiner.y)
|
|
859
|
+
* (1.0 - smoothstep(reach - ${I(Be.lowerReachSoftness)}, reach, lo.y));
|
|
860
|
+
float lower = makeupShapeProfile(lo.x / wl, makeupEyeSoftness(softness, wl, pixelCm))
|
|
861
|
+
* (1.0 - gate) * lowerOn * makeupEyeBlinkFade(rest);
|
|
862
|
+
float wing = 0.0;
|
|
863
|
+
if (uWingStart.z > 0.0) {
|
|
864
|
+
wing = makeupEyeCapsule(p, uWingStart, uWingEnd, softness, pixelCm)
|
|
865
|
+
* (1.0 - (1.0 - gate) * smoothstep(0.0, ${I(Be.wingBelow)}, lo.y));
|
|
866
|
+
}
|
|
867
|
+
return 1.0 - (1.0 - upper) * (1.0 - lower) * (1.0 - wing);
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
// Eyeshadow zones, each 0..1: the lid colour up to uShadow.x of the way from the lash line to the
|
|
871
|
+
// brow (none at 0), the lower lash line, the wing, the crease band at the lid colour's top edge
|
|
872
|
+
// (lifted above it and cut there by uShadowCut.x), and the inner corner (plus the lid centre for
|
|
873
|
+
// halo shapes).
|
|
874
|
+
struct MakeupEyeshadowZones {
|
|
875
|
+
float lid;
|
|
876
|
+
float lower;
|
|
877
|
+
float wing;
|
|
878
|
+
float crease;
|
|
879
|
+
float inner;
|
|
880
|
+
};
|
|
881
|
+
|
|
882
|
+
MakeupEyeshadowZones eyeshadowZones(vec3 rest, float pixelCm) {
|
|
883
|
+
vec2 p = makeupEyePoint(rest);
|
|
884
|
+
vec2 up = makeupEyeLine(p, MAKEUP_EYE_LINE_UPPER);
|
|
885
|
+
vec2 lo = makeupEyeLine(p, MAKEUP_EYE_LINE_LOWER);
|
|
886
|
+
float gate = makeupEyeLidGate(p, up.x, lo.x);
|
|
887
|
+
float soft = uSoftness;
|
|
888
|
+
float lash = makeupEyeLineHeight(p.x, MAKEUP_EYE_LINE_UPPER);
|
|
889
|
+
float gap = max(makeupEyeLineHeight(p.x, MAKEUP_EYE_LINE_BROW_EDGE) - lash, ${I(he.minGap)});
|
|
890
|
+
float t = (p.y - lash) / gap;
|
|
891
|
+
float u = dot(p - ${mt(e.inner)}, ${mt(e.axis)}) / ${I(e.axisLength)};
|
|
892
|
+
float lean = clamp(t, 0.0, 1.0);
|
|
893
|
+
lean *= lean;
|
|
894
|
+
float lateral = (1.0 - smoothstep(0.0, ${I(he.outerReach[0])} + ${I(he.outerReach[1])} * soft, (u - 1.0) * ${I(e.axisLength)} + ${I(he.outerSlope)} * lean))
|
|
895
|
+
* (1.0 - smoothstep(0.0, ${I(he.innerReach)}, -u * ${I(e.axisLength)} + ${I(he.innerSlope)} * lean));
|
|
896
|
+
float top = 1.0 - smoothstep(${I(he.top[0])}, ${I(he.top[1])}, t);
|
|
897
|
+
// The lid colour's top edge: feathered by softness, or sharp down to the pixel footprint.
|
|
898
|
+
float edge = mix(${I(he.edge[0])} + ${I(he.edge[1])} * soft,
|
|
899
|
+
max(${I(he.sharpEdgeCm)}, ${I(Je.antialiasPx)} * pixelCm) / gap, uShadowCut.y);
|
|
900
|
+
float lidEdge = smoothstep(uShadow.x - edge, uShadow.x + edge, t);
|
|
901
|
+
MakeupEyeshadowZones z;
|
|
902
|
+
// Height 0 paints no lid colour.
|
|
903
|
+
z.lid = (1.0 - lidEdge) * smoothstep(0.0, edge, uShadow.x) * top * gate * lateral;
|
|
904
|
+
float creaseWidth = ${I(he.creaseWidth[0])} + ${I(he.creaseWidth[1])} * soft;
|
|
905
|
+
float centre = clamp(uShadow.x + uShadowCut.x * creaseWidth, ${I(he.creaseCentre[0])}, ${I(he.creaseCentre[1])});
|
|
906
|
+
// Lifted, the band holds full from its centre down to the lid edge and stops there.
|
|
907
|
+
float dt = t - centre;
|
|
908
|
+
float across = dt > 0.0 ? dt : -dt * (1.0 - uShadowCut.x);
|
|
909
|
+
float outerBias = mix(1.0, 1.0 - ${I(he.outerBias)} * up.y, uShadowShape.x);
|
|
910
|
+
z.crease = uShadow.y * (1.0 - smoothstep(0.0, creaseWidth, across)) * mix(1.0, lidEdge, uShadowCut.x)
|
|
911
|
+
* outerBias * top * gate * lateral;
|
|
912
|
+
float lowerWidth = ${I(he.lowerWidth[0])} + ${I(he.lowerWidth[1])} * uShadow.z;
|
|
913
|
+
z.lower = uShadow.z * makeupShapeProfile(lo.x / lowerWidth, makeupEyeSoftness(soft, lowerWidth, pixelCm))
|
|
914
|
+
* (1.0 - gate) * lateral * makeupEyeBlinkFade(rest);
|
|
915
|
+
z.wing = 0.0;
|
|
916
|
+
if (uShadowShape.y > 0.0) {
|
|
917
|
+
z.wing = uShadowShape.y
|
|
918
|
+
* makeupEyeCapsule(p, vec3(${mt(t)}, ${I(he.wingRadius[0])}), vec3(${mt(n)}, ${I(he.wingRadius[1])}), soft, pixelCm)
|
|
919
|
+
* (1.0 - (1.0 - gate) * smoothstep(0.0, ${I(Be.wingBelow)}, lo.y));
|
|
920
|
+
}
|
|
921
|
+
float innerSpot = makeupShapeProfile(length(p - ${mt(e.inner)}) / ${I(he.innerRadius)},
|
|
922
|
+
makeupEyeSoftness(soft, ${I(he.innerRadius)}, pixelCm));
|
|
923
|
+
float haloSpot = makeupShapeProfile(length(p - ${mt(e.lidCentre)}) / ${I(he.haloRadius)},
|
|
924
|
+
makeupEyeSoftness(soft, ${I(he.haloRadius)}, pixelCm)) * gate;
|
|
925
|
+
z.inner = uShadow.w * max(innerSpot, uShadowShape.z * haloSpot);
|
|
926
|
+
return z;
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
float eyeshadowMask(MakeupEyeshadowZones z) {
|
|
930
|
+
return 1.0 - (1.0 - z.lid) * (1.0 - z.lower) * (1.0 - z.wing) * (1.0 - z.crease) * (1.0 - z.inner);
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
vec4 makeupEyeOver(vec4 acc, vec3 color, float w) {
|
|
934
|
+
return vec4(color * w + acc.rgb * (1.0 - w), w + acc.a * (1.0 - w));
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
// The zones' colours laid over each other: lid and lower in the shade, the wing toward the crease
|
|
938
|
+
// colour, the crease band, then the inner corner.
|
|
939
|
+
vec3 eyeshadowColor(MakeupEyeshadowZones z, vec3 shade) {
|
|
940
|
+
vec4 acc = vec4(shade * z.lid, z.lid);
|
|
941
|
+
acc = makeupEyeOver(acc, shade, z.lower);
|
|
942
|
+
acc = makeupEyeOver(acc, mix(shade, uShadowCreaseColor, uShadow.y), z.wing);
|
|
943
|
+
acc = makeupEyeOver(acc, uShadowCreaseColor, z.crease);
|
|
944
|
+
acc = makeupEyeOver(acc, uShadowInnerColor, z.inner);
|
|
945
|
+
return acc.a > 1e-6 ? acc.rgb / acc.a : shade;
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
// Brows: the band around the shaped centre line (uBrowStart / uBrowEnd: xy and half-width per
|
|
949
|
+
// segment, tail -> head) and procedural hair strokes along the hair direction.
|
|
950
|
+
struct MakeupBrow {
|
|
951
|
+
float band;
|
|
952
|
+
float strokes;
|
|
953
|
+
float along; // 0 tail .. 1 head
|
|
954
|
+
};
|
|
955
|
+
|
|
956
|
+
// One hair-stroke pattern in the brow's frame (s cm along the centre line from the tail, n cm
|
|
957
|
+
// across it, + above): lanes of strokes at degrees from the brow line, toward the tail and up.
|
|
958
|
+
float makeupBrowHairs(float s, float n, float degrees, uint salt, float pixelCm) {
|
|
959
|
+
float angle = radians(degrees);
|
|
960
|
+
float across = (s * sin(angle) + n * cos(angle)) / ${I(ye.strokeSpacing)};
|
|
961
|
+
float lane = floor(across);
|
|
962
|
+
uint laneBits = uint(int(lane) + MAKEUP_BROW_LANE_OFFSET);
|
|
963
|
+
vec3 r1 = makeupUnit3(makeupPcg3d(uvec3(laneBits, 0u, salt)));
|
|
964
|
+
float length2 = (-s * cos(angle) + n * sin(angle)) / ${I(ye.strokeLength)} + r1.x;
|
|
965
|
+
float segment = floor(length2);
|
|
966
|
+
vec3 r2 = makeupUnit3(makeupPcg3d(uvec3(laneBits, uint(int(segment) + MAKEUP_BROW_LANE_OFFSET), salt)));
|
|
967
|
+
float fraction = length2 - segment;
|
|
968
|
+
float x = abs(across - lane - 0.5 - (r2.y - 0.5) * ${I(ye.strokeJitter)});
|
|
969
|
+
float line = (1.0 - smoothstep(${I(ye.strokeWidth[0])}, ${I(ye.strokeWidth[1])}, x))
|
|
970
|
+
* smoothstep(0.0, ${I(ye.strokeFade[0])}, fraction) * (1.0 - smoothstep(${I(ye.strokeFade[1])}, 1.0, fraction))
|
|
971
|
+
* step(r2.x, ${I(ye.strokeKeep)});
|
|
972
|
+
float resolve = smoothstep(${I(ye.strokeResolvePx[0])}, ${I(ye.strokeResolvePx[1])}, ${I(ye.strokeSpacing)} / max(pixelCm, 1e-6));
|
|
973
|
+
return mix(${I(ye.strokeMean)}, line, resolve);
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
// The brow's own frame at p: (s cm along the tail -> head chord, n cm above the shaped centre line
|
|
977
|
+
// there, the chord's length); continuous across the control points.
|
|
978
|
+
vec3 makeupBrowFrame(vec2 p) {
|
|
979
|
+
vec2 tail = uBrowStart[MAKEUP_BROW_FIRST].xy;
|
|
980
|
+
vec2 chord = uBrowEnd[MAKEUP_BROW_LAST].xy - tail;
|
|
981
|
+
float span = max(length(chord), 1e-6);
|
|
982
|
+
vec2 c = chord / span;
|
|
983
|
+
vec2 q = p - tail;
|
|
984
|
+
float u = dot(q, c);
|
|
985
|
+
float v = dot(q, vec2(-c.y, c.x));
|
|
986
|
+
float centre = 0.0;
|
|
987
|
+
float nearest = 1e6;
|
|
988
|
+
for (int i = 0; i < MAKEUP_BROW_SEGMENTS; i++) {
|
|
989
|
+
vec2 a = uBrowStart[i].xy - tail;
|
|
990
|
+
vec2 b = uBrowEnd[i].xy - tail;
|
|
991
|
+
vec2 ca = vec2(dot(a, c), dot(a, vec2(-c.y, c.x)));
|
|
992
|
+
vec2 cb = vec2(dot(b, c), dot(b, vec2(-c.y, c.x)));
|
|
993
|
+
float cu = clamp(u, ca.x, cb.x);
|
|
994
|
+
float gap = abs(u - cu);
|
|
995
|
+
if (gap < nearest) {
|
|
996
|
+
nearest = gap;
|
|
997
|
+
centre = mix(ca.y, cb.y, (cu - ca.x) / max(cb.x - ca.x, 1e-6));
|
|
998
|
+
}
|
|
999
|
+
}
|
|
1000
|
+
return vec3(u, v - centre, span);
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
MakeupBrow browGeometry(vec3 rest, float pixelCm) {
|
|
1004
|
+
vec2 p = makeupEyePoint(rest);
|
|
1005
|
+
float best = 1e6;
|
|
1006
|
+
float radius = 1.0;
|
|
1007
|
+
float along = 0.0;
|
|
1008
|
+
for (int i = 0; i < MAKEUP_BROW_SEGMENTS; i++) {
|
|
1009
|
+
vec3 a = uBrowStart[i];
|
|
1010
|
+
vec3 b = uBrowEnd[i];
|
|
1011
|
+
vec2 ab = b.xy - a.xy;
|
|
1012
|
+
float t = clamp(dot(p - a.xy, ab) / max(dot(ab, ab), 1e-8), 0.0, 1.0);
|
|
1013
|
+
float r = max(mix(a.z, b.z, t), 1e-3);
|
|
1014
|
+
float d = length(p - a.xy - ab * t) / r;
|
|
1015
|
+
if (d < best) {
|
|
1016
|
+
best = d;
|
|
1017
|
+
radius = r;
|
|
1018
|
+
along = (float(i) + t) / float(MAKEUP_BROW_SEGMENTS);
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1021
|
+
float soft = makeupEyeSoftness(uSoftness, radius, pixelCm);
|
|
1022
|
+
MakeupBrow brow;
|
|
1023
|
+
brow.band = makeupShapeProfile(best, soft);
|
|
1024
|
+
brow.along = along;
|
|
1025
|
+
brow.strokes = 0.0;
|
|
1026
|
+
if (uBrow.y > 0.0) {
|
|
1027
|
+
vec3 frame = makeupBrowFrame(p);
|
|
1028
|
+
float wide = makeupShapeProfile(best / ${I(ye.strokeReach)}, soft);
|
|
1029
|
+
float head = smoothstep(${I(ye.strokeHeadBlend[0])}, ${I(ye.strokeHeadBlend[1])}, frame.x / frame.z);
|
|
1030
|
+
float body = makeupBrowHairs(frame.x, frame.y, ${I(ye.strokeAngle[0])}, MAKEUP_BROW_SALT, pixelCm);
|
|
1031
|
+
float up = makeupBrowHairs(frame.x, frame.y, ${I(ye.strokeAngle[1])}, MAKEUP_BROW_SALT + 1u, pixelCm);
|
|
1032
|
+
brow.strokes = uBrow.y * wide * mix(body, up, head);
|
|
1033
|
+
}
|
|
1034
|
+
return brow;
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
// What the brow can paint before the camera is read (the early discard's bound).
|
|
1038
|
+
float browReach(MakeupBrow brow) {
|
|
1039
|
+
return max(brow.band, brow.strokes);
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
// The brow's mask: the band times the real hairs (darker than the local skin: (1 - lum(C) / lum(L))
|
|
1043
|
+
// x uBrow.z), mixed toward a full powder fill by uBrow.x, joined with the strokes. Needs the colours.
|
|
1044
|
+
float browMask(MakeupSample s, MakeupBrow brow) {
|
|
1045
|
+
float hair = clamp((1.0 - makeupLuma(s.camera) / max(makeupLuma(s.skinLocal), MAKEUP_EPSILON)) * uBrow.z, 0.0, 1.0);
|
|
1046
|
+
float filled = brow.band * mix(hair, 1.0, clamp(uBrow.x, 0.0, 1.0));
|
|
1047
|
+
return 1.0 - (1.0 - filled) * (1.0 - brow.strokes);
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
float browShape(MakeupSample s) {
|
|
1051
|
+
return browMask(s, browGeometry(s.rest, s.pixelCm));
|
|
1052
|
+
}
|
|
1053
|
+
`},Xm=qm(),Ym=()=>({uBlink:{value:new d.Vector2(0,0)},uLiner:{value:new d.Vector4(0,0,1,0)},uWingStart:{value:new d.Vector3(0,0,0)},uWingEnd:{value:new d.Vector3(0,0,0)},uShadow:{value:new d.Vector4(0,0,0,0)},uShadowShape:{value:new d.Vector3(0,0,0)},uShadowCut:{value:new d.Vector2(0,0)},uShadowCreaseColor:{value:new d.Color(0,0,0)},uShadowInnerColor:{value:new d.Color(1,1,1)},uBrowStart:{value:new Float32Array(Bn*3)},uBrowEnd:{value:new Float32Array(Bn*3)},uBrow:{value:new d.Vector3(0,0,1)}}),Fe=Tu,Ie=ku,Qm=`
|
|
1054
|
+
// Blinn-Phong lobe with a peak of 1, gated to the lit side.
|
|
1055
|
+
float makeupLobe(vec3 n, vec3 h, vec3 l, float roughness) {
|
|
1056
|
+
float e = max(2.0 / max(roughness * roughness, 0.001) - 2.0, 1.0);
|
|
1057
|
+
return pow(max(dot(n, h), 0.0), e) * smoothstep(0.0, 0.2, dot(n, l));
|
|
1058
|
+
}
|
|
1059
|
+
|
|
1060
|
+
float makeupFresnel(float nv, float f0) {
|
|
1061
|
+
return f0 + (1.0 - f0) * pow(1.0 - nv, 5.0);
|
|
1062
|
+
}
|
|
1063
|
+
|
|
1064
|
+
vec3 makeupFresnel(float nv, vec3 f0) {
|
|
1065
|
+
return f0 + (vec3(1.0) - f0) * pow(1.0 - nv, 5.0);
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1068
|
+
// sparkleColor, or (sparkleColor "") the shade mixed toward white.
|
|
1069
|
+
vec3 makeupSparkleTint(vec3 color) {
|
|
1070
|
+
return uSparkleAuto > 0.5 ? mix(vec3(1.0), color, ${I(Fe.sparkleTintMix)}) : uSparkleColor;
|
|
1071
|
+
}
|
|
1072
|
+
|
|
1073
|
+
MakeupFlakes makeupFinishFlakes(MakeupSample s, vec3 h, bool glitter, vec3 tint) {
|
|
1074
|
+
float quality = clamp(uSparkleQuality, 0.0, 1.0);
|
|
1075
|
+
float density = clamp(uSparkleDensity, 0.0, 1.0);
|
|
1076
|
+
float diameter = max(uSparkleSize, 0.01) / 10.0;
|
|
1077
|
+
if (glitter) {
|
|
1078
|
+
return makeupFlakes(
|
|
1079
|
+
s.rest, s.facet, s.flakeNormal, s.headUp, h, s.pixelCm, diameter,
|
|
1080
|
+
${I(Ie.glitter.cellScale)}, density * mix(${I(Ie.lowQualityGlitterDensity)}, 1.0, quality),
|
|
1081
|
+
${I(Ie.glitter.kappa)}, ${I(Ie.glitter.sharpness)}, ${I(Ie.glitter.hueJitter)}, 1.0, tint
|
|
1082
|
+
);
|
|
1083
|
+
}
|
|
1084
|
+
return makeupFlakes(
|
|
1085
|
+
s.rest, s.facet, s.flakeNormal, s.headUp, h, s.pixelCm, diameter,
|
|
1086
|
+
${I(Ie.shimmer.cellScale)}, density,
|
|
1087
|
+
${I(Ie.shimmer.kappa)}, ${I(Ie.shimmer.sharpness)}, ${I(Ie.shimmer.hueJitter)}, quality, tint
|
|
1088
|
+
);
|
|
1089
|
+
}
|
|
1090
|
+
|
|
1091
|
+
MakeupLayer makeupFinish(MakeupSample s, vec3 color, float mask) {
|
|
1092
|
+
int finish = uFinish;
|
|
1093
|
+
float m = clamp(mask, 0.0, 1.0) * s.fade;
|
|
1094
|
+
float opacity = clamp(uOpacity, 0.0, 1.0);
|
|
1095
|
+
float k = m * opacity;
|
|
1096
|
+
float mg = m * smoothstep(0.0, ${I(Fe.maskTermsFullOpacity)}, opacity);
|
|
1097
|
+
float shine = clamp(uShine, 0.0, 1.0);
|
|
1098
|
+
MakeupLight lt = makeupLighting(s, makeupClipFor(finish));
|
|
1099
|
+
vec3 diffuse = makeupDiffuse(s, lt, color, uCoverage, finish);
|
|
1100
|
+
vec3 n = s.normal;
|
|
1101
|
+
vec3 v = s.viewDir;
|
|
1102
|
+
vec3 l = s.light;
|
|
1103
|
+
vec3 h = normalize(l + v);
|
|
1104
|
+
float nv = max(dot(n, v), 0.0);
|
|
1105
|
+
float gate = smoothstep(0.0, 0.2, dot(n, l));
|
|
1106
|
+
float level = clamp(lt.local, 0.0, ${I(nt.maxLightLevel)});
|
|
1107
|
+
float satinHighlight = ${I(Fe.satin.cameraHighlight)} * lt.highlight
|
|
1108
|
+
+ shine * ${I(Fe.satin.lobe)} * level * makeupLobe(n, h, l, ${I(Fe.satin.roughness)});
|
|
1109
|
+
vec3 highlight = vec3(0.0);
|
|
1110
|
+
float amount = k;
|
|
1111
|
+
if (finish == MAKEUP_FINISH_SATIN) {
|
|
1112
|
+
highlight = vec3(k * satinHighlight);
|
|
1113
|
+
} else if (finish == MAKEUP_FINISH_GLOSS) {
|
|
1114
|
+
float fresnel = (makeupFresnel(nv, ${I(Fe.gloss.f0)}) - ${I(Fe.gloss.f0)}) / ${I(1-Fe.gloss.f0)};
|
|
1115
|
+
highlight = vec3(mg * (
|
|
1116
|
+
(${I(Fe.gloss.cameraHighlight)} + ${I(Fe.gloss.cameraHighlightShine)} * shine) * lt.highlight
|
|
1117
|
+
+ shine * level * (${I(Fe.gloss.lobe)} * makeupLobe(n, h, l, ${I(Fe.gloss.roughness)}) + ${I(Fe.gloss.fresnel)} * fresnel)
|
|
1118
|
+
));
|
|
1119
|
+
} else if (finish == MAKEUP_FINISH_SHIMMER) {
|
|
1120
|
+
vec3 tint = makeupSparkleTint(color);
|
|
1121
|
+
MakeupFlakes flakes = makeupFinishFlakes(s, h, false, tint);
|
|
1122
|
+
highlight = vec3(k * satinHighlight)
|
|
1123
|
+
+ tint * (k * shine * ${I(Ie.shimmer.gain)} * level * gate * flakes.glint);
|
|
1124
|
+
} else if (finish == MAKEUP_FINISH_METALLIC) {
|
|
1125
|
+
vec3 reflected = lt.lightTint * (${I(Fe.metallic.environment)} * clamp(uCoverage, 0.0, 1.0) * lt.diffuse)
|
|
1126
|
+
+ vec3(lt.highlight + shine * ${I(Fe.metallic.lobe)} * level * makeupLobe(n, h, l, ${I(Fe.metallic.roughness)}));
|
|
1127
|
+
highlight = k * makeupFresnel(nv, color) * reflected;
|
|
1128
|
+
} else if (finish == MAKEUP_FINISH_GLITTER) {
|
|
1129
|
+
vec3 tint = makeupSparkleTint(color);
|
|
1130
|
+
MakeupFlakes flakes = makeupFinishFlakes(s, h, true, tint);
|
|
1131
|
+
float flakeCover = flakes.cover * mg;
|
|
1132
|
+
vec3 body = flakes.tint * (${I(Ie.glitter.body)} * lt.diffuse) * lt.lightTint;
|
|
1133
|
+
float combined = 1.0 - (1.0 - k) * (1.0 - flakeCover);
|
|
1134
|
+
if (combined > MAKEUP_EPSILON) {
|
|
1135
|
+
diffuse = (diffuse * (k * (1.0 - flakeCover)) + body * flakeCover) / combined;
|
|
1136
|
+
}
|
|
1137
|
+
amount = combined;
|
|
1138
|
+
highlight = vec3(k * satinHighlight)
|
|
1139
|
+
+ flakes.tint * (mg * shine * ${I(Ie.glitter.gain)} * level * gate * flakes.glint);
|
|
1140
|
+
}
|
|
1141
|
+
return MakeupLayer(diffuse, amount, highlight);
|
|
1142
|
+
}
|
|
1143
|
+
`,gt=nt,He=Lu,Jm=`
|
|
1144
|
+
struct MakeupLight {
|
|
1145
|
+
float ratio; // S = lum(C) / lum(Rs)
|
|
1146
|
+
float local; // lum(L) / lum(Rs)
|
|
1147
|
+
float diffuse; // Sd: S with the skin's shine clipped
|
|
1148
|
+
float highlight; // Hcam: the real highlight on the skin
|
|
1149
|
+
vec3 lightTint; // the cast of a change in light colour
|
|
1150
|
+
};
|
|
1151
|
+
|
|
1152
|
+
struct MakeupLayer {
|
|
1153
|
+
vec3 diffuse;
|
|
1154
|
+
float amount;
|
|
1155
|
+
vec3 highlight;
|
|
1156
|
+
};
|
|
1157
|
+
|
|
1158
|
+
// x unchanged up to knee, then compressed toward knee * (1 + clip); hard at clip 0.
|
|
1159
|
+
float makeupSoftClip(float x, float knee, float clip) {
|
|
1160
|
+
if (x <= knee) return x;
|
|
1161
|
+
float c = clip * knee;
|
|
1162
|
+
return c > MAKEUP_EPSILON ? knee + c * (1.0 - exp(-(x - knee) / c)) : knee;
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
float makeupClipFor(int finish) {
|
|
1166
|
+
return finish == MAKEUP_FINISH_MATTE ? 0.0 : ${I(gt.clip)};
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
MakeupLight makeupLighting(MakeupSample s, float clip) {
|
|
1170
|
+
MakeupLight m;
|
|
1171
|
+
float lumC = makeupLuma(s.camera);
|
|
1172
|
+
float lumSlow = max(makeupLuma(s.skinSlow), MAKEUP_EPSILON);
|
|
1173
|
+
float lumFast = max(makeupLuma(s.skinFast), MAKEUP_EPSILON);
|
|
1174
|
+
float lumLocal = max(makeupLuma(s.skinLocal), MAKEUP_EPSILON);
|
|
1175
|
+
m.ratio = clamp(lumC / lumSlow, 0.0, ${I(gt.maxRatio)});
|
|
1176
|
+
m.local = clamp(lumLocal / lumSlow, 0.0, ${I(gt.maxRatio)});
|
|
1177
|
+
m.diffuse = makeupSoftClip(m.ratio, m.local, clip);
|
|
1178
|
+
m.highlight = max(0.0, lumC - ${I(gt.highlightKnee)} * lumLocal);
|
|
1179
|
+
m.lightTint = clamp(
|
|
1180
|
+
(s.skinFast / lumFast) / max(s.skinSlow / lumSlow, vec3(MAKEUP_EPSILON)),
|
|
1181
|
+
vec3(${I(gt.tintMin)}),
|
|
1182
|
+
vec3(${I(gt.tintMax)})
|
|
1183
|
+
);
|
|
1184
|
+
return m;
|
|
1185
|
+
}
|
|
1186
|
+
|
|
1187
|
+
// Opaque: the shade under this light, relative to the person's skin.
|
|
1188
|
+
// Sheer: the person's own colour filtered by the shade, never lighter.
|
|
1189
|
+
// Metallic darkens the body with coverage: x mix(1, 0.45, coverage).
|
|
1190
|
+
vec3 makeupDiffuse(MakeupSample s, MakeupLight lt, vec3 color, float coverage, int finish) {
|
|
1191
|
+
vec3 opaque = color * lt.diffuse * lt.lightTint;
|
|
1192
|
+
vec3 camera = finish == MAKEUP_FINISH_MATTE
|
|
1193
|
+
? s.camera * min(1.0, lt.diffuse / max(lt.ratio, MAKEUP_EPSILON))
|
|
1194
|
+
: s.camera;
|
|
1195
|
+
float peak = max(max(max(color.r, color.g), color.b), makeupLuma(s.skinSlow));
|
|
1196
|
+
vec3 sheer = camera * (color / max(peak, MAKEUP_EPSILON));
|
|
1197
|
+
float cover = clamp(coverage, 0.0, 1.0);
|
|
1198
|
+
vec3 d = mix(sheer, opaque, cover);
|
|
1199
|
+
return finish == MAKEUP_FINISH_METALLIC ? d * mix(1.0, ${I(Tu.metallic.diffuse)}, cover) : d;
|
|
1200
|
+
}
|
|
1201
|
+
|
|
1202
|
+
vec3 makeupDiffuse(MakeupSample s, vec3 color, float coverage) {
|
|
1203
|
+
return makeupDiffuse(s, makeupLighting(s, makeupClipFor(uFinish)), color, coverage, uFinish);
|
|
1204
|
+
}
|
|
1205
|
+
|
|
1206
|
+
vec3 makeupSaturation(vec3 c, float amount) {
|
|
1207
|
+
return mix(vec3(makeupLuma(c)), c, amount);
|
|
1208
|
+
}
|
|
1209
|
+
|
|
1210
|
+
// shade: "auto", derived from the person (no readback, no labels).
|
|
1211
|
+
vec3 makeupAutoShade(MakeupSample s, int mode) {
|
|
1212
|
+
float lumSlow = makeupLuma(s.skinSlow);
|
|
1213
|
+
vec3 local = s.skinLocal * (lumSlow / max(makeupLuma(s.skinLocal), MAKEUP_EPSILON));
|
|
1214
|
+
if (mode == MAKEUP_AUTO_LIPS) return makeupSaturation(s.lip, ${I(He.lips.saturation)}) * ${I(He.lips.value)};
|
|
1215
|
+
if (mode == MAKEUP_AUTO_BLUSH) {
|
|
1216
|
+
vec3 rose = ${ln(He.blush.rose)} * (makeupLuma(local) / ${I(De(He.blush.rose))});
|
|
1217
|
+
return mix(local, rose, ${I(He.blush.mix)}) * ${I(He.blush.value)};
|
|
1218
|
+
}
|
|
1219
|
+
if (mode == MAKEUP_AUTO_CONTOUR) return makeupSaturation(local, ${I(He.contour.saturation)}) * ${I(He.contour.value)};
|
|
1220
|
+
if (mode == MAKEUP_AUTO_HIGHLIGHTER) {
|
|
1221
|
+
vec3 warm = ${ln(He.highlighter.warm)} * makeupLuma(local);
|
|
1222
|
+
return min(mix(local, warm, ${I(He.highlighter.mix)}) * ${I(He.highlighter.value)}, vec3(1.0));
|
|
1223
|
+
}
|
|
1224
|
+
if (mode == MAKEUP_AUTO_BROWS) return s.brow;
|
|
1225
|
+
return uColor;
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1228
|
+
// The region's shade: uColor, or the auto shade when uAutoShade is set.
|
|
1229
|
+
vec3 makeupShade(MakeupSample s) {
|
|
1230
|
+
return makeupAutoShade(s, uAutoShade);
|
|
1231
|
+
}
|
|
1232
|
+
|
|
1233
|
+
void makeupOutput(MakeupSample s, vec3 diffuse, float amount, vec3 highlight) {
|
|
1234
|
+
float k = clamp(amount, 0.0, 1.0);
|
|
1235
|
+
vec3 h = max(highlight, vec3(0.0));
|
|
1236
|
+
if (k < ${I(gt.discardBelow)} && max(max(h.r, h.g), h.b) < ${I(gt.discardBelow)}) discard;
|
|
1237
|
+
vec3 base = mix(s.camera, diffuse, k);
|
|
1238
|
+
vec3 spec = makeupEncode(base + h) - makeupEncode(base);
|
|
1239
|
+
gl_FragColor = vec4(k * makeupEncode(diffuse) + spec, k);
|
|
1240
|
+
}
|
|
1241
|
+
|
|
1242
|
+
void makeupOutput(MakeupSample s, MakeupLayer layer) {
|
|
1243
|
+
makeupOutput(s, layer.diffuse, layer.amount, layer.highlight);
|
|
1244
|
+
}
|
|
1245
|
+
`,Zm=`
|
|
1246
|
+
#define MAKEUP_SHAPE_MAX ${ht}
|
|
1247
|
+
uniform vec4 uShapeStart[MAKEUP_SHAPE_MAX];
|
|
1248
|
+
uniform vec4 uShapeEnd[MAKEUP_SHAPE_MAX];
|
|
1249
|
+
uniform float uShapeWeight[MAKEUP_SHAPE_MAX];
|
|
1250
|
+
uniform int uShapeCount;
|
|
1251
|
+
uniform float uSoftness;
|
|
1252
|
+
uniform vec2 uEyeGuard;
|
|
1253
|
+
uniform float uLipGuard;
|
|
1254
|
+
|
|
1255
|
+
// 1 inside, 0.5 on the radius, 0 from 1 + softness out (compact support).
|
|
1256
|
+
float makeupShapeProfile(float x, float softness) {
|
|
1257
|
+
float s = clamp(softness, ${I(bm)}, 1.0);
|
|
1258
|
+
return 1.0 - smoothstep(1.0 - s, 1.0 + s, x);
|
|
1259
|
+
}
|
|
1260
|
+
|
|
1261
|
+
// Distance from p to a tapered capsule (xyz ends, w radii); the radius at the closest point.
|
|
1262
|
+
float makeupCapsule(vec3 p, vec4 a, vec4 b, out float radius) {
|
|
1263
|
+
vec3 ab = b.xyz - a.xyz;
|
|
1264
|
+
float t = clamp(dot(p - a.xyz, ab) / max(dot(ab, ab), 1e-6), 0.0, 1.0);
|
|
1265
|
+
radius = mix(a.w, b.w, t);
|
|
1266
|
+
return length(p - a.xyz - ab * t);
|
|
1267
|
+
}
|
|
1268
|
+
|
|
1269
|
+
// The rest point on the canonical -X half, where shapes are authored.
|
|
1270
|
+
vec3 makeupFold(vec3 rest) {
|
|
1271
|
+
return vec3(-abs(rest.x), rest.y, rest.z);
|
|
1272
|
+
}
|
|
1273
|
+
|
|
1274
|
+
// The capsules' soft union at a rest point (cm).
|
|
1275
|
+
float makeupShapeMask(vec3 rest) {
|
|
1276
|
+
vec3 p = makeupFold(rest);
|
|
1277
|
+
float keep = 1.0;
|
|
1278
|
+
for (int i = 0; i < MAKEUP_SHAPE_MAX; i++) {
|
|
1279
|
+
if (i >= uShapeCount) break;
|
|
1280
|
+
float radius;
|
|
1281
|
+
float d = makeupCapsule(p, uShapeStart[i], uShapeEnd[i], radius);
|
|
1282
|
+
keep *= 1.0 - clamp(uShapeWeight[i], 0.0, 1.0) * makeupShapeProfile(d / max(radius, 1e-3), uSoftness);
|
|
1283
|
+
}
|
|
1284
|
+
return 1.0 - keep;
|
|
1285
|
+
}
|
|
1286
|
+
|
|
1287
|
+
// Keeps a shape off the lash line and lids (eyeRing: 0 on the lash line, 3 on the under-eye row).
|
|
1288
|
+
float makeupEyeGuard() {
|
|
1289
|
+
return uEyeGuard.y > uEyeGuard.x ? smoothstep(uEyeGuard.x, uEyeGuard.y, vMakeupEyeRing) : 1.0;
|
|
1290
|
+
}
|
|
1291
|
+
|
|
1292
|
+
// Fades a shape off the lips (lipEdge: 0 on the outer lip line, 1 one triangle row off the lips).
|
|
1293
|
+
float makeupLipGuard() {
|
|
1294
|
+
return uLipGuard > 0.0 ? smoothstep(0.0, uLipGuard, vMakeupLipEdge) : 1.0;
|
|
1295
|
+
}
|
|
1296
|
+
|
|
1297
|
+
// A face region's mask: its capsules, kept off the eyes and the lips.
|
|
1298
|
+
float makeupRegionShape(vec3 rest) {
|
|
1299
|
+
return makeupShapeMask(rest) * makeupEyeGuard() * makeupLipGuard();
|
|
1300
|
+
}
|
|
1301
|
+
|
|
1302
|
+
float blushShape(vec3 rest) {
|
|
1303
|
+
return makeupRegionShape(rest);
|
|
1304
|
+
}
|
|
1305
|
+
|
|
1306
|
+
float contourShape(vec3 rest) {
|
|
1307
|
+
return makeupRegionShape(rest);
|
|
1308
|
+
}
|
|
1309
|
+
|
|
1310
|
+
float highlighterShape(vec3 rest) {
|
|
1311
|
+
return makeupRegionShape(rest);
|
|
1312
|
+
}
|
|
1313
|
+
`,eg=()=>({uShapeStart:{value:new Float32Array(ht*4)},uShapeEnd:{value:new Float32Array(ht*4)},uShapeWeight:{value:new Float32Array(ht)},uShapeCount:{value:0},uSoftness:{value:.5},uEyeGuard:{value:new d.Vector2(0,0)},uLipGuard:{value:0}}),ha=ku,tg=`
|
|
1314
|
+
struct MakeupFlakes {
|
|
1315
|
+
float cover; // fraction of the pixel covered by flakes
|
|
1316
|
+
float glint; // coverage-weighted glint
|
|
1317
|
+
vec3 tint; // flake tint (hue-jittered when resolved)
|
|
1318
|
+
float resolved; // 0 = expected value only, 1 = fully resolved
|
|
1319
|
+
};
|
|
1320
|
+
|
|
1321
|
+
uvec3 makeupPcg3d(uvec3 v) {
|
|
1322
|
+
v = v * 1664525u + 1013904223u;
|
|
1323
|
+
v.x += v.y * v.z;
|
|
1324
|
+
v.y += v.z * v.x;
|
|
1325
|
+
v.z += v.x * v.y;
|
|
1326
|
+
v ^= v >> 16u;
|
|
1327
|
+
v.x += v.y * v.z;
|
|
1328
|
+
v.y += v.z * v.x;
|
|
1329
|
+
v.z += v.x * v.y;
|
|
1330
|
+
return v;
|
|
1331
|
+
}
|
|
1332
|
+
|
|
1333
|
+
vec3 makeupUnit3(uvec3 v) {
|
|
1334
|
+
return vec3(v >> 8u) * (1.0 / 16777216.0);
|
|
1335
|
+
}
|
|
1336
|
+
|
|
1337
|
+
vec3 makeupHueRotate(vec3 c, float angle) {
|
|
1338
|
+
vec3 k = vec3(${I(1/Math.sqrt(3))});
|
|
1339
|
+
float ca = cos(angle);
|
|
1340
|
+
return c * ca + cross(k, c) * sin(angle) + k * (dot(k, c) * (1.0 - ca));
|
|
1341
|
+
}
|
|
1342
|
+
|
|
1343
|
+
// Expected flake coverage: density x sphere volume / cell volume.
|
|
1344
|
+
float makeupFlakeVolume(float density, float cellScale) {
|
|
1345
|
+
return density * (MAKEUP_PI / 6.0) / (cellScale * cellScale * cellScale);
|
|
1346
|
+
}
|
|
1347
|
+
|
|
1348
|
+
// Mean of exp(sharpness * (dot(nf, h) - 1)) over von Mises-Fisher normals around n.
|
|
1349
|
+
float makeupFlakeGlintMean(vec3 n, vec3 h, float kappa, float sharpness) {
|
|
1350
|
+
float m = max(length(sharpness * h + kappa * n), 0.001);
|
|
1351
|
+
return kappa * (exp(m - sharpness - kappa) - exp(-m - sharpness - kappa))
|
|
1352
|
+
/ (m * (1.0 - exp(-2.0 * kappa)));
|
|
1353
|
+
}
|
|
1354
|
+
|
|
1355
|
+
// p: rest position (cm); facet: rest-space facet normal; n: flake base normal (view);
|
|
1356
|
+
// up: head +Y (view); h: half vector (view); diameter: flake diameter (cm).
|
|
1357
|
+
MakeupFlakes makeupFlakes(
|
|
1358
|
+
vec3 p, vec3 facet, vec3 n, vec3 up, vec3 h, float pixelCm,
|
|
1359
|
+
float diameter, float cellScale, float density, float kappa, float sharpness,
|
|
1360
|
+
float hueJitter, float quality, vec3 tint
|
|
1361
|
+
) {
|
|
1362
|
+
float volume = makeupFlakeVolume(density, cellScale);
|
|
1363
|
+
MakeupFlakes fl = MakeupFlakes(volume, volume * makeupFlakeGlintMean(n, h, kappa, sharpness), tint, 0.0);
|
|
1364
|
+
float sizePx = diameter / max(pixelCm, 1e-6);
|
|
1365
|
+
float t = clamp(quality, 0.0, 1.0)
|
|
1366
|
+
* clamp((sizePx - ${I(ha.resolveStartPx)}) / ${I(ha.resolveFullPx-ha.resolveStartPx)}, 0.0, 1.0);
|
|
1367
|
+
if (t <= 0.0 || density <= 0.0) return fl;
|
|
1368
|
+
float cell = diameter * cellScale;
|
|
1369
|
+
float r = 0.5 * diameter;
|
|
1370
|
+
vec3 id = floor(p / cell);
|
|
1371
|
+
uvec3 a = makeupPcg3d(uvec3(ivec3(id) + ${ha.cellOffset}));
|
|
1372
|
+
uvec3 b = makeupPcg3d(a ^ 0x9E3779B9u);
|
|
1373
|
+
vec3 ra = makeupUnit3(a);
|
|
1374
|
+
vec3 rb = makeupUnit3(b);
|
|
1375
|
+
float cover = 0.0;
|
|
1376
|
+
float glint = 0.0;
|
|
1377
|
+
vec3 flakeTint = tint;
|
|
1378
|
+
if (rb.z < density) {
|
|
1379
|
+
vec3 centre = id * cell + r + ra * (cell - 2.0 * r);
|
|
1380
|
+
vec3 d = p - centre;
|
|
1381
|
+
float dn = dot(d, facet);
|
|
1382
|
+
float disc2 = r * r - dn * dn;
|
|
1383
|
+
if (disc2 > 0.0) {
|
|
1384
|
+
float disc = sqrt(disc2);
|
|
1385
|
+
float ramp = 2.0 * disc * min(pixelCm, disc);
|
|
1386
|
+
cover = clamp((disc2 - (dot(d, d) - dn * dn)) / ramp + 0.5, 0.0, 1.0);
|
|
1387
|
+
vec3 tangent = cross(up, n);
|
|
1388
|
+
if (dot(tangent, tangent) < 1e-8) tangent = cross(vec3(0.0, 0.0, 1.0), n);
|
|
1389
|
+
tangent = normalize(tangent);
|
|
1390
|
+
vec3 bitangent = cross(n, tangent);
|
|
1391
|
+
float c = 1.0 + log(rb.x + (1.0 - rb.x) * exp(-2.0 * kappa)) / kappa;
|
|
1392
|
+
float sn = sqrt(max(0.0, 1.0 - c * c));
|
|
1393
|
+
float phi = 2.0 * MAKEUP_PI * rb.y;
|
|
1394
|
+
vec3 nf = c * n + sn * (cos(phi) * tangent + sin(phi) * bitangent);
|
|
1395
|
+
glint = cover * exp(sharpness * (dot(nf, h) - 1.0));
|
|
1396
|
+
flakeTint = max(makeupHueRotate(tint, ((rb.z / density) * 2.0 - 1.0) * hueJitter), vec3(0.0));
|
|
1397
|
+
}
|
|
1398
|
+
}
|
|
1399
|
+
fl.cover = mix(fl.cover, cover, t);
|
|
1400
|
+
fl.glint = mix(fl.glint, glint, t);
|
|
1401
|
+
fl.tint = mix(tint, flakeTint, t);
|
|
1402
|
+
fl.resolved = t;
|
|
1403
|
+
return fl;
|
|
1404
|
+
}
|
|
1405
|
+
`,Wu=()=>({uCameraMap:{value:null},uSkinStats:{value:null},uSkinStatsPacked:{value:0},uSkinMap:{value:null},uSkinLod:{value:Zt(128)},uSkinSqrt:{value:0},uColor:{value:new d.Color(1,1,1)},uAutoShade:{value:0},uOpacity:{value:1},uCoverage:{value:1},uFinish:{value:Ze.matte},uShine:{value:0},uSparkleColor:{value:new d.Color(1,1,1)},uSparkleAuto:{value:1},uSparkleDensity:{value:.5},uSparkleSize:{value:.8},uSparkleQuality:{value:1},uSide:{value:new d.Vector2(1,1)},uPersonLeftSign:{value:1},uPresence:{value:1}}),fe=Object.freeze({atlasVertex:Lm,common:Cm,shading:Jm,sparkle:tg,finish:Qm,shapes:Zm,design:Rm,eyes:Xm}),ng=Object.freeze({seam:.004,highlightSharp:96,highlightBroad:4,fullShading:.999}),Xi=(e,t,n)=>Math.min(Math.max(e,t),n),ag=e=>{const t=Xi(e.opacity,0,1),n=e.splitLips?Xi(e.lowerLipOpacity,0,1):t;return{opacity:Math.max(t,n),upper:t,lower:n}},xn=ng,qu="LIP_EFFECT_SKIN_STATS",Xu=`
|
|
1406
|
+
${zu}
|
|
1407
|
+
attribute vec2 faceUv;
|
|
1408
|
+
${po}
|
|
1409
|
+
${Uu}
|
|
1410
|
+
varying vec2 vFaceUv;
|
|
1411
|
+
varying vec2 vUv;
|
|
1412
|
+
varying float vLipEdge;
|
|
1413
|
+
varying vec3 vNormal;
|
|
1414
|
+
varying vec3 vViewDir;
|
|
1415
|
+
|
|
1416
|
+
void main() {
|
|
1417
|
+
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
|
|
1418
|
+
vec4 viewPosition = modelViewMatrix * vec4(position, 1.0);
|
|
1419
|
+
vec4 base = projectionMatrix * modelViewMatrix * vec4(basePosition, 1.0);
|
|
1420
|
+
vMakeupCamera = base.xyw;
|
|
1421
|
+
vMakeupUv = uv;
|
|
1422
|
+
vMakeupRest = restPosition;
|
|
1423
|
+
vMakeupNormal = normalMatrix * normal;
|
|
1424
|
+
vMakeupFlakeNormal = normalMatrix * restNormal;
|
|
1425
|
+
vMakeupViewPosition = viewPosition.xyz;
|
|
1426
|
+
vMakeupEdge = edge;
|
|
1427
|
+
vMakeupLipEdge = lipEdge;
|
|
1428
|
+
vMakeupEyeRing = eyeRing;
|
|
1429
|
+
vMakeupHeadUp = normalMatrix * vec3(0.0, 1.0, 0.0);
|
|
1430
|
+
#ifdef ${qu}
|
|
1431
|
+
makeupWriteSkinStats();
|
|
1432
|
+
#else
|
|
1433
|
+
// No probe bound (a custom material without skin.uniforms): "not ready".
|
|
1434
|
+
vMakeupSkinSlow = vec3(0.0);
|
|
1435
|
+
vMakeupSkinReady = 0.0;
|
|
1436
|
+
vMakeupSkinFast = vec3(0.0);
|
|
1437
|
+
vMakeupLight = vec4(0.0);
|
|
1438
|
+
vMakeupLipColor = vec3(0.0);
|
|
1439
|
+
vMakeupBrowColor = vec3(0.0);
|
|
1440
|
+
#endif
|
|
1441
|
+
|
|
1442
|
+
vFaceUv = faceUv;
|
|
1443
|
+
vUv = uv;
|
|
1444
|
+
vLipEdge = lipEdge;
|
|
1445
|
+
vNormal = normalize(normalMatrix * normal);
|
|
1446
|
+
vViewDir = -viewPosition.xyz;
|
|
1447
|
+
}
|
|
1448
|
+
`,sg=`
|
|
1449
|
+
uniform sampler2D uDesignMap;
|
|
1450
|
+
uniform sampler2D uLowerDesignMap;
|
|
1451
|
+
uniform vec2 uDesignDecode;
|
|
1452
|
+
uniform vec3 uLowerColor;
|
|
1453
|
+
uniform float uLowerAuto;
|
|
1454
|
+
uniform vec2 uLipOpacity;
|
|
1455
|
+
uniform float uIntensity;
|
|
1456
|
+
uniform float uShading;
|
|
1457
|
+
uniform float uGloss;
|
|
1458
|
+
uniform float uRoughness;
|
|
1459
|
+
uniform vec3 uHighlightColor;
|
|
1460
|
+
uniform vec3 uGradientColor;
|
|
1461
|
+
uniform float uGradientAmount;
|
|
1462
|
+
uniform float uGradientDirection;
|
|
1463
|
+
uniform float uEdgeSoftness;
|
|
1464
|
+
uniform vec3 uInnerLipColor;
|
|
1465
|
+
uniform float uInnerLipAmount;
|
|
1466
|
+
uniform float uInnerLipWidth;
|
|
1467
|
+
uniform float uMouthLineV;
|
|
1468
|
+
uniform vec2 uLipMin;
|
|
1469
|
+
uniform vec2 uLipSize;
|
|
1470
|
+
uniform mat3 uTextureTransform;
|
|
1471
|
+
|
|
1472
|
+
// sRGB -> linear, for design textures the GPU does not decode (no SRGBColorSpace tag).
|
|
1473
|
+
vec3 lipDecodeSrgb(vec3 c) {
|
|
1474
|
+
vec3 x = max(c, vec3(0.0));
|
|
1475
|
+
return mix(
|
|
1476
|
+
pow(x * 0.9478672986 + vec3(0.0521327014), vec3(2.4)),
|
|
1477
|
+
x * 0.0773993808,
|
|
1478
|
+
vec3(lessThanEqual(x, vec3(0.04045)))
|
|
1479
|
+
);
|
|
1480
|
+
}
|
|
1481
|
+
|
|
1482
|
+
vec4 lipDesign(sampler2D map, vec2 uv, float decode) {
|
|
1483
|
+
vec4 texel = texture(map, uv);
|
|
1484
|
+
return vec4(mix(texel.rgb, lipDecodeSrgb(texel.rgb), decode), texel.a);
|
|
1485
|
+
}
|
|
1486
|
+
|
|
1487
|
+
// Lips are darker and redder than the skin: against the skin (Rs) their own
|
|
1488
|
+
// colour would read as shadow. Re-base the light terms on the person's own
|
|
1489
|
+
// lip colour (the probe's settled lip average): Rs' = lip, the local low-pass
|
|
1490
|
+
// scaled to the lip's level (same local light, highlight above the lip), Rf
|
|
1491
|
+
// keeping its light colour (lipEffectReferenceSample).
|
|
1492
|
+
MakeupSample lipReferenceSample(MakeupSample s) {
|
|
1493
|
+
float w = s.ready * step(MAKEUP_EPSILON, makeupLuma(vMakeupLipColor));
|
|
1494
|
+
if (w <= 0.0) return s;
|
|
1495
|
+
float lumSlow = max(makeupLuma(s.skinSlow), MAKEUP_EPSILON);
|
|
1496
|
+
float lumFast = max(makeupLuma(s.skinFast), MAKEUP_EPSILON);
|
|
1497
|
+
vec3 lip = mix(s.skinSlow, vMakeupLipColor, w);
|
|
1498
|
+
float level = max(makeupLuma(lip), MAKEUP_EPSILON) / lumSlow;
|
|
1499
|
+
vec3 lightCast = (s.skinFast / lumFast) / max(s.skinSlow / lumSlow, vec3(MAKEUP_EPSILON));
|
|
1500
|
+
s.skinFast = lip * lightCast * (lumFast / lumSlow);
|
|
1501
|
+
s.skinLocal = s.skinLocal * level;
|
|
1502
|
+
s.skinSlow = lip;
|
|
1503
|
+
return s;
|
|
1504
|
+
}
|
|
1505
|
+
|
|
1506
|
+
// shading < 1 flattens the light the paint follows: the skin references move
|
|
1507
|
+
// toward this pixel's own light, so S, the local clip and the light colour go
|
|
1508
|
+
// to neutral and the camera highlight to 0 (lipEffectShadingSample).
|
|
1509
|
+
MakeupSample lipShadingSample(MakeupSample s, float shading) {
|
|
1510
|
+
float t = clamp(shading, 0.0, 1.0);
|
|
1511
|
+
if (t >= ${I(xn.fullShading)}) return s;
|
|
1512
|
+
float lumC = max(makeupLuma(s.camera), MAKEUP_EPSILON);
|
|
1513
|
+
float lumSlow = max(makeupLuma(s.skinSlow), MAKEUP_EPSILON);
|
|
1514
|
+
float lumLocal = max(makeupLuma(s.skinLocal), MAKEUP_EPSILON);
|
|
1515
|
+
float lumFast = max(makeupLuma(s.skinFast), MAKEUP_EPSILON);
|
|
1516
|
+
float ratio = clamp(lumC / lumSlow, MAKEUP_EPSILON, ${I(nt.maxRatio)});
|
|
1517
|
+
float local = clamp(lumLocal / lumSlow, 0.0, ${I(nt.maxRatio)});
|
|
1518
|
+
float slow = lumC / mix(1.0, ratio, t);
|
|
1519
|
+
vec3 fast = mix(s.skinSlow / lumSlow, s.skinFast / lumFast, t);
|
|
1520
|
+
s.skinLocal = s.skinLocal * (mix(1.0, local, t) * slow / lumLocal);
|
|
1521
|
+
s.skinFast = fast * (lumFast * slow / lumSlow);
|
|
1522
|
+
s.skinSlow = s.skinSlow * (slow / lumSlow);
|
|
1523
|
+
return s;
|
|
1524
|
+
}
|
|
1525
|
+
|
|
1526
|
+
// alpha.8's lip highlight (gloss, roughness, highlightColor), on top of the
|
|
1527
|
+
// finish: lit by the probe's light (or the key light), dimmed with the local
|
|
1528
|
+
// light level, scaled by the product's amount.
|
|
1529
|
+
vec3 lipHighlight(MakeupSample s, float amount) {
|
|
1530
|
+
vec3 h = normalize(s.light + s.viewDir);
|
|
1531
|
+
float exponent = mix(${I(xn.highlightSharp)}, ${I(xn.highlightBroad)}, clamp(uRoughness, 0.0, 1.0));
|
|
1532
|
+
float gate = smoothstep(0.0, 0.2, dot(s.normal, s.light));
|
|
1533
|
+
float level = clamp(makeupLighting(s, 0.0).local, 0.0, ${I(nt.maxLightLevel)});
|
|
1534
|
+
float specular = pow(max(dot(s.normal, h), 0.0), exponent);
|
|
1535
|
+
return uHighlightColor * (clamp(uGloss, 0.0, 1.0) * amount * level * gate * specular);
|
|
1536
|
+
}
|
|
1537
|
+
|
|
1538
|
+
void main() {
|
|
1539
|
+
MakeupSample s = makeupSample();
|
|
1540
|
+
float upper = smoothstep(${I(-xn.seam)}, ${I(xn.seam)}, s.uv.y - uMouthLineV);
|
|
1541
|
+
// Designs are painted as on an unmirrored photo (image-left = the person's
|
|
1542
|
+
// right): on the mirrored webcam the person's sides swap, so read (1 - u, v).
|
|
1543
|
+
vec2 lipUv = uPersonLeftSign < 0.0 ? vec2(1.0 - s.uv.x, s.uv.y) : s.uv;
|
|
1544
|
+
vec2 designUv = (uTextureTransform * vec3(lipUv, 1.0)).xy;
|
|
1545
|
+
vec4 design = mix(
|
|
1546
|
+
lipDesign(uLowerDesignMap, designUv, uDesignDecode.y),
|
|
1547
|
+
lipDesign(uDesignMap, designUv, uDesignDecode.x),
|
|
1548
|
+
upper
|
|
1549
|
+
);
|
|
1550
|
+
|
|
1551
|
+
vec3 shade = makeupShade(s);
|
|
1552
|
+
vec3 tint = mix(mix(uLowerColor, shade, uLowerAuto), shade, upper);
|
|
1553
|
+
float gradientT = uGradientDirection < 0.5
|
|
1554
|
+
? 1.0 - vMakeupLipEdge
|
|
1555
|
+
: uGradientDirection < 1.5
|
|
1556
|
+
? clamp((lipUv.y - uLipMin.y) / max(uLipSize.y, 1e-4), 0.0, 1.0)
|
|
1557
|
+
: clamp((lipUv.x - uLipMin.x) / max(uLipSize.x, 1e-4), 0.0, 1.0);
|
|
1558
|
+
tint = mix(tint, uGradientColor, gradientT * clamp(uGradientAmount, 0.0, 1.0));
|
|
1559
|
+
float inner = smoothstep(1.0 - max(uInnerLipWidth, 1e-4), 1.0, vMakeupLipEdge);
|
|
1560
|
+
tint = mix(tint, uInnerLipColor, inner * clamp(uInnerLipAmount, 0.0, 1.0));
|
|
1561
|
+
vec3 pigment = mix(design.rgb, design.rgb * tint, clamp(uIntensity, 0.0, 1.0));
|
|
1562
|
+
|
|
1563
|
+
float feather = uEdgeSoftness > 0.0 ? smoothstep(0.0, uEdgeSoftness, vMakeupLipEdge) : 1.0;
|
|
1564
|
+
float lipOpacity = mix(uLipOpacity.y, uLipOpacity.x, upper);
|
|
1565
|
+
float mask = design.a * feather * (uOpacity > MAKEUP_EPSILON ? lipOpacity / uOpacity : 0.0);
|
|
1566
|
+
|
|
1567
|
+
MakeupSample lit = lipShadingSample(lipReferenceSample(s), uShading);
|
|
1568
|
+
MakeupLayer layer = makeupFinish(lit, pigment, mask);
|
|
1569
|
+
layer.highlight += lipHighlight(lit, clamp(mask, 0.0, 1.0) * lit.fade * clamp(uOpacity, 0.0, 1.0));
|
|
1570
|
+
makeupOutput(lit, layer);
|
|
1571
|
+
}
|
|
1572
|
+
`,Yu=[fe.common,fe.shading,fe.sparkle,fe.finish,sg].join(`
|
|
1573
|
+
`),st=(e,t,n)=>({x:e*n,y:(1-t)*n}),rg=(e,t)=>({u:1-e,v:t}),Ge={face:"#64748b",skin:"#d4a373",lips:"#e85d75",mouth:"#2563eb",eyes:"#0ea5e9",lids:"#8b5cf6",brows:"#78350f",cheeks:"#f97316",nose:"#10b981",forehead:"#eab308",jaw:"#6366f1",wireframe:"#94a3b8",text:"#0f172a",frame:"#cbd5e1"},og=["lips","mouth","eyes","lids","brows","cheeks","nose","forehead","jaw"],ig=new Set(["eyes","lids","brows","cheeks"]),cg={lids:.05,lips:.03,mouth:-.035},Ne=e=>Number(e.toFixed(2)).toString(),lg=e=>e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">"),ug=(e,t)=>e<t?e*65536+t:t*65536+e,hg=e=>{const t=new Map;return e.forEach(n=>{const[a,s,r]=T.FACE_ATLAS_TRIANGLES.subarray(n*3,n*3+3);[[a,s],[s,r],[r,a]].forEach(([o,i])=>{const c=ug(o,i),u=t.get(c);t.set(c,u?[o,i,u[2]+1]:[o,i,1])})}),[...t.values()].filter(([,,n])=>n===1)},Jn=(e={})=>{const{size:t=1024,regions:n=og,wireframe:a=!0,labels:s=!0,background:r}=e,o=m=>{const{x:E,y:S}=st(T.FACE_ATLAS_UVS[m*2],T.FACE_ATLAS_UVS[m*2+1],t);return`${Ne(E)},${Ne(S)}`},i=m=>{const E=[];for(let S=0;S<m.length;S+=1){const g=m[S],[A,v,M]=T.FACE_ATLAS_TRIANGLES.subarray(g*3,g*3+3);E.push(`M${o(A)}L${o(v)}L${o(M)}Z`)}return E.join("")},c=t/100,u=c*.25,l=c*1.6,h=`font-family="ui-monospace, SFMono-Regular, Menlo, monospace" font-size="${Ne(l)}" fill="${Ge.text}"`,f=(m,E,S,g="middle",A="")=>`<text x="${Ne(m)}" y="${Ne(E)}" text-anchor="${g}" ${h}${A}>${lg(S)}</text>`,p=[];if(r&&p.push(`<rect width="${t}" height="${t}" fill="${r}"/>`),p.push(`<rect x="${Ne(u/2)}" y="${Ne(u/2)}" width="${Ne(t-u)}" height="${Ne(t-u)}" fill="none" stroke="${Ge.frame}" stroke-width="${Ne(u)}"/>`),a){const m=Array.from({length:T.FACE_ATLAS_SOURCE.triangleCount},(E,S)=>S);p.push(`<path d="${i(m)}" fill="none" stroke="${Ge.wireframe}" stroke-width="${Ne(u*.4)}" stroke-linejoin="round"/>`)}if(n.forEach(m=>{const E=T.getFaceAtlasRegionTriangles(m),S=Ge[m],g=hg(E).map(([A,v])=>`M${o(A)}L${o(v)}`).join("");p.push(`<path d="${i(E)}" fill="${S}" fill-opacity="0.18" stroke="none"/>`,`<path d="${g}" fill="none" stroke="${S}" stroke-width="${Ne(u)}" stroke-linecap="round"/>`)}),s){n.forEach(g=>{const A=new Map;T.getFaceAtlasRegionTriangles(g).forEach(v=>{let M=0,y=0,x=0;for(let k=0;k<3;k+=1){const R=T.FACE_ATLAS_TRIANGLES[v*3+k];M+=T.FACE_ATLAS_UVS[R*2]/3,y+=T.FACE_ATLAS_UVS[R*2+1]/3,x+=V.CANONICAL_FACE_POSITIONS[R*3]/3}const F=ig.has(g)?x<0?"negX":"posX":"all",w=A.get(F)??{u:0,v:0,n:0};A.set(F,{u:w.u+M,v:w.v+y,n:w.n+1})}),A.forEach(({u:v,v:M,n:y})=>{const{x,y:F}=st(v/y,M/y+(cg[g]??0),t);p.push(f(x,F+l*.35,g,"middle",' font-weight="bold" fill-opacity="0.85"'))})});const m=c*2.5,E=l*1.3,S=[`${t}×${t}: FACE_ATLAS_UVS, the LipEffect / Canonical_Face_Color.png layout.`,"Paint as on an unmirrored photo: image LEFT = the person's RIGHT.","Mirror art by u → 1 − u (exact). Not CANONICAL_FACE_UVS."];p.push(f(m,m+l,"Face atlas template","start",' font-weight="bold"'),...S.map((g,A)=>f(m,m+l+E*(A+1),g,"start")),f(t*.25,t-m,"◂ person's RIGHT","middle",' font-weight="bold"'),f(t*.75,t-m,"person's LEFT ▸","middle",' font-weight="bold"'),f(t-m,t-m-E,"generated from canonical_face_model.obj","end"))}return`<svg xmlns="http://www.w3.org/2000/svg" width="${t}" height="${t}" viewBox="0 0 ${t} ${t}">${p.join("")}</svg>`},fg=e=>`data:image/svg+xml;charset=utf-8,${encodeURIComponent(Jn(e))}`,mo=(e,t,n)=>new Promise((a,s)=>{const r=new Image;r.onload=()=>{const o=document.createElement("canvas");o.width=t,o.height=t;const i=o.getContext("2d");if(!i){s(new Error(`${n}: 2D canvas context unavailable`));return}i.drawImage(r,0,0,t,t),o.toBlob(c=>{c?a(c):s(new Error(`${n}: PNG encoding failed`))},"image/png")},r.onerror=()=>s(new Error(`${n}: could not rasterize the SVG`)),r.src=`data:image/svg+xml;charset=utf-8,${encodeURIComponent(e)}`}),pg=(e={})=>mo(Jn(e),e.size??1024,"face atlas guide"),dg={minU:.382,maxU:.618,minV:.263,maxV:.35,mouthV:.305},kr={outerRing:Ge.lips,innerRing:Ge.mouth,wireframe:Ge.wireframe,text:Ge.text,frame:Ge.frame},Ca=st,Yi=(e,t,n)=>{const a={minU:1/0,maxU:-1/0,minV:1/0,maxV:-1/0};t.forEach(r=>{const o=e[r*2],i=e[r*2+1];a.minU=Math.min(a.minU,o),a.maxU=Math.max(a.maxU,o),a.minV=Math.min(a.minV,i),a.maxV=Math.max(a.maxV,i)});const s=n.reduce((r,o)=>r+e[o*2+1],0)/n.length;return{...a,mouthV:s}};let Fs=null;const gn=e=>e?Yi(e.uvs,oe.CANONICAL_OUTER_LIP_RING,oe.CANONICAL_INNER_LIP_RING):(Fs||(Fs=Object.freeze(Yi(T.FACE_ATLAS_UVS,T.FACE_ATLAS_LIP_RINGS.outer,T.FACE_ATLAS_LIP_RINGS.inner))),Fs),mg=e=>typeof e=="object"&&e!==null&&"uvs"in e&&"lipIndices"in e,Qu=(e,t)=>mg(e)?t??{}:e??{},ze=e=>Number(e.toFixed(2)).toString(),gg=e=>e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">"),Sg=e=>e.slice(e.indexOf(">")+1,e.lastIndexOf("</svg>")),go=(e,t)=>{const{size:n=1024,region:a="canvas",wireframe:s=!0,labels:r=!0,background:o}=Qu(e,t),i=gn(),c=y=>{const{x,y:F}=Ca(T.FACE_ATLAS_UVS[y*2],T.FACE_ATLAS_UVS[y*2+1],n);return`${ze(x)},${ze(F)}`},u=Ca(i.minU,i.maxV,n),l=Ca(i.maxU,i.minV,n),h=l.x-u.x,f=l.y-u.y,p=(u.x+l.x)/2,m=a==="lips"?Math.max(h,f)*.45:0,E=a==="lips"?[u.x-m,u.y-m,h+m*2,f+m*2]:[0,0,n,n],S=E[2]/100,g=S*.25,A=S*1.6,v=`font-family="ui-monospace, SFMono-Regular, Menlo, monospace" font-size="${ze(A)}" fill="${kr.text}"`,M=[Sg(Jn({size:n,regions:["lips","mouth"],wireframe:!1,labels:!1,background:o}))];if(s){const y=T.getFaceAtlasRegionTriangles("lips"),x=[];y.forEach(F=>{const[w,k,R]=T.FACE_ATLAS_TRIANGLES.subarray(F*3,F*3+3);x.push(`M${c(w)}L${c(k)}L${c(R)}Z`)}),M.push(`<path d="${x.join("")}" fill="none" stroke="${kr.wireframe}" stroke-width="${ze(g*.5)}" stroke-linejoin="round"/>`)}if(r){const y=S*1.2,x=A*1.3,F=(k,R,b,N="middle",P="")=>`<text x="${ze(k)}" y="${ze(R)}" text-anchor="${N}" ${v}${P}>${gg(b)}</text>`,w=(u.y+l.y)/2;if(M.push(F(u.x-y,w,"person's RIGHT ▸","end"),F(l.x+y,w,"◂ person's LEFT","start"),F(p,u.y-y,"upper lip (pink outline = painted edge)"),F(p,l.y+y+A,"lower lip · blue = mouth interior, cut out in outer-and-inner-lips mode"),F(p,l.y+y+A+x,`lip region: u ${ze(i.minU)}–${ze(i.maxU)}, v ${ze(i.minV)}–${ze(i.maxV)} (image x ${Math.round(i.minU*100)}–${Math.round(i.maxU*100)}%, y ${Math.round((1-i.maxV)*100)}–${Math.round((1-i.minV)*100)}%)`)),a==="canvas"){const k=S*2.5,R=[`${n}×${n} canvas: the face atlas (FACE_ATLAS_UVS, as Canonical_Face_Color.png).`,"Only the lip triangles are sampled; transparent pixels leave the skin untouched.","Paint as on an unmirrored photo: image LEFT = the person's RIGHT on every feed","(the SDK flips the design on the mirrored webcam)."];M.push(F(k,k+A,"Lip template: the face atlas","start",' font-weight="bold"'),...R.map((b,N)=>F(k,k+A+x*(N+1),b,"start")),F(k,n-k,"generated from the bundled face atlas data","start"))}}return`<svg xmlns="http://www.w3.org/2000/svg" width="${n}" height="${n}" viewBox="${E.map(ze).join(" ")}">${M.join("")}</svg>`},Eg=(e,t)=>`data:image/svg+xml;charset=utf-8,${encodeURIComponent(go(e,t))}`,Ag=(e,t)=>{const n=Qu(e,t);return mo(go(n),n.size??1024,"lip UV guide")};let fa=null;const vg=()=>(fa||(fa=new d.DataTexture(new Uint8Array([255,255,255,255]),1,1),fa.needsUpdate=!0),fa),Lr=e=>e.isRenderTargetTexture||e.colorSpace===d.SRGBColorSpace||e.colorSpace===d.LinearSRGBColorSpace?0:1,Ju=new WeakMap,Zu=new WeakSet,Mg=(e,t)=>{Ju.set(e,t)},yg=(e,t)=>{const n=Ju.get(t);if(!n)return!1;const a=e.uniforms;return a.uCameraMap.value=n.layer.uCameraMap.value,a.uPresence.value=n.layer.uPresence.value,a.uPersonLeftSign.value=n.layer.uPersonLeftSign.value,a.uSkinMap.value=n.skin.uSkinMap.value,a.uSkinLod.value=n.skin.uSkinLod.value,a.uSkinSqrt.value=n.skin.uSkinSqrt.value,a.uSkinStats.value=n.skin.uSkinStats.value,a.uSkinStatsPacked.value=n.skin.uSkinStatsPacked.value,a.uSparkleQuality.value=n.sparkleQuality.value,e.uniformsNeedUpdate=!0,!0},eh=e=>e instanceof d.Material&&Zu.has(e),So=()=>{const e={...Wu(),uSkinStatsPacked:{value:0},uDesignMap:{value:null},uLowerDesignMap:{value:null},uDesignDecode:{value:new d.Vector2},uLowerColor:{value:new d.Color},uLowerAuto:{value:0},uLipOpacity:{value:new d.Vector2(1,1)},uIntensity:{value:1},uShading:{value:1},uGloss:{value:0},uRoughness:{value:.5},uHighlightColor:{value:new d.Color},uGradientColor:{value:new d.Color},uGradientAmount:{value:0},uGradientDirection:{value:0},uEdgeSoftness:{value:0},uInnerLipColor:{value:new d.Color},uInnerLipAmount:{value:0},uInnerLipWidth:{value:0},uMouthLineV:{value:gn().mouthV},uLipMin:{value:new d.Vector2},uLipSize:{value:new d.Vector2},uTextureTransform:{value:new d.Matrix3}},t=new d.ShaderMaterial({name:"LipEffectMaterial",defines:{[qu]:""},uniforms:e,vertexShader:Xu,fragmentShader:Yu,...de.MAKEUP_BLENDING,side:d.DoubleSide,depthTest:!0,depthFunc:d.LessEqualDepth,depthWrite:!1,toneMapped:!1,stencilWrite:!0,stencilRef:de.FACE_ATLAS_STENCIL.mouth,stencilFuncMask:de.FACE_ATLAS_STENCIL.mouth,stencilWriteMask:0,stencilFunc:d.AlwaysStencilFunc,stencilFail:d.KeepStencilOp,stencilZFail:d.KeepStencilOp,stencilZPass:d.KeepStencilOp});return t.onBeforeRender=(n,a,s,r)=>{yg(t,r)},Zu.add(t),t},Eo=(e,{cameraTexture:t,designTexture:n,lowerDesignTexture:a=null,settings:s,lipUvBounds:r=gn(),subtractMouth:o=!1,personLeftSign:i=1})=>{const c=e.uniforms,u=vg(),l=s.colorMode==="solid",h=l?u:n??u,f=l?u:s.splitLips?a??n??u:h;c.uCameraMap.value=t,c.uDesignMap.value=h,c.uLowerDesignMap.value=f,c.uDesignDecode.value.set(Lr(h),Lr(f)),c.uPersonLeftSign.value=i;const p=s.shade==="auto";c.uColor.value.set(s.color),c.uAutoShade.value=p?Re.lips:Re.none,c.uLowerColor.value.set(s.splitLips?s.lowerLipColor:s.color),c.uLowerAuto.value=p&&!s.splitLips?1:0;const m=ag(s);c.uOpacity.value=m.opacity,c.uLipOpacity.value.set(m.upper,m.lower),c.uCoverage.value=s.coverage,c.uFinish.value=Ze[s.finish],c.uShine.value=s.shine;const E=s.sparkleColor.trim();return c.uSparkleAuto.value=E?0:1,E&&c.uSparkleColor.value.set(E),c.uSparkleDensity.value=s.sparkleDensity,c.uSparkleSize.value=s.sparkleSize,c.uIntensity.value=s.intensity,c.uShading.value=s.shading,c.uGloss.value=s.gloss,c.uRoughness.value=s.roughness,c.uHighlightColor.value.set(s.highlightColor),c.uGradientColor.value.set(s.gradientColor),c.uGradientAmount.value=s.gradientAmount,c.uGradientDirection.value=O.LIP_EFFECT_GRADIENT_DIRECTIONS.indexOf(s.gradientDirection),c.uEdgeSoftness.value=s.edgeSoftness,c.uInnerLipColor.value.set(s.innerLipColor),c.uInnerLipAmount.value=s.innerLipAmount,c.uInnerLipWidth.value=s.innerLipWidth,c.uMouthLineV.value=r.mouthV,c.uLipMin.value.set(r.minU,r.minV),c.uLipSize.value.set(r.maxU-r.minU,r.maxV-r.minV),O.createLipTextureTransform(s,r,c.uTextureTransform.value),e.stencilFunc=o?d.NotEqualStencilFunc:d.AlwaysStencilFunc,e},Rr=(e,t)=>{const n=_.useMemo(()=>t?So():null,[t]);return _.useEffect(()=>()=>n==null?void 0:n.dispose(),[n]),n&&Eo(n,e),n},th=e=>{const t=_.useMemo(So,[]);return _.useEffect(()=>()=>t.dispose(),[t]),Eo(t,e),t},nh=e=>{const t=th(e);return L.jsx("primitive",{object:t,attach:"material"})},Ao=(e,t)=>{const[n,a]=J.useLoader(d.TextureLoader,[typeof e=="string"?e:mi.TRANSPARENT_TEXTURE_DATA_URL,typeof t=="string"?t:mi.TRANSPARENT_TEXTURE_DATA_URL]);return{designTexture:typeof e=="string"?n:e??null,lowerDesignTexture:typeof t=="string"?a:t??null}},ah=e=>(e??O.DEFAULT_LIP_EFFECT_SETTINGS.maskMode)==="outer-and-inner-lips";let xs=null;const wg=()=>(xs||(xs=new d.MeshBasicMaterial({name:"LipEffectMouthStencil",colorWrite:!1,depthWrite:!1,depthTest:!1,side:d.DoubleSide,stencilWrite:!0,stencilRef:de.FACE_ATLAS_STENCIL.mouth,stencilWriteMask:de.FACE_ATLAS_STENCIL.mouth,stencilFuncMask:de.FACE_ATLAS_STENCIL.mouth,stencilFunc:d.AlwaysStencilFunc,stencilFail:d.KeepStencilOp,stencilZFail:d.KeepStencilOp,stencilZPass:d.ReplaceStencilOp})),xs),_g=(e,t,n)=>{let a=e.get(t);return(!a||a.skin!==n)&&(a={skin:n,merged:{...t,...n}},e.set(t,a)),a.merged},Fg=e=>eh(e)||_.isValidElement(e)&&e.type===nh,xg=({faceUv:e,material:t,sharedMaterial:n})=>e!==void 0?e:n?!eh(n):t!=null&&!Fg(t),sh=({faceIndex:e,numFaces:t,mirrored:n,designTexture:a,lowerDesignTexture:s,material:r,sharedMaterial:o,faceUv:i,holdMs:c,renderOrder:u=Wa,...l})=>{const h=O.resolveLipEffectSettings(l),{enabled:f}=h,p=Ao(f?a:void 0,f?s:void 0),m=ae.useXRCameraTexture()??null,E=ae.useXRMirrored(),S=ee.personLeftSign(n??E),g=ge(),A=Te.useTrackerContext(),v=T.resolveFaceAtlasBinding({faceIndex:e,numFaces:t,rigFaceIndex:g?g.current.faceIndex:null,trackerFaceIndex:(A==null?void 0:A.type)==="face"?A.faceIndex??0:null}).faceIndex,M=Va({faceIndex:v,enabled:f}),{index:y,tiers:x}=Pn.useXRQuality(),F=_.useMemo(()=>({value:1}),[]),w=_.useMemo(()=>new WeakMap,[]);F.value=xu(y,x.length)==="low"?0:1;const k=gn(),R=ah(h.maskMode),b=f&&!o&&!r,N={cameraTexture:m,...p,settings:h,lipUvBounds:k,personLeftSign:S},P=Rr({...N,subtractMouth:R},b),G=Rr({...N,subtractMouth:!1},b&&!R);if(!f)return null;const U=xg({faceUv:i,material:r,sharedMaterial:o}),H=X=>j=>{const D={layer:j.uniforms,skin:M.uniforms,sparkleQuality:F};if(Mg(j.geometry,D),o)return o;if(r){const $={cameraTexture:m,designTexture:p.designTexture,lowerDesignTexture:p.lowerDesignTexture,faceUv:j.geometry.getAttribute("faceUv"),lipEdge:j.geometry.getAttribute("lipEdge"),restPosition:j.geometry.getAttribute("restPosition"),faceIndex:j.faceIndex,maskMode:h.maskMode,lipUvBounds:k,settings:h,personLeftSign:j.personLeftSign,skin:M,uniforms:_g(w,j.uniforms,M.uniforms)};return typeof r=="function"?r($):r}return X},z={faceIndex:e,numFaces:t,holdMs:c,mirrored:n};return L.jsxs(L.Fragment,{children:[L.jsx(Cr,{...z,region:"mouth",renderOrder:u-Fm,material:R?wg():H(G),faceUv:U&&!R}),L.jsx(Cr,{...z,region:"lips",renderOrder:u,material:H(P),faceUv:U})]})},rh={},oh=(e,t)=>typeof e=="function"?e(t):e??rh,Cg=({maxFaces:e=2,faces:t,shareMaterial:n=typeof t!="function",holdMs:a,renderOrder:s=Wa})=>{const r=typeof t=="function"?rh:t,{designTexture:o,lowerDesignTexture:i,material:c,sharedMaterial:u,...l}=r,h=O.resolveLipEffectSettings(l),f=h.enabled&&n&&!c&&!u,p=Ao(f?o:void 0,f?i:void 0),m=ae.useXRCameraTexture()??null,E=ae.useXRMirrored(),S=Rr({cameraTexture:m,...p,settings:h,lipUvBounds:gn(),subtractMouth:ah(h.maskMode),personLeftSign:ee.personLeftSign(r.mirrored??E)},f),g=u??S??void 0,A=Math.max(0,Math.round(e));return L.jsx(L.Fragment,{children:Array.from({length:A},(v,M)=>{const y=oh(t,M);return y?L.jsx(sh,{numFaces:A,...y,faceIndex:M,sharedMaterial:y.sharedMaterial??g,holdMs:y.holdMs??a,renderOrder:y.renderOrder??s},M):null})})},ih=23.5,Qi={region:"skin",erodeCm:.5},Tg=[.75,1],kg=(e=128,t="top")=>{const n=Qi.erodeCm/ih*e*.43,a=Math.max(1,Math.round(Math.sqrt(n*n+.25)-.5)),s=Xn({include:Qi.region,size:e,feather:a*2/e,origin:t}),r=s.data,[o,i]=Tg;for(let c=0;c<r.length;c+=1){const u=Math.min(1,Math.max(0,(r[c]/255-o)/(i-o)));r[c]=Math.round(u*u*(3-2*u)*255)}return s},Ji=new Map,ch=(e=128)=>{let t=Ji.get(e);if(!t){const n=kg(e,"bottom");t=new Ae.DataTexture(new Uint8Array(n.data.buffer,n.data.byteOffset,n.data.length),n.width,n.height,Ae.RedFormat,Ae.UnsignedByteType),t.flipY=!1,t.unpackAlignment=1,t.magFilter=Ae.LinearFilter,t.minFilter=Ae.LinearFilter,t.generateMipmaps=!1,t.needsUpdate=!0,Ji.set(e,t)}return t},vo=_.createContext(null),lh=(e={})=>{const t=e.enabled!==!1,n=J.useThree(l=>l.gl),a=ae.useXRCameraTexture(),[s,r]=_.useState(null),[o,i]=_.useState(!1),c=_.useRef(!1);_.useEffect(()=>{if(!t)return;const l=T.acquireMadeUpCamera(n);return c.current=l.ready,r(l),i(l.ready),()=>{T.releaseMadeUpCamera(n,l),c.current=!1,r(h=>h===l?null:h),i(!1)}},[n,t]);const u=_.useRef(a);return u.current=a,J.useFrame(l=>{s&&(s.renderOnce(l.clock.elapsedTime,l.gl,l.scene,l.camera,u.current??null),c.current!==s.ready&&(c.current=s.ready,i(s.ready)))},T.MADE_UP_CAMERA_FRAME_PRIORITY),_.useMemo(()=>s?{texture:s.texture,ready:o,get frame(){return s.frame},get width(){return s.width},get height(){return s.height}}:null,[s,o])},Lg=({children:e,enabled:t})=>{const n=lh({enabled:t});return L.jsx(vo.Provider,{value:n,children:e})},Rg=()=>_.useContext(vo),qa=()=>{const e=_.useContext(vo),t=ae.useXRCameraTexture();return e!=null&&e.ready&&t?e.texture:t??null},Mo={lips:O.LIP_EFFECT_PRESET_KEYS,contour:["soft","sculpted","bronzed","nose"],blush:["apples","lifted","draped","sunKissed"],highlighter:["cheekbones","strobe","glow","nose"],eyeshadow:["lid","crease","smoky","cutCrease","halo","winged"],eyeliner:["tightline","classic","winged","catEye","smudged","kohl"],brows:["natural","softArch","straight","highArch","bold","thin"]},yo={lips:O.LIP_EFFECT_PRESETS,contour:{soft:{size:1,softness:.85,coverage:.25},sculpted:{size:1.1,softness:.6,coverage:.4},bronzed:{size:1.3,softness:.9,coverage:.3},nose:{size:.8,softness:.7,coverage:.3}},blush:{apples:{size:.9,lift:-.3,softness:.7,coverage:.35},lifted:{size:1,lift:.4,softness:.7,coverage:.35},draped:{size:1.25,lift:.8,softness:.75,coverage:.4},sunKissed:{size:1.2,lift:.1,softness:.85,coverage:.25}},highlighter:{cheekbones:{size:1,softness:.75,coverage:.4},strobe:{size:1.15,softness:.65,coverage:.5},glow:{size:1.4,softness:.9,coverage:.3},nose:{size:.8,softness:.6,coverage:.45}},eyeshadow:{lid:{height:.45,crease:0,lower:0,inner:0,softness:.6,coverage:.6},crease:{height:.6,crease:.6,lower:0,inner:0,softness:.7,coverage:.55},smoky:{height:.75,crease:.5,lower:.6,inner:0,softness:.85,coverage:.7},cutCrease:{height:.7,crease:.8,lower:0,inner:.3,softness:.35,coverage:.8},halo:{height:.55,crease:.4,lower:.2,inner:.7,softness:.7,coverage:.65},winged:{height:.55,crease:.3,lower:.2,inner:0,softness:.5,coverage:.7}},eyeliner:{tightline:{thickness:.4,wing:0,wingAngle:15,lower:0,smudge:0,softness:.2,coverage:.9},classic:{thickness:1,wing:0,wingAngle:15,lower:0,smudge:0,softness:.25,coverage:1},winged:{thickness:1.2,wing:6,wingAngle:18,lower:0,smudge:0,softness:.2,coverage:1},catEye:{thickness:1.6,wing:10,wingAngle:25,lower:.3,smudge:0,softness:.2,coverage:1},smudged:{thickness:1.4,wing:2,wingAngle:15,lower:.5,smudge:.7,softness:.6,coverage:.8},kohl:{thickness:1.2,wing:0,wingAngle:10,lower:1,smudge:.3,softness:.4,coverage:.95}},brows:{natural:{boldness:.5,fill:.2,strokes:.3,softness:.5,coverage:.6},softArch:{boldness:.55,fill:.3,strokes:.3,softness:.5,coverage:.6},straight:{boldness:.55,fill:.3,strokes:.3,softness:.45,coverage:.6},highArch:{boldness:.6,fill:.35,strokes:.3,softness:.4,coverage:.65},bold:{boldness:.85,fill:.55,strokes:.5,softness:.4,coverage:.7},thin:{boldness:.25,fill:.25,strokes:.2,softness:.35,coverage:.6}}},wo=(e,t)=>typeof t=="string"&&Mo[e].includes(t),Xa={lips:O.DEFAULT_LIP_EFFECT_SETTINGS,contour:{enabled:!0,shape:"soft",shade:"medium",color:O.MAKEUP_SHADES.contour.medium,opacity:.45,coverage:.25,finish:"matte",...O.MAKEUP_FINISH_DEFAULTS.matte,sparkleColor:"",softness:.85,side:"both",size:1},blush:{enabled:!0,shape:"apples",shade:"rose",color:O.MAKEUP_SHADES.blush.rose,opacity:.5,coverage:.35,finish:"satin",...O.MAKEUP_FINISH_DEFAULTS.satin,sparkleColor:"",softness:.7,side:"both",size:.9,lift:-.3},highlighter:{enabled:!0,shape:"cheekbones",shade:"champagne",color:O.MAKEUP_SHADES.highlighter.champagne,opacity:.5,coverage:.4,finish:"shimmer",...O.MAKEUP_FINISH_DEFAULTS.shimmer,sparkleColor:"",softness:.75,side:"both",size:1},eyeshadow:{enabled:!0,shape:"lid",shade:"taupe",color:O.MAKEUP_SHADES.eyeshadow.taupe,opacity:.6,coverage:.6,finish:"satin",...O.MAKEUP_FINISH_DEFAULTS.satin,sparkleColor:"",softness:.6,side:"both",height:.45,crease:0,creaseShade:"warmBrown",creaseColor:O.MAKEUP_SHADES.eyeshadow.warmBrown,lower:0,inner:0,innerShade:"champagne",innerColor:O.MAKEUP_SHADES.eyeshadow.champagne},eyeliner:{enabled:!0,shape:"classic",shade:"black",color:O.MAKEUP_SHADES.eyeliner.black,opacity:.9,coverage:1,finish:"matte",...O.MAKEUP_FINISH_DEFAULTS.matte,sparkleColor:"",softness:.25,side:"both",thickness:1,wing:0,wingAngle:15,lower:0,smudge:0},brows:{enabled:!0,shape:"natural",shade:"mediumBrown",color:O.MAKEUP_SHADES.brows.mediumBrown,opacity:.5,coverage:.6,finish:"matte",...O.MAKEUP_FINISH_DEFAULTS.matte,sparkleColor:"",softness:.5,side:"both",boldness:.5,fill:.2,strokes:.3}},Le=[0,1],Cs=[.5,1.5],jt={opacity:Le,coverage:Le,shine:Le,sparkleDensity:Le,sparkleSize:O.MAKEUP_SPARKLE_SIZE_RANGE,softness:Le},uh={contour:{...jt,size:Cs},blush:{...jt,size:Cs,lift:[-1,1]},highlighter:{...jt,size:Cs},eyeshadow:{...jt,height:Le,crease:Le,lower:Le,inner:Le},eyeliner:{...jt,thickness:[.2,4],wing:[0,15],wingAngle:[0,45],lower:Le,smudge:Le},brows:{...jt,boldness:Le,fill:Le,strokes:Le}},hh={contour:[["shade","color"]],blush:[["shade","color"]],highlighter:[["shade","color"]],eyeshadow:[["shade","color"],["creaseShade","creaseColor"],["innerShade","innerColor"]],eyeliner:[["shade","color"]],brows:[["shade","color"]]},bg=(e,[t,n],a)=>typeof e=="number"&&Number.isFinite(e)?Math.min(n,Math.max(t,e)):a,Ig=(e,t,n)=>typeof t=="string"&&e.includes(t)?t:n,Ng=e=>Object.fromEntries(Object.entries(e).filter(([,t])=>t!==void 0)),fh=e=>typeof e=="string"&&O.MAKEUP_FINISHES.includes(e),ph=(e,t)=>{const n=Xa[e],a=Ng(t),s=a.shape==="custom"||wo(e,a.shape)?a.shape:n.shape,r=s==="custom"?{}:yo[e][s],o={...n,...r},i=fh(a.finish)?a.finish:o.finish,c={...o,...O.MAKEUP_FINISH_DEFAULTS[i]},u={...c,...a},l={};for(const h of Object.keys(n))l[h]=c[h];l.enabled=typeof u.enabled=="boolean"?u.enabled:c.enabled,l.shape=s,l.finish=i,l.side=Ig(O.MAKEUP_SIDES,u.side,c.side),l.sparkleColor=typeof u.sparkleColor=="string"?u.sparkleColor.trim():c.sparkleColor;for(const[h,f]of Object.entries(uh[e]))l[h]=bg(u[h],f,c[h]);for(const[h,f]of hh[e]){const p=O.resolveMakeupShadePair(e,a[h],a[f],c[h],c[f]);l[h]=p.shade,l[f]=p.color}return l};function rt(e,t={}){return e==="lips"?O.resolveLipEffectSettings(t):ph(e,t)}function _o(e,t,n){if(e==="lips")return O.patchLipEffectSettings(t,n);const a=e,s=t,r=n,o=Object.keys(s).some(u=>r[u]===void 0),i=Object.fromEntries(Object.entries(r).filter(([u,l])=>l!==void 0&&(o||l!==s[u]))),c={...s};if(i.shape!==s.shape&&wo(a,i.shape)&&Object.assign(c,yo[a][i.shape]),Object.assign(c,i),c.finish!==s.finish&&fh(c.finish)){Object.assign(c,O.MAKEUP_FINISH_DEFAULTS[c.finish]);for(const u of O.MAKEUP_FINISH_KEYS)i[u]!==void 0&&(c[u]=i[u])}for(const[u,l]of hh[a])i[l]===void 0?c[u]!=="custom"&&delete c[l]:i[u]===void 0&&i[l]!==s[l]&&(c[u]="custom");return ph(a,c)}const me=(e,t,n=.01)=>{const[a,s]=uh[e][t];return{type:"number",min:a,max:s,step:n}},Og=e=>({head:[{key:"enabled",label:"On",type:"boolean"},{key:"shape",label:"Shape",type:"select",options:[{label:"Custom",value:"custom"},...Mo[e].map(t=>({label:O.makeupNameLabel(t),value:t}))]},{key:"shade",label:"Shade",type:"select",options:O.makeupShadeOptions(e)},{key:"color",label:"Color",type:"color"},{key:"opacity",label:"Opacity",...me(e,"opacity")},{key:"coverage",label:"Coverage (sheer → opaque)",...me(e,"coverage")}],finish:[{key:"finish",label:"Finish",type:"select",options:O.MAKEUP_FINISHES.map(t=>({label:O.makeupNameLabel(t),value:t}))},{key:"shine",label:"Shine",...me(e,"shine")},{key:"sparkleColor",label:"Sparkle color (blank = from shade)",type:"text"},{key:"sparkleDensity",label:"Sparkle density",...me(e,"sparkleDensity")},{key:"sparkleSize",label:"Sparkle size (mm)",...me(e,"sparkleSize",.05)}],tail:[{key:"softness",label:"Softness",...me(e,"softness")},{key:"side",label:"Side (the person's own)",type:"select",options:[{label:"Both",value:"both"},{label:"Left only",value:"left"},{label:"Right only",value:"right"}]}]}),Sn=(e,t)=>{const n=Og(e);return[...n.head,...t,...n.finish,...n.tail]},Pg=Sn("blush",[{key:"size",label:"Size",...me("blush","size")},{key:"lift",label:"Lift (toward the temple)",...me("blush","lift")}]),Ug=Sn("contour",[{key:"size",label:"Size",...me("contour","size")}]),Dg=Sn("highlighter",[{key:"size",label:"Size",...me("highlighter","size")}]),Gg=Sn("eyeshadow",[{key:"height",label:"Height (lash line → brow)",...me("eyeshadow","height")},{key:"crease",label:"Crease",...me("eyeshadow","crease")},{key:"creaseShade",label:"Crease shade",type:"select",options:O.makeupShadeOptions("eyeshadow")},{key:"creaseColor",label:"Crease color",type:"color"},{key:"lower",label:"Lower lash line",...me("eyeshadow","lower")},{key:"inner",label:"Inner corner",...me("eyeshadow","inner")},{key:"innerShade",label:"Inner corner shade",type:"select",options:O.makeupShadeOptions("eyeshadow")},{key:"innerColor",label:"Inner corner color",type:"color"}]),$g=Sn("eyeliner",[{key:"thickness",label:"Thickness (mm)",...me("eyeliner","thickness",.05)},{key:"wing",label:"Wing (mm)",...me("eyeliner","wing",.1)},{key:"wingAngle",label:"Wing angle°",...me("eyeliner","wingAngle",1)},{key:"lower",label:"Lower line",...me("eyeliner","lower")},{key:"smudge",label:"Smudge",...me("eyeliner","smudge")}]),Bg=Sn("brows",[{key:"boldness",label:"Boldness",...me("brows","boldness")},{key:"fill",label:"Fill (hairs → powder)",...me("brows","fill")},{key:"strokes",label:"Hair strokes",...me("brows","strokes")}]),Hg={lips:O.LIP_EFFECT_SETTINGS_FIELDS,contour:Ug,blush:Pg,highlighter:Dg,eyeshadow:Gg,eyeliner:$g,brows:Bg},dh=["natural","softGlam","sunKissed","glam","smokyEye","boldLip","editorial","glitter"],Vt={enabled:!1},mh={natural:{label:"Natural",description:"The person's own colouring, gently defined: tinted lips, a warm flush, brows.",lips:{enabled:!0,preset:"tint",shade:"auto",opacity:.6,finish:"satin"},contour:Vt,blush:{enabled:!0,shape:"apples",shade:"auto",opacity:.35,finish:"satin"},highlighter:Vt,eyeshadow:{enabled:!0,shape:"lid",shade:"sand",opacity:.3,finish:"matte"},eyeliner:{enabled:!0,shape:"tightline",shade:"brownBlack",opacity:.6,finish:"matte"},brows:{enabled:!0,shape:"natural",shade:"auto",opacity:.4,finish:"matte"}},softGlam:{label:"Soft glam",description:"Polished and warm: soft contour, rosy cheeks, a champagne glow, satin lips.",lips:{enabled:!0,preset:"lipstick",shade:"rosewood",opacity:.75,finish:"satin"},contour:{enabled:!0,shape:"soft",shade:"medium",opacity:.35,finish:"matte"},blush:{enabled:!0,shape:"lifted",shade:"rose",opacity:.4,finish:"satin"},highlighter:{enabled:!0,shape:"cheekbones",shade:"champagne",opacity:.45,finish:"shimmer"},eyeshadow:{enabled:!0,shape:"crease",shade:"warmBrown",opacity:.55,finish:"satin"},eyeliner:{enabled:!0,shape:"classic",shade:"brownBlack",opacity:.8,finish:"matte"},brows:{enabled:!0,shape:"softArch",shade:"softBrown",opacity:.45,finish:"matte"}},sunKissed:{label:"Sun-kissed",description:"Bronzed warmth on the high points, terracotta cheeks, a gold glow, glossy lips.",lips:{enabled:!0,preset:"gloss",shade:"peach",opacity:.6,finish:"gloss"},contour:{enabled:!0,shape:"bronzed",shade:"bronzeLight",opacity:.4,finish:"satin"},blush:{enabled:!0,shape:"sunKissed",shade:"terracotta",opacity:.4,finish:"satin"},highlighter:{enabled:!0,shape:"glow",shade:"gold",opacity:.45,finish:"shimmer"},eyeshadow:{enabled:!0,shape:"lid",shade:"bronze",opacity:.45,finish:"shimmer"},eyeliner:{enabled:!0,shape:"tightline",shade:"brown",opacity:.7,finish:"matte"},brows:{enabled:!0,shape:"natural",shade:"softBrown",opacity:.35,finish:"matte"}},glam:{label:"Glam",description:"Evening glam: sculpted contour, strobed highlight, a cut crease, winged liner, red lips.",lips:{enabled:!0,preset:"lipstick",shade:"classicRed",opacity:.9,finish:"satin"},contour:{enabled:!0,shape:"sculpted",shade:"tan",opacity:.45,finish:"matte"},blush:{enabled:!0,shape:"draped",shade:"mauve",opacity:.4,finish:"satin"},highlighter:{enabled:!0,shape:"strobe",shade:"champagne",opacity:.55,finish:"shimmer"},eyeshadow:{enabled:!0,shape:"cutCrease",shade:"champagne",opacity:.7,finish:"shimmer",creaseShade:"espresso",innerShade:"ivory"},eyeliner:{enabled:!0,shape:"winged",shade:"black",opacity:.95,finish:"matte"},brows:{enabled:!0,shape:"highArch",shade:"mediumBrown",opacity:.55,finish:"matte"}},smokyEye:{label:"Smoky eye",description:"Charcoal smoked-out eyes with kohl liner, a soft nude lip and a little sculpt.",lips:{enabled:!0,preset:"lipstick",shade:"nude",opacity:.7,finish:"satin"},contour:{enabled:!0,shape:"soft",shade:"medium",opacity:.3,finish:"matte"},blush:{enabled:!0,shape:"lifted",shade:"mauve",opacity:.3,finish:"matte"},highlighter:Vt,eyeshadow:{enabled:!0,shape:"smoky",shade:"charcoal",opacity:.75,finish:"satin",creaseShade:"espresso"},eyeliner:{enabled:!0,shape:"kohl",shade:"black",opacity:.9,finish:"matte"},brows:{enabled:!0,shape:"natural",shade:"darkBrown",opacity:.5,finish:"matte"}},boldLip:{label:"Bold lip",description:"Clean skin and a statement berry lip; everything else stays quiet.",lips:{enabled:!0,preset:"matte",shade:"berry",opacity:.95,finish:"matte"},contour:Vt,blush:{enabled:!0,shape:"apples",shade:"softPink",opacity:.25,finish:"satin"},highlighter:Vt,eyeshadow:Vt,eyeliner:{enabled:!0,shape:"classic",shade:"black",opacity:.8,finish:"matte"},brows:{enabled:!0,shape:"bold",shade:"darkBrown",opacity:.5,finish:"matte"}},editorial:{label:"Editorial",description:"Graphic and fashion-forward: an emerald halo eye, a sharp cat-eye, a metallic plum lip.",lips:{enabled:!0,preset:"metallic",shade:"plum",opacity:.85,finish:"metallic"},contour:{enabled:!0,shape:"sculpted",shade:"tan",opacity:.4,finish:"matte"},blush:{enabled:!0,shape:"draped",shade:"berry",opacity:.4,finish:"matte"},highlighter:{enabled:!0,shape:"strobe",shade:"pearl",opacity:.5,finish:"metallic"},eyeshadow:{enabled:!0,shape:"halo",shade:"emerald",opacity:.7,finish:"shimmer",innerShade:"gold"},eyeliner:{enabled:!0,shape:"catEye",shade:"black",opacity:1,finish:"matte"},brows:{enabled:!0,shape:"straight",shade:"softBlack",opacity:.55,finish:"matte"}},glitter:{label:"Glitter",description:"Party sparkle: glitter lids and lips, a rose-gold strobe, winged liner.",lips:{enabled:!0,preset:"glitter",shade:"softPink",opacity:.75,finish:"glitter"},contour:{enabled:!0,shape:"soft",shade:"medium",opacity:.3,finish:"matte"},blush:{enabled:!0,shape:"lifted",shade:"rose",opacity:.4,finish:"shimmer"},highlighter:{enabled:!0,shape:"strobe",shade:"roseGold",opacity:.55,finish:"shimmer"},eyeshadow:{enabled:!0,shape:"halo",shade:"roseGold",opacity:.75,finish:"glitter",innerShade:"champagne"},eyeliner:{enabled:!0,shape:"winged",shade:"black",opacity:.85,finish:"matte"},brows:{enabled:!0,shape:"softArch",shade:"mediumBrown",opacity:.45,finish:"matte"}}},gh=e=>typeof e=="string"&&dh.includes(e),Zi=e=>e?Object.fromEntries(Object.entries(e).filter(([,t])=>t!==void 0)):{},zg=(e,t={})=>{const n=typeof e=="string"?mh[gh(e)?e:"natural"]:e,a=s=>rt(s,{...Zi(n[s]),...Zi(t[s])});return{lips:a("lips"),contour:a("contour"),blush:a("blush"),highlighter:a("highlighter"),eyeshadow:a("eyeshadow"),eyeliner:a("eyeliner"),brows:a("brows")}},Fo=Object.freeze({enabled:!0,region:"face",color:"",opacity:1,coverage:1,finish:"matte",...O.MAKEUP_FINISH_DEFAULTS.matte,sparkleColor:"",side:"both"}),pa=[0,1],Sh=Object.freeze({opacity:pa,coverage:pa,shine:pa,sparkleDensity:pa,sparkleSize:O.MAKEUP_SPARKLE_SIZE_RANGE}),xo=e=>typeof e=="string"&&O.MAKEUP_FINISHES.includes(e),Kg=e=>typeof e=="string"&&T.FACE_ATLAS_REGIONS.includes(e),jg=(e,[t,n],a)=>typeof e=="number"&&Number.isFinite(e)?Math.min(n,Math.max(t,e)):a,Co=(e,t)=>{if(Kg(e))return e;if(!Array.isArray(e))return t;const n=T.FACE_ATLAS_REGIONS.filter(a=>e.includes(a));return n.length===0?t:n.length===1?n[0]:n},Eh=(e,t)=>{const n={...e,...t},a={};for(const s of Object.keys(Fo))a[s]=e[s];a.enabled=typeof n.enabled=="boolean"?n.enabled:e.enabled,a.region=Co(n.region,e.region),a.color=typeof n.color=="string"?n.color.trim():e.color,a.finish=xo(n.finish)?n.finish:e.finish,a.sparkleColor=typeof n.sparkleColor=="string"?n.sparkleColor.trim():e.sparkleColor,a.side=O.MAKEUP_SIDES.includes(n.side)?n.side:e.side;for(const[s,r]of Object.entries(Sh))a[s]=jg(n[s],r,e[s]);return a},Vg=e=>Object.fromEntries(Object.entries(e).filter(([,t])=>t!==void 0)),To=(e={})=>{const t=Vg(e),n=Fo,a=xo(t.finish)?t.finish:n.finish;return Eh({...n,...O.MAKEUP_FINISH_DEFAULTS[a]},t)},Ah=(e,t)=>{const n=e,a=t,s=Object.keys(n).some(i=>a[i]===void 0),r=Object.fromEntries(Object.entries(a).filter(([i,c])=>c!==void 0&&(s||c!==n[i]))),o={...n,...r};if(o.finish!==n.finish&&xo(o.finish)){Object.assign(o,O.MAKEUP_FINISH_DEFAULTS[o.finish]);for(const i of O.MAKEUP_FINISH_KEYS)r[i]!==void 0&&(o[i]=r[i])}return Eh(n,o)},ec=new Map,Wg=(e=T.FACE_ATLAS_REGIONS)=>{const t=Co(e,"face"),n=typeof t=="string"?t:t.join(",");let a=ec.get(n);return a||(a=T.getFaceAtlasRegionTriangles(t),ec.set(n,a)),a},qg=e=>({srgb:e!==null&&e.colorSpace!==d.SRGBColorSpace&&e.colorSpace!==d.LinearSRGBColorSpace,premultiplied:e!==null&&e.premultiplyAlpha}),tc=new WeakSet,vh=(e,t)=>{const{srgb:n,premultiplied:a}=qg(t);t&&a&&t.colorSpace===d.SRGBColorSpace&&!tc.has(t)&&(tc.add(t),console.warn(`[MakeupDesign] "${t.name}" is premultiplied and tagged SRGBColorSpace: its soft edges darken. Leave a premultiplied texture untagged (it is read as sRGB) or set premultiplyAlpha = false.`)),e.uDesignMap.value=t,e.uDesignSrgb.value=n?1:0,e.uDesignPremultiplied.value=a?1:0},Cn=(e,t=.01)=>{const[n,a]=Sh[e];return{type:"number",min:n,max:a,step:t}},Xg=[["cheeks","nose"],["lids","cheeks","forehead"],["lids","forehead"]],nc=e=>(typeof e=="string"?[e]:e).map((t,n)=>n===0?O.makeupNameLabel(t):t).join(" + "),Yg=[{key:"enabled",label:"On",type:"boolean"},{key:"region",label:"Region",type:"select",options:[...T.FACE_ATLAS_REGIONS.map(e=>({label:nc(e),value:e})),...Xg.map(e=>{const t=Co(e,"face");return{label:nc(t),value:t}})]},{key:"color",label:"Tint (blank = the art's colours)",type:"text"},{key:"opacity",label:"Opacity",...Cn("opacity")},{key:"coverage",label:"Coverage (sheer → opaque)",...Cn("coverage")},{key:"finish",label:"Finish",type:"select",options:O.MAKEUP_FINISHES.map(e=>({label:O.makeupNameLabel(e),value:e}))},{key:"shine",label:"Shine",...Cn("shine")},{key:"sparkleColor",label:"Sparkle color (blank = from the art)",type:"text"},{key:"sparkleDensity",label:"Sparkle density",...Cn("sparkleDensity")},{key:"sparkleSize",label:"Sparkle size (mm)",...Cn("sparkleSize",.05)},{key:"side",label:"Side (the person's own)",type:"select",options:[{label:"Both",value:"both"},{label:"Left only",value:"left"},{label:"Right only",value:"right"}]}],Qg=Object.freeze({lid:{outer:.3,wing:0,halo:0,creaseLift:0,lidSharpness:0},crease:{outer:.5,wing:0,halo:0,creaseLift:0,lidSharpness:0},smoky:{outer:.4,wing:.35,halo:0,creaseLift:0,lidSharpness:0},cutCrease:{outer:.3,wing:0,halo:0,creaseLift:1,lidSharpness:1},halo:{outer:.6,wing:0,halo:1,creaseLift:0,lidSharpness:0},winged:{outer:.7,wing:1,halo:0,creaseLift:0,lidSharpness:0}}),Jg=Object.freeze({tightline:{taper:.8},classic:{taper:.4},winged:{taper:.35},catEye:{taper:.3},smudged:{taper:.6},kohl:{taper:.7}}),Ts=[1,1,1,1,1],ks=[0,0,0,0,0],Mh=Object.freeze({natural:{lift:ks,width:Ts},softArch:{lift:[.02,.1,.08,.02,0],width:[.9,1,1,1,1]},straight:{lift:[.35,.05,-.15,-.15,0],width:Ts},highArch:{lift:[-.05,.28,.16,.03,0],width:[.8,1,1,1,1]},bold:{lift:ks,width:Ts},thin:{lift:ks,width:[.9,1,1,1,.95]}}),Ya=(e,t)=>t==="custom"?Xa[e].shape:t,je=(e,t)=>typeof e=="number"&&Number.isFinite(e)?e:t,Ve=(e,t,n)=>Math.min(n,Math.max(t,e)),Oa=(e,t,n)=>e+(t-e)*n,Zg=e=>{const[t,n,a]=pt.brow.boldnessWidth,s=Ve(je(e,.5),0,1);return s<=.5?Oa(t,n,s/.5):Oa(n,a,(s-.5)/.5)},yh=e=>{const{lift:t,width:n}=Mh[Ya("brows",e.shape)],a=Zg(e.boldness);return Qn().brow.map(([s,r,o],i)=>[s,r+t[i],o*n[i]*a*(i===0?pt.brow.tailTaper:1)])},ko=e=>Ve(je(e.thickness,1),.2,4)/10,br=(e,t,n)=>{const a=Qn(),[s,r]=Vu(a.axis,n),o=pt.liner;return{start:[a.outer[0],a.outer[1],e],end:[a.outer[0]+s*t,a.outer[1]+r*t,Math.max(e*o.wingTip,o.wingTipMinCm)]}},e0=e=>{const t=Ve(je(e.wing,0),0,15)/10;if(t<=0)return null;const n=ko(e)*(1+Ve(je(e.smudge,0),0,1));return br(n,t,Ve(je(e.wingAngle,15),0,45))},ac=(e,t)=>{t&&e.set(t)},t0=(e,t)=>{const n=Qg[Ya("eyeshadow",t.shape)];e.uShadow.value.set(t.height,t.crease,t.lower,t.inner),e.uShadowShape.value.set(n.outer,n.wing,n.halo),e.uShadowCut.value.set(n.creaseLift,n.lidSharpness),ac(e.uShadowCreaseColor.value,t.creaseColor),ac(e.uShadowInnerColor.value,t.innerColor)},n0=(e,t)=>{const{taper:n}=Jg[Ya("eyeliner",t.shape)];e.uLiner.value.set(ko(t),t.lower,n,t.smudge);const a=e0(t);a?(e.uWingStart.value.fromArray(a.start),e.uWingEnd.value.fromArray(a.end)):(e.uWingStart.value.set(0,0,0),e.uWingEnd.value.set(0,0,0))},a0=(e,t)=>{const n=yh(t);for(let r=0;r<Bn;r+=1)e.uBrowStart.value.set(n[r],r*3),e.uBrowEnd.value.set(n[r+1],r*3);const[a,s]=pt.brow.hairGain;e.uBrow.value.set(t.fill,t.strokes,Oa(a,s,Ve(t.boldness,0,1)))},s0=(e,t)=>{e.uBlink.value.set(je(t[qi.negX],0),je(t[qi.posX],0))},r0=.2;let Ls=null;const o0=()=>{if(!Ls){const e=new Set(T.getFaceAtlasRegionTriangles("lips"));Ls=Array.from(T.getFaceAtlasRegionTriangles("face")).filter(t=>!e.has(t))}return Ls},Rs=new Float64Array(14),i0=e=>{const t=V.CANONICAL_FACE_POSITIONS,n=[];for(const a of o0()){const s=T.FACE_ATLAS_TRIANGLES[a*3]*3,r=T.FACE_ATLAS_TRIANGLES[a*3+1]*3,o=T.FACE_ATLAS_TRIANGLES[a*3+2]*3,i=-Math.abs(t[s]),c=-Math.abs(t[r]),u=-Math.abs(t[o]),l=t[s+1],h=t[r+1],f=t[o+1];Rs.set([i,l,c,h,u,f,(i+c)/2,(l+h)/2,(c+u)/2,(h+f)/2,(u+i)/2,(f+l)/2,(i+c+u)/3,(l+h+f)/3]);let p=!1;for(let m=0;m<14&&!p;m+=2)for(const E of e)if(E(Rs[m],Rs[m+1])){p=!0;break}p&&n.push(a)}return Uint16Array.from(n).sort()},c0=[0,0],en=r0,Nn=(e,t)=>(n,a)=>Wm(e,n,a,c0)[0]<=t+en,sn=(e,t,n=2)=>(a,s)=>{const r=t[0]-e[0],o=t[1]-e[1],i=Ve(((a-e[0])*r+(s-e[1])*o)/Math.max(r*r+o*o,1e-8),0,1),c=Oa(e[2],t[2],i);return Math.hypot(a-e[0]-r*i,s-e[1]-o*i)<=c*n+en},sc=new Map,Pa=(e,t)=>{let n=sc.get(e);return n||(n=i0(t()),sc.set(e,n)),n},l0=.05,da=5,Ir=(e,t)=>Math.ceil(e/t-1e-9)*t,u0=()=>Pa("eyeshadow",()=>{const e=Qn(),t=pt.shadow,n=e.outer[0]-(t.outerReach[0]+t.outerReach[1])-en,a=e.inner[0]+t.innerReach+en,s=(c,u)=>{if(c<n||c>a)return!1;const l=Wi(e.lines.upper,c),h=Wi(e.lines.browLower,c);return u>=l-en&&u<=l+Math.max(h-l,t.minGap)*t.top[1]+en},r=(t.lowerWidth[0]+t.lowerWidth[1])*2,[o,i]=e.shadowWing;return[s,Nn(e.lines.lower,r),sn([...o,t.wingRadius[0]],[...i,t.wingRadius[1]]),sn([...e.inner,t.innerRadius],[...e.inner,t.innerRadius]),sn([...e.lidCentre,t.haloRadius],[...e.lidCentre,t.haloRadius])]}),h0=e=>{const t=Qn(),n=pt.liner;if(!e)return Pa("eyeliner|reach",()=>{const f=[Nn(t.lines.upper,1.6),Nn(t.lines.lower,.8*n.lowerWidth*2)];for(let p=0;p<=45;p+=da){const m=br(.8,1.5,p);f.push(sn(m.start,m.end))}return f});const a=Ve(je(e.smudge,0),0,1),s=Ir(ko(e)*(1+a),l0),r=e.lower>0,o=Ir(Ve(je(e.wing,0),0,15),1),i=Ve(je(e.wingAngle,15),0,45),c=Math.floor(i/da)*da,u=o>0?[c,Math.min(45,c+da)]:[],l=`eyeliner|${s.toFixed(2)}|${r?1:0}|${o}|${o>0?c:0}`;return Pa(l,()=>{const h=[Nn(t.lines.upper,s*2)];r&&h.push(Nn(t.lines.lower,s*n.lowerWidth*2));for(const f of u){const p=br(s,o/10,f);h.push(sn(p.start,p.end))}return h})},f0=e=>{const t=pt.brow.strokeReach*2,n=e?[Ya("brows",e.shape)]:Object.keys(Mh),a=e?Math.min(1,Ir(Ve(je(e.boldness,.5),0,1),.1)):1,s=e?`brows|${n[0]}|${a.toFixed(1)}`:"brows|reach";return Pa(s,()=>n.flatMap(r=>{const o=yh({shape:r,boldness:a}),i=[];for(let c=1;c<ju;c+=1)i.push(sn(o[c-1],o[c],t));return i}))},p0=(e,t)=>e==="eyeshadow"?u0():e==="eyeliner"?h0(t):f0(t),d0={from:[-7.2,-.9],to:[-4.7,-2.5],radius:[1.1,.7]},bs=(e,t)=>({from:[-5.8,-5.3],to:[-2.6,-8.2],radius:[e,e*.7],weight:t}),Is=(e,t)=>({from:[-6.4,6],to:[-7,3.5],radius:e,weight:t}),rc=e=>({from:[-.85,3.1],to:[-1.3,.3],radius:[.4,.42],weight:e}),oc={from:[-4.2,.1],to:[-6.3,1],radius:[.7,.55]},Ns=(e,t)=>({from:[0,3.4],to:[0,.4],radius:e,weight:t}),ic=(e,t)=>({from:[0,-7],to:[0,-7.5],radius:e,weight:t}),wh={contour:{soft:[d0,bs(.85,.6),Is(1,.6)],sculpted:[{from:[-7.2,-.8],to:[-4.4,-2.6],radius:[.85,.5]},bs(.8,.8),Is(.9,.5),rc(.4)],bronzed:[Is(1.2,.8),{from:[-4.6,-.3],to:[-6.8,1],radius:[1.2,1],weight:.8},Ns(.6,.4),bs(1,.5)],nose:[rc(1)]},blush:{apples:[{from:[-3.6,-.75],to:[-4.4,-.35],radius:1.6}],lifted:[{from:[-3.9,-.9],to:[-6,.3],radius:[1.45,1.15]}],draped:[{from:[-4.4,-.9],to:[-6.6,2],radius:[1.35,1]}],sunKissed:[{from:[-3.7,-.6],to:[-4.5,-.2],radius:1.35,weight:.9},{from:[-2.6,.15],to:[0,.55],radius:.75,weight:.6}]},highlighter:{cheekbones:[oc],strobe:[oc,{from:[-3.5,4],to:[-5,3.65],radius:.3,weight:.7},Ns(.3,.8),{from:[-.45,-2.9],radius:.3,weight:.8},ic(.6,.7)],glow:[{from:[-4,0],to:[-6.4,1.2],radius:[1.1,.9],weight:.9},{from:[-1.2,6],to:[0,6.2],radius:1.3,weight:.5},Ns(.45,.7),ic(.8,.6)],nose:[{from:[0,3.4],to:[0,.2],radius:[.28,.34]},{from:[0,-.35],radius:.42,weight:.8}]}},Lo={contour:{eyeGuard:[.5,1.5],lipGuard:1},blush:{eyeGuard:[1,2.5],lipGuard:1,lift:{direction:[-.502,.865],cm:1}},highlighter:{eyeGuard:[.5,1.5],lipGuard:.5}},cc=(e,t)=>Um(e[0],e[1],t),_h=(e,t)=>{const n=t.shape==="custom"?Xa[e].shape:t.shape,a=wh[e][n],s=Number.isFinite(t.size)?t.size:1,{lift:r}=Lo[e],o=r&&Number.isFinite(t.lift)?t.lift*r.cm:0,i=r?r.direction[0]*o:0,c=r?r.direction[1]*o:0;return a.map(({from:u,to:l=u,radius:h,weight:f=1})=>{const p=(u[0]+l[0])/2,m=(u[1]+l[1])/2,E=A=>[p+(A[0]-p)*s+i,m+(A[1]-m)*s+c],[S,g]=typeof h=="number"?[h,h]:h;return{a:cc(E(u),[0,0,0]),b:cc(E(l),[0,0,0]),ra:S*s,rb:g*s,weight:f}})},lc=new WeakMap,m0=(e,t,n)=>{const a=`${t}|${n.shape}|${n.size}|${n.lift??0}`;if(lc.get(e)!==a){const o=_h(t,n),i={count:0,start:e.uShapeStart.value,end:e.uShapeEnd.value,weight:e.uShapeWeight.value};Nm(o,i),e.uShapeCount.value=i.count,lc.set(e,a)}const{eyeGuard:s,lipGuard:r}=Lo[t];e.uEyeGuard.value.set(s[0],s[1]),e.uLipGuard.value=r},g0=.75,rn=.25,S0=[-1,-.75,-.5,-.25,0,.25,.5,.75,1],uc=new Map;let Os=null;const Ps=(e,t)=>typeof e=="number"&&Number.isFinite(e)?e:t,hc=(e,t)=>Math.min(t,Math.max(rn,Math.ceil(e/rn-1e-9)*rn)),E0=(e,t)=>{const n=Lo[e];let a,s,r;if(t){const m=hc(Ps(t.size,1),1.5);s=hc(Ps(t.softness,1),1);const E=n.lift?Math.min(1,Math.max(-1,Ps(t.lift,0))):0,S=Math.max(-1,Math.floor(E/rn+1e-9)*rn);a=(n.lift?[S,Math.min(1,S+rn)]:[0]).map(A=>({shape:t.shape,size:m,lift:A})),r=`${e}|${t.shape}|${m}|${s}|${S}`}else s=1,a=Object.keys(wh[e]).flatMap(m=>(n.lift?S0:[0]).map(E=>({shape:m,size:1.5,lift:E}))),r=`${e}|reach`;const o=uc.get(r);if(o)return o;if(!Os){const m=new Set(T.getFaceAtlasRegionTriangles("lips"));Os=Array.from(T.getFaceAtlasRegionTriangles("face")).filter(E=>!m.has(E))}const i=a.flatMap(m=>_h(e,m)),c=[0,0,0],u=[0,0],l=Dm(Os,m=>(c[0]=-Math.abs(V.CANONICAL_FACE_POSITIONS[m*3]),c[1]=V.CANONICAL_FACE_POSITIONS[m*3+1],c[2]=V.CANONICAL_FACE_POSITIONS[m*3+2],i.some(({a:E,b:S,ra:g,rb:A})=>(Om(c,E,S,g,A,u),u[0]<u[1]*(1+s)+g0)))),{eyeRing:h}=T.getFaceAtlasAttributes(),[f]=n.eyeGuard,p=l.filter(m=>h[T.FACE_ATLAS_TRIANGLES[m*3]]>f||h[T.FACE_ATLAS_TRIANGLES[m*3+1]]>f||h[T.FACE_ATLAS_TRIANGLES[m*3+2]]>f);return uc.set(r,p),p},A0=`
|
|
1574
|
+
void main() {
|
|
1575
|
+
MakeupSample s = makeupSampleGeometry();
|
|
1576
|
+
float mask = makeupRegionShape(s.rest);
|
|
1577
|
+
if (mask * s.fade < MAKEUP_SHAPE_DISCARD) discard;
|
|
1578
|
+
makeupSampleColor(s);
|
|
1579
|
+
makeupOutput(s, makeupFinish(s, makeupShade(s), mask));
|
|
1580
|
+
}
|
|
1581
|
+
`;let fc=null;const v0=()=>(fc??(fc=[fe.common,fe.shading,fe.sparkle,fe.finish,fe.shapes,`#define MAKEUP_SHAPE_DISCARD ${(1/255).toFixed(6)}`,A0].join(`
|
|
1582
|
+
`)),fc),Us=e=>({fragmentShader:v0,createUniforms:()=>({}),resolve:t=>rt(e,t),patch:(t,n)=>_o(e,t,n),updateUniforms:(t,n)=>m0(t,e,n),triangles:t=>E0(e,t),autoShade:Re[e],renderOrder:de.MAKEUP_RENDER_ORDER[e]}),M0=`
|
|
1583
|
+
void main() {
|
|
1584
|
+
MakeupSample s = makeupSampleGeometry();
|
|
1585
|
+
vec4 art = makeupDesignSample(s.uv);
|
|
1586
|
+
float mask = art.a;
|
|
1587
|
+
if (mask * s.fade < MAKEUP_SHAPE_DISCARD) discard;
|
|
1588
|
+
makeupSampleColor(s);
|
|
1589
|
+
makeupOutput(s, makeupFinish(s, art.rgb * uColor, mask));
|
|
1590
|
+
}
|
|
1591
|
+
`;let pc=null;const y0=()=>(pc??(pc=[fe.common,fe.shading,fe.sparkle,fe.finish,fe.shapes,fe.design,`#define MAKEUP_SHAPE_DISCARD ${(1/255).toFixed(6)}`,M0].join(`
|
|
1592
|
+
`)),pc),w0={fragmentShader:y0,createUniforms:Ku,resolve:To,patch:Ah,updateUniforms:(e,t)=>{t.color===""&&e.uColor.value.setRGB(1,1,1)},triangles:e=>Wg(e==null?void 0:e.region),autoShade:Re.none,renderOrder:de.MAKEUP_RENDER_ORDER.design},_0=`#define MAKEUP_SHAPE_DISCARD ${(1/255).toFixed(6)}`,F0={eyeshadow:`
|
|
1593
|
+
void main() {
|
|
1594
|
+
MakeupSample s = makeupSampleGeometry();
|
|
1595
|
+
MakeupEyeshadowZones z = eyeshadowZones(s.rest, s.pixelCm);
|
|
1596
|
+
float mask = eyeshadowMask(z);
|
|
1597
|
+
if (mask * s.fade < MAKEUP_SHAPE_DISCARD) discard;
|
|
1598
|
+
makeupSampleColor(s);
|
|
1599
|
+
makeupOutput(s, makeupFinish(s, eyeshadowColor(z, makeupShade(s)), mask));
|
|
1600
|
+
}
|
|
1601
|
+
`,eyeliner:`
|
|
1602
|
+
void main() {
|
|
1603
|
+
MakeupSample s = makeupSampleGeometry();
|
|
1604
|
+
float mask = eyelinerShape(s.rest, s.pixelCm);
|
|
1605
|
+
if (mask * s.fade < MAKEUP_SHAPE_DISCARD) discard;
|
|
1606
|
+
makeupSampleColor(s);
|
|
1607
|
+
makeupOutput(s, makeupFinish(s, makeupShade(s), mask));
|
|
1608
|
+
}
|
|
1609
|
+
`,brows:`
|
|
1610
|
+
void main() {
|
|
1611
|
+
MakeupSample s = makeupSampleGeometry();
|
|
1612
|
+
MakeupBrow brow = browGeometry(s.rest, s.pixelCm);
|
|
1613
|
+
if (browReach(brow) * s.fade < MAKEUP_SHAPE_DISCARD) discard;
|
|
1614
|
+
makeupSampleColor(s);
|
|
1615
|
+
float mask = browMask(s, brow);
|
|
1616
|
+
makeupOutput(s, makeupFinish(s, makeupShade(s), mask));
|
|
1617
|
+
}
|
|
1618
|
+
`},ma={},x0=e=>()=>(ma[e]??(ma[e]=[fe.common,fe.shading,fe.sparkle,fe.finish,fe.shapes,fe.eyes,_0,F0[e]].join(`
|
|
1619
|
+
`)),ma[e]),C0={eyeshadow:(e,t)=>t0(e,t),eyeliner:(e,t)=>n0(e,t),brows:(e,t)=>a0(e,t)},Ds=e=>({fragmentShader:x0(e),createUniforms:Ym,resolve:t=>rt(e,t),patch:(t,n)=>_o(e,t,n),updateUniforms:(t,n)=>C0[e](t,n),triangles:t=>p0(e,t),autoShade:e==="brows"?Re.brows:Re.none,renderOrder:de.MAKEUP_RENDER_ORDER[e],onFrame:(t,n)=>{t.uBlink&&s0(t,n.rig.current.morphs)}}),Et={contour:Us("contour"),blush:Us("blush"),highlighter:Us("highlighter"),eyeshadow:Ds("eyeshadow"),eyeliner:Ds("eyeliner"),brows:Ds("brows"),design:w0},Fh=e=>Et[e],xh=e=>({...Wu(),...eg(),...Et[e].createUniforms()}),dc=(e,t)=>{t&&e.set(t)},Ch=(e,{quality:t,mirrored:n})=>{t!==void 0&&(e.uSparkleQuality.value=t==="low"?0:1),n!==void 0&&(e.uPersonLeftSign.value=ee.personLeftSign(n))},T0=(e,t,n,a={})=>{dc(e.uColor.value,t.color),e.uAutoShade.value=t.shade==="auto"?n:Re.none,e.uOpacity.value=t.opacity,e.uCoverage.value=t.coverage,e.uFinish.value=Ze[t.finish]??Ze.matte,e.uShine.value=t.shine,e.uSparkleAuto.value=t.sparkleColor===""?1:0,dc(e.uSparkleColor.value,t.sparkleColor),e.uSparkleDensity.value=t.sparkleDensity,e.uSparkleSize.value=t.sparkleSize,t.softness!==void 0&&(e.uSoftness.value=t.softness);const[s,r]=Gm(t.side);e.uSide.value.set(s,r),Ch(e,a)},Th=(e,t,n,a)=>{const s=Fh(t);T0(e,n,s.autoShade,a),s.updateUniforms(e,n)},k0=Object.freeze({...de.MAKEUP_BLENDING,depthWrite:!1,depthTest:!0,depthFunc:d.LessEqualDepth,side:d.FrontSide,toneMapped:!1,glslVersion:d.GLSL3}),kh=(e,t=xh(e))=>{const n=new d.ShaderMaterial({name:`makeup-${e}`,uniforms:t,vertexShader:fe.atlasVertex,fragmentShader:Et[e].fragmentShader(),...k0});return n.userData.makeupRegion=e,n},Lh=e=>{var t;return e.isShaderMaterial===!0&&typeof((t=e.userData)==null?void 0:t.makeupRegion)=="string"&&e.userData.makeupRegion in Et},L0=(e,{settings:t,quality:n,mirrored:a}={})=>{if(!Lh(e))throw new Error("updateMakeupMaterial: not a material from createMakeupMaterial");const s=e.userData.makeupRegion;if(t){const r=Fh(s),o=e.userData.makeupSettings,i=o?r.patch(o,t):r.resolve(t);e.userData.makeupSettings=i,Th(e.uniforms,s,i)}return Ch(e.uniforms,{quality:n,mirrored:a}),e},mc=(e,t)=>{const n=e;n.uSkinMap=t.uSkinMap,n.uSkinLod=t.uSkinLod,n.uSkinSqrt=t.uSkinSqrt,n.uSkinStats=t.uSkinStats,n.uSkinStatsPacked=t.uSkinStatsPacked},gc=(e,t)=>{const n=e;n.uCameraMap=t.uCameraMap,n.uPresence=t.uPresence,n.uPersonLeftSign=t.uPersonLeftSign},R0=new Set(["uBlink","uCameraMap","uPresence","uPersonLeftSign","uSkinMap","uSkinLod","uSkinSqrt","uSkinStats","uSkinStatsPacked"]),b0=e=>{const t=new d.ShaderMaterial;d.Material.prototype.copy.call(t,e),t.vertexShader=e.vertexShader,t.fragmentShader=e.fragmentShader,t.defines={...e.defines},t.extensions={...e.extensions},t.glslVersion=e.glslVersion,t.lights=e.lights,t.fog=e.fog,t.clipping=e.clipping,t.onBeforeCompile=e.onBeforeCompile,t.customProgramCacheKey=e.customProgramCacheKey,t.uniforms={...e.uniforms};const n=e.uniforms.uBlink;return n&&(t.uniforms.uBlink={value:n.value.clone()}),t.userData={makeupRegion:e.userData.makeupRegion},t},I0=(e,t)=>{const n=t.uniforms,a=e.uniforms;for(const s in n)a[s]!==n[s]&&!R0.has(s)&&(a[s]=n[s]);(e.fragmentShader!==t.fragmentShader||e.vertexShader!==t.vertexShader)&&(e.fragmentShader=t.fragmentShader,e.vertexShader=t.vertexShader,e.needsUpdate=!0)},N0=2e3;let Sc=null;const Nr=new WeakMap,O0=e=>{const t=Nr.get(e);if(t&&t.pending>0){t.dispose=!0;return}e.dispose()},P0=(e,t,n,a)=>{if(typeof e.compileAsync!="function")return Promise.resolve();try{Sc??(Sc=new d.BufferGeometry);const s=new d.Mesh(Sc,t),r=e.compileAsync(s,n,a),o=Nr.get(t)??{pending:0,dispose:!1};Nr.set(t,o),o.pending+=1,o.dispose=!1;const i=Promise.resolve(r).then(()=>{},()=>{}).then(()=>{o.pending-=1,o.pending===0&&o.dispose&&(o.dispose=!1,t.dispose())});let c;const u=new Promise(l=>{c=setTimeout(l,N0)});return Promise.race([i,u]).then(()=>clearTimeout(c))}catch{return Promise.resolve()}},U0=e=>{const t=J.useThree(i=>i.gl),n=J.useThree(i=>i.camera),a=J.useThree(i=>i.scene),s=_.useRef({camera:n,scene:a});s.current.camera=n,s.current.scene=a;const[r,o]=_.useState(null);return _.useEffect(()=>{if(!e)return;let i=!0;return P0(t,e,s.current.camera,s.current.scene).then(()=>{i&&o(e)}),()=>{i=!1}},[t,e]),e===null||r===e},D0=e=>{const t=_.useRef(e);return t.current=e,_.useMemo(()=>({get probe(){return t.current.probe},get skinMap(){return t.current.skinMap},get featureMap(){return t.current.featureMap},get lightingMap(){return t.current.lightingMap},get uniforms(){return t.current.uniforms},get ready(){return t.current.ready},get format(){return t.current.format},get faceIndex(){return t.current.faceIndex}}),[])},G0=e=>typeof e=="object"&&e!==null&&e.isMaterial===!0&&Lh(e)?e:null,Ec=new WeakSet,$0=(e,t,n)=>{const a=e.userData.makeupRegion;Ec.has(e)||a===t&&!n||(Ec.add(e),console.warn(`[Makeup] a "${a}" material from createMakeupMaterial on the ${t} region${n?" (through material)":""} is drawn with its own settings, over the ${a} triangles at the ${a} order. Pass it as sharedMaterial to the ${a} component.`))},B0=({region:e,settings:t,triangles:n,uniforms:a,faceIndex:s,numFaces:r,mirrored:o,renderOrder:i,material:c,sharedMaterial:u})=>{const l=Et[e],h=fo({faceIndex:s,numFaces:r}),f=Va({faceIndex:(h==null?void 0:h.faceIndex)??0,enabled:h!==null}),p=D0(f),m=_.useMemo(()=>xh(e),[e]);a&&Object.assign(m,a),mc(m,f.uniforms),Th(m,e,t,{quality:(h==null?void 0:h.quality)??"high"});const E=G0(u??c);E&&$0(E,e,u===void 0);const S=_.useMemo(()=>E?b0(E):null,[E]);_.useEffect(()=>()=>S==null?void 0:S.dispose(),[S]),S&&mc(S.uniforms,f.uniforms);const g=!u&&!c,A=_.useMemo(()=>g?kh(e,m):null,[g,e,m]);_.useEffect(()=>()=>{A&&O0(A)},[A]);const v=U0(A),M=_.useRef(t);M.current=t;const y=_.useRef(null),x=_.useRef([]);_.useEffect(()=>{x.current.length>0&&x.current.splice(0).forEach(R=>R.dispose())});const F=_.useCallback(R=>{if(gc(m,R.uniforms),S)return gc(S.uniforms,R.uniforms),S;if(u)return u;if(A)return A;if(typeof c!="function")return c;const b=y.current;if(b&&b.factory===c&&b.uniforms===m)return b.result;const N=c({...R,uniforms:m,region:e,settings:M.current,skin:p,vertexShader:fe.atlasVertex,fragmentShader:l.fragmentShader()}),P=b==null?void 0:b.result;return P&&P!==N&&P.isMaterial===!0&&x.current.push(P),y.current={factory:c,uniforms:m,result:N},N},[m,S,u,A,c,e,p,l]);if(J.useFrame(()=>{if(S&&E&&I0(S,E),!h)return;l.onFrame&&l.onFrame(m,h);const R=E?Et[E.userData.makeupRegion]:null;S&&(R!=null&&R.onFrame)&&R.onFrame(S.uniforms,h)}),!h)return null;const w=E?Et[E.userData.makeupRegion]:l;let k=n??l.triangles(t);return!n&&E&&(k=E.userData.makeupRegion==="design"&&e==="design"?Et.design.triangles(t):w.triangles()),L.jsx(Hu,{handle:h,triangles:k,material:F,renderOrder:i??w.renderOrder,mirrored:o,visible:v&&t.opacity>0})},$t=e=>e.settings.enabled?L.jsx(B0,{...e}):null,H0=({faceIndex:e,numFaces:t,mirrored:n,renderOrder:a,material:s,sharedMaterial:r,...o})=>L.jsx($t,{region:"blush",settings:rt("blush",o),faceIndex:e,numFaces:t,mirrored:n,renderOrder:a,material:s,sharedMaterial:r}),z0=({faceIndex:e,numFaces:t,mirrored:n,renderOrder:a,material:s,sharedMaterial:r,...o})=>L.jsx($t,{region:"contour",settings:rt("contour",o),faceIndex:e,numFaces:t,mirrored:n,renderOrder:a,material:s,sharedMaterial:r}),K0=({faceIndex:e,numFaces:t,mirrored:n,renderOrder:a,material:s,sharedMaterial:r,...o})=>L.jsx($t,{region:"highlighter",settings:rt("highlighter",o),faceIndex:e,numFaces:t,mirrored:n,renderOrder:a,material:s,sharedMaterial:r}),j0=({faceIndex:e,numFaces:t,mirrored:n,renderOrder:a,material:s,sharedMaterial:r,...o})=>L.jsx($t,{region:"eyeshadow",settings:rt("eyeshadow",o),faceIndex:e,numFaces:t,mirrored:n,renderOrder:a,material:s,sharedMaterial:r}),V0=({faceIndex:e,numFaces:t,mirrored:n,renderOrder:a,material:s,sharedMaterial:r,...o})=>L.jsx($t,{region:"eyeliner",settings:rt("eyeliner",o),faceIndex:e,numFaces:t,mirrored:n,renderOrder:a,material:s,sharedMaterial:r}),W0=({faceIndex:e,numFaces:t,mirrored:n,renderOrder:a,material:s,sharedMaterial:r,...o})=>L.jsx($t,{region:"brows",settings:rt("brows",o),faceIndex:e,numFaces:t,mirrored:n,renderOrder:a,material:s,sharedMaterial:r}),q0=4,Ac=new Set,X0=e=>{const t=typeof e=="string"?e.trim():"",[n,a]=_.useState(null);return _.useEffect(()=>{if(t===""){a(null);return}let s=!0;return new d.TextureLoader().load(t,r=>{if(!s){r.dispose();return}r.name=`makeup-design:${t}`,r.premultiplyAlpha=!0,r.anisotropy=q0,r.needsUpdate=!0,a(r)},void 0,()=>{s&&(a(null),Ac.has(t)||(Ac.add(t),console.warn(`[MakeupDesign] could not load the art "${t}"`)))}),()=>{s=!1}},[t]),_.useEffect(()=>()=>n==null?void 0:n.dispose(),[n]),e instanceof d.Texture?e:t===""?null:n},Y0=({texture:e,faceIndex:t,numFaces:n,mirrored:a,renderOrder:s,material:r,sharedMaterial:o,...i})=>{const c=X0(o?null:e),u=_.useMemo(()=>Ku(),[]);vh(u,c);const l=To(i),h=c!==null||o!==void 0||r!==void 0;return L.jsx($t,{region:"design",settings:h?l:{...l,enabled:!1},uniforms:u,faceIndex:t,numFaces:n,mirrored:a,renderOrder:s,material:r,sharedMaterial:o})},Q0=["fair","light","medium","tan","deep","rich"],J0=["cool","neutral","warm"],$e=Object.freeze({depthIta:Object.freeze({fair:55,light:41,medium:28,tan:10,deep:-30}),coolHue:50,warmHue:60,undertoneKneeL:50,undertoneHueShift:.25,minUndertoneChroma:6,minFeatureSeen:.25,recommendations:3,readbackMs:500,minReadbackMs:200}),Gs=[.95047,1,1.08883],Z0=(6/29)**3,$s=e=>e>Z0?Math.cbrt(e):e/(3*(6/29)**2)+4/29,Ro=e=>{const t=Math.max(e[0],0),n=Math.max(e[1],0),a=Math.max(e[2],0),s=(.4124564*t+.3575761*n+.1804375*a)/Gs[0],r=(.2126729*t+.7151522*n+.072175*a)/Gs[1],o=(.0193339*t+.119192*n+.9503041*a)/Gs[2],i=$s(s),c=$s(r),u=$s(o);return[116*c-16,500*(i-c),200*(c-u)]},Lt=e=>{const t=Number.parseInt(e.replace("#","").slice(0,6),16);return Ud([(t>>16&255)/255,(t>>8&255)/255,(t&255)/255])},Bs=e=>`#${Pd([Math.min(e[0],1),Math.min(e[1],1),Math.min(e[2],1)]).map(n=>Math.round(Math.min(Math.max(n,0),1)*255).toString(16).padStart(2,"0")).join("")}`,eS=(e,t)=>Math.hypot(e[0]-t[0],e[1]-t[1],e[2]-t[2]),tS=e=>Math.atan2(e[0]-50,e[2])*180/Math.PI,Rh=e=>{const t=$e.depthIta;return e>t.fair?"fair":e>t.light?"light":e>t.medium?"medium":e>t.tan?"tan":e>t.deep?"deep":"rich"},bh=(e,t,n)=>{if(!(t>=$e.minUndertoneChroma))return"neutral";const s=(Number.isFinite(n)?Math.max(0,$e.undertoneKneeL-n):0)*$e.undertoneHueShift;return e<$e.coolHue-s?"cool":e>$e.warmHue-s?"warm":"neutral"};let vc=null;const nS=()=>(vc??(vc=Object.fromEntries(O.MAKEUP_REGIONS.map(e=>[e,O.MAKEUP_SHADE_NAMES[e].map(t=>Ro(Lt(O.MAKEUP_SHADES[e][t])))]))),vc),aS=Object.freeze({warm:{blush:Lt("#f0a07c"),highlighter:Lt("#e9c27a"),eyeshadow:Lt("#a8743f")},cool:{blush:Lt("#d97a85"),highlighter:Lt("#f2eef6"),eyeshadow:Lt("#8f7a6e")}}),Hs=.45,zs=(e,t,n)=>{const a=De(e)/Math.max(De(t),1e-6);return[e[0]+(t[0]*a-e[0])*n,e[1]+(t[1]*a-e[1])*n,e[2]+(t[2]*a-e[2])*n]},sS=(e,t,n,a="neutral")=>{const s={skinSlow:e,skinLocal:e,lip:t??Ti({skinSlow:e,skinLocal:e,lip:e,brow:e},"blush",e),brow:n??ba([e[0]*.18,e[1]*.18,e[2]*.18],.8)},r=u=>Ti(s,u,e);let o=r("blush"),i=r("highlighter"),c=ba(e,.9).map(u=>u*.45);if(a!=="neutral"){const u=aS[a];o=zs(o,u.blush,Hs),i=zs(i,u.highlighter,Hs),c=zs(c,u.eyeshadow,Hs)}return{lips:r("lips"),contour:r("contour"),blush:o,highlighter:i,eyeshadow:c,eyeliner:s.brow.map(u=>u*.35),brows:r("brows")}},Ih=(e,t,n=$e.recommendations)=>{const a=Ro(t),s=O.MAKEUP_SHADE_NAMES[e],r=nS()[e];return s.map((o,i)=>({name:o,d:eS(a,r[i])})).sort((o,i)=>o.d-i.d).slice(0,Math.max(0,Math.floor(n))).map(o=>o.name)},Nh=.99,Oh=(e,t={})=>{if(!(e.ready>=Nh))return null;const n=e.skinSlow;if(!(De(n)>1e-4))return null;const a=Ro(n),s=tS(a),r=Math.atan2(a[2],a[1])*180/Math.PI,o=r<0?r+360:r,i=Math.hypot(a[1],a[2]),c=$e.minFeatureSeen,u=e.lipSeen>=c&&De(e.lip)>1e-4?e.lip:null,l=e.browSeen>=c&&De(e.brow)>1e-4?e.brow:null,h=bh(o,i,a[0]),f=sS(n,u,l,h),p=t.count??$e.recommendations,m=Object.fromEntries(O.MAKEUP_REGIONS.map(E=>[E,Ih(E,f[E],p)]));return{skin:Bs(n),lab:a,depth:Rh(s),ita:s,undertone:h,hue:o,chroma:i,lips:u?Bs(u):null,brows:l?Bs(l):null,recommendations:m}},rS=(e,t)=>e===t?!1:!e||!t||e.skin!==t.skin||e.depth!==t.depth||e.undertone!==t.undertone||e.lips!==t.lips||e.brows!==t.brows?!0:O.MAKEUP_REGIONS.some(n=>{const a=e.recommendations[n],s=t.recommendations[n];return a.length!==s.length||a.some((r,o)=>r!==s[o])}),oS=-.45,iS=(e={})=>{const t=e.enabled!==!1,n=ge(),a=Te.useTrackerContext(),s=T.resolveFaceAtlasBinding({faceIndex:e.faceIndex,numFaces:e.numFaces,rigFaceIndex:n?n.current.faceIndex:null,trackerFaceIndex:(a==null?void 0:a.type)==="face"?a.faceIndex??0:null});dn(t&&s.acquire,s.numFaces);const r=Va({faceIndex:s.faceIndex,quality:e.quality,enabled:t}),o=J.useThree(h=>h.gl),[i,c]=_.useState(null),u=_.useRef({intervalMs:e.intervalMs,count:e.count});u.current.intervalMs=e.intervalMs,u.current.count=e.count;const l=_.useMemo(()=>({buffer:new Float32Array(Pt*4),inFlight:!1,lastMs:-1/0,current:null,generation:0}),[]);return _.useEffect(()=>(l.generation+=1,l.current=null,l.lastMs=-1/0,c(null),()=>{l.generation+=1}),[l,r.probe]),J.useFrame(()=>{const{probe:h}=r;if(!t||!h||l.inFlight||h.updateCount===0)return;const f=performance.now(),p=Math.max($e.minReadbackMs,u.current.intervalMs??$e.readbackMs);if(f-l.lastMs<p)return;l.lastMs=f,l.inFlight=!0;const{generation:m}=l;h.readStatsAsync(o,l.buffer).then(E=>{if(!E||l.generation!==m)return;const S=Oh(lo(E),{count:u.current.count});!S||!rS(l.current,S)||(l.current=S,c(S))}).finally(()=>{l.inFlight=!1})},oS),t?i:null},Mc=new WeakMap,vt=(e,t,n)=>{let a=Mc.get(e);return a||(a=new Map,Mc.set(e,a)),a.has(t)||a.set(t,n()),a.get(t)},Ks=new Map,Bt=(e,t)=>(Ks.has(e)||Ks.set(e,t()),Ks.get(e)),Ce=e=>{},cS=["leftEye","rightEye","eyes","mouth","nose","face"],on={leftEye:{width:.8,height:.55},rightEye:{width:.8,height:.55},eyes:{width:1.8,height:.55},mouth:{width:1.2,height:1},nose:{width:.8,height:1},face:{width:2.5,height:3}},bo=e=>on[e].width/on[e].height,lS=[.35,.6],Io=()=>({center:{x:.5,y:.5},axisX:{x:0,y:0},axisY:{x:0,y:0},unit:0,ellipses:[{x:0,y:0,rx:1,ry:1,alpha:1},{x:0,y:0,rx:1,ry:1,alpha:0}],count:1}),yc=[263,362],wc=[33,133],uS=[6,2],hS=[10,152],fS=[13,14],Oe={x:0,y:0,z:0},Pe={x:0,y:0,z:0},Tn={x:0,y:0,z:0},js={x:0,y:0,z:0},Xe={x:0,y:0,z:0},kn=(e,[t,n],a,s)=>{const r=e[t],o=e[n];return s.x=(r.x+o.x)/2*a,s.y=(r.y+o.y)/2,s.z=((r.z??0)+(o.z??0))/2*a,s},pS=(e,t,n)=>{n.x=0,n.y=0;for(const a of tt.OUTER_LIPS)n.x+=e[a].x,n.y+=e[a].y;return n.x=n.x/tt.OUTER_LIPS.length*t,n.y/=tt.OUTER_LIPS.length,n.z=0,n},_c=(e,[t,n],a)=>Math.hypot((e[t].x-e[n].x)*a,e[t].y-e[n].y),dS=e=>Math.min(1,Math.max(0,e)),Vs=(e,t)=>{if(t<=0)return 1;const[n,a]=lS;return dS((e/t-n)/(a-n))},No=(e,t,n,{size:a=1,mirrored:s=!1},r)=>{if(!e||e.length<468||!(n>0))return!1;const o=ee.feedSidedName(t,s);kn(e,yc,n,Oe),kn(e,wc,n,Pe);const i=Math.hypot(Oe.x-Pe.x,Oe.y-Pe.y,Oe.z-Pe.z),c=Math.hypot(Oe.x-Pe.x,Oe.y-Pe.y);if(!(i>1e-6)||!(c>1e-9))return!1;Tn.x=(Oe.x+Pe.x)/2,Tn.y=(Oe.y+Pe.y)/2;let u=(Oe.x-Pe.x)/c,l=(Oe.y-Pe.y)/c;kn(e,fS,n,js),-l*(js.x-Tn.x)+u*(js.y-Tn.y)<0&&(u=-u,l=-l);const h=-l,f=u;switch(o){case"leftEye":Object.assign(Xe,Oe);break;case"rightEye":Object.assign(Xe,Pe);break;case"eyes":Object.assign(Xe,Tn);break;case"mouth":pS(e,n,Xe);break;case"nose":kn(e,uS,n,Xe);break;default:kn(e,hS,n,Xe)}const p=on[o],m=Math.max(.01,a),E=p.width/2*i*m,S=p.height/2*i*m;r.center.x=Xe.x/n,r.center.y=Xe.y,r.axisX.x=u*E/n,r.axisX.y=l*E,r.axisY.x=h*S/n,r.axisY.y=f*S,r.unit=i;const[g,A]=r.ellipses;if(Object.assign(g,{x:0,y:0,rx:1,ry:1,alpha:1}),Object.assign(A,{x:0,y:0,rx:1,ry:1,alpha:0}),r.count=1,o==="leftEye"||o==="rightEye"||o==="eyes"){const v=_c(e,yc,n),M=_c(e,wc,n),y=Math.max(v,M);if(o==="leftEye")g.alpha=Vs(v,y);else if(o==="rightEye")g.alpha=Vs(M,y);else{const x=on.leftEye.width/p.width,F=on.leftEye.height/p.height,w=(k,R,b)=>{const N=k.x-Xe.x,P=k.y-Xe.y;R.x=(N*u+P*l)/E,R.y=(N*h+P*f)/S,R.rx=x,R.ry=F,R.alpha=Vs(b,y)};w(Oe,g,v),w(Pe,A,M),r.count=2}}return!0},mS=`
|
|
1620
|
+
uniform vec2 insetCenter;
|
|
1621
|
+
uniform vec2 insetAxisX;
|
|
1622
|
+
uniform vec2 insetAxisY;
|
|
1623
|
+
uniform vec2 insetDraw;
|
|
1624
|
+
uniform float insetMagnify;
|
|
1625
|
+
varying vec2 vBox;
|
|
1626
|
+
varying vec2 vCamera;
|
|
1627
|
+
void main() {
|
|
1628
|
+
// Box space: -1..1 across, y down the face.
|
|
1629
|
+
vec2 q = vec2(position.x, -position.y) * 2.0;
|
|
1630
|
+
vBox = q;
|
|
1631
|
+
vec2 offset = q.x * insetAxisX + q.y * insetAxisY;
|
|
1632
|
+
vec2 source = insetCenter + offset;
|
|
1633
|
+
vCamera = vec2(source.x, 1.0 - source.y);
|
|
1634
|
+
#ifdef FACE_INSET_FILL
|
|
1635
|
+
gl_Position = vec4(q.x, -q.y, 0.0, 1.0);
|
|
1636
|
+
#else
|
|
1637
|
+
vec2 drawn = insetDraw + offset * insetMagnify;
|
|
1638
|
+
// Just behind the near plane: only a HandCutout (drawn earlier, at the
|
|
1639
|
+
// near plane) hides it.
|
|
1640
|
+
gl_Position = vec4(drawn.x * 2.0 - 1.0, 1.0 - drawn.y * 2.0, -0.999, 1.0);
|
|
1641
|
+
#endif
|
|
1642
|
+
}
|
|
1643
|
+
`,gS=`
|
|
1644
|
+
uniform sampler2D insetCamera;
|
|
1645
|
+
uniform vec4 insetEllipses[2];
|
|
1646
|
+
uniform vec2 insetEllipseAlpha;
|
|
1647
|
+
uniform float insetFeather;
|
|
1648
|
+
uniform float insetOpacity;
|
|
1649
|
+
varying vec2 vBox;
|
|
1650
|
+
varying vec2 vCamera;
|
|
1651
|
+
float ellipse(vec4 e, float alpha) {
|
|
1652
|
+
float r = length((vBox - e.xy) / e.zw);
|
|
1653
|
+
// A hard edge still gets a pixel of antialiasing.
|
|
1654
|
+
float inner = 1.0 - max(insetFeather, max(fwidth(r), 1e-4));
|
|
1655
|
+
return alpha * (1.0 - smoothstep(inner, 1.0, r));
|
|
1656
|
+
}
|
|
1657
|
+
void main() {
|
|
1658
|
+
float a = max(
|
|
1659
|
+
ellipse(insetEllipses[0], insetEllipseAlpha.x),
|
|
1660
|
+
ellipse(insetEllipses[1], insetEllipseAlpha.y)
|
|
1661
|
+
) * insetOpacity;
|
|
1662
|
+
#ifndef FACE_INSET_FILL
|
|
1663
|
+
if (a <= 0.0) discard;
|
|
1664
|
+
#endif
|
|
1665
|
+
gl_FragColor = vec4(texture2D(insetCamera, clamp(vCamera, 0.0, 1.0)).rgb, a);
|
|
1666
|
+
#include <colorspace_fragment>
|
|
1667
|
+
}
|
|
1668
|
+
`,SS=()=>({insetCamera:{value:null},insetCenter:{value:new d.Vector2(.5,.5)},insetAxisX:{value:new d.Vector2},insetAxisY:{value:new d.Vector2},insetDraw:{value:new d.Vector2(.5,.5)},insetMagnify:{value:1},insetEllipses:{value:[new d.Vector4(0,0,1,1),new d.Vector4(0,0,1,1)]},insetEllipseAlpha:{value:new d.Vector2(1,0)},insetFeather:{value:.4},insetOpacity:{value:1}}),Ph=e=>new d.ShaderMaterial({uniforms:SS(),vertexShader:mS,fragmentShader:gS,defines:e==="fill"?{FACE_INSET_FILL:""}:{},...e==="fill"?{blending:d.NoBlending}:le.faceSurfaceBlending,depthTest:e!=="fill",depthWrite:!1,side:d.DoubleSide,toneMapped:!1}),Uh=()=>({camera:null,feather:.4,opacity:1,draw:null,magnify:1}),Dh=(e,t,n)=>{e.insetCamera.value=n.camera,e.insetCenter.value.set(t.center.x,t.center.y),e.insetAxisX.value.set(t.axisX.x,t.axisX.y),e.insetAxisY.value.set(t.axisY.x,t.axisY.y);const a=n.draw??t.center;e.insetDraw.value.set(a.x,a.y),e.insetMagnify.value=n.magnify;const[s,r]=t.ellipses;e.insetEllipses.value[0].set(s.x,s.y,s.rx,s.ry),e.insetEllipses.value[1].set(r.x,r.y,r.rx,r.ry),e.insetEllipseAlpha.value.set(s.alpha,t.count>1?r.alpha:0),e.insetFeather.value=Math.min(1,Math.max(0,n.feather)),e.insetOpacity.value=Math.min(1,Math.max(0,n.opacity))},Gh=250,$h=e=>{const t=Te.useTrackerContext();return e??((t==null?void 0:t.type)==="face"?t.faceIndex:void 0)??0},Bh=(e,t)=>{const n=e==null?void 0:e.image;return n!=null&&n.width&&(n!=null&&n.height)?n.width/n.height:t.width/Math.max(1,t.height)},ES=(e,t)=>{const n=bo(e),a=Math.min(2048,Math.max(16,Math.round(t)||256));return n>=1?[a,Math.max(1,Math.round(a/n))]:[Math.max(1,Math.round(a*n)),a]},AS=(e,t)=>{const n=new d.WebGLRenderTarget(e,t,{colorSpace:d.SRGBColorSpace,depthBuffer:!1,generateMipmaps:!1,minFilter:d.LinearFilter,magFilter:d.LinearFilter}),a=new d.FramebufferTexture(e,t);return a.colorSpace=d.SRGBColorSpace,a.minFilter=d.LinearFilter,a.magFilter=d.LinearFilter,{target:n,texture:a}},Fc=new d.Color,Hh=({part:e,feather:t=.4,size:n=1,resolution:a=256,faceIndex:s,active:r=!0})=>{const o=$h(s),i=ae.useXRModelNode(ee.XRModel.FACE_TRACKER),c=qa(),u=J.useThree(g=>g.gl),l=J.useThree(g=>g.size),[h,f]=ES(e,a),p=_.useMemo(()=>AS(h,f),[h,f]);_.useEffect(()=>()=>{p.target.dispose(),p.texture.dispose()},[p]);const m=_.useMemo(()=>{const g=Ph("fill"),A=new d.PlaneGeometry(1,1),v=new d.Mesh(A,g);v.frustumCulled=!1;const M=new d.Scene;return M.add(v),{material:g,geometry:A,scene:M,camera:new d.OrthographicCamera(-1,1,1,-1,0,1),frame:Io(),look:Uh(),frameOptions:{size:1,mirrored:!0}}},[]);_.useEffect(()=>()=>{m.geometry.dispose(),Ce(m.material)},[m]);const E=_.useRef({part:e,feather:t,size:n,faceIndex:o,active:r});E.current={part:e,feather:t,size:n,faceIndex:o,active:r};const S=_.useRef({landmarks:null,texture:null,version:-1,part:e,feather:Number.NaN,size:Number.NaN,surface:null,seen:-1/0,cleared:!0});return J.useFrame(()=>{var w,k,R;const g=E.current;if(!g.active)return;const A=S.current,v=(k=(w=i==null?void 0:i.detectionResults)==null?void 0:w.faceLandmarks)==null?void 0:k[g.faceIndex],M=Bh(c,l),y=performance.now();m.frameOptions.size=g.size,m.frameOptions.mirrored=((R=i==null?void 0:i.getFace(g.faceIndex))==null?void 0:R.mirrored)!==!1;const x=u.getRenderTarget();if(c&&No(v,g.part,M,m.frameOptions,m.frame)){if(A.seen=y,v===A.landmarks&&c===A.texture&&T.feedTextureVersion(c)===A.version&&g.part===A.part&&g.feather===A.feather&&g.size===A.size&&p===A.surface)return;A.landmarks=v,A.texture=c,A.version=T.feedTextureVersion(c),A.part=g.part,A.feather=g.feather,A.size=g.size,A.surface=p,A.cleared=!1,m.look.camera=c,m.look.feather=g.feather,Dh(m.material.uniforms,m.frame,m.look);const b=u.xr.enabled;u.xr.enabled=!1,u.setRenderTarget(p.target),u.render(m.scene,m.camera),u.copyFramebufferToTexture(p.texture),u.setRenderTarget(x),u.xr.enabled=b;return}if(A.cleared||y-A.seen<Gh)return;A.cleared=!0,A.landmarks=null,u.getClearColor(Fc);const F=u.getClearAlpha();u.setRenderTarget(p.target),u.setClearColor(0,0),u.clear(!0,!1,!1),u.copyFramebufferToTexture(p.texture),u.setRenderTarget(x),u.setClearColor(Fc,F)}),p.texture},zh=le.FACE_SURFACE_RENDER_ORDER+.5,vS=["face","plane"],MS=({renderOrder:e,...t})=>{const n=ae.useXRModelNode(ee.XRModel.FACE_TRACKER),a=qa(),s=J.useThree(f=>f.size),r=_.useMemo(()=>Ph("face"),[]);_.useEffect(()=>()=>Ce(),[r]);const o=_.useMemo(Io,[]),i=_.useMemo(()=>({x:0,y:0,z:0,visibility:0}),[]),c=_.useMemo(Uh,[]),u=_.useMemo(()=>({size:1,mirrored:!0}),[]),l=_.useRef(null),h=_.useRef(t);return h.current=t,J.useFrame(()=>{var g,A,v;const f=l.current;if(!f)return;const p=h.current,m=(A=(g=n==null?void 0:n.detectionResults)==null?void 0:g.faceLandmarks)==null?void 0:A[p.faceIndex];u.size=p.size,u.mirrored=((v=n==null?void 0:n.getFace(p.faceIndex))==null?void 0:v.mirrored)!==!1;let E=!!a&&No(m,p.part,Bh(a,s),u,o);const S=E&&p.at&&m?eo.resolveFaceAnchorPoint(p.at,m,void 0,i,u.mirrored):null;p.at&&!S&&(E=!1),f.visible=E,E&&(c.camera=a??null,c.feather=p.feather,c.opacity=p.opacity,c.draw=S,c.magnify=p.magnify,Dh(r.uniforms,o,c))}),L.jsx("mesh",{ref:l,material:r,renderOrder:e,frustumCulled:!1,visible:!1,children:L.jsx("planeGeometry",{args:[1,1]})})},yS=({part:e,height:t,feather:n,size:a,opacity:s,faceIndex:r,resolution:o,renderOrder:i})=>{const c=Hh({part:e,feather:n,size:a,resolution:o,faceIndex:r});return L.jsxs("mesh",{scale:[t*bo(e),t,1],renderOrder:i,children:[L.jsx("planeGeometry",{args:[1,1]}),L.jsx("meshBasicMaterial",{map:c,transparent:!0,opacity:s,depthWrite:!1,toneMapped:!1,side:d.DoubleSide})]})},wS=({part:e,placement:t="face",magnify:n=1.5,height:a=1,at:s,feather:r=.4,size:o=1,opacity:i=1,faceIndex:c,resolution:u=256,renderOrder:l})=>{const h=$h(c);if(t==="plane")return L.jsx("group",{children:L.jsx(yS,{part:e,height:a,feather:r,size:o,opacity:i,faceIndex:h,resolution:u,renderOrder:l??0})});const f=e==="eyes"&&!s?["leftEye","rightEye"]:[e];return L.jsx("group",{children:f.map(p=>L.jsx(MS,{part:p,at:s,magnify:n,feather:r,size:o,opacity:i,faceIndex:h,renderOrder:l??zh},p))})},_S=()=>{const e=K.CANONICAL_FACE_TRIANGLES,t=new Map,n=(o,i)=>o<i?o*1024+i:i*1024+o;for(let o=0;o<e.length;o+=3)for(let i=0;i<3;i+=1){const c=n(e[o+i],e[o+(i+1)%3]);t.set(c,(t.get(c)??0)+1)}const a=new Map;for(let o=0;o<e.length;o+=3)for(let i=0;i<3;i+=1){const c=e[o+i],u=e[o+(i+1)%3];t.get(n(c,u))===1&&a.set(c,u)}const s=[],r=new Set;for(const o of a.keys()){if(r.has(o))continue;const i=[];let c=o;for(;c!==void 0&&!r.has(c);)r.add(c),i.push(c),c=a.get(c);s.push(i)}return s.sort((o,i)=>i.length-o.length)},FS=()=>{const e=_S(),[t,...n]=e;if(!t||n.length<3)throw new Error("faceReprojection: the canonical face has no eye / mouth openings");const a=V.CANONICAL_FACE_POSITIONS,s=(v,M)=>v.reduce((y,x)=>y+a[x*3+M],0)/v.length,r=n.slice(0,3).sort((v,M)=>s(v,1)-s(M,1)),o=r[0],[i,c]=r.slice(1).sort((v,M)=>s(M,0)-s(v,0)),u=[["leftEye",i],["rightEye",c],["mouth",o]],l=K.CANONICAL_FACE_LANDMARK_COUNT,h=l+u.length,f=new Float32Array(h*3);f.set(a.subarray(0,l*3));const p=new Float32Array(h*2);p.set(K.CANONICAL_FACE_UVS.subarray(0,l*2));const m=u.reduce((v,[,M])=>v+M.length,0),E=new Uint16Array(K.CANONICAL_FACE_TRIANGLES.length+m*3);E.set(K.CANONICAL_FACE_TRIANGLES);let S=K.CANONICAL_FACE_TRIANGLES.length;const g={};u.forEach(([v,M],y)=>{const x=l+y,F=S/3;for(let w=0;w<3;w+=1)f[x*3+w]=s(M,w);for(let w=0;w<2;w+=1)p[x*2+w]=M.reduce((k,R)=>k+p[R*2+w],0)/M.length;for(let w=0;w<M.length;w+=1)E[S]=M[(w+1)%M.length],E[S+1]=M[w],E[S+2]=x,S+=3;g[v]={ring:Int32Array.from(M),centre:x,triangles:[F,M.length]}});const A=new Float32Array(h).fill(1);for(const v of t)A[v]=0;return{count:h,positions:f,uvs:p,index:E,faceTriangleCount:K.CANONICAL_FACE_TRIANGLES.length/3,feather:A,openings:g}};let xc=null;const pe=()=>(xc??(xc=FS()),xc);let Cc=null;const Oo=()=>(Cc??(Cc=Object.values(pe().openings)),Cc),Kh=[.05,.3],Po=(e,t,n)=>{if(t<=e)return n<e?0:1;const a=Math.min(1,Math.max(0,(n-e)/(t-e)));return a*a*(3-2*a)},Uo=(e,t,n,a)=>{const s=pe(),r=K.CANONICAL_FACE_LANDMARK_COUNT;if(a.length<s.count)throw new RangeError(`writeFaceFacing: out needs ${s.count} entries (${r} landmarks, then the opening centres), got ${a.length}`);if(e.length<r)throw new RangeError(`writeFaceFacing: needs ${r} landmarks, got ${e.length}`);const o=K.CANONICAL_FACE_TRIANGLES,i=CS.fill(0),c=TS.fill(0);let u=0;const l=xS(o.length/3);for(let p=0;p<o.length/3;p+=1){const m=e[o[p*3]],E=e[o[p*3+1]],S=e[o[p*3+2]],g=(E.x-m.x)*t,A=E.y-m.y,v=((E.z??0)-(m.z??0))*t,M=(S.x-m.x)*t,y=S.y-m.y,x=((S.z??0)-(m.z??0))*t,F=g*y-A*M,w=Math.hypot(A*x-v*y,v*M-g*x,F);l[p]=w>1e-12?F/w:0,u+=F}const h=u<0?-1:1;for(let p=0;p<o.length/3;p+=1)for(let m=0;m<3;m+=1){const E=o[p*3+m];i[E]+=l[p]*h,c[E]+=1}for(let p=0;p<r;p+=1){const m=c[p]?i[p]/c[p]:0;a[p]=Po(n[0],n[1],m)}const f=Oo();for(let p=0;p<f.length;p+=1){const{ring:m,centre:E}=f[p];let S=0;for(let g=0;g<m.length;g+=1)S+=a[m[g]];a[E]=S/m.length}},Do=(e,t,{facing:n=Kh,inFrame:a=!1},s,r)=>{const o=pe(),i=K.CANONICAL_FACE_LANDMARK_COUNT;if(s.length<o.count*2)throw new RangeError(`writeFaceUnwrapFrame: cameraUv needs ${o.count*2} entries, got ${s.length}`);Uo(e,t,n,r);let c=!1;for(let l=0;l<i;l+=1){const{x:h,y:f}=e[l];s[l*2]=h,s[l*2+1]=1-f,r[l]*=o.feather[l],a&&!(h>=0&&h<=1&&f>=0&&f<=1)&&(r[l]=0,c=!0)}const u=Oo();for(let l=0;l<u.length;l+=1){const{ring:h,centre:f}=u[l];let p=0,m=0,E=0;for(let S=0;S<h.length;S+=1){const g=h[S];p+=s[g*2],m+=s[g*2+1],E+=r[g]}s[f*2]=p/h.length,s[f*2+1]=m/h.length,c&&(r[f]=E/h.length)}};let Ws=new Float32Array(0);const xS=e=>(Ws.length<e&&(Ws=new Float32Array(e)),Ws),CS=new Float32Array(K.CANONICAL_FACE_LANDMARK_COUNT),TS=new Uint8Array(K.CANONICAL_FACE_LANDMARK_COUNT),Tc=new WeakSet,Hn=(e=K.CANONICAL_FACE_UVS)=>{const t=pe();return e===K.CANONICAL_FACE_UVS||e===t.uvs?t.uvs:e instanceof Float32Array&&Tc.has(e)?e:vt(e,"faceUnwrapUvs",()=>{const n=K.CANONICAL_FACE_LANDMARK_COUNT;if(e.length<n*2)throw new Error(`getFaceUnwrapUvs: needs ${n} [u, v] pairs, got ${e.length/2}`);const a=new Float32Array(t.count*2);for(let s=0;s<n*2;s+=1)a[s]=e[s];for(const{ring:s,centre:r}of Oo())for(let o=0;o<2;o+=1){let i=0;for(const c of s)i+=a[c*2+o];a[r*2+o]=i/s.length}return Tc.add(a),a})};let qs=null;const kS=()=>{if(qs)return qs;const e=pe(),t=K.CANONICAL_FACE_LANDMARK_COUNT,n=new Int32Array(e.count);for(let o=0;o<t;o+=1)n[o]=T.FACE_ATLAS_MIRROR[o];const{leftEye:a,rightEye:s,mouth:r}=e.openings;return n[a.centre]=s.centre,n[s.centre]=a.centre,n[r.centre]=r.centre,qs=n,n},LS=[.2,.5],RS=(e,t,n,a)=>{const s=kS(),[r,o]=LS;for(let i=0;i<s.length;i+=1){const c=s[i];n[i*2]=e[c*2],n[i*2+1]=e[c*2+1];const u=t[i],l=t[c]-u;a[i]=l>0&&u<1?Po(r,o,l)*l/(1-u):0}},jh=(e,t,n=new Float32Array(e.triangle.length*2))=>{if(n.length<e.triangle.length*2)throw new RangeError(`writeFaceReprojectionLayoutUv: out needs ${e.triangle.length*2} entries, got ${n.length}`);const a=Hn(t),s=pe().index;for(let r=0;r<e.triangle.length;r+=1){const o=e.triangle[r];if(o<0){n[r*2]=0,n[r*2+1]=0;continue}let i=0,c=0;for(let u=0;u<3;u+=1){const l=s[o*3+u];i+=e.weights[r*3+u]*a[l*2],c+=e.weights[r*3+u]*a[l*2+1]}n[r*2]=i,n[r*2+1]=c}return n},Vh=["leftEye","rightEye","mouth"],lt={u:0,v:0,w:0,d2:0},bS=(e,t,n,a,s,r,o)=>{const i=e[r]-e[s],c=e[r+1]-e[s+1],u=e[r+2]-e[s+2],l=e[o]-e[s],h=e[o+1]-e[s+1],f=e[o+2]-e[s+2],p=t-e[s],m=n-e[s+1],E=a-e[s+2],S=i*p+c*m+u*E,g=l*p+h*m+f*E;let A=1,v=0,M=0;if(!(S<=0&&g<=0)){const w=t-e[r],k=n-e[r+1],R=a-e[r+2],b=i*w+c*k+u*R,N=l*w+h*k+f*R,P=t-e[o],G=n-e[o+1],U=a-e[o+2],H=i*P+c*G+u*U,z=l*P+h*G+f*U,X=S*N-b*g,j=H*g-S*z,D=b*z-H*N;if(b>=0&&N<=b)[A,v,M]=[0,1,0];else if(z>=0&&H<=z)[A,v,M]=[0,0,1];else if(X<=0&&S>=0&&b<=0){const $=S/(S-b);[A,v,M]=[1-$,$,0]}else if(j<=0&&g>=0&&z<=0){const $=g/(g-z);[A,v,M]=[1-$,0,$]}else if(D<=0&&N-b>=0&&H-z>=0){const $=(N-b)/(N-b+(H-z));[A,v,M]=[0,1-$,$]}else{const $=1/(D+j+X);v=j*$,M=X*$,A=1-v-M}}const y=A*e[s]+v*e[r]+M*e[o],x=A*e[s+1]+v*e[r+1]+M*e[o+1],F=A*e[s+2]+v*e[r+2]+M*e[o+2];lt.u=A,lt.v=v,lt.w=M,lt.d2=(t-y)**2+(n-x)**2+(a-F)**2},Qa=(e,t,n)=>{const a=e,s=t,r=Math.floor(s.length/3);let o=1/0,i=1/0,c=1/0,u=-1/0,l=-1/0,h=-1/0,f=0;for(let w=0;w<r;w+=1){for(let b=0;b<3;b+=1){const N=s[w*3+b]*3;o=Math.min(o,a[N]),i=Math.min(i,a[N+1]),c=Math.min(c,a[N+2]),u=Math.max(u,a[N]),l=Math.max(l,a[N+1]),h=Math.max(h,a[N+2])}const k=s[w*3]*3,R=s[w*3+1]*3;f+=Math.hypot(a[k]-a[R],a[k+1]-a[R+1],a[k+2]-a[R+2])}const p=Math.max(.001,2*f/Math.max(1,r)),m=Math.max(1,Math.ceil((u-o)/p)+1),E=Math.max(1,Math.ceil((l-i)/p)+1),S=Math.max(1,Math.ceil((h-c)/p)+1),g=new Map,A=w=>Math.min(m-1,Math.max(0,Math.floor((w-o)/p))),v=w=>Math.min(E-1,Math.max(0,Math.floor((w-i)/p))),M=w=>Math.min(S-1,Math.max(0,Math.floor((w-c)/p)));for(let w=0;w<r;w+=1){if(n!=null&&n[w])continue;const k=[s[w*3]*3,s[w*3+1]*3,s[w*3+2]*3],R=A(Math.min(...k.map(H=>a[H]))),b=A(Math.max(...k.map(H=>a[H]))),N=v(Math.min(...k.map(H=>a[H+1]))),P=v(Math.max(...k.map(H=>a[H+1]))),G=M(Math.min(...k.map(H=>a[H+2]))),U=M(Math.max(...k.map(H=>a[H+2])));for(let H=R;H<=b;H+=1)for(let z=N;z<=P;z+=1)for(let X=G;X<=U;X+=1){const j=(H*E+z)*S+X;let D=g.get(j);D||(D=[],g.set(j,D)),D.push(w)}}const y=new Int32Array(r).fill(-1);let x=0;const F=Math.max(m,E,S);return(w,k,R,b)=>{b.triangle=-1,b.d2=1/0,x+=1;const N=Math.floor((w-o)/p),P=Math.floor((k-i)/p),G=Math.floor((R-c)/p),U=Math.max(o-w,w-u,i-k,k-l,c-R,R-h,0),H=Math.max(0,Math.floor(U/p)-1);for(let z=H;z<=F+H;z+=1){const X=Math.max(0,(z-1)*p);if(b.triangle>=0&&X*X>b.d2)break;for(let j=N-z;j<=N+z;j+=1)if(!(j<0||j>=m)){for(let D=P-z;D<=P+z;D+=1)if(!(D<0||D>=E))for(let $=G-z;$<=G+z;$+=1){if($<0||$>=S||Math.max(Math.abs(j-N),Math.abs(D-P),Math.abs($-G))!==z)continue;const q=g.get((j*E+D)*S+$);if(q)for(const Q of q)y[Q]!==x&&(y[Q]=x,bS(a,w,k,R,s[Q*3]*3,s[Q*3+1]*3,s[Q*3+2]*3),lt.d2<b.d2&&(b.d2=lt.d2,b.triangle=Q,b.u=lt.u,b.v=lt.v,b.w=lt.w))}}}return b}},Xs=[0,.5,-4],Ut=(e,{falloff:t=[1,3],openings:n=Vh}={})=>vt(e,`${t.join()}|${[...n].sort().join()}`,()=>IS(e,t,n)),IS=(e,t,n)=>{const a=pe(),s=a.positions,r=a.index,o=r.length/3,i=new Uint8Array(o);for(const m of Vh){if(n.includes(m))continue;const[E,S]=a.openings[m].triangles;i.fill(1,E,E+S)}const c=Qa(s,r,i),u={triangle:-1,u:0,v:0,w:0,d2:0},l=e.length/3,h={triangle:new Int32Array(l).fill(-1),weights:new Float32Array(l*3),canonicalUv:new Float32Array(l*2),coverage:new Float32Array(l),distance:new Float32Array(l)},[f,p]=t;for(let m=0;m<l;m+=1){const E=e[m*3],S=e[m*3+1],g=e[m*3+2];c(E,S,g,u);const A=u.triangle,v=u.d2,[M,y,x]=[u.u,u.v,u.w];if(A<0)continue;const[F,w,k]=[r[A*3],r[A*3+1],r[A*3+2]];h.triangle[m]=A,h.weights[m*3]=M,h.weights[m*3+1]=y,h.weights[m*3+2]=x;const R=a.uvs;h.canonicalUv[m*2]=M*R[F*2]+y*R[w*2]+x*R[k*2],h.canonicalUv[m*2+1]=M*R[F*2+1]+y*R[w*2+1]+x*R[k*2+1];const b=M*s[F*3]+y*s[w*3]+x*s[k*3],N=M*s[F*3+1]+y*s[w*3+1]+x*s[k*3+1],P=M*s[F*3+2]+y*s[w*3+2]+x*s[k*3+2],G=(E-b)*(b-Xs[0])+(S-N)*(N-Xs[1])+(g-P)*(P-Xs[2]),U=Math.sqrt(v)*(G<0?-1:1);h.distance[m]=U,h.coverage[m]=1-Po(f,p,Math.abs(U))}return h},Go=()=>{const e=pe(),t=e.positions,n=(a,s,r)=>{const{ring:o,centre:i}=e.openings[a];let c=0,u=0;for(const l of o)c=Math.max(c,Math.abs(t[l*3]-t[i*3])),u=Math.max(u,Math.abs(t[l*3+1]-t[i*3+1]));return[t[i*3],t[i*3+1],c+s,u+r]};return[n("leftEye",.7,1.1),n("rightEye",.7,1.1),n("mouth",.8,1.2)]},Or=e=>{switch(e){case"eyes":return[1,1,0,0];case"mouth":return[0,0,1,0];case"eyesAndMouth":return[1,1,1,0];default:return[0,0,0,1]}},$o=()=>({faceReprojectionMap:{value:null},faceReprojectionAmount:{value:1},faceReprojectionLit:{value:0},faceReprojectionFill:{value:0},faceReprojectionFillReach:{value:Bo},faceReprojectionFillTexelsPerCm:{value:Ho(512)}}),Bo=30,Ho=e=>{const{positions:t,uvs:n}=pe();let a=1/0,s=-1/0,r=1/0,o=-1/0;for(let i=0;i<n.length/2;i+=1)a=Math.min(a,t[i*3]),s=Math.max(s,t[i*3]),r=Math.min(r,n[i*2]),o=Math.max(o,n[i*2]);return(o-r)/Math.max(1e-6,s-a)*e},NS=`
|
|
1669
|
+
vec4 faceReprojectionFillColor(vec2 uv, float d) {
|
|
1670
|
+
float w = faceReprojectionFill * (1.0 - smoothstep(faceReprojectionFillReach * 0.8, faceReprojectionFillReach, d));
|
|
1671
|
+
if (w <= 0.0) return vec4(0.0);
|
|
1672
|
+
float lod = log2(1.0 + max(d, 0.0) * faceReprojectionFillTexelsPerCm);
|
|
1673
|
+
vec4 acc = vec4(0.0);
|
|
1674
|
+
for (int k = 0; k < 12; k++) {
|
|
1675
|
+
acc += (1.0 - acc.a) * textureLod(faceReprojectionMap, uv, lod + float(k));
|
|
1676
|
+
if (acc.a > 0.99) break;
|
|
1677
|
+
}
|
|
1678
|
+
return acc.a > 0.0 ? vec4(acc.rgb / acc.a, 1.0) * w : vec4(0.0);
|
|
1679
|
+
}
|
|
1680
|
+
`,zo=(e,t,{attributes:n=!1,fill:a=!1}={})=>{const s=n&&a,r=e.onBeforeCompile;e.onBeforeCompile=(i,c)=>{r.call(e,i,c),Object.assign(i.uniforms,t),i.vertexShader=i.vertexShader.replace("#include <common>",(n?`#include <common>
|
|
1681
|
+
attribute vec2 faceUv;
|
|
1682
|
+
attribute float faceCoverage;
|
|
1683
|
+
varying vec2 vFaceReprojectionUv;
|
|
1684
|
+
varying float vFaceCoverage;`:`#include <common>
|
|
1685
|
+
varying vec2 vFaceReprojectionUv;
|
|
1686
|
+
varying float vFaceCoverage;`)+(s?`
|
|
1687
|
+
attribute float faceDistance;
|
|
1688
|
+
varying float vFaceDistance;`:"")).replace("#include <uv_vertex>",(n?`#include <uv_vertex>
|
|
1689
|
+
vFaceReprojectionUv = faceUv;
|
|
1690
|
+
vFaceCoverage = faceCoverage;`:`#include <uv_vertex>
|
|
1691
|
+
vFaceReprojectionUv = uv;
|
|
1692
|
+
vFaceCoverage = 1.0;`)+(s?`
|
|
1693
|
+
vFaceDistance = faceDistance;`:""));const u=i.fragmentShader.includes("#include <emissivemap_fragment>"),l=u?"faceReprojectionLit":"1.0";i.fragmentShader=i.fragmentShader.replace("#include <common>",["#include <common>","uniform sampler2D faceReprojectionMap;","uniform float faceReprojectionAmount;","uniform float faceReprojectionLit;","varying vec2 vFaceReprojectionUv;","varying float vFaceCoverage;",...s?["uniform float faceReprojectionFill;","uniform float faceReprojectionFillReach;","uniform float faceReprojectionFillTexelsPerCm;","varying float vFaceDistance;",NS]:[]].join(`
|
|
1694
|
+
`)).replace("#include <map_fragment>",["#include <map_fragment>","vec4 faceReprojection = texture2D(faceReprojectionMap, vFaceReprojectionUv) * (faceReprojectionAmount * vFaceCoverage);",...s?["faceReprojection += (1.0 - faceReprojection.a) * faceReprojectionFillColor(vFaceReprojectionUv, vFaceDistance) * faceReprojectionAmount;"]:[],`diffuseColor.rgb = diffuseColor.rgb * (1.0 - faceReprojection.a) + faceReprojection.rgb * ${l};`].join(`
|
|
1695
|
+
`)),u&&(i.fragmentShader=i.fragmentShader.replace("#include <emissivemap_fragment>",["#include <emissivemap_fragment>","totalEmissiveRadiance = totalEmissiveRadiance * (1.0 - faceReprojection.a) + faceReprojection.rgb * (1.0 - faceReprojectionLit);"].join(`
|
|
1696
|
+
`)))};const o=e.customProgramCacheKey.bind(e);e.customProgramCacheKey=()=>`${o()}|faceReprojection${n?"Attributes":""}${s?"Fill":""}`,e.needsUpdate=!0},kc=`
|
|
1697
|
+
attribute vec2 cameraUv;
|
|
1698
|
+
attribute float weight;
|
|
1699
|
+
attribute vec3 canonical;
|
|
1700
|
+
varying vec2 vCameraUv;
|
|
1701
|
+
varying float vWeight;
|
|
1702
|
+
varying vec3 vCanonical;
|
|
1703
|
+
void main() {
|
|
1704
|
+
vCameraUv = cameraUv;
|
|
1705
|
+
vWeight = weight;
|
|
1706
|
+
vCanonical = canonical;
|
|
1707
|
+
gl_Position = vec4(position.xy * 2.0 - 1.0, 0.0, 1.0);
|
|
1708
|
+
}
|
|
1709
|
+
`,Lc=`
|
|
1710
|
+
uniform sampler2D cameraMap;
|
|
1711
|
+
uniform vec4 regions[3];
|
|
1712
|
+
uniform vec4 regionMask;
|
|
1713
|
+
uniform float regionSoftness;
|
|
1714
|
+
uniform float inFrame;
|
|
1715
|
+
varying vec2 vCameraUv;
|
|
1716
|
+
varying float vWeight;
|
|
1717
|
+
varying vec3 vCanonical;
|
|
1718
|
+
float inside(vec4 e) {
|
|
1719
|
+
float r = length((vCanonical.xy - e.xy) / e.zw);
|
|
1720
|
+
return 1.0 - smoothstep(1.0 - regionSoftness, 1.0, r);
|
|
1721
|
+
}
|
|
1722
|
+
void main() {
|
|
1723
|
+
float region = regionMask.w;
|
|
1724
|
+
region = max(region, regionMask.x * inside(regions[0]));
|
|
1725
|
+
region = max(region, regionMask.y * inside(regions[1]));
|
|
1726
|
+
region = max(region, regionMask.z * inside(regions[2]));
|
|
1727
|
+
// inFrame: nothing from past the image's edge (a clamped sample is not the face).
|
|
1728
|
+
vec2 c = vCameraUv;
|
|
1729
|
+
float image = step(0.0, c.x) * step(c.x, 1.0) * step(0.0, c.y) * step(c.y, 1.0);
|
|
1730
|
+
float a = clamp(vWeight, 0.0, 1.0) * region * mix(1.0, image, inFrame);
|
|
1731
|
+
gl_FragColor = vec4(texture2D(cameraMap, vCameraUv).rgb * a, a);
|
|
1732
|
+
}
|
|
1733
|
+
`,OS=`
|
|
1734
|
+
attribute vec2 canonicalUv;
|
|
1735
|
+
attribute float coverage;
|
|
1736
|
+
varying vec2 vUv;
|
|
1737
|
+
varying vec2 vCanonicalUv;
|
|
1738
|
+
varying float vCoverage;
|
|
1739
|
+
void main() {
|
|
1740
|
+
vUv = uv;
|
|
1741
|
+
vCanonicalUv = canonicalUv;
|
|
1742
|
+
vCoverage = coverage;
|
|
1743
|
+
gl_Position = vec4(uv * 2.0 - 1.0, 0.0, 1.0);
|
|
1744
|
+
}
|
|
1745
|
+
`,PS=`
|
|
1746
|
+
uniform sampler2D unwrapMap;
|
|
1747
|
+
uniform sampler2D maskMap;
|
|
1748
|
+
uniform float useMask;
|
|
1749
|
+
uniform sampler2D canonicalMaskMap;
|
|
1750
|
+
uniform float useCanonicalMask;
|
|
1751
|
+
varying vec2 vUv;
|
|
1752
|
+
varying vec2 vCanonicalUv;
|
|
1753
|
+
varying float vCoverage;
|
|
1754
|
+
void main() {
|
|
1755
|
+
float m = vCoverage;
|
|
1756
|
+
m *= mix(1.0, texture2D(maskMap, vUv).r, useMask);
|
|
1757
|
+
m *= mix(1.0, texture2D(canonicalMaskMap, vCanonicalUv).r, useCanonicalMask);
|
|
1758
|
+
gl_FragColor = texture2D(unwrapMap, vCanonicalUv) * m;
|
|
1759
|
+
}
|
|
1760
|
+
`,US=`
|
|
1761
|
+
varying vec2 vUv;
|
|
1762
|
+
void main() {
|
|
1763
|
+
vUv = uv;
|
|
1764
|
+
gl_Position = vec4(position.xy, 0.0, 1.0);
|
|
1765
|
+
}
|
|
1766
|
+
`,DS=`
|
|
1767
|
+
uniform sampler2D source;
|
|
1768
|
+
uniform vec2 texel;
|
|
1769
|
+
uniform float padding;
|
|
1770
|
+
varying vec2 vUv;
|
|
1771
|
+
vec4 best;
|
|
1772
|
+
void take(vec2 d) {
|
|
1773
|
+
vec4 s = texture2D(source, vUv + d * texel);
|
|
1774
|
+
if (s.a > best.a) best = s;
|
|
1775
|
+
}
|
|
1776
|
+
void main() {
|
|
1777
|
+
vec4 c = texture2D(source, vUv);
|
|
1778
|
+
best = vec4(0.0);
|
|
1779
|
+
if (c.a <= 0.0) {
|
|
1780
|
+
for (int r = 1; r <= PAD_MAX; r++) {
|
|
1781
|
+
if (float(r) > padding) break;
|
|
1782
|
+
float f = float(r);
|
|
1783
|
+
take(vec2(f, 0.0)); take(vec2(-f, 0.0)); take(vec2(0.0, f)); take(vec2(0.0, -f));
|
|
1784
|
+
take(vec2(f, f)); take(vec2(-f, f)); take(vec2(f, -f)); take(vec2(-f, -f));
|
|
1785
|
+
if (best.a > 0.0) break;
|
|
1786
|
+
}
|
|
1787
|
+
c = best;
|
|
1788
|
+
}
|
|
1789
|
+
gl_FragColor = c;
|
|
1790
|
+
}
|
|
1791
|
+
`,Rc=16,ga=(e,t)=>new d.WebGLRenderTarget(e,e,{colorSpace:d.SRGBColorSpace,depthBuffer:!1,generateMipmaps:t,minFilter:t?d.LinearMipmapLinearFilter:d.LinearFilter,magFilter:d.LinearFilter}),Ta=e=>Object.assign(e,{side:d.DoubleSide,depthTest:!1,depthWrite:!1,blending:d.NoBlending,toneMapped:!1}),GS=e=>Object.assign(Ta(e),{blending:d.CustomBlending,blendEquation:d.AddEquation,blendSrc:d.OneMinusDstAlphaFactor,blendDst:d.OneFactor,blendEquationAlpha:d.AddEquation,blendSrcAlpha:d.OneMinusDstAlphaFactor,blendDstAlpha:d.OneFactor}),Pr=(e,t)=>{const n=pe(),a=new d.BufferGeometry;t?(a.setAttribute("position",t.getAttribute("position")),a.setAttribute("canonical",t.getAttribute("canonical")),a.setIndex(t.getIndex())):(a.setAttribute("position",new d.BufferAttribute(new Float32Array(n.count*3),3)),Wh(a,Hn(e)),a.setAttribute("canonical",new d.BufferAttribute(n.positions,3)),a.setIndex(new d.BufferAttribute(n.index,1)));const s=r=>new d.BufferAttribute(new Float32Array(n.count*r),r).setUsage(d.DynamicDrawUsage);return a.setAttribute("cameraUv",s(2)),a.setAttribute("weight",s(1)),a},Wh=(e,t)=>{const n=e.getAttribute("position"),a=n.array;for(let s=0;s<n.count;s+=1)a[s*3]=t[s*2],a[s*3+1]=t[s*2+1],a[s*3+2]=0;n.needsUpdate=!0},bc=new d.Color;class Ja{constructor(t={}){C(this,"unwrapTarget");C(this,"target");C(this,"remapTarget");C(this,"unwrapRawTarget",null);C(this,"padUniforms",{source:{value:null},texel:{value:new d.Vector2},padding:{value:2}});C(this,"padScene",new d.Scene);C(this,"padMaterial");C(this,"unwrapPadUniforms",{source:{value:null},texel:{value:new d.Vector2},padding:{value:0}});C(this,"unwrapPadScene",new d.Scene);C(this,"unwrapPadMaterial");C(this,"unwrapUniforms",{cameraMap:{value:null},regions:{value:Go().map(t=>new d.Vector4(...t))},regionMask:{value:new d.Vector4(...Or("face"))},regionSoftness:{value:.4},inFrame:{value:0}});C(this,"remapUniforms",{unwrapMap:{value:null},maskMap:{value:null},useMask:{value:0},canonicalMaskMap:{value:null},useCanonicalMask:{value:0}});C(this,"camera",new d.OrthographicCamera(-1,1,1,-1,0,1));C(this,"unwrapScene",new d.Scene);C(this,"remapScene",new d.Scene);C(this,"unwrapGeometry");C(this,"unwrapMaterial");C(this,"mirrorGeometry");C(this,"mirrorMesh");C(this,"mirrorMaterial");C(this,"remapMaterial");C(this,"remapMeshes",[]);C(this,"remapBindings",[]);C(this,"layout");C(this,"options");C(this,"frame",{});this.options={...t},this.layout=Hn(t.uvs),this.unwrapTarget=ga(t.unwrapResolution??512,!!t.unwrapMipmaps),this.target=ga(t.resolution??1024,!0),this.remapTarget=ga(t.resolution??1024,!1),this.remapUniforms.unwrapMap.value=this.unwrapTarget.texture,this.padUniforms.source.value=this.remapTarget.texture;const n=(r,o)=>Ta(new d.ShaderMaterial({uniforms:r,defines:{PAD_MAX:o},vertexShader:US,fragmentShader:DS})),a=(r,o)=>{const i=new d.Mesh(new d.PlaneGeometry(2,2),o);i.frustumCulled=!1,r.add(i)};this.padMaterial=n(this.padUniforms,4),a(this.padScene,this.padMaterial),this.unwrapPadMaterial=n(this.unwrapPadUniforms,Rc),a(this.unwrapPadScene,this.unwrapPadMaterial),this.unwrapGeometry=Pr(this.options.uvs),this.unwrapMaterial=Ta(new d.ShaderMaterial({uniforms:this.unwrapUniforms,vertexShader:kc,fragmentShader:Lc}));const s=new d.Mesh(this.unwrapGeometry,this.unwrapMaterial);s.frustumCulled=!1,this.unwrapScene.add(s),this.mirrorGeometry=Pr(void 0,this.unwrapGeometry),this.mirrorMaterial=GS(new d.ShaderMaterial({uniforms:this.unwrapUniforms,vertexShader:kc,fragmentShader:Lc})),this.mirrorMesh=new d.Mesh(this.mirrorGeometry,this.mirrorMaterial),this.mirrorMesh.frustumCulled=!1,this.mirrorMesh.renderOrder=1,this.mirrorMesh.visible=!1,this.unwrapScene.add(this.mirrorMesh),this.remapMaterial=Ta(new d.ShaderMaterial({uniforms:this.remapUniforms,vertexShader:OS,fragmentShader:PS}))}get texture(){return this.target.texture}get unwrapTexture(){return this.unwrapTarget.texture}setOptions(t){var s;this.options={...this.options,...t};const n=t.unwrapResolution;n&&n!==this.unwrapTarget.width&&(this.unwrapTarget.setSize(n,n),(s=this.unwrapRawTarget)==null||s.setSize(n,n));const a=t.resolution;if(a&&a!==this.target.width&&(this.target.setSize(a,a),this.remapTarget.setSize(a,a)),"unwrapMipmaps"in t){const r=!!t.unwrapMipmaps,o=this.unwrapTarget.texture;o.generateMipmaps!==r&&(o.generateMipmaps=r,o.minFilter=r?d.LinearMipmapLinearFilter:d.LinearFilter,this.unwrapTarget.dispose())}if("uvs"in t){const r=Hn(t.uvs);r!==this.layout&&(this.layout=r,Wh(this.unwrapGeometry,r),this.remapMeshes.forEach((o,i)=>this.writeRemapUv(o,this.remapBindings[i])))}}setRegion(t){this.unwrapUniforms.regionMask.value.set(...Or(t))}setMasks(t,n){this.remapUniforms.maskMap.value=t,this.remapUniforms.useMask.value=t?1:0,this.remapUniforms.canonicalMaskMap.value=n,this.remapUniforms.useCanonicalMask.value=n?1:0}setTargets(t){this.clearTargets();for(const{geometry:n,canonical:a,openings:s}of t){const r=n.getAttribute("uv");if(!r)continue;const o=Ut(a,{falloff:this.options.falloff,openings:s}),i=new d.BufferGeometry,c=new Float32Array(r.count*2);for(let l=0;l<r.count;l+=1)c[l*2]=r.getX(l),c[l*2+1]=r.getY(l);i.setAttribute("position",new d.BufferAttribute(new Float32Array(r.count*3),3)),i.setAttribute("uv",new d.BufferAttribute(c,2)),i.setAttribute("coverage",new d.BufferAttribute(o.coverage,1)),n.index&&i.setIndex(n.index.clone());const u=new d.Mesh(i,this.remapMaterial);u.frustumCulled=!1,this.writeRemapUv(u,o),this.remapMeshes.push(u),this.remapBindings.push(o),this.remapScene.add(u)}}writeRemapUv(t,n){const a=t.geometry;if(this.layout===pe().uvs){a.setAttribute("canonicalUv",new d.BufferAttribute(n.canonicalUv,2));return}const s=a.getAttribute("canonicalUv"),r=s&&s.array!==n.canonicalUv?s:new d.BufferAttribute(new Float32Array(n.triangle.length*2),2);jh(n,this.layout,r.array),r.needsUpdate=!0,r!==s&&a.setAttribute("canonicalUv",r)}render(t,n,a){const s=n.image,r=s!=null&&s.width&&(s!=null&&s.height)?s.width/s.height:1,o=this.unwrapGeometry.getAttribute("cameraUv"),i=this.unwrapGeometry.getAttribute("weight"),c=!!this.options.mirrorFill;if(this.frame.facing=this.options.facing,this.frame.inFrame=this.options.inFrame??c,this.unwrapUniforms.inFrame.value=this.frame.inFrame?1:0,Do(a,r,this.frame,o.array,i.array),o.needsUpdate=!0,i.needsUpdate=!0,this.mirrorMesh.visible=c,c){const p=this.mirrorGeometry.getAttribute("cameraUv"),m=this.mirrorGeometry.getAttribute("weight");RS(o.array,i.array,p.array,m.array),p.needsUpdate=!0,m.needsUpdate=!0}this.unwrapUniforms.cameraMap.value=n;const u=Math.min(Rc,Math.max(0,this.options.unwrapPadding??0)),l=t.getRenderTarget();t.getClearColor(bc);const h=t.getClearAlpha(),f=t.xr.enabled;if(t.xr.enabled=!1,t.setClearColor(0,0),u>0){const p=this.rawUnwrapTarget();t.setRenderTarget(p),t.clear(!0,!1,!1),t.render(this.unwrapScene,this.camera),this.unwrapPadUniforms.source.value=p.texture,this.unwrapPadUniforms.texel.value.set(1/p.width,1/p.height),this.unwrapPadUniforms.padding.value=u,t.setRenderTarget(this.unwrapTarget),t.render(this.unwrapPadScene,this.camera)}else t.setRenderTarget(this.unwrapTarget),t.clear(!0,!1,!1),t.render(this.unwrapScene,this.camera);if(!this.remapMeshes.length){this.restore(t,l,h,f);return}t.setRenderTarget(this.remapTarget),t.clear(!0,!1,!1),t.render(this.remapScene,this.camera),this.padUniforms.texel.value.set(1/this.remapTarget.width,1/this.remapTarget.height),this.padUniforms.padding.value=Math.min(4,Math.max(0,this.options.padding??2)),t.setRenderTarget(this.target),t.render(this.padScene,this.camera),this.restore(t,l,h,f)}rawUnwrapTarget(){return this.unwrapRawTarget??(this.unwrapRawTarget=ga(this.unwrapTarget.width,!1)),this.unwrapRawTarget}restore(t,n,a,s){t.setRenderTarget(n),t.setClearColor(bc,a),t.xr.enabled=s}clearTargets(){for(const t of this.remapMeshes)this.remapScene.remove(t),t.geometry.dispose();this.remapMeshes=[],this.remapBindings=[]}dispose(){var t;this.clearTargets(),this.mirrorGeometry.dispose(),this.unwrapGeometry.dispose(),Ce(this.unwrapMaterial),Ce(this.mirrorMaterial),Ce(this.remapMaterial),Ce(this.padMaterial),Ce(this.unwrapPadMaterial),this.padScene.children[0].geometry.dispose(),this.unwrapPadScene.children[0].geometry.dispose(),this.unwrapTarget.dispose(),(t=this.unwrapRawTarget)==null||t.dispose(),this.remapTarget.dispose(),this.target.dispose()}}const Za=K.CANONICAL_FACE_LANDMARK_COUNT+3,Ic=K.CANONICAL_FACE_LANDMARK_COUNT,Nc=K.CANONICAL_FACE_LANDMARK_COUNT+1,Oc=K.CANONICAL_FACE_LANDMARK_COUNT+2,qh=(()=>{const e=new Int32Array(Za);return e.set(T.FACE_ATLAS_MIRROR),e[Ic]=Nc,e[Nc]=Ic,e[Oc]=Oc,e})(),Ur=478,$S=[[468,473],[469,476],[470,475],[471,474],[472,477]],BS=(()=>{const e=new Int32Array(Ur);e.set(T.FACE_ATLAS_MIRROR);for(const[t,n]of $S)e[t]=n,e[n]=t;return e})(),HS=(e,t=[])=>{const n=e.length;if(n<K.CANONICAL_FACE_LANDMARK_COUNT)throw new Error(`mirrorFaceLandmarks: needs ${K.CANONICAL_FACE_LANDMARK_COUNT} landmarks or more, got ${n}`);if(t===e)throw new Error("mirrorFaceLandmarks: out must not be the input array");const a=n>=Ur?Ur:K.CANONICAL_FACE_LANDMARK_COUNT;t.length=n;for(let s=0;s<n;s+=1){const r=e[s<a?BS[s]:s],o=t[s];o?(o.x=r.x,o.y=r.y,o.z=r.z):t[s]=r.z===void 0?{x:r.x,y:r.y}:{x:r.x,y:r.y,z:r.z}}return t},Xh=(e,t)=>ee.personLeftSign(e)!==ee.personLeftSign(t);let Ys=null;const Yh=()=>{if(Ys)return Ys;const e=pe(),t=new Float32Array(e.count*2);t.set(T.FACE_ATLAS_UVS.subarray(0,K.CANONICAL_FACE_LANDMARK_COUNT*2));for(const{ring:n,centre:a}of Object.values(e.openings))for(let s=0;s<2;s+=1){let r=0;for(const o of n)r+=T.FACE_ATLAS_UVS[o*2+s];t[a*2+s]=r/n.length}return Ys=t,t},zS=720,KS=16,Ua={eye:1,mouth:2},Dr=(e,t,n)=>{const a=[e,t,n].sort((s,r)=>s-r);return(a[0]*1024+a[1])*1024+a[2]},Ln=(e,t)=>e<t?e*1024+t:t*1024+e,Qh=()=>{const e=pe(),t=new Uint8Array(e.index.length/3);for(const[s,{triangles:r}]of Object.entries(e.openings))t.fill(s==="mouth"?Ua.mouth:Ua.eye,r[0],r[0]+r[1]);const n=new Set,a=[];for(let s=0;s<e.index.length/3;s+=1){const r=Dr(e.index[s*3],e.index[s*3+1],e.index[s*3+2]);n.has(r)||(n.add(r),a.push(s))}return{mesh:e,parents:a,kinds:t}},jS=(e,t)=>{const n=e.positions,a=e.index,s=r=>n[a[r*3]*3+2]+n[a[r*3+1]*3+2]+n[a[r*3+2]*3+2];return[...t].sort((r,o)=>s(r)-s(o)||r-o)},Sa=(e,t,n,a)=>{const s=e.length,r=s*t,o=new Float64Array(r*3),i=new Float64Array(r*2),c=h=>e[(h%s+s)%s],u=(h,f)=>Math.sqrt(Math.hypot(n[h*3]-n[f*3],n[h*3+1]-n[f*3+1],n[h*3+2]-n[f*3+2]))||1e-6,l=(h,f,p,m,E)=>{const S=[(f-E)/(f-h),(E-h)/(f-h),0,0],g=[0,(p-E)/(p-f),(E-f)/(p-f),0],A=[0,0,(m-E)/(m-p),(E-p)/(m-p)],v=S.map((y,x)=>(p-E)/(p-h)*y+(E-h)/(p-h)*g[x]),M=g.map((y,x)=>(m-E)/(m-f)*y+(E-f)/(m-f)*A[x]);return v.map((y,x)=>(p-E)/(p-f)*y+(E-f)/(p-f)*M[x])};for(let h=0;h<s;h+=1){const f=[c(h-1),c(h),c(h+1),c(h+2)],p=u(f[0],f[1]),m=p+u(f[1],f[2]),E=m+u(f[2],f[3]);for(let S=0;S<t;S+=1){const g=l(0,p,m,E,p+(m-p)*S/t),A=h*t+S;for(let v=0;v<4;v+=1){for(let M=0;M<3;M+=1)o[A*3+M]+=g[v]*n[f[v]*3+M];for(let M=0;M<2;M+=1)i[A*2+M]+=g[v]*a[f[v]*2+M]}}}return{xyz:o,uv:i,count:r}},Pc=(e,t,n,a,s,r)=>{const o=a[s*3],i=a[s*3+1],c=a[s*3+2],u=a[r*3]-o,l=a[r*3+1]-i,h=a[r*3+2]-c,f=u*u+l*l+h*h,p=f>0?Math.min(1,Math.max(0,((e-o)*u+(t-i)*l+(n-c)*h)/f)):0;return(e-o-p*u)**2+(t-i-p*l)**2+(n-c-p*h)**2},Qs=(e,t,n,{xyz:a,count:s})=>{let r=0,o=1/0;for(let u=0;u<s;u+=1){const l=(e-a[u*3])**2+(t-a[u*3+1])**2+(n-a[u*3+2])**2;l<o&&(o=l,r=u)}const i=(r+s-1)%s,c=(r+1)%s;return Math.sqrt(Math.min(Pc(e,t,n,a,i,r),Pc(e,t,n,a,r,c)))},Js=(e,t,{uv:n,count:a})=>{let s=!1;for(let r=0,o=a-1;r<a;o=r,r+=1){const i=n[r*2],c=n[r*2+1],u=n[o*2],l=n[o*2+1];c>t!=l>t&&e<(u-i)*(t-c)/(l-c)+i&&(s=!s)}return s},Zs=1,Jh=(e,t,n,a,s)=>{const r=e.positions,o=e.index;let i=[-1,0,0,0],c=1/0,u=[-1,0,0,0],l=1/0;for(const E of t){const S=o[E*3]*3,g=o[E*3+1]*3,A=o[E*3+2]*3,v=(r[g]-r[S])*(r[A+1]-r[S+1])-(r[A]-r[S])*(r[g+1]-r[S+1]);if(Math.abs(v)<1e-12)continue;const M=((n-r[S])*(r[A+1]-r[S+1])-(r[A]-r[S])*(a-r[S+1]))/v,y=((r[g]-r[S])*(a-r[S+1])-(n-r[S])*(r[g+1]-r[S+1]))/v,x=1-M-y,F=-Math.min(x,M,y);if(F<=1e-5){const w=x*r[S+2]+M*r[g+2]+y*r[A+2],k=s===null?-w:Math.abs(w-s);k<c&&(c=k,i=[E,x,M,y])}else F<l&&(l=F,u=[E,x,M,y])}if(i[0]>=0)return i;const[h,...f]=u,p=f.map(E=>Math.max(0,E)),m=p[0]+p[1]+p[2]||1;return[h,p[0]/m,p[1]/m,p[2]/m]},VS=e=>{const{mesh:t,parents:n,kinds:a}=Qh(),s=t.positions,r=t.index,o=Yh(),i=2**e,c=i*i,u=jS(t,n),l=[],h=[];for(let D=0;D<Za;D+=1)l.push(D,D,D),h.push(1,0,0);const f=new Map,p=(D,$,q)=>{const[Q,se,Z]=D<$?[D,$,q]:[$,D,i-q],B=Ln(Q,se)*8+Z;let Y=f.get(B);return Y===void 0&&(Y=l.length/3,f.set(B,Y),l.push(Q,se,se),h.push(1-Z/i,Z/i,0)),Y},m=new Uint16Array(u.length*c*3);let E=0;const S=new Int32Array((i+1)*(i+1));for(const D of u){const $=r[D*3],q=r[D*3+1],Q=r[D*3+2];for(let B=0;B<=i;B+=1)for(let Y=0;Y<=i-B;Y+=1){const te=i-B-Y;let ie;B===0&&Y===0?ie=$:B===i?ie=q:Y===i?ie=Q:Y===0?ie=p($,q,B):B===0?ie=p($,Q,Y):te===0?ie=p(q,Q,Y):(ie=l.length/3,l.push($,q,Q),h.push(te/i,B/i,Y/i)),S[B*(i+1)+Y]=ie}const se=(B,Y,te)=>{m[E]=B,m[E+1]=Y,m[E+2]=te,E+=3},Z=(B,Y)=>S[B*(i+1)+Y];for(let B=0;B<i;B+=1)for(let Y=0;Y<i-B;Y+=1)se(Z(B,Y),Z(B+1,Y),Z(B,Y+1)),B+Y<i-1&&se(Z(B+1,Y),Z(B+1,Y+1),Z(B,Y+1))}const g=l.length/3,A=new Float32Array(g*3),v=new Float32Array(g*2),M=new Float32Array(g*2),y=new Float32Array(g),x=new Float32Array(g),F=new Float32Array(g),w=new Float32Array(g),k=new Set,R=new Set;for(const D of n){const[$,q,Q]=[r[D*3],r[D*3+1],r[D*3+2]];k.add(Ln($,q)).add(Ln(q,Q)).add(Ln(Q,$)),R.add(Dr($,q,Q))}const b=qh,N=Sa(T.FACE_ATLAS_OVAL_RING,zS/T.FACE_ATLAS_OVAL_RING.length,s,o),P=KS,G=[Sa(T.FACE_ATLAS_EYE_RINGS.negX,P,s,o),Sa(T.FACE_ATLAS_EYE_RINGS.posX,P,s,o)],U=Sa(T.FACE_ATLAS_LIP_RINGS.inner,P,s,o),H=D=>t.openings[D].centre,z=new Set([H("leftEye"),H("rightEye")]),X=H("mouth");for(let D=0;D<g;D+=1){const $=[l[D*3],l[D*3+1],l[D*3+2]],q=[h[D*3],h[D*3+1],h[D*3+2]];let Q=0,se=0,Z=0,B=0,Y=0;for(let ce=0;ce<3;ce+=1)Q+=q[ce]*s[$[ce]*3],se+=q[ce]*s[$[ce]*3+1],Z+=q[ce]*s[$[ce]*3+2],B+=q[ce]*o[$[ce]*2],Y+=q[ce]*o[$[ce]*2+1];A.set([Q,se,Z],D*3),v[D*2]=B,v[D*2+1]=Y,y[D]=Math.abs(Q)<1e-4?0:Math.sign(Q);const te=[0,1,2].filter(ce=>q[ce]>0).map(ce=>$[ce]);if(te.length===1||te.length===2&&k.has(Ln(b[te[0]],b[te[1]]))||te.length===3&&R.has(Dr(b[$[0]],b[$[1]],b[$[2]]))){let ce=0,ot=0;for(let it=0;it<3;it+=1)ce+=q[it]*o[b[$[it]]*2],ot+=q[it]*o[b[$[it]]*2+1];M[D*2]=ce,M[D*2+1]=ot}else{const[ce,ot,it,fi]=Jh(t,n,-Q,se,Z),Ht=[r[ce*3],r[ce*3+1],r[ce*3+2]];M[D*2]=ot*o[Ht[0]*2]+it*o[Ht[1]*2]+fi*o[Ht[2]*2],M[D*2+1]=ot*o[Ht[0]*2+1]+it*o[Ht[1]*2+1]+fi*o[Ht[2]*2+1]}const _e=$.some((ce,ot)=>q[ot]>0&&z.has(ce)),ne=$.some((ce,ot)=>q[ot]>0&&ce===X),ue=Qs(Q,se,Z,N),Me=ue<Zs&&!Js(B,Y,N);x[D]=Me?-ue:ue;const wt=G.map(ce=>Qs(Q,se,Z,ce)),hi=wt[0]<=wt[1]?0:1,cs=wt[hi],id=cs<Zs?Js(B,Y,G[hi]):_e;F[D]=id?-cs:cs;const ls=Qs(Q,se,Z,U),cd=ls<Zs?Js(B,Y,U):ne;w[D]=cd?-ls:ls}const j=Uint8Array.from(u,D=>a[D]);return{level:e,vertexCount:g,corners:Uint16Array.from(l),bary:Float32Array.from(h),position:A,uv:v,uvMirror:M,faceSide:y,edge:x,eyeCm:F,mouthCm:w,trianglesPerParent:c,parents:Uint16Array.from(u),parentKinds:j,index:m}},Ko=e=>Bt(`faceTransferGeometry:${e}`,()=>VS(e)),WS=(e,t,n)=>Bt(`faceTransferIndex:${e}:${t?1:0}${n?1:0}`,()=>{const a=Ko(e);if(!t&&!n)return a.index;const{parentKinds:s,trianglesPerParent:r,index:o}=a,i=f=>!(t&&f===Ua.eye||n&&f===Ua.mouth),c=s.reduce((f,p)=>f+(i(p)?1:0),0),u=new Uint16Array(c*r*3),l=r*3;let h=0;return s.forEach((f,p)=>{i(f)&&(u.set(o.subarray(p*l,(p+1)*l),h),h+=l)}),u}),Uc=64,qS=()=>Bt("faceTransferUpsideDownEllipses",()=>{const{mesh:e,parents:t}=Qh(),n=Yh(),a=e.index,s=[e.openings.leftEye.centre,e.openings.rightEye.centre,e.openings.mouth.centre],r=Go().map(([o,i,c,u],l)=>{const h=n[s[l]*2],f=n[s[l]*2+1];let p=0,m=0;for(let E=0;E<Uc;E+=1){const S=2*Math.PI*E/Uc,[g,A,v,M]=Jh(e,t,o+c*Math.cos(S),i+u*Math.sin(S),null),y=[a[g*3],a[g*3+1],a[g*3+2]],x=A*n[y[0]*2]+v*n[y[1]*2]+M*n[y[2]*2],F=A*n[y[0]*2+1]+v*n[y[1]*2+1]+M*n[y[2]*2+1];p=Math.max(p,Math.abs(x-h)),m=Math.max(m,Math.abs(F-f))}return[h,f,p,m]});return[r[0],r[1],r[2]]}),Da=[.25,4],zn=[.15,.3],Zh=.5,jo=2,Un=[.2126,.7152,.0722],At=1e-4,XS=2,ef=(e,t,n)=>{if(t<=e)return n<e?0:1;const a=Math.min(1,Math.max(0,(n-e)/(t-e)));return a*a*(3-2*a)},Jt=(e,t,n)=>e+(t-e)*n,Dc=(e,t,n)=>e*Un[0]+t*Un[1]+n*Un[2],YS={sM:[0,0,0],tM:[0,0,0],sR:[0,0,0],tR:[0,0,0]},Gc=(e,t)=>{const n=Math.max(e[3],At);for(let a=0;a<3;a+=1)t[a]=Math.max(e[a]/n,At)},$c=(e,t,n)=>{const a=Math.max(e[3],At),s=ef(zn[0],zn[1],e[3]);for(let r=0;r<3;r+=1)n[r]=Jt(t[r],e[r]/a,s)/t[r]},QS=(e,t,n=[1,1,1])=>{const{sM:a,tM:s,sR:r,tR:o}=YS;Gc(e.sourceMean,a),Gc(e.targetMean,s),$c(e.sourceLow,a,r),$c(e.targetLow,s,o);const i=Math.max(Dc(r[0],r[1],r[2]),At),c=Math.max(Dc(o[0],o[1],o[2]),At),u=ef(t.edgeInset,t.edgeInset+jo*t.edgeSoftness,e.edge),l=Jt(Math.max(t.matchSkinTone,t.edgeMatch),t.matchSkinTone,u),h=Jt(Math.max(t.matchLighting,t.edgeMatch),t.matchLighting,u);for(let f=0;f<3;f+=1){const p=s[f]/a[f],m=o[f]/c/Math.max(r[f]/i,At),E=c/i*Jt(1,m,Zh),S=Jt(1,p,l)*Jt(1,E,h);n[f]=Math.min(Da[1],Math.max(Da[0],S))}return n},JS=["asIs","flip","leftLeft","rightRight","upsideDown"],ZS=(e,t)=>e==="leftLeft"?ee.personLeftSign(t):e==="rightRight"?ee.personLeftSign(t)===1?-1:1:0,eE=.3,Ye=e=>{const t=String(e);return/[.e]/.test(t)?t:`${t}.0`},tf=`
|
|
1792
|
+
const float FT_GAIN_MIN = ${Ye(Da[0])};
|
|
1793
|
+
const float FT_GAIN_MAX = ${Ye(Da[1])};
|
|
1794
|
+
const float FT_LOW_COVERAGE_MIN = ${Ye(zn[0])};
|
|
1795
|
+
const float FT_LOW_COVERAGE_FULL = ${Ye(zn[1])};
|
|
1796
|
+
const float FT_CHROMA = ${Ye(Zh)};
|
|
1797
|
+
const float FT_EDGE_BAND = ${Ye(jo)};
|
|
1798
|
+
const float FT_EPSILON = ${Ye(At)};
|
|
1799
|
+
const float FT_DETAIL_MAX_BIAS = ${Ye(XS)};
|
|
1800
|
+
const float FT_UPSIDE_DOWN_SOFTNESS = ${Ye(eE)};
|
|
1801
|
+
const vec3 FT_LUMA = vec3(${Un.map(Ye).join(", ")});
|
|
1802
|
+
|
|
1803
|
+
vec3 ftMean(vec4 mean) {
|
|
1804
|
+
return max(mean.rgb / max(mean.a, FT_EPSILON), vec3(FT_EPSILON));
|
|
1805
|
+
}
|
|
1806
|
+
|
|
1807
|
+
vec3 ftRatio(vec4 low, vec3 mean) {
|
|
1808
|
+
vec3 local = low.rgb / max(low.a, FT_EPSILON);
|
|
1809
|
+
float w = smoothstep(FT_LOW_COVERAGE_MIN, FT_LOW_COVERAGE_FULL, low.a);
|
|
1810
|
+
return mix(mean, local, w) / mean;
|
|
1811
|
+
}
|
|
1812
|
+
|
|
1813
|
+
vec3 faceTransferGain(vec4 sourceMean, vec4 targetMean, vec4 sourceLow, vec4 targetLow,
|
|
1814
|
+
float edge, float matchSkinTone, float matchLighting, float edgeMatch,
|
|
1815
|
+
float edgeInset, float edgeSoftness) {
|
|
1816
|
+
vec3 sM = ftMean(sourceMean);
|
|
1817
|
+
vec3 tM = ftMean(targetMean);
|
|
1818
|
+
vec3 sR = ftRatio(sourceLow, sM);
|
|
1819
|
+
vec3 tR = ftRatio(targetLow, tM);
|
|
1820
|
+
float yS = max(dot(sR, FT_LUMA), FT_EPSILON);
|
|
1821
|
+
float yT = max(dot(tR, FT_LUMA), FT_EPSILON);
|
|
1822
|
+
float inner = smoothstep(edgeInset, edgeInset + FT_EDGE_BAND * edgeSoftness, edge);
|
|
1823
|
+
float c = mix(max(matchSkinTone, edgeMatch), matchSkinTone, inner);
|
|
1824
|
+
float l = mix(max(matchLighting, edgeMatch), matchLighting, inner);
|
|
1825
|
+
vec3 tone = tM / sM;
|
|
1826
|
+
vec3 chroma = (tR / yT) / max(sR / yS, vec3(FT_EPSILON));
|
|
1827
|
+
vec3 light = (yT / yS) * mix(vec3(1.0), chroma, FT_CHROMA);
|
|
1828
|
+
vec3 gain = mix(vec3(1.0), tone, c) * mix(vec3(1.0), light, l);
|
|
1829
|
+
return clamp(gain, vec3(FT_GAIN_MIN), vec3(FT_GAIN_MAX));
|
|
1830
|
+
}
|
|
1831
|
+
|
|
1832
|
+
vec4 faceTransferSourceLow(vec4 read, vec4 twin) {
|
|
1833
|
+
return mix(twin, read, smoothstep(FT_LOW_COVERAGE_MIN, FT_LOW_COVERAGE_FULL, read.a));
|
|
1834
|
+
}
|
|
1835
|
+
|
|
1836
|
+
float ftRim(bool own, float distanceCm, float softness) {
|
|
1837
|
+
return own ? smoothstep(0.0, softness, distanceCm) : 1.0;
|
|
1838
|
+
}
|
|
1839
|
+
|
|
1840
|
+
float transferAlpha(float coverage, float facing, float edge, float eyeCm, float mouthCm,
|
|
1841
|
+
float amount, float edgeInset, float edgeSoftness,
|
|
1842
|
+
bool ownEyes, bool ownMouth, float featureSoftness) {
|
|
1843
|
+
return amount * coverage * clamp(facing, 0.0, 1.0)
|
|
1844
|
+
* smoothstep(edgeInset, edgeInset + edgeSoftness, edge)
|
|
1845
|
+
* ftRim(ownEyes, eyeCm, featureSoftness)
|
|
1846
|
+
* ftRim(ownMouth, mouthCm, featureSoftness);
|
|
1847
|
+
}
|
|
1848
|
+
|
|
1849
|
+
float faceTransferDetailBias(float detail) {
|
|
1850
|
+
return (1.0 - clamp(detail, 0.0, 1.0)) * FT_DETAIL_MAX_BIAS;
|
|
1851
|
+
}
|
|
1852
|
+
|
|
1853
|
+
bool faceTransferReadsMirror(bool mirror, float keptSide, float faceSide) {
|
|
1854
|
+
return (faceSide * keptSide < 0.0) ? !mirror : mirror;
|
|
1855
|
+
}
|
|
1856
|
+
|
|
1857
|
+
float ftSoftEllipse(vec2 uv, vec4 ellipse) {
|
|
1858
|
+
float r = length((uv - ellipse.xy) / max(ellipse.zw, vec2(FT_EPSILON)));
|
|
1859
|
+
return 1.0 - smoothstep(1.0 - FT_UPSIDE_DOWN_SOFTNESS, 1.0, r);
|
|
1860
|
+
}
|
|
1861
|
+
|
|
1862
|
+
vec3 faceTransferUpsideDown(vec2 uv, vec4 ellipses[3]) {
|
|
1863
|
+
vec3 result = vec3(uv, 0.0);
|
|
1864
|
+
for (int i = 0; i < 3; i++) {
|
|
1865
|
+
float weight = ftSoftEllipse(uv, ellipses[i]);
|
|
1866
|
+
if (weight > result.z) {
|
|
1867
|
+
result = vec3(uv.x, 2.0 * ellipses[i].y - uv.y, weight);
|
|
1868
|
+
}
|
|
1869
|
+
}
|
|
1870
|
+
return result;
|
|
1871
|
+
}
|
|
1872
|
+
`,Kn=Za,nf=Kh,tE=-.999,Bc=["leftEye","rightEye","mouth"],er=new Float32Array(Za),af=(e,t,n,a=nf)=>{if(n.length<Kn*4)throw new RangeError(`writeFaceTransferLiveMap: out needs ${Kn*4} entries, got ${n.length}`);Uo(e,t,a,er);for(let r=0;r<K.CANONICAL_FACE_LANDMARK_COUNT;r+=1){const o=e[r];n[r*4]=o.x,n[r*4+1]=o.y,n[r*4+2]=er[r],n[r*4+3]=1}const{openings:s}=pe();for(let r=0;r<Bc.length;r+=1){const{ring:o,centre:i}=s[Bc[r]];let c=0,u=0;for(let l=0;l<o.length;l+=1)c+=n[o[l]*4],u+=n[o[l]*4+1];n[i*4]=c/o.length,n[i*4+1]=u/o.length,n[i*4+2]=er[i],n[i*4+3]=1}return n},sf=()=>{const e=new d.DataTexture(new Float32Array(Kn*4),Kn,1,d.RGBAFormat,d.FloatType);return e.minFilter=d.NearestFilter,e.magFilter=d.NearestFilter,e.generateMipmaps=!1,e.needsUpdate=!0,e},rf=`
|
|
1873
|
+
uniform sampler2D uLiveMap;
|
|
1874
|
+
uniform sampler2D uSourceLow;
|
|
1875
|
+
uniform sampler2D uSourceMean;
|
|
1876
|
+
uniform sampler2D uTargetLow;
|
|
1877
|
+
uniform sampler2D uTargetMean;
|
|
1878
|
+
uniform float uSourceFlat;
|
|
1879
|
+
uniform float uMirror;
|
|
1880
|
+
uniform float uKeptSide;
|
|
1881
|
+
uniform float uMatchSkinTone;
|
|
1882
|
+
uniform float uMatchLighting;
|
|
1883
|
+
uniform float uEdgeMatch;
|
|
1884
|
+
uniform float uEdgeInset;
|
|
1885
|
+
uniform float uEdgeSoftness;
|
|
1886
|
+
uniform float uDepth;
|
|
1887
|
+
attribute vec3 ftCorners;
|
|
1888
|
+
attribute vec3 ftBary;
|
|
1889
|
+
attribute vec2 ftUvMirror;
|
|
1890
|
+
attribute float ftFaceSide;
|
|
1891
|
+
attribute float ftEdge;
|
|
1892
|
+
attribute float ftEyeCm;
|
|
1893
|
+
attribute float ftMouthCm;
|
|
1894
|
+
varying vec2 vUv;
|
|
1895
|
+
varying vec3 vGain;
|
|
1896
|
+
varying float vFacing;
|
|
1897
|
+
varying float vEdge;
|
|
1898
|
+
varying float vEyeCm;
|
|
1899
|
+
varying float vMouthCm;
|
|
1900
|
+
${tf}
|
|
1901
|
+
vec4 ftLive(float vertex) {
|
|
1902
|
+
return texelFetch(uLiveMap, ivec2(int(vertex + 0.5), 0), 0);
|
|
1903
|
+
}
|
|
1904
|
+
void main() {
|
|
1905
|
+
vec4 p = ftBary.x * ftLive(ftCorners.x) + ftBary.y * ftLive(ftCorners.y)
|
|
1906
|
+
+ ftBary.z * ftLive(ftCorners.z);
|
|
1907
|
+
vFacing = p.z;
|
|
1908
|
+
bool readsMirror = faceTransferReadsMirror(uMirror > 0.5, uKeptSide, ftFaceSide);
|
|
1909
|
+
vUv = readsMirror ? ftUvMirror : uv;
|
|
1910
|
+
vec2 twinUv = readsMirror ? uv : ftUvMirror;
|
|
1911
|
+
vec4 sourceMean = texelFetch(uSourceMean, ivec2(0), 0);
|
|
1912
|
+
vec4 targetMean = texelFetch(uTargetMean, ivec2(0), 0);
|
|
1913
|
+
vec4 sourceLow = uSourceFlat > 0.5 ? sourceMean
|
|
1914
|
+
: faceTransferSourceLow(texture(uSourceLow, vUv), texture(uSourceLow, twinUv));
|
|
1915
|
+
vec4 targetLow = texture(uTargetLow, uv);
|
|
1916
|
+
vGain = faceTransferGain(sourceMean, targetMean, sourceLow, targetLow, ftEdge,
|
|
1917
|
+
uMatchSkinTone, uMatchLighting, uEdgeMatch, uEdgeInset, uEdgeSoftness);
|
|
1918
|
+
vEdge = ftEdge;
|
|
1919
|
+
vEyeCm = ftEyeCm;
|
|
1920
|
+
vMouthCm = ftMouthCm;
|
|
1921
|
+
gl_Position = vec4(p.x * 2.0 - 1.0, 1.0 - p.y * 2.0, uDepth, 1.0);
|
|
1922
|
+
}
|
|
1923
|
+
`,of=`
|
|
1924
|
+
uniform sampler2D uSourceMap;
|
|
1925
|
+
uniform float uAmount;
|
|
1926
|
+
uniform float uDetail;
|
|
1927
|
+
uniform float uEdgeInset;
|
|
1928
|
+
uniform float uEdgeSoftness;
|
|
1929
|
+
uniform float uOwnEyes;
|
|
1930
|
+
uniform float uOwnMouth;
|
|
1931
|
+
uniform float uFeatureSoftness;
|
|
1932
|
+
uniform float uFacingFloor;
|
|
1933
|
+
uniform float uUpsideDown;
|
|
1934
|
+
uniform vec4 uEllipses[3];
|
|
1935
|
+
varying vec2 vUv;
|
|
1936
|
+
varying vec3 vGain;
|
|
1937
|
+
varying float vFacing;
|
|
1938
|
+
varying float vEdge;
|
|
1939
|
+
varying float vEyeCm;
|
|
1940
|
+
varying float vMouthCm;
|
|
1941
|
+
${tf}
|
|
1942
|
+
void main() {
|
|
1943
|
+
float bias = faceTransferDetailBias(uDetail);
|
|
1944
|
+
vec4 s = texture(uSourceMap, vUv, bias);
|
|
1945
|
+
if (uUpsideDown > 0.5) {
|
|
1946
|
+
vec3 flipped = faceTransferUpsideDown(vUv, uEllipses);
|
|
1947
|
+
s = mix(s, texture(uSourceMap, flipped.xy, bias), flipped.z);
|
|
1948
|
+
}
|
|
1949
|
+
vec3 rgb = s.rgb / max(s.a, FT_EPSILON) * vGain;
|
|
1950
|
+
float a = transferAlpha(s.a, max(vFacing, uFacingFloor), vEdge, vEyeCm, vMouthCm, uAmount, uEdgeInset,
|
|
1951
|
+
uEdgeSoftness, uOwnEyes > 0.5, uOwnMouth > 0.5, uFeatureSoftness);
|
|
1952
|
+
gl_FragColor = vec4(rgb, a);
|
|
1953
|
+
#include <colorspace_fragment>
|
|
1954
|
+
}
|
|
1955
|
+
`,nE=()=>({uLiveMap:{value:null},uSourceMap:{value:null},uSourceLow:{value:null},uSourceMean:{value:null},uTargetLow:{value:null},uTargetMean:{value:null},uSourceFlat:{value:0},uMirror:{value:0},uKeptSide:{value:0},uMatchSkinTone:{value:O.DEFAULT_FACE_SWAP_SETTINGS.matchSkinTone},uMatchLighting:{value:O.DEFAULT_FACE_SWAP_SETTINGS.matchLighting},uEdgeMatch:{value:O.DEFAULT_FACE_SWAP_SETTINGS.edgeMatch},uEdgeInset:{value:O.DEFAULT_FACE_SWAP_SETTINGS.edgeInset},uEdgeSoftness:{value:O.DEFAULT_FACE_SWAP_SETTINGS.edgeSoftness},uFeatureSoftness:{value:O.DEFAULT_FACE_SWAP_SETTINGS.featureSoftness},uFacingFloor:{value:0},uDetail:{value:O.DEFAULT_FACE_SWAP_SETTINGS.detail},uOwnEyes:{value:O.DEFAULT_FACE_SWAP_SETTINGS.ownEyes?1:0},uOwnMouth:{value:O.DEFAULT_FACE_SWAP_SETTINGS.ownMouth?1:0},uAmount:{value:0},uUpsideDown:{value:0},uEllipses:{value:qS().map(e=>new d.Vector4(e[0],e[1],e[2],e[3]))},uDepth:{value:tE}}),Hc=["matchSkinTone","matchLighting","edgeMatch","edgeSoftness","edgeInset","featureSoftness","detail"],aE=(e,t)=>{const[n,a]=O.FACE_SWAP_SETTINGS_RANGES[e];return Math.min(a,Math.max(n,t))},sE=e=>Bt(`faceTransferFloatCorners:${e}`,()=>Float32Array.from(Ko(e).corners)),zc=(e,t,n)=>{const a=Ko(e),s=new d.BufferGeometry;return s.setAttribute("position",new d.BufferAttribute(a.position,3)),s.setAttribute("uv",new d.BufferAttribute(a.uv,2)),s.setAttribute("ftCorners",new d.BufferAttribute(sE(e),3)),s.setAttribute("ftBary",new d.BufferAttribute(a.bary,3)),s.setAttribute("ftUvMirror",new d.BufferAttribute(a.uvMirror,2)),s.setAttribute("ftFaceSide",new d.BufferAttribute(a.faceSide,1)),s.setAttribute("ftEdge",new d.BufferAttribute(a.edge,1)),s.setAttribute("ftEyeCm",new d.BufferAttribute(a.eyeCm,1)),s.setAttribute("ftMouthCm",new d.BufferAttribute(a.mouthCm,1)),s.setIndex(new d.BufferAttribute(WS(e,t,n),1)),s};class cf{constructor(t={}){C(this,"mesh");C(this,"uniforms",nE());C(this,"levelValue");C(this,"liveData",new Float32Array(Kn*4));C(this,"ownLiveMap",null);C(this,"sharedLiveMap",null);C(this,"ownTarget",!1);C(this,"source",null);C(this,"targetStats",null);C(this,"amountValue",1);C(this,"layoutValue","asIs");C(this,"feedMirrored",!1);C(this,"unseenValue","fade");C(this,"settings",{matchSkinTone:O.DEFAULT_FACE_SWAP_SETTINGS.matchSkinTone,matchLighting:O.DEFAULT_FACE_SWAP_SETTINGS.matchLighting,edgeMatch:O.DEFAULT_FACE_SWAP_SETTINGS.edgeMatch,edgeSoftness:O.DEFAULT_FACE_SWAP_SETTINGS.edgeSoftness,edgeInset:O.DEFAULT_FACE_SWAP_SETTINGS.edgeInset,ownEyes:O.DEFAULT_FACE_SWAP_SETTINGS.ownEyes,ownMouth:O.DEFAULT_FACE_SWAP_SETTINGS.ownMouth,featureSoftness:O.DEFAULT_FACE_SWAP_SETTINGS.featureSoftness,detail:O.DEFAULT_FACE_SWAP_SETTINGS.detail});this.levelValue=t.level??2;const n=new d.ShaderMaterial({uniforms:this.uniforms,vertexShader:rf,fragmentShader:of,...le.faceSurfaceBlending,side:d.DoubleSide,depthTest:!0,depthWrite:!1,toneMapped:!1});n.name="FaceTransfer",this.mesh=new d.Mesh(zc(this.levelValue,this.settings.ownEyes,this.settings.ownMouth),n),this.mesh.name="FaceTransfer",this.mesh.renderOrder=le.FACE_SURFACE_RENDER_ORDER,this.mesh.frustumCulled=!1,this.mesh.matrixAutoUpdate=!1,this.mesh.onBeforeRender=()=>this.sync(!1),this.sync(!0)}get level(){return this.levelValue}get layout(){return this.layoutValue}get currentSettings(){return this.settings}get ready(){var t;return(this.ownTarget||this.sharedLiveMap!==null)&&!!((t=this.source)!=null&&t.map)&&this.source.ready&&this.targetStats!==null}setLevel(t){t!==this.levelValue&&(this.levelValue=t,this.rebuildGeometry())}rebuildGeometry(){this.mesh.geometry.dispose(),this.mesh.geometry=zc(this.levelValue,this.settings.ownEyes,this.settings.ownMouth)}setTarget(t,n,a=nf){af(t,n,this.liveData,a),this.ownLiveMap??(this.ownLiveMap=sf()),this.ownLiveMap.image.data.set(this.liveData),this.ownLiveMap.needsUpdate=!0,this.ownTarget=!0,this.sharedLiveMap=null,this.sync(!0)}setTargetMap(t){t!==this.sharedLiveMap&&(this.sharedLiveMap=t,this.sync(!0))}setSource(t){this.source=t,this.sync(!0)}setTargetStats(t){this.targetStats=t,this.sync(!0)}setLayout(t,n){this.layoutValue=t,this.feedMirrored=n,this.sync(!0)}setSettings(t){const n=this.settings;for(let r=0;r<Hc.length;r+=1){const o=Hc[r],i=t[o];typeof i=="number"&&Number.isFinite(i)&&(n[o]=aE(o,i))}const a=typeof t.ownEyes=="boolean"?t.ownEyes:n.ownEyes,s=typeof t.ownMouth=="boolean"?t.ownMouth:n.ownMouth;(a!==n.ownEyes||s!==n.ownMouth)&&(n.ownEyes=a,n.ownMouth=s,this.rebuildGeometry()),this.sync(!0)}setUnseen(t){this.unseenValue=t,this.sync(!0)}setAmount(t){this.amountValue=Number.isFinite(t)?Math.min(1,Math.max(0,t)):0,this.sync(!0)}update(){this.sync(!0)}dispose(){var t;this.mesh.geometry.dispose(),(t=this.ownLiveMap)==null||t.dispose(),this.ownLiveMap=null,Ce(this.mesh.material),this.source=null,this.targetStats=null,this.sharedLiveMap=null,this.ownTarget=!1,this.sync(!0)}sync(t){var i,c;const n=this.uniforms,a=this.settings,s=this.source,r=this.ready;n.uLiveMap.value=this.sharedLiveMap??(this.ownTarget?this.ownLiveMap:null),n.uSourceMap.value=(s==null?void 0:s.map)??null,n.uSourceLow.value=(s==null?void 0:s.low)??null,n.uSourceMean.value=(s==null?void 0:s.mean)??null,n.uSourceFlat.value=(s==null?void 0:s.kind)==="canonical"?1:0,n.uTargetLow.value=((i=this.targetStats)==null?void 0:i.low)??null,n.uTargetMean.value=((c=this.targetStats)==null?void 0:c.mean)??null;const o=Xh((s==null?void 0:s.mirrored)??!1,this.feedMirrored);n.uMirror.value=o!==(this.layoutValue==="flip")?1:0,n.uKeptSide.value=ZS(this.layoutValue,this.feedMirrored),n.uUpsideDown.value=this.layoutValue==="upsideDown"?1:0,n.uMatchSkinTone.value=a.matchSkinTone,n.uMatchLighting.value=a.matchLighting,n.uEdgeMatch.value=a.edgeMatch,n.uEdgeInset.value=a.edgeInset,n.uEdgeSoftness.value=a.edgeSoftness,n.uFeatureSoftness.value=a.featureSoftness,n.uFacingFloor.value=this.unseenValue==="cover"?1:0,n.uDetail.value=a.detail,n.uOwnEyes.value=a.ownEyes?1:0,n.uOwnMouth.value=a.ownMouth?1:0,n.uAmount.value=r?this.amountValue:0,t&&(this.mesh.visible=r&&this.amountValue>0)}}const xe={skinSize:128,size:64,sigmaCm:.8,taps:13,robustSpread:.35,robustKeep:[.05,.15],tauMs:250,meanGrid:16,facing:[.1,.4]},rE=(e=xe.size)=>{const{taps:t,sigmaCm:n}=xe,a=n/ih*e,s=(t-1)/2,r=new Float32Array(t),o=new Float32Array(t);let i=0;for(let c=0;c<t;c+=1){const u=c-s;r[c]=u,o[c]=Math.exp(-.5*(u/a)**2),i+=o[c]}for(let c=0;c<t;c+=1)o[c]/=i;return{offsets:r,weights:o}},oE=(e,t=!1,n=xe.tauMs)=>t||!(n>0)?1:!(e>0)||!Number.isFinite(e)?0:1-Math.exp(-e/n),iE=(e,t=xe.size)=>{const n=2*t,a=Math.log2(e/n);if(!(Number.isInteger(a)&&a>=0))throw new RangeError(`faceStatsInputLod: a ${e}px map has no ${n}px mip level; use ${n} × a power of two (${n}, ${n*2}, ${n*4}, ${n*8} …)`);return a},Kc=new WeakMap,cE=e=>{const t=e.getContext(),n=Kc.get(t);if(n!==void 0)return n;let a=e.extensions.has("EXT_color_buffer_float")||e.extensions.has("EXT_color_buffer_half_float");if(a){const s=new d.WebGLRenderTarget(1,1,{type:d.HalfFloatType,depthBuffer:!1,generateMipmaps:!1}),r=e.getRenderTarget(),o=e.getActiveCubeFace(),i=e.getActiveMipmapLevel();e.setRenderTarget(s),a=t.checkFramebufferStatus(t.FRAMEBUFFER)===t.FRAMEBUFFER_COMPLETE,e.setRenderTarget(r,o,i),s.dispose()}return Kc.set(t,a),a},lf=(e,t)=>t&&cE(e)?"float":"srgb8",ka=(e,t)=>new d.WebGLRenderTarget(e,t,{depthBuffer:!1,generateMipmaps:!1,minFilter:d.LinearFilter,magFilter:d.LinearFilter,type:d.UnsignedByteType,colorSpace:d.SRGBColorSpace}),uf=(e,t)=>{const n=e.texture,a=t==="float"?d.HalfFloatType:d.UnsignedByteType,s=t==="float"?d.NoColorSpace:d.SRGBColorSpace;return n.type===a&&n.colorSpace===s?!1:(n.type=a,n.colorSpace=s,e.dispose(),!0)};class hf{constructor(){C(this,"target",null);C(this,"face",0);C(this,"level",0);C(this,"clear",new d.Color);C(this,"alpha",0);C(this,"autoClear",!0);C(this,"xr",!1)}save(t){this.target=t.getRenderTarget(),this.face=t.getActiveCubeFace(),this.level=t.getActiveMipmapLevel(),t.getClearColor(this.clear),this.alpha=t.getClearAlpha(),this.autoClear=t.autoClear,this.xr=t.xr.enabled,t.autoClear=!1,t.xr.enabled=!1,t.setClearColor(0,0)}restore(t){t.setRenderTarget(this.target,this.face,this.level),t.setClearColor(this.clear,this.alpha),t.autoClear=this.autoClear,t.xr.enabled=this.xr,this.target=null}}const ff=e=>Object.assign(e,{side:d.DoubleSide,depthTest:!1,depthWrite:!1,blending:d.NoBlending,toneMapped:!1}),Dn=e=>Number.isInteger(e)?`${e}.0`:`${e}`,es=`
|
|
1956
|
+
precision highp float;
|
|
1957
|
+
const vec3 STATS_LUMA = vec3(${Un.map(Dn).join(", ")});
|
|
1958
|
+
const float STATS_EPS = ${Dn(At)};
|
|
1959
|
+
`,lE=`
|
|
1960
|
+
out vec2 vUv;
|
|
1961
|
+
void main() {
|
|
1962
|
+
vUv = uv;
|
|
1963
|
+
gl_Position = vec4(position.xy, 0.0, 1.0);
|
|
1964
|
+
}
|
|
1965
|
+
`,uE=`
|
|
1966
|
+
in vec2 cameraUv;
|
|
1967
|
+
in float weight;
|
|
1968
|
+
out vec2 vCameraUv;
|
|
1969
|
+
out float vWeight;
|
|
1970
|
+
out vec2 vAtlasUv;
|
|
1971
|
+
void main() {
|
|
1972
|
+
vCameraUv = cameraUv;
|
|
1973
|
+
vWeight = weight;
|
|
1974
|
+
vAtlasUv = position.xy;
|
|
1975
|
+
gl_Position = vec4(position.xy * 2.0 - 1.0, 0.0, 1.0);
|
|
1976
|
+
}
|
|
1977
|
+
`,hE=`
|
|
1978
|
+
${es}
|
|
1979
|
+
uniform sampler2D imageMap;
|
|
1980
|
+
uniform sampler2D maskMap;
|
|
1981
|
+
in vec2 vCameraUv;
|
|
1982
|
+
in float vWeight;
|
|
1983
|
+
in vec2 vAtlasUv;
|
|
1984
|
+
layout(location = 0) out highp vec4 fragColor;
|
|
1985
|
+
void main() {
|
|
1986
|
+
// Nothing from past the image's edge (a clamped sample is not skin).
|
|
1987
|
+
vec2 c = vCameraUv;
|
|
1988
|
+
float image = step(0.0, c.x) * step(c.x, 1.0) * step(0.0, c.y) * step(c.y, 1.0);
|
|
1989
|
+
float a = clamp(vWeight, 0.0, 1.0) * image * texture(maskMap, vAtlasUv).r;
|
|
1990
|
+
fragColor = vec4(texture(imageMap, vCameraUv).rgb * a, a);
|
|
1991
|
+
}
|
|
1992
|
+
`,pf=xe.taps,fE=`
|
|
1993
|
+
${es}
|
|
1994
|
+
#define TAPS ${pf}
|
|
1995
|
+
const float SPREAD = ${Dn(xe.robustSpread)};
|
|
1996
|
+
const vec2 KEEP = vec2(${xe.robustKeep.map(Dn).join(", ")});
|
|
1997
|
+
const vec2 COVERAGE = vec2(${zn.map(Dn).join(", ")});
|
|
1998
|
+
uniform sampler2D inputMap;
|
|
1999
|
+
uniform float inputLod;
|
|
2000
|
+
uniform sampler2D maskMap;
|
|
2001
|
+
uniform float useMask;
|
|
2002
|
+
uniform sampler2D prevLow;
|
|
2003
|
+
uniform sampler2D prevMean;
|
|
2004
|
+
uniform float robust;
|
|
2005
|
+
uniform float texel;
|
|
2006
|
+
// Half an input texel (at the read level): a tap's 2×2 input texel centres.
|
|
2007
|
+
uniform vec2 inputHalfTexel;
|
|
2008
|
+
uniform float offsets[TAPS];
|
|
2009
|
+
uniform float weights[TAPS];
|
|
2010
|
+
in vec2 vUv;
|
|
2011
|
+
layout(location = 0) out highp vec4 fragColor;
|
|
2012
|
+
|
|
2013
|
+
// The previous local skin luminance at uv (the previous mean where little skin was seen).
|
|
2014
|
+
float referenceLum(vec2 uv, float meanLum) {
|
|
2015
|
+
vec4 l = texture(prevLow, uv);
|
|
2016
|
+
float local = dot(l.rgb, STATS_LUMA) / max(l.a, STATS_EPS);
|
|
2017
|
+
return mix(meanLum, local, smoothstep(COVERAGE.x, COVERAGE.y, l.a));
|
|
2018
|
+
}
|
|
2019
|
+
|
|
2020
|
+
const vec2 SUB[4] = vec2[4](vec2(-1.0, -1.0), vec2(1.0, -1.0), vec2(-1.0, 1.0), vec2(1.0, 1.0));
|
|
2021
|
+
|
|
2022
|
+
void main() {
|
|
2023
|
+
vec4 m = texture(prevMean, vec2(0.5));
|
|
2024
|
+
float meanLum = dot(m.rgb, STATS_LUMA) / max(m.a, STATS_EPS);
|
|
2025
|
+
vec4 plain = vec4(0.0);
|
|
2026
|
+
vec4 kept = vec4(0.0);
|
|
2027
|
+
for (int k = 0; k < TAPS; k++) {
|
|
2028
|
+
vec2 uv = vec2(vUv.x + offsets[k] * texel, vUv.y);
|
|
2029
|
+
float g = 0.25 * weights[k];
|
|
2030
|
+
float ref = robust > 0.5 ? referenceLum(uv, meanLum) : 0.0;
|
|
2031
|
+
for (int s = 0; s < 4; s++) {
|
|
2032
|
+
vec2 at = uv + SUB[s] * inputHalfTexel;
|
|
2033
|
+
vec4 c = textureLod(inputMap, at, inputLod);
|
|
2034
|
+
c *= mix(1.0, texture(maskMap, at).r, useMask);
|
|
2035
|
+
plain += g * c;
|
|
2036
|
+
float r = 1.0;
|
|
2037
|
+
if (ref > STATS_EPS && c.a > STATS_EPS) {
|
|
2038
|
+
float d = (dot(c.rgb, STATS_LUMA) / c.a - ref) / (SPREAD * ref);
|
|
2039
|
+
r = exp(-d * d);
|
|
2040
|
+
}
|
|
2041
|
+
kept += (g * r) * c;
|
|
2042
|
+
}
|
|
2043
|
+
}
|
|
2044
|
+
if (plain.a <= STATS_EPS) {
|
|
2045
|
+
fragColor = vec4(0.0);
|
|
2046
|
+
return;
|
|
2047
|
+
}
|
|
2048
|
+
vec3 plainColor = plain.rgb / plain.a;
|
|
2049
|
+
vec3 keptColor = kept.rgb / max(kept.a, STATS_EPS);
|
|
2050
|
+
float t = smoothstep(KEEP.x, KEEP.y, kept.a / plain.a);
|
|
2051
|
+
fragColor = vec4(mix(plainColor, keptColor, t) * plain.a, plain.a);
|
|
2052
|
+
}
|
|
2053
|
+
`,pE=`
|
|
2054
|
+
${es}
|
|
2055
|
+
#define TAPS ${pf}
|
|
2056
|
+
uniform sampler2D horizontalMap;
|
|
2057
|
+
uniform float texel;
|
|
2058
|
+
uniform float offsets[TAPS];
|
|
2059
|
+
uniform float weights[TAPS];
|
|
2060
|
+
in vec2 vUv;
|
|
2061
|
+
layout(location = 0) out highp vec4 fragColor;
|
|
2062
|
+
void main() {
|
|
2063
|
+
vec4 s = vec4(0.0);
|
|
2064
|
+
for (int k = 0; k < TAPS; k++) {
|
|
2065
|
+
s += weights[k] * texture(horizontalMap, vec2(vUv.x, vUv.y + offsets[k] * texel));
|
|
2066
|
+
}
|
|
2067
|
+
fragColor = s;
|
|
2068
|
+
}
|
|
2069
|
+
`,dE=xe.meanGrid,mE=`
|
|
2070
|
+
${es}
|
|
2071
|
+
#define GRID ${dE}
|
|
2072
|
+
uniform sampler2D lowMap;
|
|
2073
|
+
uniform sampler2D maskMap;
|
|
2074
|
+
layout(location = 0) out highp vec4 fragColor;
|
|
2075
|
+
void main() {
|
|
2076
|
+
vec4 s = vec4(0.0);
|
|
2077
|
+
float m = 0.0;
|
|
2078
|
+
for (int y = 0; y < GRID; y++) {
|
|
2079
|
+
for (int x = 0; x < GRID; x++) {
|
|
2080
|
+
vec2 uv = (vec2(float(x), float(y)) + 0.5) / float(GRID);
|
|
2081
|
+
s += texture(lowMap, uv);
|
|
2082
|
+
m += texture(maskMap, uv).r;
|
|
2083
|
+
}
|
|
2084
|
+
}
|
|
2085
|
+
float coverage = clamp(s.a / max(m, STATS_EPS), 0.0, 1.0);
|
|
2086
|
+
fragColor = s.a > STATS_EPS ? vec4(s.rgb / s.a * coverage, coverage) : vec4(0.0);
|
|
2087
|
+
}
|
|
2088
|
+
`;class gE{constructor(t={}){C(this,"target");C(this,"geometry");C(this,"material");C(this,"scene",new d.Scene);C(this,"camera",new d.OrthographicCamera(-1,1,1,-1,0,1));C(this,"state",new hf);C(this,"uniforms",{imageMap:{value:null},maskMap:{value:null}});C(this,"options");C(this,"frame");C(this,"resolvedFormat",null);this.options={size:t.size??xe.skinSize,float:t.float??!0,facing:t.facing??xe.facing,mask:t.mask??null},this.frame={facing:this.options.facing,inFrame:!0},this.target=ka(this.options.size,this.options.size),this.geometry=Pr(T.FACE_ATLAS_UVS),this.material=ff(new d.ShaderMaterial({glslVersion:d.GLSL3,uniforms:this.uniforms,vertexShader:uE,fragmentShader:hE}));const n=new d.Mesh(this.geometry,this.material);n.frustumCulled=!1,this.scene.add(n)}get texture(){return this.target.texture}get format(){return this.resolvedFormat}setOptions(t){t.size&&t.size!==this.options.size&&(this.options.size=t.size,this.target.setSize(t.size,t.size)),t.float!==void 0&&(this.options.float=t.float),t.facing&&(this.options.facing=t.facing,this.frame.facing=t.facing),t.mask!==void 0&&(this.options.mask=t.mask)}render(t,n,a,s){const r=lf(t,this.options.float);r!==this.resolvedFormat&&(uf(this.target,r),this.resolvedFormat=r);const o=n.image,i=s??(o!=null&&o.width&&(o!=null&&o.height)?o.width/o.height:1),c=this.geometry.getAttribute("cameraUv"),u=this.geometry.getAttribute("weight");Do(a,i,this.frame,c.array,u.array),c.needsUpdate=!0,u.needsUpdate=!0,this.uniforms.imageMap.value=n,this.uniforms.maskMap.value=this.options.mask??ch(this.options.size),this.state.save(t),t.setRenderTarget(this.target),t.clear(!0,!1,!1),t.render(this.scene,this.camera),this.state.restore(t)}dispose(){this.geometry.dispose(),Ce(this.material),this.target.dispose()}}const SE=e=>e!==d.LinearFilter&&e!==d.NearestFilter,EE=new d.PlaneGeometry(2,2);class Vo{constructor(t={}){C(this,"low");C(this,"mean");C(this,"lowTarget");C(this,"meanTarget");C(this,"horizontalTarget");C(this,"skinPass",null);C(this,"scene",new d.Scene);C(this,"quad");C(this,"camera",new d.OrthographicCamera(-1,1,1,-1,0,1));C(this,"state",new hf);C(this,"horizontalUniforms",{inputMap:{value:null},inputLod:{value:0},maskMap:{value:null},useMask:{value:0},prevLow:{value:null},prevMean:{value:null},robust:{value:0},texel:{value:0},inputHalfTexel:{value:new d.Vector2},offsets:{value:new Float32Array(xe.taps)},weights:{value:new Float32Array(xe.taps)}});C(this,"verticalUniforms",{horizontalMap:{value:null},texel:{value:0},offsets:{value:new Float32Array(xe.taps)},weights:{value:new Float32Array(xe.taps)}});C(this,"meanUniforms",{lowMap:{value:null},maskMap:{value:null}});C(this,"horizontal");C(this,"vertical");C(this,"meanMaterial");C(this,"size");C(this,"float");C(this,"tauMs");C(this,"resolvedFormat",null);C(this,"valid",!1);C(this,"restartPending",!1);C(this,"imageUpdate",{dtMs:0});this.size=t.size??xe.size,this.float=t.float??!0,this.tauMs=t.tauMs??xe.tauMs,this.lowTarget=ka(this.size,this.size),this.horizontalTarget=ka(this.size,this.size),this.meanTarget=ka(1,1),this.low=this.lowTarget.texture,this.mean=this.meanTarget.texture;const n=rE(this.size),a=ch(this.readSize),s=this.horizontalUniforms;s.maskMap.value=a,s.prevLow.value=this.low,s.prevMean.value=this.mean,s.texel.value=1/this.size,s.inputHalfTexel.value.set(.5/this.readSize,.5/this.readSize),s.offsets.value=n.offsets,s.weights.value=n.weights;const r=this.verticalUniforms;r.horizontalMap.value=this.horizontalTarget.texture,r.texel.value=1/this.size,r.offsets.value=n.offsets,r.weights.value=n.weights,this.meanUniforms.lowMap.value=this.low,this.meanUniforms.maskMap.value=a;const o=(i,c)=>ff(new d.ShaderMaterial({glslVersion:d.GLSL3,uniforms:i,vertexShader:lE,fragmentShader:c}));this.horizontal=o(this.horizontalUniforms,fE),this.meanMaterial=o(this.meanUniforms,mE),this.vertical=Object.assign(o(this.verticalUniforms,pE),{blending:d.CustomBlending,blendEquation:d.AddEquation,blendSrc:d.ConstantAlphaFactor,blendDst:d.OneMinusConstantAlphaFactor,blendEquationAlpha:d.AddEquation,blendSrcAlpha:d.ConstantAlphaFactor,blendDstAlpha:d.OneMinusConstantAlphaFactor}),this.quad=new d.Mesh(EE,this.horizontal),this.quad.frustumCulled=!1,this.scene.add(this.quad)}get format(){return this.resolvedFormat}get ready(){return this.valid}get readSize(){return 2*this.size}get skinTexture(){var t;return((t=this.skinPass)==null?void 0:t.texture)??null}setOptions(t){var n;t.float!==void 0&&(this.float=t.float,(n=this.skinPass)==null||n.setOptions({float:t.float})),t.tauMs!==void 0&&(this.tauMs=t.tauMs)}reset(){this.restartPending=!0}update(t,n,a){const s=a.lod??0;this.checkInput(n,s),this.ensureFormat(t);const r=!!a.reset||this.restartPending||!this.valid,o=r?1:oE(a.dtMs,!1,this.tauMs);if(o<=0)return;const i=this.horizontalUniforms;i.inputMap.value=n,i.inputLod.value=s,i.useMask.value=a.mask?1:0,this.state.save(t),r?(this.passes(t,!1,1),this.passes(t,!0,1)):this.passes(t,!0,o),this.state.restore(t),this.valid=!0,this.restartPending=!1}updateFromImage(t,n,a,s){this.skinPass??(this.skinPass=new gE({float:this.float,size:this.readSize})),this.skinPass.render(t,n,a,s.aspect),this.imageUpdate.dtMs=s.dtMs,this.imageUpdate.reset=s.reset,this.update(t,this.skinPass.texture,this.imageUpdate)}checkInput(t,n){var s;if(!(Number.isInteger(n)&&n>=0))throw new RangeError(`FaceTextureStats.update: lod must be a whole mip level (faceStatsInputLod), got ${n}`);const a=(s=t.image)==null?void 0:s.width;if(a){if(Math.floor(a/2**n)!==this.readSize)throw new RangeError(`FaceTextureStats.update: the input is ${a}px, ${Math.floor(a/2**n)}px at level ${n}; it must be ${this.readSize}px there (faceStatsInputLod(${a}))`);if(n>0&&!SE(t.minFilter))throw new RangeError(`FaceTextureStats.update: level ${n} of an input without mipmaps (unwrapMipmaps, or a mipmap minFilter)`)}}ensureFormat(t){const n=lf(t,this.float);if(n!==this.resolvedFormat){this.resolvedFormat=n;for(const a of[this.lowTarget,this.horizontalTarget,this.meanTarget])uf(a,n),t.initRenderTarget(a);this.valid=!1}}passes(t,n,a){this.horizontalUniforms.robust.value=n?1:0,this.quad.material=this.horizontal,t.setRenderTarget(this.horizontalTarget),t.render(this.scene,this.camera),this.vertical.blendAlpha=a,this.quad.material=this.vertical,t.setRenderTarget(this.lowTarget),t.render(this.scene,this.camera),this.quad.material=this.meanMaterial,t.setRenderTarget(this.meanTarget),t.render(this.scene,this.camera)}dispose(){var t;(t=this.skinPass)==null||t.dispose(),this.skinPass=null,Ce(this.horizontal),Ce(this.vertical),Ce(this.meanMaterial),this.lowTarget.dispose(),this.horizontalTarget.dispose(),this.meanTarget.dispose(),this.valid=!1}}const Zn={maxCutoffHz:12,minCutoffHz:.5,beta:40,derivativeCutoffHz:1,snapJump:.1,maxGapMs:500,fadeInSmoothing:.1},AE=(e=K.CANONICAL_FACE_LANDMARK_COUNT)=>({count:e,points:new Float32Array(e*3),initialized:!1,centreX:0,centreY:0,velocityX:0,velocityY:0,timeMs:0,alpha:1}),vE=e=>{e.initialized=!1},df=(e,t)=>1/(1+1/(2*Math.PI*e*t)),ME=(e,t,n)=>{const a=Math.min(1,Math.max(0,(n-e)/(t-e)));return a*a*(3-2*a)},yE=(e,t)=>{if(!(e>0))return 1/0;const{maxCutoffHz:n,minCutoffHz:a,beta:s}=Zn,r=Math.min(1,e);return n*(a/n)**r+s*Math.max(0,t)},wE=(e,t,n)=>{const a=yE(e,t);if(!Number.isFinite(a)||!(n>0))return 1;const s=df(a,n/1e3);return 1-ME(0,Zn.fadeInSmoothing,e)*(1-s)},jc=(e,t,n,a,s)=>{const r=e.points;for(let o=0;o<e.count;o+=1){const i=t[o];r[o*3]=i.x,r[o*3+1]=i.y,r[o*3+2]=i.z??0}return e.initialized=!0,e.centreX=n,e.centreY=a,e.velocityX=0,e.velocityY=0,e.timeMs=s,e.alpha=1,"snap"},_E=(e,t,n,a,s)=>{const r=e.count;if(t.length<r)return"skip";let o=0,i=0;for(let A=0;A<r;A+=1)o+=t[A].x,i+=t[A].y;const c=o/r,u=i/r/(n>0?n:1);if(!e.initialized)return jc(e,t,c,u,a);const l=a-e.timeMs;if(!(l>0))return"skip";const{snapJump:h,maxGapMs:f,derivativeCutoffHz:p}=Zn;if(l>f||Math.hypot(c-e.centreX,u-e.centreY)>h)return jc(e,t,c,u,a);const m=l/1e3,E=df(p,m);e.velocityX+=E*((c-e.centreX)/m-e.velocityX),e.velocityY+=E*((u-e.centreY)/m-e.velocityY);const S=wE(s,Math.hypot(e.velocityX,e.velocityY),l),g=e.points;for(let A=0;A<r;A+=1){const v=t[A];g[A*3]+=S*(v.x-g[A*3]),g[A*3+1]+=S*(v.y-g[A*3+1]),g[A*3+2]+=S*((v.z??0)-g[A*3+2])}return e.centreX=c,e.centreY=u,e.timeMs=a,e.alpha=S,"smooth"},Vc=1,FE=Zn.snapJump,mf=(e=K.CANONICAL_FACE_LANDMARK_COUNT)=>({smoother:AE(e),tracked:!1,lastSeenMs:null,noseX:0,noseY:0,camera:null,update:{tracked:!1,smoothing:"none",resetStatistics:!1,reason:null}}),gf=(e,t)=>{const n=e.update,{landmarks:a}=t;if(!a||a.length<=Vc)return e.tracked=!1,n.tracked=!1,n.smoothing="none",n.resetStatistics=!1,n.reason=null,n;const s=t.aspect>0?t.aspect:1,r=a[Vc],o=r.x,i=r.y/s;let c=null;return e.lastSeenMs===null||!(t.timeMs-e.lastSeenMs<=Zn.maxGapMs)?c="acquired":t.camera!==e.camera?c="camera":Math.hypot(o-e.noseX,i-e.noseY)>FE&&(c="jump"),c&&vE(e.smoother),n.smoothing=_E(e.smoother,a,s,t.timeMs,t.smoothing),!c&&n.smoothing==="snap"&&(c="jump"),e.tracked=!0,e.lastSeenMs=t.timeMs,e.noseX=o,e.noseY=i,e.camera=t.camera,n.tracked=!0,n.resetStatistics=c!==null,n.reason=c,n},xE=["auto","high","medium","low"],CE={high:{key:"high",meshLevel:2,mapMax:1024,mirrorFill:!0,statisticsHz:15,floatStatistics:!0},medium:{key:"medium",meshLevel:2,mapMax:768,mirrorFill:!0,statisticsHz:10,floatStatistics:!0},low:{key:"low",meshLevel:1,mapMax:512,mirrorFill:!1,statisticsHz:6,floatStatistics:!1}},Sf={min:256,step:128,perFacePx:1.3,hysteresis:.15,waitMs:1e3},Gr=(e,t,n)=>e!=="auto"?e:t<=0||n<=1?"high":t>=n-1?"low":"medium",Ef=(e,t,n)=>{const a=e[10],s=e[152];return!a||!s?0:Math.hypot((s.x-a.x)*t,(s.y-a.y)*n)},TE=(e,t)=>{const{min:n,step:a,perFacePx:s}=Sf,r=Number.isFinite(e)?Math.max(0,e):0;return Math.min(t,Math.max(n,Math.ceil(s*r/a)*a))},kE=(e,t=null)=>{const n=CE[Gr(e.quality,e.tierIndex,e.tierCount)],a=e.faceHeightPx!==null&&Number.isFinite(e.faceHeightPx),s=a?TE(e.faceHeightPx,n.mapMax):n.mapMax;if(!t||t.key!==n.key){const f=a||!t?s:Math.min(t.mapSize,n.mapMax);return{...n,mapSize:f,pendingSinceMs:null}}if(!a)return t;const{min:r,perFacePx:o,hysteresis:i,waitMs:c}=Sf,u=Math.max(r,o*e.faceHeightPx),l=t.mapSize;return s!==l&&Math.abs(u-l)>i*l?t.pendingSinceMs===null?{...t,pendingSinceMs:e.nowMs}:e.nowMs-t.pendingSinceMs>=c?{...t,mapSize:s,pendingSinceMs:null}:t:t.pendingSinceMs===null?t:{...t,pendingSinceMs:null}},Wc={low:0,medium:1,high:2},tr=O.DEFAULT_FACE_SWAP_SETTINGS.smoothing,LE=-.75,RE={createReprojector:e=>new Ja(e),createStats:e=>new Vo(e)},bE=e=>{const t=e==null?void 0:e.image;return{width:(t==null?void 0:t.width)??0,height:(t==null?void 0:t.height)??0}};class IE{constructor(t,n,a=RE){C(this,"faceIndex");C(this,"face");C(this,"liveMap");C(this,"track",mf());C(this,"landmarks",Array.from({length:K.CANONICAL_FACE_LANDMARK_COUNT},()=>({x:0,y:0,z:0})));C(this,"quality",null);C(this,"resultStamp",Number.NaN);C(this,"positionsReady",!1);C(this,"mapReady",!1);C(this,"statsReady",!1);C(this,"mutableFace");C(this,"stats");C(this,"reprojector",null);C(this,"mapSize",0);C(this,"mapMirrorFill",!1);C(this,"requestIds",[]);C(this,"requests",[]);C(this,"refs",0);C(this,"stamp",Number.NaN);C(this,"lastResults");C(this,"lastStatsMs",-1/0);C(this,"wantMap",!1);C(this,"wantMirrorFill",!1);C(this,"wantMadeUp",!1);C(this,"qualityKey","high");C(this,"smoothing",tr);C(this,"trackInput",{landmarks:null,aspect:1,timeMs:0,camera:null,smoothing:tr});C(this,"qualityInput",{quality:"auto",tierIndex:-1,tierCount:0,faceHeightPx:null,nowMs:0});C(this,"statsUpdate",{dtMs:0,reset:!1,aspect:1});this.renderer=t,this.gpu=a,this.faceIndex=n,this.liveMap=sf(),this.stats=a.createStats({float:!0}),this.mutableFace={kind:"live",map:null,low:this.stats.low,mean:this.stats.mean,mirrored:!1,landmarks:null,faceIndex:n,version:0,ready:!1},this.face=this.mutableFace}get references(){return this.refs}get smoothingInUse(){return this.smoothing}request(t,n){const a=this.requestIds.indexOf(t);if(a>=0){this.requests[a]=n;return}this.requestIds.push(t),this.requests.push(n)}unrequest(t){const n=this.requestIds.indexOf(t);n<0||(this.requestIds.splice(n,1),this.requests.splice(n,1))}step(t){var E,S;if(t.stamp===this.stamp)return;this.stamp=t.stamp,this.aggregate(t);const n=this.mutableFace;n.mirrored=t.feedMirrored,!this.wantMap&&this.reprojector&&this.dropMap();const a=(E=t.node)==null?void 0:E.detectionResults;if(a===this.lastResults)return;this.lastResults=a,this.resultStamp=t.stamp;const s=((S=a==null?void 0:a.faceLandmarks)==null?void 0:S[this.faceIndex])??null,r=t.cameraTexture,{width:o,height:i}=bE(r),c=o>0&&i>0?o/i:1,u=this.trackInput;u.landmarks=s&&s.length>=K.CANONICAL_FACE_LANDMARK_COUNT?s:null,u.aspect=c,u.timeMs=t.nowMs,u.camera=r,u.smoothing=this.smoothing;const l=gf(this.track,u);if(u.landmarks=null,l.resetStatistics&&this.stats.reset(),!l.tracked||l.smoothing==="skip"||!r)return;const h=this.track.smoother.points;for(let g=0;g<K.CANONICAL_FACE_LANDMARK_COUNT;g+=1){const A=this.landmarks[g];A.x=h[g*3],A.y=h[g*3+1],A.z=h[g*3+2]}af(this.landmarks,c,this.liveMap.image.data),this.liveMap.needsUpdate=!0,this.positionsReady=!0;const f=this.qualityInput;f.quality=this.qualityKey,f.tierIndex=t.tierIndex,f.tierCount=t.tierCount,f.faceHeightPx=o>0?Ef(this.landmarks,o,i):null,f.nowMs=t.nowMs;const p=kE(f,this.quality);if(this.quality=p,this.wantMap){const g=this.wantMadeUp&&t.madeUpTexture?t.madeUpTexture:r;this.renderMap(g,p)}const m=1e3/Math.max(.001,p.statisticsHz);if(!this.statsReady||l.resetStatistics||t.nowMs-this.lastStatsMs>=m-1){this.stats.setOptions({float:p.floatStatistics});const g=this.statsUpdate;g.dtMs=Number.isFinite(this.lastStatsMs)?t.nowMs-this.lastStatsMs:0,g.reset=l.resetStatistics,g.aspect=c,this.stats.updateFromImage(this.renderer,r,this.landmarks,g),this.lastStatsMs=t.nowMs,this.statsReady=this.stats.ready}n.version+=1,n.ready=this.statsReady&&(!this.wantMap||this.mapReady)}dispose(){this.dropMap(),this.stats.dispose(),this.liveMap.dispose(),this.requestIds.length=0,this.requests.length=0,this.statsReady=!1,this.positionsReady=!1,this.mutableFace.ready=!1}retain(){this.refs+=1}releaseOne(){return this.refs=Math.max(0,this.refs-1),this.refs}aggregate(t){let n=!1,a=!1,s=!1,r=null,o=null;const{requests:i}=this;for(let c=0;c<i.length;c+=1){const u=i[c];n||(n=u.map),a||(a=u.mirrorFill),s||(s=u.madeUp===!0);const l=Gr(u.quality,t.tierIndex,t.tierCount);(r===null||Wc[l]>Wc[r])&&(r=l);const h=u.smoothing;typeof h=="number"&&Number.isFinite(h)&&(o=o===null?h:Math.max(o,h))}this.wantMap=n,this.wantMirrorFill=a,this.wantMadeUp=s,this.qualityKey=r??Gr("auto",t.tierIndex,t.tierCount),this.smoothing=Math.min(1,Math.max(0,o??tr))}renderMap(t,n){const a=n.mapSize,s=this.wantMirrorFill&&n.mirrorFill;this.reprojector?(a!==this.mapSize||s!==this.mapMirrorFill)&&(this.reprojector.setOptions({unwrapResolution:a,mirrorFill:s}),this.mapSize=a,this.mapMirrorFill=s):(this.reprojector=this.gpu.createReprojector({uvs:T.FACE_ATLAS_UVS,unwrapResolution:a,unwrapMipmaps:!0,mirrorFill:s,resolution:1}),this.mapSize=a,this.mapMirrorFill=s,this.mutableFace.map=this.reprojector.unwrapTexture),this.reprojector.render(this.renderer,t,this.landmarks),this.mapReady=!0}dropMap(){var n;(n=this.reprojector)==null||n.dispose(),this.reprojector=null,this.mapReady=!1,this.mapSize=0;const t=this.mutableFace;t.map&&(t.map=null,t.version+=1),t.ready=this.statsReady}}const Ga=new WeakMap,NE=(e,t,n)=>{let a=Ga.get(e);a||(a=new Map,Ga.set(e,a));let s=a.get(t);return s||(s=new IE(e,t,n),a.set(t,s)),s.retain(),s},OE=(e,t)=>{if(t.releaseOne()>0)return;t.dispose();const n=Ga.get(e);(n==null?void 0:n.get(t.faceIndex))===t&&n.delete(t.faceIndex)},Af=(e,t)=>{var n;return(n=Ga.get(e))==null?void 0:n.get(t)},Mt=e=>typeof e=="number"?e:e.current,Wo=e=>"current"in e&&e.current!==null&&typeof e.current=="object"?e.current:e,vf=Object.freeze({kind:"eachOther"}),PE=e=>e.kind==="faceTexture"?{kind:e.kind,face:e.face}:{kind:e.kind},UE=e=>e.kind==="photo"||e.kind==="canonicalTexture"?e:null,DE=e=>e==="idle"?"waiting":e,ts=({eachOther:e=!1,faceIndex:t,numFaces:n,modelFaces:a})=>{if(e)return{numFaces:de.resolveNumFaces(1,n??2),targets:[0,1],checkFace:1};if(t!==void 0){const i=de.resolveFaceIndex(t);return{numFaces:de.resolveNumFaces(i,n??1),targets:[i],checkFace:i}}const s=de.resolveNumFaces(0,n??1),r=typeof a=="number"&&Number.isFinite(a)?Math.round(a):0,o=Math.max(s,r);return{numFaces:s,targets:Array.from({length:o},(i,c)=>c),checkFace:s-1}},GE=.001,$r=e=>le.FACE_SURFACE_RENDER_ORDER+Math.max(0,e)*GE,$E=(e,t)=>e===t||e.length===t.length&&e.every((n,a)=>n===t[a]),BE=(e,t)=>e===t||!!e&&!!t&&e.code===t.code&&e.message===t.message,HE=(e,t)=>!!e&&e.active===t.active&&e.faces===t.faces&&e.source===t.source&&$E(e.warnings,t.warnings)&&BE(e.error,t.error),Mf=e=>{const t={...e};return delete t.amount,delete t.smoothing,t},ea=["leftEye","rightEye","noseTip","noseBridge","mouth","leftMouthCorner","rightMouthCorner","chin","leftJaw","rightJaw","leftCheek","rightCheek","leftFaceSide","rightFaceSide","forehead","faceCenter"],nr={leftEye:[263,362],rightEye:[33,133],noseTip:[4],noseBridge:[168],mouth:[13,14],leftMouthCorner:[291],rightMouthCorner:[61],chin:[152],leftJaw:[397],rightJaw:[172],leftCheek:[280],rightCheek:[50],leftFaceSide:[323],rightFaceSide:[93],forehead:[151],faceCenter:[10,152]},zE=10,KE=152,Br=2.803,yf=[.35,.6],wf=()=>({aspect:1,mirrored:!1,visibility:{left:1,right:1},unit:0,axisX:{x:0,y:0},axisY:{x:0,y:0},points:Object.fromEntries(ea.map(e=>[e,{x:0,y:0}])),landmarks:null}),jE=(e,t,n,a)=>{let s=0,r=0;for(const o of t)s+=e[o].x,r+=e[o].y;return a.x=s/t.length*n,a.y=r/t.length,a},qc=(e,t,n,a)=>Math.hypot((e[t].x-e[n].x)*a,e[t].y-e[n].y),Hr=(e,t)=>{if(!(t>0))return 1;const[n,a]=yf;return Math.min(1,Math.max(0,(e/t-n)/(a-n)))},Wt={x:0,y:0,z:0},qt={x:0,y:0,z:0},Xc=(e,[t,n],a,s)=>(s.x=(e[t].x+e[n].x)/2*a,s.y=(e[t].y+e[n].y)/2,s.z=((e[t].z??0)+(e[n].z??0))/2*a,s),_f=(e,t,n,a)=>{if(!e||e.length<468||!(t>0))return!1;Xc(e,nr.leftEye,t,Wt),Xc(e,nr.rightEye,t,qt);const s=Math.hypot(Wt.x-qt.x,Wt.y-qt.y,Wt.z-qt.z);if(!(s>1e-6))return!1;const r=ee.personLeftSign(n),o=(Wt.x-qt.x)*r,i=(Wt.y-qt.y)*r,c=e[zE],u=e[KE],l=(c.x-u.x)*t/Br,h=(c.y-u.y)/Br;if(!(Math.hypot(o,i)>1e-9)||!(Math.hypot(l,h)>1e-9))return!1;a.aspect=t,a.mirrored=n,a.unit=s;const f=qc(e,263,362,t),p=qc(e,33,133,t),m=Math.max(f,p),E=Hr(f,m),S=Hr(p,m);a.visibility.left=n?S:E,a.visibility.right=n?E:S,a.axisX.x=o,a.axisX.y=i,a.axisY.x=l,a.axisY.y=h;for(const g of ea)jE(e,nr[ee.feedSidedName(g,n)],t,a.points[g]);return a.landmarks=e,!0},Ff=(e,t,n)=>{var s;const a=(s=e.landmarks)==null?void 0:s[t];return a?(n.x=a.x*e.aspect,n.y=a.y,!0):!1},qo=["bulge","pinch","push","stretch","swirl"],Nt={bulge:0,pinch:1,push:2,stretch:3,swirl:4},Xo={bulge:.9,pinch:1.15,push:.6,stretch:.9,swirl:1},$a=3,xf=1.5,hn=32,Dt=8,Ea=(e,t,n)=>Math.min(n,Math.max(t,e)),zr=e=>!Number.isFinite(e)||e<=0?0:(Math.min(e,$a)/$a)**xf,Cf=e=>{if(!(e<1))return 0;const t=1-e*e;return t*t},Tf=(e,t,n,a,s)=>{const r=t*Dt,o=e[r],i=e[r+1],c=e[r+2],u=e[r+3],l=e[r+4],h=e[r+5],f=e[r+6];if(s.x=n,s.y=a,!(c>0)||!(l>0))return s;const p=n-o,m=a-i,E=Cf(Math.hypot(p,m)/c);if(E<=0)return s;switch(u){case 0:{const S=1-l*E;s.x=o+p*S,s.y=i+m*S;break}case 1:{const S=1+l*E;s.x=o+p*S,s.y=i+m*S;break}case 2:{s.x=n-l*c*E*h,s.y=a-l*c*E*f;break}case 3:{const S=(p*h+m*f)*l*E;s.x=n-S*h,s.y=a-S*f;break}default:{const S=-h*l*Math.PI*E,g=Math.cos(S),A=Math.sin(S);s.x=o+p*g-m*A,s.y=i+p*A+m*g}}return s},VE=(e,t,n,a,s={x:0,y:0})=>{s.x=n,s.y=a;for(let r=t-1;r>=0;r-=1)Tf(e,r,s.x,s.y,s);return s},kf=(e,t,n,a={minX:0,minY:0,maxX:0,maxY:0})=>{if(!(n>0))return null;let s=1/0,r=1/0,o=-1/0,i=-1/0;for(let c=0;c<t;c+=1){const u=c*Dt,l=e[u+2];!(l>0)||!(e[u+4]>0)||(s=Math.min(s,(e[u]-l)/n),o=Math.max(o,(e[u]+l)/n),r=Math.min(r,e[u+1]-l),i=Math.max(i,e[u+1]+l))}return!(o>s)||!(i>r)||(a.minX=Ea(s,0,1),a.minY=Ea(r,0,1),a.maxX=Ea(o,0,1),a.maxY=Ea(i,0,1),!(a.maxX>a.minX)||!(a.maxY>a.minY))?null:a},WE={bulge:"#4ade80",pinch:"#fb923c",push:"#22d3ee",stretch:"#e879f9",swirl:"#facc15"},qE=Object.fromEntries(qo.map(e=>[e,new d.Color(WE[e])])),Yc=new d.Color("#ffffff"),ar=24e3,XE=48,YE=`
|
|
2089
|
+
varying vec3 vColor;
|
|
2090
|
+
void main() {
|
|
2091
|
+
vColor = color;
|
|
2092
|
+
gl_Position = vec4(position.xy, 0.0, 1.0);
|
|
2093
|
+
}`,QE=`
|
|
2094
|
+
varying vec3 vColor;
|
|
2095
|
+
void main() {
|
|
2096
|
+
gl_FragColor = vec4(vColor, 1.0);
|
|
2097
|
+
}`;class JE{constructor(t){C(this,"geometry",new d.BufferGeometry);C(this,"material",new d.ShaderMaterial({name:"FaceLiquifyDebug",vertexShader:YE,fragmentShader:QE,vertexColors:!0,depthTest:!1,depthWrite:!1,transparent:!0,toneMapped:!1}));C(this,"mesh");C(this,"positions",new Float32Array(ar*3));C(this,"colors",new Float32Array(ar*3));C(this,"count",0);C(this,"aspect",1);this.geometry.setAttribute("position",new d.BufferAttribute(this.positions,3).setUsage(d.DynamicDrawUsage)),this.geometry.setAttribute("color",new d.BufferAttribute(this.colors,3).setUsage(d.DynamicDrawUsage)),this.geometry.setDrawRange(0,0),this.mesh=new d.LineSegments(this.geometry,this.material),this.mesh.name="FaceLiquifyDebug",this.mesh.frustumCulled=!1,this.mesh.renderOrder=t}begin(t){this.aspect=t>0?t:1,this.count=0}line(t,n,a,s,r,o){this.count+2>ar||(this.vertex(t,n,r,o),this.vertex(a,s,r,o))}vertex(t,n,a,s){const r=this.count*3;this.positions[r]=t/this.aspect*2-1,this.positions[r+1]=1-n*2,this.positions[r+2]=0,this.colors[r]=a.r*s,this.colors[r+1]=a.g*s,this.colors[r+2]=a.b*s,this.count+=1}arc(t,n,a,s,r,o,i){const c=Math.max(4,Math.round(XE*Math.abs(r-s)/(2*Math.PI)));for(let u=0;u<c;u+=1){const l=s+(r-s)*u/c,h=s+(r-s)*(u+1)/c;this.line(t+a*Math.cos(l),n+a*Math.sin(l),t+a*Math.cos(h),n+a*Math.sin(h),o,i)}}arrow(t,n,a,s,r,o){this.line(t,n,a,s,r,o);const i=Math.atan2(s-n,a-t),c=Math.hypot(a-t,s-n)*.3;this.line(a,s,a-c*Math.cos(i+.5),s-c*Math.sin(i+.5),r,o),this.line(a,s,a-c*Math.cos(i-.5),s-c*Math.sin(i-.5),r,o)}drawPoints(t){const n=t.unit*.06;for(const a of ea){const{x:s,y:r}=t.points[a];this.line(s-n,r,s+n,r,Yc,.8),this.line(s,r-n,s,r+n,Yc,.8)}}drawOps(t,n){for(let a=0;a<n;a+=1){const s=a*Dt,r=t[s],o=t[s+1],i=t[s+2],c=qo[Math.round(t[s+3])],u=t[s+4],l=t[s+5],h=t[s+6];if(!c||!(i>0))continue;const f=qE[c],p=.35+.65*Math.min(1,Math.max(0,u/Xo[c]));if(this.arc(r,o,i,0,Math.PI*2,f,p),c==="push")this.arrow(r,o,r+l*i*.7,o+h*i*.7,f,p);else if(c==="stretch")this.arrow(r,o,r+l*i*.7,o+h*i*.7,f,p),this.arrow(r,o,r-l*i*.7,o-h*i*.7,f,p);else if(c==="swirl"){const m=l*Math.PI*1.5;this.arc(r,o,i*.5,0,m,f,p);const E=r+i*.5*Math.cos(m),S=o+i*.5*Math.sin(m),g=-Math.sin(m)*l,A=Math.cos(m)*l;this.arrow(E-g*i*.2,S-A*i*.2,E,S,f,p)}else{const[m,E]=c==="bulge"?[.45,.85]:[.85,.45];for(let S=0;S<4;S+=1){const g=S*Math.PI/2+Math.PI/4,A=Math.cos(g),v=Math.sin(g);this.arrow(r+A*i*m,o+v*i*m,r+A*i*E,o+v*i*E,f,p)}}}}end(){this.geometry.setDrawRange(0,this.count),this.geometry.attributes.position.needsUpdate=!0,this.geometry.attributes.color.needsUpdate=!0}get vertices(){return this.count}dispose(){this.geometry.dispose(),this.material.dispose()}}const ZE={FACE_LIQUIFY_MAX_OPS:hn,KIND_BULGE:Nt.bulge,KIND_PINCH:Nt.pinch,KIND_PUSH:Nt.push,KIND_STRETCH:Nt.stretch,KIND_SWIRL:Nt.swirl},eA=`
|
|
2098
|
+
uniform vec4 uOps[FACE_LIQUIFY_MAX_OPS * 2];
|
|
2099
|
+
|
|
2100
|
+
vec2 faceLiquifyApply(int i, vec2 q, inout bool moved) {
|
|
2101
|
+
vec4 a = uOps[i * 2];
|
|
2102
|
+
vec4 b = uOps[i * 2 + 1];
|
|
2103
|
+
float radius = a.z;
|
|
2104
|
+
float k = b.x;
|
|
2105
|
+
if (!(radius > 0.0) || !(k > 0.0)) return q;
|
|
2106
|
+
vec2 c = a.xy;
|
|
2107
|
+
vec2 p = q - c;
|
|
2108
|
+
float r2 = dot(p, p) / (radius * radius);
|
|
2109
|
+
if (!(r2 < 1.0)) return q;
|
|
2110
|
+
float t = 1.0 - r2;
|
|
2111
|
+
float w = t * t;
|
|
2112
|
+
if (w <= 0.0) return q;
|
|
2113
|
+
moved = true;
|
|
2114
|
+
int kind = int(a.w + 0.5);
|
|
2115
|
+
vec2 d = b.yz;
|
|
2116
|
+
if (kind == KIND_BULGE) return c + p * (1.0 - k * w);
|
|
2117
|
+
if (kind == KIND_PINCH) return c + p * (1.0 + k * w);
|
|
2118
|
+
if (kind == KIND_PUSH) return q - k * radius * w * d;
|
|
2119
|
+
if (kind == KIND_STRETCH) return q - dot(p, d) * k * w * d;
|
|
2120
|
+
// swirl: dir.x is the signed turn
|
|
2121
|
+
float an = -d.x * k * 3.141592653589793 * w;
|
|
2122
|
+
float cs = cos(an);
|
|
2123
|
+
float sn = sin(an);
|
|
2124
|
+
return c + vec2(p.x * cs - p.y * sn, p.x * sn + p.y * cs);
|
|
2125
|
+
}
|
|
2126
|
+
`,tA=`
|
|
2127
|
+
uniform vec4 uRect;
|
|
2128
|
+
void main() {
|
|
2129
|
+
// On the near plane (depth 0), tested with LESS: it draws everywhere except
|
|
2130
|
+
// where HandCutout wrote the near plane, so hand pixels stay as they are.
|
|
2131
|
+
gl_Position = vec4(mix(uRect.xy, uRect.zw, position.xy), -1.0, 1.0);
|
|
2132
|
+
}
|
|
2133
|
+
`,nA=`
|
|
2134
|
+
uniform sampler2D uCopy;
|
|
2135
|
+
uniform int uCount;
|
|
2136
|
+
uniform float uAspect;
|
|
2137
|
+
uniform vec2 uTarget;
|
|
2138
|
+
uniform vec2 uCopyOrigin;
|
|
2139
|
+
uniform vec2 uCopySize;
|
|
2140
|
+
uniform sampler2D uHandMask;
|
|
2141
|
+
uniform float uHands;
|
|
2142
|
+
${eA}
|
|
2143
|
+
void main() {
|
|
2144
|
+
vec2 frag = gl_FragCoord.xy;
|
|
2145
|
+
// Aspect space, y down.
|
|
2146
|
+
vec2 p = vec2(frag.x / uTarget.x * uAspect, 1.0 - frag.y / uTarget.y);
|
|
2147
|
+
bool moved = false;
|
|
2148
|
+
// As sampleFaceLiquify: the screen point goes through the warps last to first.
|
|
2149
|
+
for (int i = FACE_LIQUIFY_MAX_OPS - 1; i >= 0; --i) {
|
|
2150
|
+
if (i < uCount) p = faceLiquifyApply(i, p, moved);
|
|
2151
|
+
}
|
|
2152
|
+
if (!moved) {
|
|
2153
|
+
gl_FragColor = texelFetch(uCopy, ivec2(frag - uCopyOrigin), 0);
|
|
2154
|
+
return;
|
|
2155
|
+
}
|
|
2156
|
+
vec2 px = vec2(p.x / uAspect * uTarget.x, (1.0 - p.y) * uTarget.y);
|
|
2157
|
+
vec4 color = texture2D(uCopy, (px - uCopyOrigin) / uCopySize);
|
|
2158
|
+
if (uHands > 0.5) {
|
|
2159
|
+
// Never pull a hand into the face: where the warped point lands on a hand
|
|
2160
|
+
// (HandCutout's silhouettes), keep this pixel's own, unmoved colour.
|
|
2161
|
+
float hand = texture2D(uHandMask, vec2(p.x / uAspect, 1.0 - p.y)).r;
|
|
2162
|
+
if (hand > 0.0) color = mix(color, texelFetch(uCopy, ivec2(frag - uCopyOrigin), 0), hand);
|
|
2163
|
+
}
|
|
2164
|
+
gl_FragColor = color;
|
|
2165
|
+
}
|
|
2166
|
+
`,aA=e=>{const t={uCopy:{value:e},uOps:{value:new Float32Array(hn*Dt)},uCount:{value:0},uAspect:{value:1},uTarget:{value:new d.Vector2(1,1)},uCopyOrigin:{value:new d.Vector2},uCopySize:{value:new d.Vector2(1,1)},uRect:{value:new d.Vector4(-1,-1,1,1)},uHandMask:{value:e},uHands:{value:0}};return new d.ShaderMaterial({name:"FaceLiquify",uniforms:t,defines:{...ZE},vertexShader:tA,fragmentShader:nA,transparent:!0,blending:d.NoBlending,depthTest:!0,depthFunc:d.LessDepth,depthWrite:!1,stencilWrite:!1,side:d.FrontSide,toneMapped:!1,dithering:!1,fog:!1,lights:!1})},sA={xr:"an XR / ArrayCamera image is drawn without the warp",layout:"a cube, 3D, array or multi-target render target is drawn without the warp",msaa:"a multisampled render target (an effect composer?) is drawn without the warp",type:"a float render target (an effect composer?) is drawn without the warp",format:"a render target that is not RGBA is drawn without the warp",broken:"this target kind failed its GL check; drawn without the warp"},Xt=(e,t=!0)=>({skip:e,warn:t}),rA=({target:e,camera:t,xrPresenting:n,alpha:a,broken:s})=>{var o,i;if(n||t.isArrayCamera)return Xt("xr");let r;if(!e)r=a?"canvas":"canvas-rgb";else{if(e.isWebGLCubeRenderTarget||e.isWebGL3DRenderTarget||e.isWebGLArrayRenderTarget||(((o=e.textures)==null?void 0:o.length)??1)>1)return Xt("layout");if((e.samples??0)>0)return Xt("msaa");const c=e.texture??((i=e.textures)==null?void 0:i[0]);if(!c||c.type!==d.UnsignedByteType)return Xt("type");if(c.format!==d.RGBAFormat)return Xt("format");r=c.colorSpace===d.SRGBColorSpace?"srgb-target":"linear-target"}return s.has(r)?Xt("broken",!1):{kind:r}},oA=64,iA=2,tn=(e,t,n)=>Math.min(n,Math.max(t,e)),cA=(e,t,n)=>{if(!e||!(t>0)||!(n>0))return null;const a=iA,s=tn(Math.floor(e.minX*t)-a,0,t),r=tn(Math.ceil(e.maxX*t)+a,0,t),o=tn(Math.floor((1-e.maxY)*n)-a,0,n),i=tn(Math.ceil((1-e.minY)*n)+a,0,n);if(!(r>s)||!(i>o))return null;const c=oA;return{x0:s,y0:o,x1:r,y1:i,width:Math.min(Math.ceil((r-s)/c)*c,t),height:Math.min(Math.ceil((i-o)/c)*c,n)}},lA=(e,t,n,a,s,r)=>(r.x=tn(e.x0-Math.floor((t-(e.x1-e.x0))/2),0,Math.max(0,a-t)),r.y=tn(e.y0-Math.floor((n-(e.y1-e.y0))/2),0,Math.max(0,s-n)),r),uA=(e,t,n,a,s)=>!e||e.kind!==t||n.width>e.width||n.height>e.height||e.width>a||e.height>s,Yo=ou.RENDER_LAYERS.SCREEN_UI-2,hA="[xr-sdk face] FaceLiquify:",fA=()=>{const e=new d.BufferGeometry;return e.setAttribute("position",new d.BufferAttribute(new Float32Array([0,0,0,1,0,0,1,1,0,0,1,0]),3)),e.setIndex([0,1,2,0,2,3]),e},Qc=256,pA=`
|
|
2167
|
+
void main() {
|
|
2168
|
+
gl_Position = vec4(position.xy, 0.0, 1.0);
|
|
2169
|
+
}
|
|
2170
|
+
`,dA=`
|
|
2171
|
+
void main() {
|
|
2172
|
+
gl_FragColor = vec4(1.0);
|
|
2173
|
+
}
|
|
2174
|
+
`;class mA{constructor(){C(this,"target",new d.WebGLRenderTarget(Qc,Qc,{format:d.RedFormat,type:d.UnsignedByteType,depthBuffer:!1,stencilBuffer:!1,generateMipmaps:!1,minFilter:d.LinearFilter,magFilter:d.LinearFilter}));C(this,"scene",new d.Scene);C(this,"camera",new d.OrthographicCamera(-1,1,1,-1,0,1));C(this,"material",new d.ShaderMaterial({name:"FaceLiquifyHandMask",vertexShader:pA,fragmentShader:dA,depthTest:!1,depthWrite:!1,side:d.DoubleSide}));C(this,"meshes",new Map);C(this,"clearColor",new d.Color);C(this,"drawn",new Map);C(this,"drawnRenderer",null);C(this,"hasHands",!1);C(this,"draws",0)}changed(t,n){if(t!==this.drawnRenderer)return!0;let a=0;for(const s of n){if(s.drawRange.count<=0)continue;a+=1;const r=this.drawn.get(s),o=s.getAttribute("position");if(!r||r.version!==((o==null?void 0:o.version)??0)||r.count!==s.drawRange.count)return!0}return a!==this.drawn.size}draw(t,n){const a=T.getHandCutoutShapes(n);for(const[h,f]of this.meshes)a.has(h)||(this.scene.remove(f),this.meshes.delete(h));if(!this.changed(t,a))return this.hasHands;this.drawn.clear(),this.drawnRenderer=t;for(const h of a){if(h.drawRange.count<=0)continue;const f=h.getAttribute("position");this.drawn.set(h,{version:(f==null?void 0:f.version)??0,count:h.drawRange.count})}if(this.hasHands=this.drawn.size>0,!this.hasHands)return!1;for(const h of a){if(this.meshes.has(h))continue;const f=new d.Mesh(h,this.material);f.frustumCulled=!1,f.matrixAutoUpdate=!1,this.meshes.set(h,f),this.scene.add(f)}const s=t.getRenderTarget(),r=t.getActiveCubeFace(),o=t.getActiveMipmapLevel();t.getClearColor(this.clearColor);const i=t.getClearAlpha(),c=t.autoClear,u=t.xr.enabled,l=t.shadowMap.autoUpdate;try{t.xr.enabled=!1,t.shadowMap.autoUpdate=!1,t.autoClear=!1,t.setRenderTarget(this.target),t.setClearColor(0,0),t.clear(!0,!1,!1),t.render(this.scene,this.camera),this.draws+=1}finally{t.setRenderTarget(s,r,o),t.setClearColor(this.clearColor,i),t.autoClear=c,t.xr.enabled=u,t.shadowMap.autoUpdate=l}return!0}dispose(){this.target.dispose(),this.material.dispose(),this.meshes.clear(),this.drawn.clear()}}const Ba=new WeakMap,gA=e=>{let t=Ba.get(e);return t||(t={mask:new mA,users:0},Ba.set(e,t)),t.users+=1,t.mask},Jc=e=>{const t=Ba.get(e);t&&(t.users-=1,t.users<=0&&(t.mask.dispose(),Ba.delete(e)))},SA=(e,t,n)=>{const a=new d.FramebufferTexture(t,n);return a.name="FaceLiquifyCopy",a.minFilter=d.LinearFilter,a.magFilter=d.LinearFilter,a.generateMipmaps=!1,a.wrapS=d.ClampToEdgeWrapping,a.wrapT=d.ClampToEdgeWrapping,a.colorSpace=e==="srgb-target"?d.SRGBColorSpace:d.NoColorSpace,e==="canvas-rgb"&&(a.format=d.RGBFormat,a.internalFormat="RGB8"),a};class EA{constructor(){C(this,"geometry",fA());C(this,"placeholder",new d.DataTexture(new Uint8Array(4),1,1));C(this,"material");C(this,"mesh");C(this,"ops");C(this,"live",!1);C(this,"bounds",{minX:0,minY:0,maxX:0,maxY:0});C(this,"canvasSlot",null);C(this,"targets",new Map);C(this,"broken",new Set);C(this,"warned",new Set);C(this,"restoreListener",null);C(this,"origin",{x:0,y:0});C(this,"copyOrigin",new d.Vector2);C(this,"handMask",null);C(this,"handScene",null);C(this,"onBeforeRender",(t,n,a,s,r)=>{var y,x;this.geometry.setDrawRange(0,0);const{uniforms:o}=this.material;if(o.uCopy.value=this.placeholder,o.uHands.value=0,o.uHandMask.value=this.placeholder,!this.live)return;const i=oe.getRenderPassContext(t);if(i&&i.index!==i.count-1||n.overrideMaterial||r!==this.material)return;const c=t.getContext(),u=t.getRenderTarget(),l=rA({target:u,camera:a,xrPresenting:!!((y=t.xr)!=null&&y.isPresenting),alpha:((x=c.getContextAttributes())==null?void 0:x.alpha)!==!1,broken:this.broken});if(l.skip!==void 0){l.warn&&this.warnOnce(l.skip,sA[l.skip]);return}const{kind:h}=l,f=u?u.width:c.drawingBufferWidth,p=u?u.height:c.drawingBufferHeight,m=cA(this.bounds,f,p);if(!m)return;this.watchRestore(t);const E=this.slotFor(h,u,m,f,p),S=lA(m,E.width,E.height,f,p,this.origin);if(this.copyOrigin.set(S.x,S.y),E.checked)t.copyFramebufferToTexture(E.texture,this.copyOrigin);else{for(let w=0;w<16&&c.getError()!==c.NO_ERROR;w+=1);t.copyFramebufferToTexture(E.texture,this.copyOrigin);const F=c.getError();if(F!==c.NO_ERROR){this.broken.add(h),this.warnOnce(`gl:${h}`,`copying the ${h} image failed (GL error ${F}); drawn without the warp`);return}E.checked=!0}if(T.getHandCutoutShapes(n).size>0){this.handScene!==n&&(this.handScene&&Jc(this.handScene),this.handMask=gA(n),this.handScene=n);const F=this.handMask.draw(t,n);o.uHands.value=F?1:0,o.uHandMask.value=F?this.handMask.target.texture:this.placeholder}else o.uHands.value=0,o.uHandMask.value=this.placeholder;o.uCopy.value=E.texture,o.uTarget.value.set(f,p),o.uCopyOrigin.value.copy(this.copyOrigin),o.uCopySize.value.set(E.width,E.height);const{minX:g,minY:A,maxX:v,maxY:M}=this.bounds;o.uRect.value.set(g*2-1,1-M*2,v*2-1,1-A*2),this.material.uniformsNeedUpdate=!0,this.geometry.setDrawRange(0,6)});this.placeholder.needsUpdate=!0,this.material=aA(this.placeholder),this.ops=this.material.uniforms.uOps.value,this.mesh=new d.Mesh(this.geometry,this.material),this.mesh.name="FaceLiquify",this.mesh.frustumCulled=!1,this.mesh.matrixAutoUpdate=!1,this.mesh.visible=!1,this.mesh.layers.set(0),this.mesh.renderOrder=Yo,this.geometry.setDrawRange(0,0),this.mesh.onBeforeRender=this.onBeforeRender}update(t,n,a){const s=t>0&&!!a;if(this.live=s,this.mesh.visible=s,!s||!a)return;const{uniforms:r}=this.material;r.uCount.value=t,r.uAspect.value=n,this.bounds.minX=a.minX,this.bounds.minY=a.minY,this.bounds.maxX=a.maxX,this.bounds.maxY=a.maxY}hide(){this.update(0,1,null)}warnOnce(t,n){this.warned.has(t)||(this.warned.add(t),console.warn(`${hA} ${n}`))}watchRestore(t){const n=t.domElement;if(this.restoreListener||!(n!=null&&n.addEventListener))return;const a=()=>{this.broken.clear(),this.disposeSlots()};n.addEventListener("webglcontextrestored",a),this.restoreListener={element:n,listener:a}}slotFor(t,n,a,s,r){let o,i;if(n){if(o=this.targets.get(n),!o){const c={slot:null,onDispose:()=>{var u;(u=c.slot)==null||u.texture.dispose(),n.removeEventListener("dispose",c.onDispose),this.targets.delete(n)}};o=c,n.addEventListener("dispose",c.onDispose),this.targets.set(n,c)}i=o.slot}else i=this.canvasSlot;return uA(i,t,a,s,r)&&(i==null||i.texture.dispose(),i={kind:t,width:a.width,height:a.height,texture:SA(t,a.width,a.height),checked:!1},o?o.slot=i:this.canvasSlot=i),i}disposeSlots(){var t,n;(t=this.canvasSlot)==null||t.texture.dispose(),this.canvasSlot=null;for(const[a,s]of this.targets)(n=s.slot)==null||n.texture.dispose(),a.removeEventListener("dispose",s.onDispose);this.targets.clear()}dispose(){this.disposeSlots(),this.restoreListener&&(this.restoreListener.element.removeEventListener("webglcontextrestored",this.restoreListener.listener),this.restoreListener=null),this.handScene&&Jc(this.handScene),this.handMask=null,this.handScene=null,this.placeholder.dispose(),this.geometry.dispose(),this.mesh.onBeforeRender=()=>{}}}const Lf=["bigEyes","smallNose","bigMouth","smile","chubbyCheeks","slimJaw","slimFace","longChin","bigForehead","bigHead","swirl"],Rf={bigEyes:[{kind:"bulge",at:"leftEye",radius:.55,strength:.8,mirror:!0}],smallNose:[{kind:"pinch",at:"noseTip",offset:[0,.15],radius:.6,strength:.95}],bigMouth:[{kind:"bulge",at:"mouth",radius:.8,strength:.85}],smile:[{kind:"push",at:"leftMouthCorner",offset:[.05,0],radius:.45,strength:.95,direction:[.35,1],mirror:!0}],chubbyCheeks:[{kind:"bulge",at:"leftCheek",offset:[.1,-.05],radius:.85,strength:.9,mirror:!0}],slimJaw:[{kind:"push",at:"leftJaw",radius:.75,strength:.8,direction:[-.8,.5],mirror:!0}],slimFace:[{kind:"push",at:"leftFaceSide",offset:[-.05,-.1],radius:.9,strength:.8,direction:[-1,.1],mirror:!0}],longChin:[{kind:"push",at:"chin",offset:[0,.05],radius:.75,strength:.85,direction:[0,-1]}],bigForehead:[{kind:"bulge",at:"forehead",offset:[0,.1],radius:1.1,strength:.75}],bigHead:[{kind:"bulge",at:"faceCenter",radius:2.1,strength:.55}],swirl:[{kind:"swirl",at:"faceCenter",radius:1.7,strength:.6}]},AA=e=>typeof e=="string"&&ea.includes(e),ct=(e,t)=>typeof e=="number"&&Number.isFinite(e)?e:t,vA=e=>typeof e=="string"?ee.swapSidedName(e):{landmark:T.FACE_ATLAS_MIRROR[e.landmark]??e.landmark},Zc=(e,t,n,a)=>{var h,f,p,m;const s=t.at,r=AA(s)||typeof s=="object"&&s!==null&&Number.isInteger(s.landmark)&&s.landmark>=0&&s.landmark<468,o=ct(t.radius,0),i=Xo[t.kind];if(!r||i===void 0||!(o>0))return;const c=Math.min(1,Math.max(0,ct(t.strength,0)))*i*n;if(!(c>0))return;const u=[ct((h=t.offset)==null?void 0:h[0],0),ct((f=t.offset)==null?void 0:f[1],0)];let l;if(t.kind==="swirl")l=[t.clockwise?-1:1,0];else{const E=ct((p=t.direction)==null?void 0:p[0],0),S=ct((m=t.direction)==null?void 0:m[1],1),g=Math.hypot(E,S);l=g>1e-9?[E/g,S/g]:[0,1]}a.push({name:e,kind:t.kind,at:s,offset:u,radius:o,strength:c,direction:l}),t.mirror&&a.push({name:e,kind:t.kind,at:vA(s),offset:[-u[0],u[1]],radius:o,strength:c,direction:t.kind==="swirl"?[-l[0],0]:[-l[0],l[1]]})},bf=(e={},t={})=>{const n=[];for(const s of Lf){const r=zr(ct(e[s],0));if(r>0)for(const o of Rf[s])Zc(s,o,r,n)}for(const[s,r]of Object.entries(t)){const o=zr(ct(e[s],$a));if(!(o>0)||!r)continue;const i=Array.isArray(r)?r:[r];for(const c of i)Zc(s,c,o,n)}const a=Math.max(0,n.length-hn);return{warps:a?n.slice(0,hn):n,dropped:a}},Rn={x:0,y:0},MA=1,If=(e,t)=>{if(typeof e.at=="string")return e.at.startsWith("left")?"left":e.at.startsWith("right")?"right":null;const n=V.CANONICAL_FACE_POSITIONS[e.at.landmark*3];return Math.abs(n)>MA?ee.personSide(n>0?"left":"right",t):null},Nf=(e,t,n,a=1)=>{if(!(e.unit>0))return 0;const s=Math.min(1,Math.max(0,ct(a,1))),{axisX:r,axisY:o}=e,i=r.x*o.y-r.y*o.x<0?-1:1;let c=0;for(const u of t){if((c+1)*Dt>n.length)break;if(typeof u.at=="string")Rn.x=e.points[u.at].x,Rn.y=e.points[u.at].y;else if(!Ff(e,u.at.landmark,Rn))continue;const[l,h]=u.offset,f=c*Dt;n[f]=Rn.x+l*r.x+h*o.x,n[f+1]=Rn.y+l*r.y+h*o.y,n[f+2]=u.radius*e.unit,n[f+3]=Nt[u.kind];const p=If(u,e.mirrored);if(n[f+4]=u.strength*s*(p?e.visibility[p]:1),u.kind==="swirl")n[f+5]=u.direction[0]*i,n[f+6]=0;else{const m=u.direction[0]*r.x+u.direction[1]*o.x,E=u.direction[0]*r.y+u.direction[1]*o.y,S=Math.hypot(m,E)||1;n[f+5]=m/S,n[f+6]=E/S}n[f+7]=0,c+=1}return c},Of=Object.freeze({inMs:150,holdMs:250,outMs:120}),Pf=()=>({fade:0,lostMs:null}),Uf=e=>{e.fade=0,e.lostMs=null},Df=(e,t,n)=>{const a=Number.isFinite(n)?Math.max(0,n):0,{inMs:s,holdMs:r,outMs:o}=Of;return t?(e.lostMs=null,e.fade=Math.min(1,e.fade+a/s),e.fade):e.fade<=0?0:(e.lostMs=(e.lostMs??0)+a,e.lostMs<=r||(e.fade=Math.max(0,e.fade-a/o)),e.fade)},Gf=-101,$f=4,Bf=.35,yA=Object.freeze({}),wA=(e,t)=>{let n=0;for(const a in e)if(Object.prototype.hasOwnProperty.call(e,a)&&(n+=1,!Object.is(e[a],t[a])||!Object.prototype.hasOwnProperty.call(t,a)))return!1;return n===Object.keys(t).length},_A=()=>({pass:new EA,track:mf(),presence:Pf(),frame:wf(),landmarks:Array.from({length:K.CANONICAL_FACE_LANDMARK_COUNT},()=>({x:0,y:0,z:0})),bounds:{minX:0,minY:0,maxX:0,maxY:0},tracked:!1,seen:!1,count:0}),FA=e=>{e.pass.dispose(),Ce(e.pass.material)},xA=({weights:e,warps:t,weight:n,faceIndex:a,numFaces:s,smoothing:r=Bf,active:o=!0,renderOrder:i=Yo,debug:c=!1})=>{const u=Te.useTrackerContext(),l=ge(),h=ae.useXRModelNode(ee.XRModel.FACE_TRACKER),f=ae.useXRMirrored(),p=ae.useXRCameraTexture(),m=J.useThree(b=>b.size),E=h==null?void 0:h.numFaces,S=(u==null?void 0:u.type)==="face"?u.faceIndex:void 0,{numFaces:g,targets:A,checkFace:v}=_.useMemo(()=>ts({faceIndex:a??S,numFaces:s,modelFaces:E}),[a,S,s,E]);dn(o&&(u==null?void 0:u.type)!=="face"&&!l,g),_.useLayoutEffect(()=>{o&&ja(h,v,"FaceLiquify")},[o,h,v]);const M=Math.min(A.length,$f),[y,x]=_.useState([]);_.useEffect(()=>{const b=Array.from({length:M},_A);return x(b),()=>{b.forEach(FA),x(N=>N===b?[]:N)}},[M]),_.useLayoutEffect(()=>{for(const b of y)b.pass.mesh.renderOrder=i},[y,i]);const[F,w]=_.useState(null);_.useEffect(()=>{if(!c)return;const b=new JE(i+1);return w(b),()=>{b.dispose(),w(N=>N===b?null:N)}},[c,i]);const k=_.useRef({weights:e,warps:t,weight:n,active:o,node:h,mirrored:f,camera:p,size:m,targets:A,smoothing:r});k.current={weights:e,warps:t,weight:n,active:o,node:h,mirrored:f,camera:p,size:m,targets:A,smoothing:r};const R=_.useMemo(()=>({results:void 0,weights:null,custom:void 0,resolved:[],warnedDropped:!1}),[]);return J.useFrame((b,N)=>{var Q,se;if(y.length===0)return;const P=k.current,G=P.size.height>0?P.size.width/P.size.height:1,U=Math.min(100,Math.max(0,N*1e3)),H=P.active?(Q=P.node)==null?void 0:Q.detectionResults:void 0,z=H!==R.results;R.results=H;const X=Wo(P.weights??yA);if(!R.weights||!wA(X,R.weights)||P.warps!==R.custom){R.weights={...X},R.custom=P.warps;const Z=bf(X,P.warps);R.resolved=Z.warps,Z.dropped>0&&!R.warnedDropped&&(R.warnedDropped=!0,console.warn(`[xr-sdk face] FaceLiquify: ${Z.dropped} warps past ${hn} were left out`))}const j=Mt(P.weight??1),D=Number.isFinite(j)?Math.min(1,Math.max(0,j)):0,$=Number.isFinite(P.smoothing)?Math.min(1,Math.max(0,P.smoothing)):0,q=performance.now();F==null||F.begin(G);for(let Z=0;Z<y.length;Z+=1){const B=y[Z],Y=P.targets[Z];if(B.count=0,!P.active||Y===void 0){B.tracked=!1,Uf(B.presence),B.pass.hide();continue}if(z){const _e=gf(B.track,{landmarks:((se=H==null?void 0:H.faceLandmarks)==null?void 0:se[Y])??null,aspect:G,timeMs:q,camera:P.camera??null,smoothing:$});if(B.tracked=_e.tracked,_e.tracked&&_e.smoothing!=="skip"){const{points:ne}=B.track.smoother;for(let ue=0;ue<B.landmarks.length;ue+=1){const Me=B.landmarks[ue];Me.x=ne[ue*3],Me.y=ne[ue*3+1],Me.z=ne[ue*3+2]}B.seen=!0}}const te=Df(B.presence,B.tracked,U);if(te<=0||!B.seen||!_f(B.landmarks,G,P.mirrored,B.frame)){B.pass.hide();continue}if(F==null||F.drawPoints(B.frame),D<=0||R.resolved.length===0){B.pass.hide();continue}const ie=Nf(B.frame,R.resolved,B.pass.ops,D*te);B.count=ie,B.pass.update(ie,G,kf(B.pass.ops,ie,G,B.bounds)),F==null||F.drawOps(B.pass.ops,ie)}F==null||F.end()},Gf),L.jsxs("group",{children:[y.map(b=>L.jsx("primitive",{object:b.pass.mesh},b.pass.mesh.uuid)),F?L.jsx("primitive",{object:F.mesh}):null]})},CA=["real","smooth"],Hf=Object.freeze(["eyes","lids","brows","nose","lips","mouth"]),at=Object.freeze({style:"real",grain:1,feather:.025}),el=[50,280,205,425,151,108,337,199],TA=()=>{const e=new Float32Array(el.length*2);return el.forEach((t,n)=>{e[n*2]=T.FACE_ATLAS_UVS[t*2],e[n*2+1]=T.FACE_ATLAS_UVS[t*2+1]}),e},kA=`
|
|
2175
|
+
out vec2 vUv;
|
|
2176
|
+
void main() {
|
|
2177
|
+
vUv = position.xy * 0.5 + 0.5;
|
|
2178
|
+
gl_Position = vec4(position.xy, 0.0, 1.0);
|
|
2179
|
+
}
|
|
2180
|
+
`,zf=`
|
|
2181
|
+
uniform sampler2D uMap;
|
|
2182
|
+
uniform sampler2D uLow;
|
|
2183
|
+
uniform sampler2D uMask;
|
|
2184
|
+
uniform float uSmooth;
|
|
2185
|
+
uniform float uGrain;
|
|
2186
|
+
uniform vec2 uMapSize;
|
|
2187
|
+
uniform vec2 uTaps[8];
|
|
2188
|
+
in vec2 vUv;
|
|
2189
|
+
layout(location = 0) out highp vec4 fragColor;
|
|
2190
|
+
|
|
2191
|
+
float faceLuma(vec3 c) {
|
|
2192
|
+
return dot(c, vec3(0.2126, 0.7152, 0.0722));
|
|
2193
|
+
}
|
|
2194
|
+
|
|
2195
|
+
float faceHash(vec2 p) {
|
|
2196
|
+
p = fract(p * vec2(123.34, 456.21));
|
|
2197
|
+
p += dot(p, p + 45.32);
|
|
2198
|
+
return fract(p.x * p.y);
|
|
2199
|
+
}
|
|
2200
|
+
|
|
2201
|
+
void main() {
|
|
2202
|
+
vec4 base = texture(uMap, vUv);
|
|
2203
|
+
float coverage = base.a;
|
|
2204
|
+
vec2 mask = texture(uMask, vUv).rg;
|
|
2205
|
+
float erase = uSmooth > 0.5 ? 1.0 : mask.r;
|
|
2206
|
+
if (erase <= 0.0) {
|
|
2207
|
+
fragColor = base;
|
|
2208
|
+
return;
|
|
2209
|
+
}
|
|
2210
|
+
vec4 low = texture(uLow, vUv);
|
|
2211
|
+
if (low.a <= 0.001 && coverage <= 0.0) {
|
|
2212
|
+
fragColor = vec4(0.0);
|
|
2213
|
+
return;
|
|
2214
|
+
}
|
|
2215
|
+
vec3 own = coverage > 0.0 ? base.rgb / coverage : low.rgb / low.a;
|
|
2216
|
+
vec3 skin = low.a > 0.001 ? low.rgb / low.a : own;
|
|
2217
|
+
// Grain: the skin's own fine detail (its luma against its blur on the
|
|
2218
|
+
// cheeks, forehead and chin), as per-texel noise on the filled skin; none
|
|
2219
|
+
// in the eye and mouth openings and the lips (they stretch on screen).
|
|
2220
|
+
// The median of the taps: a hand, hair or glasses over a few of them
|
|
2221
|
+
// does not raise it.
|
|
2222
|
+
float details[8];
|
|
2223
|
+
int count = 0;
|
|
2224
|
+
for (int i = 0; i < 8; i++) {
|
|
2225
|
+
vec4 fine = textureLod(uMap, uTaps[i], 0.0);
|
|
2226
|
+
vec4 blur = textureLod(uMap, uTaps[i], 3.0);
|
|
2227
|
+
if (fine.a > 0.5 && blur.a > 0.5) {
|
|
2228
|
+
float d = abs(faceLuma(fine.rgb / fine.a) - faceLuma(blur.rgb / blur.a));
|
|
2229
|
+
int j = count;
|
|
2230
|
+
while (j > 0 && details[j - 1] > d) {
|
|
2231
|
+
details[j] = details[j - 1];
|
|
2232
|
+
j--;
|
|
2233
|
+
}
|
|
2234
|
+
details[j] = d;
|
|
2235
|
+
count++;
|
|
2236
|
+
}
|
|
2237
|
+
}
|
|
2238
|
+
float detail = count > 0 ? details[(count - 1) / 2] : 0.0;
|
|
2239
|
+
float noise = faceHash(floor(vUv * uMapSize)) * 2.0 - 1.0;
|
|
2240
|
+
float grain = uGrain * (1.0 - uSmooth) * mask.g * detail * noise * 3.4;
|
|
2241
|
+
vec3 fill = max(skin + grain * skin / max(faceLuma(skin), 0.02), vec3(0.0));
|
|
2242
|
+
// Erased texels are covered by the fill (the camera never shows through a
|
|
2243
|
+
// nostril or a closed mouth's line); the rest keeps the face's coverage.
|
|
2244
|
+
float covered = mix(coverage, 1.0, erase);
|
|
2245
|
+
fragColor = vec4(mix(own, fill, erase) * covered, covered);
|
|
2246
|
+
}
|
|
2247
|
+
`,LA=[61,291],RA={inner:.02,outer:.045},Kf=(e=256,t=at.feather)=>{const n=Xn({include:[...Hf],size:e,feather:t*2,origin:"bottom"}),{data:a}=n;for(let o=0;o<a.length;o+=1){const i=Math.min(1,a[o]/127.5);a[o]=Math.round(i*i*(3-2*i)*255)}const{inner:s,outer:r}=RA;for(const o of LA){const i=T.FACE_ATLAS_UVS[o*2],c=T.FACE_ATLAS_UVS[o*2+1],u=Math.max(0,Math.floor((i-r)*e)),l=Math.min(e-1,Math.ceil((i+r)*e)),h=Math.max(0,Math.floor((c-r)*e)),f=Math.min(e-1,Math.ceil((c+r)*e));for(let p=h;p<=f;p+=1)for(let m=u;m<=l;m+=1){const E=Math.hypot((m+.5)/e-i,(p+.5)/e-c),S=Math.min(1,Math.max(0,(r-E)/(r-s))),g=p*e+m;a[g]=Math.max(a[g],Math.round(S*S*(3-2*S)*255))}}return n},jf=(e=256,t=at.feather)=>{const n=Xn({include:["eyes","mouth","lips"],size:e,feather:t*2,origin:"bottom"}),{data:a}=n;for(let s=0;s<a.length;s+=1){const r=Math.min(1,a[s]/127.5);a[s]=Math.round(r*r*(3-2*r)*255)}return n};let Ue=null,La=0;const bA=()=>{if(!Ue){const e=Kf(),t=jf(),n=new Uint8Array(e.data.length*2);for(let a=0;a<e.data.length;a+=1)n[a*2]=e.data[a],n[a*2+1]=255-t.data[a];Ue=new d.DataTexture(n,e.width,e.height,d.RGFormat,d.UnsignedByteType),Ue.flipY=!1,Ue.unpackAlignment=1,Ue.magFilter=d.LinearFilter,Ue.minFilter=d.LinearFilter,Ue.needsUpdate=!0,Ue.name="FacelessMask"}return La+=1,Ue},IA=()=>{La-=1,La<=0&&Ue&&(Ue.dispose(),Ue=null,La=0)};class Vf{constructor(){C(this,"face");C(this,"target",null);C(this,"scene",new d.Scene);C(this,"camera",new d.OrthographicCamera(-1,1,1,-1,0,1));C(this,"material");C(this,"mask");C(this,"lastVersion",-1);C(this,"lastLook","");C(this,"disposed",!1);this.mask=bA(),this.material=new d.ShaderMaterial({name:"Faceless",glslVersion:d.GLSL3,vertexShader:kA,fragmentShader:zf,uniforms:{uMap:{value:null},uLow:{value:null},uMask:{value:this.mask},uSmooth:{value:0},uGrain:{value:at.grain},uMapSize:{value:new d.Vector2(1,1)},uTaps:{value:Array.from({length:8},()=>new d.Vector2)}},depthTest:!1,depthWrite:!1,blending:d.NoBlending,toneMapped:!1});const t=TA();this.material.uniforms.uTaps.value.forEach((s,r)=>s.set(t[r*2],t[r*2+1]));const n=new d.Mesh(new d.PlaneGeometry(2,2),this.material);n.frustumCulled=!1,this.scene.add(n);const a={kind:"live",map:null,low:new d.Texture,mean:new d.Texture,mirrored:!1,landmarks:null,faceIndex:null,version:0,ready:!1};this.face=a}update(t,n,{style:a=at.style,grain:s=at.grain}={}){var m;const r=this.face;if(this.disposed||!(n!=null&&n.ready)||!n.map)return r.ready=!1,null;const o=`${a}:${s}`;if(n.version===this.lastVersion&&o===this.lastLook&&r.ready)return r;const i=n.map.image,c=Math.max(1,(i==null?void 0:i.width)??512),u=Math.max(1,(i==null?void 0:i.height)??512);(!this.target||this.target.width!==c||this.target.height!==u)&&((m=this.target)==null||m.dispose(),this.target=new d.WebGLRenderTarget(c,u,{colorSpace:d.SRGBColorSpace,depthBuffer:!1,stencilBuffer:!1,generateMipmaps:!0,minFilter:d.LinearMipmapLinearFilter,magFilter:d.LinearFilter}),this.target.texture.name="FacelessMap");const{uniforms:l}=this.material;l.uMap.value=n.map,l.uLow.value=n.low,l.uSmooth.value=a==="smooth"?1:0,l.uGrain.value=Math.min(1,Math.max(0,Number.isFinite(s)?s:0)),l.uMapSize.value.set(c,u);const h=t.getRenderTarget(),f=t.xr.enabled,p=t.autoClear;try{t.xr.enabled=!1,t.autoClear=!1,t.setRenderTarget(this.target),t.render(this.scene,this.camera)}finally{t.setRenderTarget(h),t.xr.enabled=f,t.autoClear=p}return l.uMap.value=null,l.uLow.value=null,r.map=this.target.texture,r.low=n.low,r.mean=n.mean,r.mirrored=n.mirrored,r.faceIndex=n.faceIndex,r.version+=1,r.ready=!0,this.lastVersion=n.version,this.lastLook=o,r}dispose(){var t;this.disposed||(this.disposed=!0,this.face.ready=!1,(t=this.target)==null||t.dispose(),this.target=null,this.material.dispose(),this.scene.children[0].geometry.dispose(),IA())}}const bn={required:2,frames:5,fadeMs:200,holdMs:250,staleMs:1e3},Wf=()=>({streak:0,lastSeenMs:null,lostSinceMs:null,on:!1,fade:0,lastStepMs:null}),NA=Object.freeze({}),Kr=(e,t,n=NA)=>{const a=n.required??bn.required,s=n.frames??bn.frames,r=n.fadeMs??bn.fadeMs,o=n.holdMs??bn.holdMs,i=n.staleMs??bn.staleMs,c=t.ready??!0;t.inference&&(t.faces>=a?(e.streak+=1,e.lastSeenMs=t.nowMs,e.lostSinceMs=null):(e.streak=0,e.lostSinceMs===null&&(e.lostSinceMs=t.nowMs)));const u=e.lastStepMs===null?0:Math.max(0,t.nowMs-e.lastStepMs);e.lastStepMs=t.nowMs;const l=r>0?u/r:1;e.fade=e.on?Math.min(1,e.fade+l):Math.max(0,e.fade-l);const h=e.lastSeenMs!==null&&(e.lostSinceMs===null?t.nowMs-e.lastSeenMs<=i:t.nowMs-e.lostSinceMs<=o);return c?e.on?e.on=h:e.on=e.streak>=s&&h:e.on=!1,r<=0&&(e.fade=e.on?1:0),e},sr=e=>(e.streak=0,e.lastSeenMs=null,e.lostSinceMs=null,e.on=!1,e.fade=0,e.lastStepMs=null,e),OA=.05;let Ct=new Float64Array(4);const PA=(e,t=null,n=[],a=OA)=>{const s=e.length;Ct.length<s&&(Ct=new Float64Array(s));for(let r=0;r<s;r+=1){const o=Number.isFinite(e[r])?Math.max(0,e[r]):0,i=t&&r<t.length?t[r]:0;Ct[r]=o*(1+a)**Math.max(0,i)}n.length=s;for(let r=0;r<s;r+=1){let o=0;for(let i=0;i<s;i+=1)(Ct[i]<Ct[r]||Ct[i]===Ct[r]&&i<r)&&(o+=1);n[r]=o}return n},qf=(e,t={})=>{const n=t.enabled!==!1,a=J.useThree(g=>g.gl),s=Te.useTrackerContext(),r=ge(),o=ee.useOptionalXRContext(),i=ae.useXRModelNode(ee.XRModel.FACE_TRACKER),c=ae.useXRCameraTexture(),u=ae.useXRMirrored(),l=Rg()!==null;dn(n&&t.startModel!==!1&&(s==null?void 0:s.type)!=="face"&&!r,de.resolveNumFaces(e,t.numFaces)),Cu(i,e,"FaceTextureLayer / useLiveFaceTexture",n);const h=_.useMemo(()=>({}),[]),f=_.useRef({map:!1,mirrorFill:!1,quality:"auto"});f.current.map=!!t.map,f.current.mirrorFill=!!t.mirrorFill,f.current.quality=t.quality??"auto",f.current.smoothing=t.smoothing,f.current.madeUp=l;const[p,m]=_.useState(null);_.useEffect(()=>{if(!n)return;const g=NE(a,e);return g.request(h,f.current),m(g),()=>{g.unrequest(h),OE(a,g),m(A=>A===g?null:A)}},[a,e,n,h]);const E=_.useRef({stamp:0,nowMs:0,node:null,cameraTexture:null,feedMirrored:!1,madeUpTexture:null,tierIndex:-1,tierCount:0}),S=_.useRef({node:i,cameraTexture:c,feedMirrored:u,xr:o});return S.current.node=i,S.current.cameraTexture=c,S.current.feedMirrored=u,S.current.xr=o,J.useFrame(g=>{var y,x,F,w;if(!p)return;const A=E.current,v=S.current,M=(y=v.xr)==null?void 0:y.session.store.getSnapshot();A.stamp=g.clock.elapsedTime,A.nowMs=performance.now(),A.node=v.node,A.cameraTexture=v.cameraTexture??null,A.feedMirrored=v.feedMirrored,A.madeUpTexture=((x=T.peekMadeUpCamera(g.gl))==null?void 0:x.texture)??null,A.tierIndex=((F=M==null?void 0:M.quality)==null?void 0:F.index)??-1,A.tierCount=((w=M==null?void 0:M.qualityConfig)==null?void 0:w.tiers.length)??0,p.step(A)},LE),p},UA=Object.freeze({required:1,frames:1}),DA=-.5,GA=(e,t)=>(e==null?void 0:e.kind)==="live"&&e.faceIndex!==null&&e.faceIndex!==t?e.faceIndex:null,$A=(e,t,n)=>e==="upsideDown"||e!=="asIs"&&(t==null?void 0:t.kind)==="live"&&t.faceIndex===n,fn=({face:e,layout:t="asIs",faceIndex:n,targetStats:a,amount:s=1,renderOrder:r=le.FACE_SURFACE_RENDER_ORDER,quality:o="auto",numFaces:i,unseen:c="fade",...u})=>{const l=Te.useTrackerContext(),h=de.resolveFaceIndex(n??((l==null?void 0:l.type)==="face"?l.faceIndex:void 0)??0),f=O.resolveFaceSwapSettings(u,{source:e?{kind:"faceTexture",face:e}:null});$A(t,e,h)&&(u.ownEyes===void 0&&(f.ownEyes=!1),u.ownMouth===void 0&&(f.ownMouth=!1));const p=GA(e,h),[m,E]=_.useState(!1);_.useEffect(()=>E(!0),[]);const S=qf(h,{map:!1,quality:o,smoothing:u.smoothing,numFaces:i??(p===null?void 0:p+1),startModel:m}),g=ae.useXRMirrored(),A=_.useMemo(()=>new cf,[]);_.useEffect(()=>()=>A.dispose(),[A]),A.mesh.renderOrder=r;const v=_.useMemo(Wf,[]),M=_.useRef({nowMs:0,inference:!1,faces:0,ready:!1}),y=_.useRef({face:e,layout:t,targetStats:a,amount:s,settings:f,feedMirrored:g,target:S,sourceIndex:p,unseen:c});return y.current.face=e,y.current.layout=t,y.current.targetStats=a,y.current.amount=s,y.current.settings=f,y.current.feedMirrored=g,y.current.target=S,y.current.sourceIndex=p,y.current.unseen=c,J.useFrame(x=>{const F=y.current,w=F.target;w!=null&&w.quality&&A.setLevel(w.quality.meshLevel),A.setTargetMap(w!=null&&w.positionsReady?w.liveMap:null),A.setSource(F.face);let k=null;F.targetStats!==void 0?k=F.targetStats:w!=null&&w.statsReady&&(k=w.face),A.setTargetStats(k),A.setLayout(F.layout,F.feedMirrored),A.setUnseen(F.unseen),A.setSettings(F.settings);const R=F.sourceIndex===null?null:Af(x.gl,F.sourceIndex),b=!!(w!=null&&w.track.tracked)&&(F.sourceIndex===null||!!(R!=null&&R.track.tracked)),N=M.current;N.nowMs=performance.now(),N.inference=!!w&&w.resultStamp===x.clock.elapsedTime,N.faces=b?1:0,N.ready=A.ready,Kr(v,N,UA),A.setAmount(Mt(F.amount)*v.fade)},DA),L.jsx("group",{children:L.jsx("primitive",{object:A.mesh,dispose:null})})},jn=(e,t={})=>{var n;return((n=qf(e,{...t,map:t.map!==!1}))==null?void 0:n.face)??null},Xf=-.6,Yf=4,Qf=(e,{style:t=at.style,grain:n=at.grain,numFaces:a,smoothing:s,quality:r,enabled:o=!0}={})=>{const i=jn(e,{mirrorFill:!0,numFaces:a,smoothing:s,quality:r,enabled:o}),[c,u]=_.useState(null);return _.useEffect(()=>{if(!o)return;const l=new Vf;return u(l),()=>{l.dispose(),u(h=>h===l?null:h)}},[o]),J.useFrame(l=>{c==null||c.update(l.gl,i,{style:t,grain:n})},Xf),(c==null?void 0:c.face)??null},BA=({faceIndex:e,amount:t,renderOrder:n,...a})=>{const s=Qf(e,a);return L.jsx(fn,{face:s,faceIndex:e,numFaces:a.numFaces,preset:"raw",ownEyes:!1,ownMouth:!1,unseen:"cover",amount:t,smoothing:a.smoothing,quality:a.quality,renderOrder:n})},HA=({style:e=at.style,grain:t=at.grain,amount:n,faceIndex:a,numFaces:s,smoothing:r,quality:o,renderOrder:i,active:c=!0})=>{const u=Te.useTrackerContext(),l=ae.useXRModelNode(ee.XRModel.FACE_TRACKER),h=(u==null?void 0:u.type)==="face"?u.faceIndex:void 0,f=l==null?void 0:l.numFaces,{numFaces:p,targets:m}=_.useMemo(()=>ts({faceIndex:a??h,numFaces:s,modelFaces:f}),[a,h,s,f]);return c?L.jsx("group",{children:m.slice(0,Yf).map(E=>L.jsx(BA,{faceIndex:E,numFaces:p,style:e,grain:t,smoothing:r,quality:o,amount:n,renderOrder:i},E))}):null},tl=new d.Vector3(0,.4,-1),zA=e=>{const t=pe(),n=Array.from(t.positions),a=Array.from(t.uvs),s=Array.from(t.feather);let r=Array.from(t.index);for(let o=0;o<e;o+=1){const i=new Map,c=(l,h)=>{const f=l<h?l*1e6+h:h*1e6+l;let p=i.get(f);if(p===void 0){p=n.length/3;for(let m=0;m<3;m+=1)n.push((n[l*3+m]+n[h*3+m])/2);for(let m=0;m<2;m+=1)a.push((a[l*2+m]+a[h*2+m])/2);s.push((s[l]+s[h])/2),i.set(f,p)}return p},u=[];for(let l=0;l<r.length;l+=3){const[h,f,p]=[r[l],r[l+1],r[l+2]],m=c(h,f),E=c(f,p),S=c(p,h);u.push(h,m,S,m,f,E,S,E,p,m,E,S)}r=u}return{positions:Float32Array.from(n),uvs:Float32Array.from(a),feather:Float32Array.from(s),index:r}},Qo=e=>Bt(`subdivide:${e}`,()=>zA(e)),Jf=(e,{subdivisions:t=2,size:n=1}={})=>{const a=Bt(`morphShape:${e}:${t}:${n}`,()=>KA(e,t,n)),s=new d.BufferGeometry;return s.setAttribute("position",new d.BufferAttribute(a.shape,3)),s.setAttribute("normal",new d.BufferAttribute(a.normal,3)),s.setAttribute("uv",new d.BufferAttribute(a.uvs,2)),s.setAttribute("color",new d.BufferAttribute(a.color,4)),s.setIndex(new d.BufferAttribute(a.index,1)),{geometry:s,base:a.base}},KA=(e,t,n)=>{const{positions:a,uvs:s,feather:r,index:o}=Qo(t),i=Float32Array.from(a),c=new Float32Array(i.length),u=new d.Vector3,l=(e==="cube"?7.4:8.6)*n;for(let m=0;m<i.length/3;m+=1)u.fromArray(i,m*3).sub(tl).normalize(),e==="cube"&&u.divideScalar(Math.max(Math.abs(u.x),Math.abs(u.y),Math.abs(u.z))),u.multiplyScalar(l).add(tl).toArray(c,m*3);const h=new d.BufferGeometry;h.setAttribute("position",new d.BufferAttribute(c,3));const f=Uint32Array.from(o);h.setIndex(new d.BufferAttribute(f,1)),h.computeVertexNormals();const p=new Float32Array(r.length*4).fill(1);return r.forEach((m,E)=>{p[E*4+3]=m}),{base:i,shape:c,uvs:s,color:p,index:f,normal:h.getAttribute("normal").array}},nl=()=>pe().count,Jo=(e,t,n,a)=>{const s=K.CANONICAL_FACE_LANDMARK_COUNT;for(let r=0;r<s*3;r+=1)n[r]=e[r],a[r]=t[r];for(const{ring:r,centre:o}of Object.values(pe().openings))for(let i=0;i<3;i+=1){let c=0,u=0;for(const l of r)c+=n[l*3+i],u+=a[l*3+i];n[o*3+i]=c/r.length,a[o*3+i]=u/r.length}},Zo=()=>({point:new Float32Array(nl()*3),expression:new Float32Array(nl()*3)}),Zf=(e,t,n,{weight:a,expression:s,scale:r},o)=>{const i=pe().index,c=Math.min(1,Math.max(0,a)),u=t.length/3;for(let l=0;l<u;l+=1){const h=e.triangle[l],f=t[l*3]*r,p=t[l*3+1]*r,m=t[l*3+2]*r;if(h<0){o[l*3]=f,o[l*3+1]=p,o[l*3+2]=m;continue}const E=e.coverage[l];let S=0,g=0,A=0,v=0,M=0,y=0;for(let b=0;b<3;b+=1){const N=e.weights[l*3+b],P=i[h*3+b]*3;S+=N*n.point[P],g+=N*n.point[P+1],A+=N*n.point[P+2],v+=N*n.expression[P],M+=N*n.expression[P+1],y+=N*n.expression[P+2]}const x=s*E,F=f+v*x,w=p+M*x,k=m+y*x,R=(1-c)*E;o[l*3]=F+(S-F)*R,o[l*3+1]=w+(g-w)*R,o[l*3+2]=k+(A-k)*R}},rr=[1.4,3],jA=[.45,0],VA=[1,0],al=new d.Vector3(0,.8,0),WA=e=>{const t=(o,i)=>o<i?`${o},${i}`:`${i},${o}`,n=new Map;for(let o=0;o<e.length;o+=3)for(let i=0;i<3;i+=1){const c=t(e[o+i],e[o+(i+1)%3]);n.set(c,(n.get(c)??0)+1)}const a=new Map;for(let o=0;o<e.length;o+=3)for(let i=0;i<3;i+=1){const c=e[o+i],u=e[o+(i+1)%3];n.get(t(c,u))===1&&a.set(c,u)}let s=[];const r=new Set;for(const o of a.keys()){if(r.has(o))continue;const i=[];let c=o;for(;c!==void 0&&!r.has(c);)r.add(c),i.push(c),c=a.get(c);i.length>s.length&&(s=i)}return s},ep=(e=2)=>Bt(`warpMesh:${e}`,()=>qA(e)),qA=e=>{const t=Qo(e),n=t.positions.length/3,a=Ut(t.positions),s=WA(t.index),r=n+s.length*rr.length,o=new Float32Array(r*3);o.set(t.positions);const i=new Int32Array(r).fill(-1),c=new Float32Array(r*3),u=new Float32Array(r).fill(1),l=new Float32Array(r).fill(1),h=t.index.slice(),f=new d.Vector3,p=new d.Vector3,m=(S,g)=>n+S*s.length+g;s.forEach((S,g)=>{f.fromArray(t.positions,S*3),p.set(f.x-al.x,f.y-al.y,0).normalize(),p.z=-.35,p.normalize(),rr.forEach((A,v)=>{const M=m(v,g);i[M]=S,u[M]=jA[v],l[M]=VA[v],p.clone().multiplyScalar(A).toArray(c,M*3),f.clone().addScaledVector(p,A).toArray(o,M*3)})});const E=[s,...rr.map((S,g)=>s.map((A,v)=>m(g,v)))];for(let S=0;S+1<E.length;S+=1)for(let g=0;g<s.length;g+=1){const A=(g+1)%s.length,[v,M,y,x]=[E[S][g],E[S][A],E[S+1][g],E[S+1][A]];h.push(M,v,y,M,y,x)}return{count:r,faceCount:n,index:h,canonical:o,triangle:Int32Array.from({length:r},(S,g)=>g<n?a.triangle[g]:-1),weights:a.weights,anchor:i,offset:c,follow:u,alpha:l}},XA=e=>{e.updateMatrixWorld(!0);const t=e.matrixWorld.clone().invert(),n=[],a=new d.Vector3,s=new d.Vector3;return e.traverse(r=>{if(!(r instanceof d.Mesh))return;const o=r.geometry,i=o.getAttribute("position"),c=new d.Matrix4().multiplyMatrices(t,r.matrixWorld),u=new d.Matrix3().setFromMatrix4(c),l=new Float32Array(i.count*3);for(let m=0;m<i.count;m+=1)a.fromBufferAttribute(i,m).applyMatrix4(c).toArray(l,m*3);const h=new Map,f=o.morphAttributes.position??[];for(const[m,E]of Object.entries(r.morphTargetDictionary??{})){const S=f[E];if(!S)continue;const g=new Float32Array(i.count*3);for(let A=0;A<i.count;A+=1)s.fromBufferAttribute(S,A),o.morphTargetsRelative||s.sub(a.fromBufferAttribute(i,A)),s.applyMatrix3(u).toArray(g,A*3);h.set(m,g)}const p=o.index?o.index.array:Uint32Array.from({length:i.count},(m,E)=>E);n.push({base:l,index:p,keys:h})}),n},YA=e=>{const t=K.CANONICAL_FACE_LANDMARK_COUNT;if(e.length<t*3)return!1;for(let n=0;n<t*3;n+=1)if(Math.abs(e[n]-V.CANONICAL_FACE_POSITIONS[n])>.05)return!1;return!0},QA=4,JA=new d.Vector3(0,.5,-4),ZA=e=>{const t=new d.BufferGeometry;t.setAttribute("position",new d.BufferAttribute(e.canonical,3)),t.setIndex(e.index),t.computeVertexNormals();const n=Float32Array.from(t.getAttribute("normal").array),a=new d.Vector3,s=new d.Vector3;for(let r=0;r<e.count;r+=1)a.fromArray(e.canonical,r*3).sub(JA),s.fromArray(n,r*3).dot(a)<0&&s.negate().toArray(n,r*3);return n},ev=(e,t)=>{const n=Math.floor(t.length/3),a=new Float32Array(n*3),s=new Float32Array(n);for(let r=0;r<n;r+=1){const[o,i,c]=[t[r*3]*3,t[r*3+1]*3,t[r*3+2]*3];for(let l=0;l<3;l+=1)a[r*3+l]=(e[o+l]+e[i+l]+e[c+l])/3;let u=0;for(const l of[o,i,c])u=Math.max(u,Math.hypot(e[l]-a[r*3],e[l+1]-a[r*3+1],e[l+2]-a[r*3+2]));s[r]=u}return(r,o,i,c,u,l)=>{const h=c[u*3],f=c[u*3+1],p=c[u*3+2];let m=null;for(let E=0;E<n;E+=1){const S=a[E*3]-r,g=a[E*3+1]-o,A=a[E*3+2]-i,v=S*h+g*f+A*p;if(Math.abs(v)>l+s[E]||S*S+g*g+A*A-v*v>s[E]*s[E])continue;const[y,x,F]=[t[E*3]*3,t[E*3+1]*3,t[E*3+2]*3],w=e[x]-e[y],k=e[x+1]-e[y+1],R=e[x+2]-e[y+2],b=e[F]-e[y],N=e[F+1]-e[y+1],P=e[F+2]-e[y+2],G=f*P-p*N,U=p*b-h*P,H=h*N-f*b,z=w*G+k*U+R*H;if(Math.abs(z)<1e-12)continue;const X=1/z,j=r-e[y],D=o-e[y+1],$=i-e[y+2],q=(j*G+D*U+$*H)*X;if(q<0||q>1)continue;const Q=D*R-$*k,se=$*w-j*R,Z=j*k-D*w,B=(h*Q+f*se+p*Z)*X;if(B<0||q+B>1)continue;const Y=(b*Q+N*se+P*Z)*X;Math.abs(Y)<=l&&(m===null||Math.abs(Y)<Math.abs(m))&&(m=Y)}return m}},tp=(e,t)=>vt(e,`${t.count}:${t.faceCount}`,()=>tv(e,t)),tv=(e,t)=>{const n=XA(e),a=[...new Set(n.flatMap(g=>[...g.keys.keys()]))],s=a.length===0;s&&a.push("shape");const r=a.map(()=>new Float32Array(t.count*3)),o=n.find(g=>g.keys.size>0&&YA(g.base));if(o){const g=pe();return a.forEach((A,v)=>{const M=o.keys.get(A);if(!M)return;const y=new Float32Array(g.count*3);y.set(M.subarray(0,K.CANONICAL_FACE_LANDMARK_COUNT*3));for(const{ring:F,centre:w}of Object.values(g.openings))for(let k=0;k<3;k+=1)y[w*3+k]=[...F].reduce((R,b)=>R+y[b*3+k],0)/F.length;const x=g.index;for(let F=0;F<t.faceCount;F+=1){const w=t.triangle[F];if(!(w<0))for(let k=0;k<3;k+=1){const R=t.weights[F*3+k],b=x[w*3+k]*3;for(let N=0;N<3;N+=1)r[v][F*3+N]+=R*y[b+N]}}}),{names:a,deltas:r}}const i=n.reduce((g,A)=>g+A.base.length/3,0),c=new Float32Array(i*3),u=a.map(()=>new Float32Array(i*3)),l=[];let h=0;for(const g of n){c.set(g.base,h*3),a.forEach((A,v)=>{const M=g.keys.get(A);M&&u[v].set(M,h*3)});for(let A=0;A<g.index.length;A+=1)l.push(g.index[A]+h);h+=g.base.length/3}const f=Qa(c,l),p=s?ev(c,l):null,m=s?ZA(t):null,E={triangle:-1,u:0,v:0,w:0,d2:0},S=t.canonical;for(let g=0;g<t.faceCount;g+=1){if(p&&m){const M=p(S[g*3],S[g*3+1],S[g*3+2],m,g,QA);if(M!==null){for(let y=0;y<3;y+=1)r[0][g*3+y]=M*m[g*3+y];continue}}if(f(S[g*3],S[g*3+1],S[g*3+2],E),E.triangle<0)continue;const A=[l[E.triangle*3],l[E.triangle*3+1],l[E.triangle*3+2]],v=[E.u,E.v,E.w];for(let M=0;M<3;M+=1){let y=0;for(let x=0;x<3;x+=1)y+=v[x]*c[A[x]*3+M];if(s){r[0][g*3+M]=y-S[g*3+M];continue}a.forEach((x,F)=>{let w=0;for(let k=0;k<3;k+=1)w+=v[k]*u[F][A[k]*3+M];r[F][g*3+M]=w})}}return{names:a,deltas:r}},nv=(e,t,n,a,{weight:s,expression:r},o,i)=>{const c=pe().index,u=r-1;for(let l=0;l<e.faceCount;l+=1){const h=e.triangle[l];for(let f=0;f<3;f+=1){let p=0,m=0;for(let g=0;g<3;g+=1){const A=e.weights[l*3+g],v=c[h*3+g]*3+f;p+=A*t.point[v],m+=A*t.expression[v]}const E=p+u*m;o[l*3+f]=E;let S=0;if(n)for(let g=0;g<n.deltas.length;g+=1)S+=a[g]*n.deltas[g][l*3+f];i[l*3+f]=E+S*s}}for(let l=e.faceCount;l<e.count;l+=1){const h=e.anchor[l];for(let f=0;f<3;f+=1){const p=o[h*3+f]+e.offset[l*3+f];o[l*3+f]=p,i[l*3+f]=p+(i[h*3+f]-o[h*3+f])*e.follow[l]}}},Ot=16,Aa=1024,np=(e,t)=>{const n=pe().index,a=e.count,s=new Float32Array(a*3),r=new Float32Array(a*3),o=new Float32Array(a),i=new Float32Array(a*3);for(let h=0;h<a;h+=1){const f=h<e.faceCount?h:e.anchor[h],p=e.triangle[f];for(let m=0;m<3;m+=1)s[h*3+m]=n[p*3+m],r[h*3+m]=e.weights[f*3+m],i[h*3+m]=e.offset[h*3+m];o[h]=f}const c=Math.min((t==null?void 0:t.deltas.length)??0,Ot),u=Math.ceil(e.faceCount/Aa),l=new Float32Array(Aa*u*Math.max(c,1)*4);for(let h=0;h<c;h+=1){const f=t.deltas[h],p=h*Aa*u;for(let m=0;m<e.faceCount;m+=1)l.set(f.subarray(m*3,m*3+3),(p+m)*4)}return{corners:s,bary:r,deltaIndex:o,skirtOffset:i,follow:e.follow,alpha:e.alpha,keyCount:c,deltaWidth:Aa,rowsPerKey:u,deltas:l}},ap=(e,t)=>{const n=e.point.length/3;for(let a=0;a<n;a+=1)for(let s=0;s<3;s+=1)t[a*4+s]=e.point[a*3+s],t[(n+a)*4+s]=e.expression[a*3+s]},av=`
|
|
2248
|
+
uniform sampler2D liveMap;
|
|
2249
|
+
uniform float liveWidth;
|
|
2250
|
+
uniform sampler2D deltaMap;
|
|
2251
|
+
uniform vec3 deltaGrid; // width, rows per key, total rows
|
|
2252
|
+
uniform float keyWeights[${Ot}];
|
|
2253
|
+
uniform float keyCount;
|
|
2254
|
+
uniform float weight;
|
|
2255
|
+
uniform float expressionGain;
|
|
2256
|
+
attribute vec3 corners;
|
|
2257
|
+
attribute vec3 bary;
|
|
2258
|
+
attribute float deltaIndex;
|
|
2259
|
+
attribute vec3 skirtOffset;
|
|
2260
|
+
attribute float follow;
|
|
2261
|
+
attribute float feather;
|
|
2262
|
+
varying vec3 vCamera;
|
|
2263
|
+
varying float vFeather;
|
|
2264
|
+
|
|
2265
|
+
vec3 liveAt(float i, float row) {
|
|
2266
|
+
return texture2D(liveMap, vec2((i + 0.5) / liveWidth, (row + 0.5) * 0.5)).xyz;
|
|
2267
|
+
}
|
|
2268
|
+
vec3 restAt(float i) {
|
|
2269
|
+
return liveAt(i, 0.0) + expressionGain * liveAt(i, 1.0);
|
|
2270
|
+
}
|
|
2271
|
+
vec3 deltaAt(float k) {
|
|
2272
|
+
float x = mod(deltaIndex, deltaGrid.x);
|
|
2273
|
+
float y = floor(deltaIndex / deltaGrid.x) + k * deltaGrid.y;
|
|
2274
|
+
return texture2D(deltaMap, vec2((x + 0.5) / deltaGrid.x, (y + 0.5) / deltaGrid.z)).xyz;
|
|
2275
|
+
}
|
|
2276
|
+
|
|
2277
|
+
void main() {
|
|
2278
|
+
vec3 rest = bary.x * restAt(corners.x) + bary.y * restAt(corners.y) + bary.z * restAt(corners.z)
|
|
2279
|
+
+ skirtOffset;
|
|
2280
|
+
vec3 d = vec3(0.0);
|
|
2281
|
+
for (int k = 0; k < ${Ot}; k++) {
|
|
2282
|
+
if (float(k) >= keyCount) break;
|
|
2283
|
+
d += keyWeights[k] * deltaAt(float(k));
|
|
2284
|
+
}
|
|
2285
|
+
vec3 deformed = rest + d * weight * follow;
|
|
2286
|
+
// Where the undeformed point sits on screen = where it is in the camera image.
|
|
2287
|
+
vec4 c = projectionMatrix * modelViewMatrix * vec4(rest, 1.0);
|
|
2288
|
+
vCamera = c.xyw;
|
|
2289
|
+
vFeather = feather;
|
|
2290
|
+
gl_Position = projectionMatrix * modelViewMatrix * vec4(deformed, 1.0);
|
|
2291
|
+
}
|
|
2292
|
+
`,sv=`
|
|
2293
|
+
uniform sampler2D cameraMap;
|
|
2294
|
+
uniform float opacity;
|
|
2295
|
+
varying vec3 vCamera;
|
|
2296
|
+
varying float vFeather;
|
|
2297
|
+
void main() {
|
|
2298
|
+
vec2 uv = vCamera.xy / vCamera.z * 0.5 + 0.5;
|
|
2299
|
+
gl_FragColor = vec4(texture2D(cameraMap, uv).rgb, opacity * vFeather);
|
|
2300
|
+
#include <colorspace_fragment>
|
|
2301
|
+
}
|
|
2302
|
+
`,sl=(e,t,n)=>{const a=new d.DataTexture(e,t,n,d.RGBAFormat,d.FloatType);return a.minFilter=d.NearestFilter,a.magFilter=d.NearestFilter,a.needsUpdate=!0,a},rl=({deformation:e=null,weights:t,weight:n=1,expression:a=1,subdivisions:s=2,opacity:r=1,onKeys:o,children:i})=>{const c=ge(),u=ae.useXRCameraTexture(),l=_.useMemo(()=>ep(s),[s]),h=_.useMemo(()=>e?tp(e,l):null,[e,l]),f=_.useRef(o);f.current=o,_.useEffect(()=>{var w;(w=f.current)==null||w.call(f,(h==null?void 0:h.names)??[])},[h]);const p=_.useMemo(()=>np(l,h),[l,h]),m=_.useMemo(()=>{const w=new d.BufferGeometry;return w.setAttribute("position",new d.BufferAttribute(l.canonical,3)),w.setAttribute("corners",new d.BufferAttribute(p.corners,3)),w.setAttribute("bary",new d.BufferAttribute(p.bary,3)),w.setAttribute("deltaIndex",new d.BufferAttribute(p.deltaIndex,1)),w.setAttribute("skirtOffset",new d.BufferAttribute(p.skirtOffset,3)),w.setAttribute("follow",new d.BufferAttribute(p.follow,1)),w.setAttribute("feather",new d.BufferAttribute(p.alpha,1)),w.setIndex(l.index),w},[l,p]);_.useEffect(()=>()=>m.dispose(),[m]);const E=_.useMemo(()=>sl(p.deltas,p.deltaWidth,p.rowsPerKey*Math.max(p.keyCount,1)),[p]);_.useEffect(()=>()=>E.dispose(),[E]);const S=_.useMemo(Zo,[]),g=S.point.length/3,A=_.useMemo(()=>sl(new Float32Array(g*2*4),g,2),[g]);_.useEffect(()=>()=>A.dispose(),[A]);const v=_.useMemo(()=>new d.ShaderMaterial({uniforms:{cameraMap:{value:null},opacity:{value:1},liveMap:{value:null},liveWidth:{value:1},deltaMap:{value:null},deltaGrid:{value:new d.Vector3(1,1,1)},keyWeights:{value:new Float32Array(Ot)},keyCount:{value:0},weight:{value:1},expressionGain:{value:0}},vertexShader:av,fragmentShader:sv,...le.faceSurfaceBlending,depthWrite:!1,toneMapped:!1}),[]);_.useEffect(()=>()=>Ce(),[v]);const M=v.uniforms;M.cameraMap.value=u??null,M.opacity.value=r,M.liveMap.value=A,M.liveWidth.value=g,M.deltaMap.value=E,M.deltaGrid.value.set(p.deltaWidth,p.rowsPerKey,p.rowsPerKey*Math.max(p.keyCount,1)),M.keyCount.value=p.keyCount;const y=_.useRef({weights:t,weight:n,expression:a});y.current={weights:t,weight:n,expression:a};const x=_.useRef(null),F=_.useRef(le.createFaceSurfaceState());return J.useFrame(()=>{const w=c==null?void 0:c.current,k=x.current;if(!k||(k.visible=!!u&&!!w&&w.tracking!=="lost",!k.visible||!w))return;Jo(w.view,w.residual,S.point,S.expression),ap(S,A.image.data),A.needsUpdate=!0;const R=y.current,b=M.keyWeights.value,N=R.weights===void 0?void 0:Wo(R.weights);h==null||h.names.slice(0,Ot).forEach((G,U)=>{b[U]=(N==null?void 0:N[G])??1}),M.weight.value=Mt(R.weight),M.expressionGain.value=Mt(R.expression)-1;const P=F.current;if(P.offsets.fill(0),P.active=!!h&&M.weight.value!==0,P.active&&h)for(let G=0;G<Math.min(h.deltas.length,Ot);G+=1){const U=b[G]*M.weight.value;if(U===0)continue;const H=h.deltas[G];for(let z=0;z<P.offsets.length;z+=1)P.offsets[z]+=U*H[z]}},le.FACE_SURFACE_FRAME_PRIORITY),L.jsxs(le.FaceSurfaceContext.Provider,{value:F,children:[L.jsx("mesh",{ref:x,geometry:m,material:v,renderOrder:le.FACE_SURFACE_RENDER_ORDER,frustumCulled:!1}),i]})},rv=({faceIndex:e,smoothing:t,expressionSmoothing:n,holdMs:a,neutral:s,neutralMs:r,leadMs:o,neutralKey:i,onTrackingChange:c,...u})=>ge()?L.jsx(rl,{...u}):L.jsx(yt,{faceIndex:e,smoothing:t,expressionSmoothing:n,holdMs:a,neutral:s,neutralMs:r,leadMs:o,neutralKey:i,onTrackingChange:c,children:L.jsx(rl,{...u})}),ov=()=>{const e=new d.BufferGeometry;return e.setAttribute("position",new d.BufferAttribute(V.CANONICAL_FACE_POSITIONS.slice(0,K.CANONICAL_FACE_LANDMARK_COUNT*3),3)),e.setAttribute("uv",new d.BufferAttribute(K.CANONICAL_FACE_UVS.slice(),2)),e.setIndex(Array.from(K.CANONICAL_FACE_TRIANGLES)),e.computeVertexNormals(),e},ei=()=>{const e=pe(),t=e.positions,n=r=>[t[r*3],t[r*3+1],t[r*3+2]],a=V.CANONICAL_FACE_POSITIONS,s=r=>[a[r*3],a[r*3+1],a[r*3+2]];return{leftEye:n(e.openings.leftEye.centre),rightEye:n(e.openings.rightEye.centre),mouth:n(e.openings.mouth.centre),nose:s(1),chin:s(152)}},or=25,jr=[];for(const e of[-25,or])for(const t of[-25,or])for(const n of[-25,or])jr.push([e,t,n]);const iv=(e,t)=>{const n=e.length,a=t[0].length;for(let s=0;s<n;s+=1){let r=s;for(let i=s+1;i<n;i+=1)Math.abs(e[i][s])>Math.abs(e[r][s])&&(r=i);[e[s],e[r]]=[e[r],e[s]],[t[s],t[r]]=[t[r],t[s]];const o=e[s][s]||1e-12;for(let i=0;i<n;i+=1){if(i===s)continue;const c=e[i][s]/o;if(c!==0){for(let u=s;u<n;u+=1)e[i][u]-=c*e[s][u];for(let u=0;u<a;u+=1)t[i][u]-=c*t[s][u]}}}return t.map((s,r)=>s.map(o=>o/(e[r][r]||1e-12)))},sp=(e,t)=>{const n=[...e,...jr],a=[...t,...jr],s=n.length,r=Array.from({length:s+4},()=>new Array(s+4).fill(0)),o=Array.from({length:s+4},()=>[0,0,0]);for(let c=0;c<s;c+=1){for(let l=0;l<s;l+=1)r[c][l]=Math.hypot(n[c][0]-n[l][0],n[c][1]-n[l][1],n[c][2]-n[l][2]);const u=[1,n[c][0],n[c][1],n[c][2]];for(let l=0;l<4;l+=1)r[c][s+l]=u[l],r[s+l][c]=u[l];o[c]=[a[c][0]-n[c][0],a[c][1]-n[c][1],a[c][2]-n[c][2]]}const i=iv(r,o);return(c,u,l,h)=>{let f=i[s][0]+i[s+1][0]*c+i[s+2][0]*u+i[s+3][0]*l,p=i[s][1]+i[s+1][1]*c+i[s+2][1]*u+i[s+3][1]*l,m=i[s][2]+i[s+1][2]*c+i[s+2][2]*u+i[s+3][2]*l;for(let E=0;E<s;E+=1){const S=Math.hypot(c-n[E][0],u-n[E][1],l-n[E][2]);f+=i[E][0]*S,p+=i[E][1]*S,m+=i[E][2]*S}return h[0]=c+f,h[1]=u+p,h[2]=l+m,h}},ns=(e,t)=>vt(e,JSON.stringify(t??null),()=>cv(e,t)),cv=(e,t)=>{const n=Float32Array.from(e);if(!t)return n;const a=ei(),s=Object.keys(t).filter(i=>t[i]);if(s.length===0)return n;const r=sp(s.map(i=>t[i]),s.map(i=>a[i])),o=[0,0,0];for(let i=0;i<n.length;i+=3)r(n[i],n[i+1],n[i+2],o),n[i]=o[0],n[i+1]=o[1],n[i+2]=o[2];return n},lv=4,uv=({children:e,faceIndex:t=0,numFaces:n=lv,scaleWithFace:a=!0,occluder:s=!0,showFaceMesh:r=!1,faceMeshMaterial:o})=>{const i=_.useMemo(()=>new d.MeshBasicMaterial({color:"#22c55e",side:d.BackSide,transparent:!0,opacity:.35,depthWrite:!1}),[]),c=s===!1?null:s===!0?{}:s;return L.jsxs(Te.FaceTracker,{faceIndex:t,numFaces:n,scaleWithFace:a,children:[c&&L.jsx(T.HeadOccluder,{fit:c.fit??"canonical",faceIndex:t,offset:c.offset,position:c.position??T.HEAD_OCCLUDER_DEFAULT_POSITION,rotation:c.rotation,scale:c.scale??T.HEAD_OCCLUDER_DEFAULT_SCALE,url:c.url,showDebugMaterial:c.showDebugMaterial,opacity:c.opacity??T.HEAD_OCCLUDER_DEFAULT_OPACITY,smoothing:c.smoothing,neck:c.neck}),e,r&&L.jsx(Te.FaceMesh,{faceIndex:t,numFaces:n,material:o??i})]})},hv=57,fv=15.5,ir=hv/Math.PI/fv,pv=-.134,dv=-.024,ft=(e,t,n)=>Math.min(n,Math.max(t,e)),rp=(e,t)=>e*t-t/2,op=(e,t)=>-(e*t-t/2),mv=({eyeMidX:e,noseX:t,offsetX:n,rawYaw:a,sideMidX:s})=>{const r=ft((Math.abs(a)-.18)/.42,0,1),o=s*.75+e*.25,i=e*.7+t*.3;return o*(1-r)+i*r+n},gv=({baseScale:e,pitchRadians:t})=>{const n=t*180/Math.PI,s=1+ft((n-6)/22,0,1)*.22;return[e[0]*s,e[1]*s,e[2]*s]},Sv=({yawRadians:e})=>{const t=Math.abs(e*180/Math.PI),a=.066*ft((t-8)/12,0,1);return Math.sign(e)*a},Ev=({pitchRadians:e})=>{const t=e*180/Math.PI;return-.026*ft((-t-6)/18,0,1)},Av=({baseOffset:e,yawRadians:t})=>{const n=Math.abs(t*180/Math.PI),a=ft((n-8)/24,0,1);return e+a*.25},vv=({baseOffsetY:e,baseScaleY:t,face:n})=>{if(!n||n.bounds.width<=0)return{aspectRatio:0,normalizedAspect:0,scaleY:t,offsetY:e};const a=n.bounds.height/n.bounds.width,s=ft((a-1.55)/.35,-1,1);return{aspectRatio:a,normalizedAspect:s,scaleY:t+s*.06,offsetY:e+s*.005}},ip=({face:e,offsetX:t,offsetY:n,scaleX:a,scaleY:s})=>{const r=e.bounds.width*a,o=e.bounds.height*s,i=e.bounds.centerX+t,c=e.bounds.centerY+n;return{x:i-r*.5,y:c-o*.5,width:r,height:o,centerX:i,centerY:c}},Mv=({face:e,height:t,lockDepth:n,lockRotation:a,model:s,offsetX:r,offsetY:o,scaleX:i,scaleY:c,scaleZ:u,width:l})=>{const h=ip({face:e,offsetX:r,offsetY:o,scaleX:i,scaleY:c}),f=e.landmarks[33],p=e.landmarks[263],m=e.landmarks[234],E=e.landmarks[454],S=e.landmarks[1],g=e.landmarks[10],A=e.landmarks[152],v=h.width*l,M=h.height*t,y=f&&p?(f.x+p.x)*.5:e.bounds.centerX,x=f&&p?(f.y+p.y)*.5:e.bounds.centerY-e.bounds.height*.15,F=m&&E?(m.x+E.x)*.5:y,w=(g==null?void 0:g.y)??e.bounds.minY,k=(A==null?void 0:A.y)??e.bounds.maxY,R=(w+k)*.5,b=f&&p?Math.atan2(p.y-f.y,p.x-f.x):0,N=S&&e.bounds.width>0?ft((S.x-e.bounds.centerX)/(e.bounds.width*.5),-1,1)*.75:0,P=mv({eyeMidX:y,noseX:(S==null?void 0:S.x)??y,offsetX:r,rawYaw:N,sideMidX:F}),G=R*.75+x*.25+o,U=s==="v2"?rp(P,l):h.centerX*l-l/2,H=s==="v2"?op(e.bounds.centerY+o*.75,t):-(h.centerY*t-t/2),z=g&&S?Math.max(1e-4,S.y-g.y):e.bounds.height*.42,X=S&&A?Math.max(1e-4,A.y-S.y):e.bounds.height*.58,j=(X-z)/(X+z),D=ft((j-pv)/.28,-1,1)*.58,$=S&&e.bounds.height>0?ft((e.bounds.centerY-S.y)/(e.bounds.height*.5)-dv,-1,1)*.18:0,q=D*.82+$*.18,Q=a?0:s==="v2"?N*.72:N,se=a?0:s==="v2"?-q*.78:-q,Z=a?0:-b,B=n?v*ir:s==="v2"?v*(ir+Math.abs(Q)*.18):v*ir;return{centerXPx:U,centerYPx:H,depthPx:B*u,heightPx:M,pitch:se,rawPitch:q,rawPitchFromBalance:D,rawPitchFromCenter:$,rawYaw:N,rotationZ:Z,roll:b,shape:h,skullAnchorX:P,skullAnchorY:G,verticalBalance:j,widthPx:v,yaw:Q}},cp=({lockDepth:e,lockRotation:t,model:n,face:a,height:s,headDepthOffset:r,offsetX:o,offsetY:i,rotationOffsetX:c,rotationOffsetY:u,rotationOffsetZ:l,scaleX:h,scaleY:f,scaleZ:p,skullCenterMode:m,skullVerticalBias:E,width:S})=>ti({lockDepth:e,lockRotation:t,model:n,face:a,height:s,headDepthOffset:r,offsetX:o,offsetY:i,rotationOffsetX:c,rotationOffsetY:u,rotationOffsetZ:l,scaleX:h,scaleY:f,scaleZ:p,skullCenterMode:m,skullVerticalBias:E,width:S}).pose,ti=({lockDepth:e,lockRotation:t,model:n,face:a,height:s,headDepthOffset:r,offsetX:o,offsetY:i,rotationOffsetX:c,rotationOffsetY:u,rotationOffsetZ:l,scaleX:h,scaleY:f,scaleZ:p,skullCenterMode:m,skullVerticalBias:E,width:S})=>{const g=Mv({face:a,height:s,lockDepth:e,lockRotation:t,model:n,offsetX:o,offsetY:i,scaleX:h,scaleY:f,scaleZ:p,width:S});if(m){const v=new Ae.Vector3(0,g.heightPx*E,-g.depthPx*r).applyEuler(new Ae.Euler(g.pitch,g.yaw,g.rotationZ,"XYZ")),M=rp(g.skullAnchorX,S),y=op(g.skullAnchorY,s);return{pose:{boxCenterZ:v.z,centerX:M+v.x,centerY:y+v.y,width:g.widthPx,height:g.heightPx,depth:g.depthPx,rotationX:g.pitch+c,rotationY:g.yaw+u,rotationZ:g.rotationZ+l},debugMetrics:{face:{centerX:g.shape.centerX,centerY:g.shape.centerY,width:g.shape.width,height:g.shape.height},normalized:{rawPitch:g.rawPitch,rawPitchFromBalance:g.rawPitchFromBalance,rawPitchFromCenter:g.rawPitchFromCenter,rawYaw:g.rawYaw,roll:g.roll,verticalBalance:g.verticalBalance},pose:{pitch:g.pitch,yaw:g.yaw,rotationX:g.pitch+c,rotationY:g.yaw+u,rotationZ:g.rotationZ+l},skullAnchor:{x:g.skullAnchorX,y:g.skullAnchorY},center:{x:M+v.x,y:y+v.y,z:v.z},depthPx:g.depthPx,screen:{widthPx:g.widthPx,heightPx:g.heightPx}}}}return{pose:{boxCenterZ:-g.depthPx*r,centerX:g.centerXPx,centerY:g.centerYPx,width:g.widthPx,height:g.heightPx,depth:g.depthPx,rotationX:g.pitch+c,rotationY:g.yaw+u,rotationZ:g.rotationZ+l},debugMetrics:{face:{centerX:g.shape.centerX,centerY:g.shape.centerY,width:g.shape.width,height:g.shape.height},normalized:{rawPitch:g.rawPitch,rawPitchFromBalance:g.rawPitchFromBalance,rawPitchFromCenter:g.rawPitchFromCenter,rawYaw:g.rawYaw,roll:g.roll,verticalBalance:g.verticalBalance},pose:{pitch:g.pitch,yaw:g.yaw,rotationX:g.pitch+c,rotationY:g.yaw+u,rotationZ:g.rotationZ+l},skullAnchor:{x:g.skullAnchorX,y:g.skullAnchorY},center:{x:g.centerXPx,y:g.centerYPx,z:-g.depthPx*r},depthPx:g.depthPx,screen:{widthPx:g.widthPx,heightPx:g.heightPx}}}},yv=({lockDepth:e,lockRotation:t,model:n,face:a,height:s,headDepthOffset:r,offsetX:o,offsetY:i,rotationOffsetX:c,rotationOffsetY:u,rotationOffsetZ:l,scaleX:h,scaleY:f,scaleZ:p,skullCenterMode:m,skullVerticalBias:E,width:S})=>ti({lockDepth:e,lockRotation:t,model:n,face:a,height:s,headDepthOffset:r,offsetX:o,offsetY:i,rotationOffsetX:c,rotationOffsetY:u,rotationOffsetZ:l,scaleX:h,scaleY:f,scaleZ:p,skullCenterMode:m,skullVerticalBias:E,width:S}).debugMetrics,wv=({boxColor:e,boxOpacity:t,face:n,headDepthOffset:a,lockDepth:s,lockRotation:r,model:o,occluderOffset:i,occluderOpacity:c,occluderScale:u,showOccluderProxy:l=!1,offsetX:h,offsetY:f,pose:p,rotationOffsetX:m,rotationOffsetY:E,rotationOffsetZ:S,scaleX:g,scaleY:A,scaleZ:v,show:M,showCenterDot:y,showFacePlaneReference:x,showGizmo:F,showHeadOccluder:w,skullCenterMode:k,skullVerticalBias:R,url:b,viewportHeight:N,viewportWidth:P})=>{const G=_.useMemo(()=>p||(!n||P<=0||N<=0?null:cp({face:n,width:P,height:N,headDepthOffset:a,lockDepth:s,lockRotation:r,model:o,offsetX:h,offsetY:f,rotationOffsetX:m,rotationOffsetY:E,rotationOffsetZ:S,scaleX:g,scaleY:A,scaleZ:v,skullCenterMode:k,skullVerticalBias:R})),[n,a,s,r,o,h,f,m,E,S,g,A,v,k,R,p,N,P]);if(!M||!G)return null;const U=k?[0,-G.height*R,G.depth*a]:[0,0,0],H=G.height,z=[T.HEAD_OCCLUDER_DEFAULT_SCALE[0]*u[0]*H,T.HEAD_OCCLUDER_DEFAULT_SCALE[1]*u[1]*H,T.HEAD_OCCLUDER_DEFAULT_SCALE[2]*u[2]*H];return L.jsxs(L.Fragment,{children:[L.jsxs("group",{position:[G.centerX,G.centerY,G.boxCenterZ],rotation:[G.rotationX,G.rotationY,G.rotationZ],children:[L.jsx("group",{scale:[G.width,G.height,G.depth],children:t>0&&L.jsxs("mesh",{children:[L.jsx("boxGeometry",{args:[1,1,1]}),L.jsx("meshBasicMaterial",{color:e,wireframe:!0,transparent:!0,opacity:t})]})}),y&&L.jsxs("mesh",{children:[L.jsx("sphereGeometry",{args:[6,20,20]}),L.jsx("meshBasicMaterial",{color:e})]}),x&&L.jsxs("group",{position:U,children:[L.jsxs("mesh",{rotation:[0,0,Math.PI/4],children:[L.jsx("ringGeometry",{args:[6,8,24]}),L.jsx("meshBasicMaterial",{color:"#f8fafc",side:Ae.DoubleSide})]}),L.jsxs("mesh",{rotation:[0,0,Math.PI/2],children:[L.jsx("planeGeometry",{args:[3,16]}),L.jsx("meshBasicMaterial",{color:"#f8fafc",transparent:!0,opacity:.9,side:Ae.DoubleSide})]}),L.jsxs("mesh",{children:[L.jsx("planeGeometry",{args:[16,3]}),L.jsx("meshBasicMaterial",{color:"#f8fafc",transparent:!0,opacity:.9,side:Ae.DoubleSide})]})]}),w&&L.jsxs(L.Fragment,{children:[l&&L.jsxs("mesh",{position:i,scale:z,renderOrder:20,children:[L.jsx("sphereGeometry",{args:[1,24,16]}),L.jsx("meshBasicMaterial",{color:"#facc15",wireframe:!0,transparent:!0,opacity:.95,depthTest:!1,depthWrite:!1})]}),L.jsx(T.HeadOccluder,{opacity:c,position:i,scale:z,showDebugMaterial:!0,url:b})]})]}),F&&L.jsx("group",{position:[G.centerX,G.centerY,G.boxCenterZ],rotation:[G.rotationX,G.rotationY,G.rotationZ],renderOrder:10,children:L.jsxs("group",{children:[L.jsxs("mesh",{children:[L.jsx("sphereGeometry",{args:[6,20,20]}),L.jsx("meshBasicMaterial",{color:"#e2e8f0",depthTest:!1,depthWrite:!1})]}),L.jsxs("mesh",{position:[18,0,0],rotation:[0,0,-Math.PI/2],children:[L.jsx("cylinderGeometry",{args:[1.6,1.6,24,12]}),L.jsx("meshBasicMaterial",{color:"#ef4444",depthTest:!1,depthWrite:!1})]}),L.jsxs("mesh",{position:[34,0,0],rotation:[0,0,-Math.PI/2],children:[L.jsx("coneGeometry",{args:[4.2,12,16]}),L.jsx("meshBasicMaterial",{color:"#ef4444",depthTest:!1,depthWrite:!1})]}),L.jsxs("mesh",{position:[0,18,0],children:[L.jsx("cylinderGeometry",{args:[1.6,1.6,24,12]}),L.jsx("meshBasicMaterial",{color:"#22c55e",depthTest:!1,depthWrite:!1})]}),L.jsxs("mesh",{position:[0,34,0],children:[L.jsx("coneGeometry",{args:[4.2,12,16]}),L.jsx("meshBasicMaterial",{color:"#22c55e",depthTest:!1,depthWrite:!1})]}),L.jsxs("mesh",{position:[0,0,18],rotation:[Math.PI/2,0,0],children:[L.jsx("cylinderGeometry",{args:[1.6,1.6,24,12]}),L.jsx("meshBasicMaterial",{color:"#3b82f6",depthTest:!1,depthWrite:!1})]}),L.jsxs("mesh",{position:[0,0,34],rotation:[Math.PI/2,0,0],children:[L.jsx("coneGeometry",{args:[4.2,12,16]}),L.jsx("meshBasicMaterial",{color:"#3b82f6",depthTest:!1,depthWrite:!1})]}),L.jsx(us.Text,{position:[42,0,0],fontSize:10,color:"#ef4444",anchorX:"center",anchorY:"middle",renderOrder:11,"material-depthTest":!1,children:"X"}),L.jsx(us.Text,{position:[0,42,0],fontSize:10,color:"#22c55e",anchorX:"center",anchorY:"middle",renderOrder:11,"material-depthTest":!1,children:"Y"}),L.jsx(us.Text,{position:[0,0,42],fontSize:10,color:"#3b82f6",anchorX:"center",anchorY:"middle",renderOrder:11,"material-depthTest":!1,children:"Z"})]})})]})},lp=Object.freeze(["pendant","charm"]),up=Object.freeze({maxAngle:35}),_v=({model:e,children:t,swing:n=!0,swingNodes:a=lp,occluder:s=!0,occluderUrl:r,offset:o,bodyIndex:i=0,...c})=>{const u=Te.useTrackerContext(),l=J.useThree(v=>v.scene),h=J.useThree(v=>v.get),f=a.join(`
|
|
2303
|
+
`),p=_.useMemo(()=>{if(!e)return null;const v=Su(e);return{root:v,pivots:mu(v,f.split(`
|
|
2304
|
+
`))}},[e,f]),m=n===!1?null:{...up,...n===!0?{}:n},E=_.useRef(m);E.current=m;const S=JSON.stringify(m),g=_.useRef([]);_.useEffect(()=>{if(!p||p.pivots.length===0)return;const v=p.pivots.map(({outer:y,inner:x})=>new ro(y,x,E.current??{}));g.current=v;const M=Gt.addSceneBeforeRender(l,()=>{const y=h().clock.elapsedTime;v.forEach(x=>{E.current?x.update(y):x.reset()})});return()=>{M(),v.forEach(y=>y.reset()),g.current===v&&(g.current=[])}},[p,l,h]),_.useEffect(()=>{const v=JSON.parse(S);v&&g.current.forEach(M=>M.setOptions(v))},[S]);const A=L.jsxs(L.Fragment,{children:[s&&L.jsx(T.ShoulderOccluder,{bodyIndex:i,url:r,smoothing:c.smoothing}),L.jsxs(T.CanonicalTorsoFrame,{bodyIndex:i,offset:o,...c,children:[p&&L.jsx("primitive",{object:p.root}),t]})]});return(u==null?void 0:u.type)==="body"?A:L.jsx(T.BodyTracker,{bodyIndex:i,children:A})},hp=(e,t)=>{const n=new d.BufferGeometry,a=e*t+1;n.setAttribute("position",new d.BufferAttribute(new Float32Array(a*3),3).setUsage(d.DynamicDrawUsage)),n.setAttribute("normal",new d.BufferAttribute(new Float32Array(a*3),3).setUsage(d.DynamicDrawUsage));const s=new Float32Array(a);for(let i=0;i<e;i+=1)s.fill(i/Math.max(1,e-1),i*t,(i+1)*t);s[a-1]=1,n.setAttribute("along",new d.BufferAttribute(s,1));const r=[];for(let i=0;i<e-1;i+=1)for(let c=0;c<t;c+=1){const u=i*t+c,l=i*t+(c+1)%t,h=u+t,f=l+t;r.push(u,h,l,l,h,f)}const o=e*t;for(let i=0;i<t;i+=1)r.push((e-1)*t+i,o,(e-1)*t+(i+1)%t);return n.setIndex(r),n.boundingSphere=new d.Sphere(new d.Vector3,1/0),n},we=new d.Vector3,Qe=new d.Vector3,ol=new d.Vector3,Tt=new d.Vector3,fp=(e,t,n,a,s)=>{const r=e.getAttribute("position"),o=e.getAttribute("normal"),i=t.length,c=r.array,u=o.array;we.copy(t[1]).sub(t[0]).normalize(),Qe.set(1,0,0),Math.abs(Qe.dot(we))>.9&&Qe.set(0,0,1);for(let f=0;f<i;f+=1){const p=t[Math.max(0,f-1)],m=t[Math.min(i-1,f+1)];we.copy(m).sub(p),we.lengthSq()<1e-12&&we.set(0,-1,0),we.normalize(),Qe.addScaledVector(we,-Qe.dot(we)),Qe.lengthSq()<1e-12&&Qe.set(we.y,-we.x,0),Qe.normalize(),ol.copy(we).cross(Qe);const E=i>1?f/(i-1):0,S=a+(s-a)*E;for(let g=0;g<n;g+=1){const A=2*Math.PI*g/n;Tt.copy(Qe).multiplyScalar(Math.cos(A)).addScaledVector(ol,Math.sin(A));const v=(f*n+g)*3;u[v]=Tt.x,u[v+1]=Tt.y,u[v+2]=Tt.z,c[v]=t[f].x+Tt.x*S,c[v+1]=t[f].y+Tt.y*S,c[v+2]=t[f].z+Tt.z*S}}const l=i*n*3,h=t[i-1];c[l]=h.x+we.x*s,c[l+1]=h.y+we.y*s,c[l+2]=h.z+we.z*s,u[l]=we.x,u[l+1]=we.y,u[l+2]=we.z,r.needsUpdate=!0,o.needsUpdate=!0},pp=Object.freeze({frequency:1.4,damping:.45,maxAngle:25}),On=Object.freeze({length:16,segments:8,thickness:Object.freeze([1.2,.3]),color:"#3b2416"}),il=3,cl=10,ll=new d.Vector3(0,-1,0),Fv=e=>{for(let t=e;t;t=t.parent)if(!t.visible)return!1;return!0},xv=e=>{const t=_.useContext(V.CanonicalHeadFrameContext),n=L.jsx(Cv,{...e});return t?n:L.jsx(V.CanonicalHeadFrame,{faceIndex:e.faceIndex,children:n})},Cv=({position:e=[0,0,0],direction:t=[0,-1,0],length:n=On.length,segments:a=On.segments,thickness:s=On.thickness,color:r=On.color,enabled:o=!0,frequency:i,damping:c,maxAngle:u})=>{const l=J.useThree(M=>M.scene),h=J.useThree(M=>M.get),f=_.useRef(null),p=Math.max(2,Math.min(32,Math.round(a))),[m,E]=typeof s=="number"?[s,s]:s,S=ao({...pp,...i!==void 0?{frequency:i}:{},...c!==void 0?{damping:c}:{},...u!==void 0?{maxAngle:u}:{}}),g=_.useRef({settings:S,enabled:o,rootRadius:m,tipRadius:E,length:n,direction:t});g.current={settings:S,enabled:o,rootRadius:m,tipRadius:E,length:n,direction:t};const A=_.useMemo(()=>hp(p*il+1,cl),[p]),v=_.useMemo(()=>new d.MeshStandardMaterial({roughness:.65}),[]);return v.color.set(r),_.useEffect(()=>()=>A.dispose(),[A]),_.useEffect(()=>()=>v.dispose(),[v]),_.useEffect(()=>{const M=new du(p),y=Array.from({length:p},()=>new d.Vector3),x=Array.from({length:p},()=>new d.Vector3),F=new Array(p).fill(0),w=[],k=new d.Vector3,R=new d.Vector3,b=new d.Matrix4,N=Array.from({length:p+1},()=>new d.Vector3),P=new d.CatmullRomCurve3(N,!1,"catmullrom",.5),G=Array.from({length:p*il+1},()=>new d.Vector3);let U=null;const H=()=>{const X=f.current;if(!X)return;const{settings:j,enabled:D,rootRadius:$,tipRadius:q,length:Q,direction:se}=g.current;R.set(se[0],se[1],se[2]),R.lengthSq()<1e-12&&R.copy(ll),R.normalize(),y.forEach((_e,ne)=>_e.lerpVectors(R,ll,ne/Math.max(1,p-1)).normalize());const Z=X.matrixWorld,B=Z.elements,Y=(Math.hypot(B[0],B[1],B[2])+Math.hypot(B[4],B[5],B[6])+Math.hypot(B[8],B[9],B[10]))/3;if(!(Y>1e-9)||!Number.isFinite(Y)){X.visible=!1,U=null;return}X.visible=!0,k.setFromMatrixPosition(Z),y.forEach((_e,ne)=>x[ne].copy(_e).transformDirection(Z)),F.fill(Q/p*Y);const te=h().clock.elapsedTime,ie=Fv(X);!ie||!D||U===null?(M.reset(k,x,F),U=ie?te:null):te>U&&(M.step(k,x,F,te-U,j,w),U=te),b.copy(Z).invert(),N[0].set(0,0,0),M.joints.forEach((_e,ne)=>N[ne+1].copy(_e.position).applyMatrix4(b)),G.forEach((_e,ne)=>P.getPoint(ne/(G.length-1),_e)),fp(A,G,cl,$,q)};return Gt.addSceneBeforeRender(l,H)},[l,h,A,p]),L.jsx("group",{ref:f,position:e,children:L.jsx("mesh",{geometry:A,material:v,frustumCulled:!1,renderOrder:5})})},as=K.CANONICAL_FACE_TRIANGLES.length/3,cr=[0,.5,-4],Ee=V.CANONICAL_FACE_POSITIONS,be=K.CANONICAL_FACE_TRIANGLES,va=new Float32Array(as*3),cn=new Float32Array(as*3);for(let e=0;e<as;e+=1){const[t,n,a]=[be[e*3]*3,be[e*3+1]*3,be[e*3+2]*3];for(let E=0;E<3;E+=1)va[e*3+E]=(Ee[t+E]+Ee[n+E]+Ee[a+E])/3;const s=Ee[n]-Ee[t],r=Ee[n+1]-Ee[t+1],o=Ee[n+2]-Ee[t+2],i=Ee[a]-Ee[t],c=Ee[a+1]-Ee[t+1],u=Ee[a+2]-Ee[t+2];let l=r*u-o*c,h=o*i-s*u,f=s*c-r*i;l*(va[e*3]-cr[0])+h*(va[e*3+1]-cr[1])+f*(va[e*3+2]-cr[2])<0&&(l=-l,h=-h,f=-f);const m=Math.hypot(l,h,f)||1;cn[e*3]=l/m,cn[e*3+1]=h/m,cn[e*3+2]=f/m}let ul=null;const Tv=()=>(ul??(ul=Qa(Ee,be)),ul),kv={triangle:-1,u:0,v:0,w:0,d2:0},Lv=(e,t,n,a,s)=>{const r=K.CANONICAL_FACE_UVS,o=be[e*3]*2,i=be[e*3+1]*2,c=be[e*3+2]*2,u=a?1-r[o+1]:r[o+1],l=a?1-r[i+1]:r[i+1],h=a?1-r[c+1]:r[c+1],f=r[i]-r[o],p=l-u,m=r[c]-r[o],E=h-u,S=t-r[o],g=n-u,A=f*E-m*p;if(Math.abs(A)<1e-12)return!1;const v=(S*E-m*g)/A,M=(f*g-S*p)/A,y=1-v-M,x=-1e-5;return y<x||v<x||M<x?!1:(s[0]=y,s[1]=v,s[2]=M,!0)},Rv=.6,bv=(e,t,n)=>{if(e<=t)return 1;if(e>=n)return 0;const a=(e-t)/(n-t);return 1-a*a*(3-2*a)},lr=(e,t,n,a,s)=>t*Ee[be[e*3]*3+s]+n*Ee[be[e*3+1]*3+s]+a*Ee[be[e*3+2]*3+s],hl=(e,t,n,a,s)=>{const r=t-lr(e,s[0],s[1],s[2],0),o=n-lr(e,s[0],s[1],s[2],1),i=a-lr(e,s[0],s[1],s[2],2),c=Math.hypot(r,o,i);return r*cn[e*3]+o*cn[e*3+1]+i*cn[e*3+2]<0?-c:c},ta=(e,t,{mode:n="auto",falloff:a=[.8,2.5],uvTolerance:s=1.5}={})=>{const r=e.length/3,o={triangle:new Int32Array(r).fill(-1),weights:new Float32Array(r*3),influence:new Float32Array(r),distance:new Float32Array(r),source:new Uint8Array(r),uvFlipped:!1},i=[0,0,0];if(t&&n!=="surface"){const l=S=>{const g=new Int32Array(r).fill(-1),A=new Float32Array(r*3);let v=0;for(let M=0;M<r;M+=1){const y=t[M*2],x=t[M*2+1];for(let F=0;F<as;F+=1){if(!Lv(F,y,x,S,i))continue;g[M]=F,A.set(i,M*3),Math.abs(hl(F,e[M*3],e[M*3+1],e[M*3+2],i))<=s&&(v+=1);break}}return{hit:g,w:A,agree:v}},h=l(!1),f=l(!0),p=f.agree>h.agree?f:h;o.uvFlipped=p===f;let m=0;for(let S=0;S<r;S+=1)p.hit[S]>=0&&(m+=1);const E=m>0&&p.agree>=m*Rv;for(let S=0;S<r&&(n==="uv"||E);S+=1){const g=p.hit[S];if(g<0)continue;i[0]=p.w[S*3],i[1]=p.w[S*3+1],i[2]=p.w[S*3+2];const A=hl(g,e[S*3],e[S*3+1],e[S*3+2],i);n==="auto"&&Math.abs(A)>s||(o.triangle[S]=g,o.weights.set(i,S*3),o.distance[S]=A,o.source[S]=1)}}if(n!=="uv")for(let l=0;l<r;l+=1){if(o.source[l]!==0)continue;const h=e[l*3],f=e[l*3+1],p=e[l*3+2];Tv()(h,f,p,kv)}const[c,u]=a;for(let l=0;l<r;l+=1)o.influence[l]=o.triangle[l]<0?0:bv(Math.abs(o.distance[l]),c,u);return o},dp=(e,t,n,a)=>{const s=e.triangle[t];if(s<0)return a[0]=a[1]=a[2]=0,a;const r=be[s*3]*3,o=be[s*3+1]*3,i=be[s*3+2]*3,c=e.weights[t*3],u=e.weights[t*3+1],l=e.weights[t*3+2];for(let h=0;h<3;h+=1)a[h]=c*n[r+h]+u*n[o+h]+l*n[i+h];return a},fl=[0,0,0],Vr=(e,t,n,a,s=1,r)=>{const o=e.triangle.length;for(let i=0;i<o;i+=1){const c=e.influence[i]*s;if(c<=0){a[i*3]=t[i*3],a[i*3+1]=t[i*3+1],a[i*3+2]=t[i*3+2];continue}dp(e,i,n,fl);let[u,l,h]=fl;if(r){const f=u,p=l,m=h;u=r[0]*f+r[1]*p+r[2]*m,l=r[3]*f+r[4]*p+r[5]*m,h=r[6]*f+r[7]*p+r[8]*m}a[i*3]=t[i*3]+u*c,a[i*3+1]=t[i*3+1]+l*c,a[i*3+2]=t[i*3+2]+h*c}return a},ni=K.CANONICAL_FACE_LANDMARK_COUNT*3,Ha=[2.5,5],Iv=(e,t,n)=>{const a=Math.min(1,Math.max(0,(n-e)/(t-e)));return a*a*(3-2*a)},pl=e=>Float32Array.from(e.distance,t=>Iv(Ha[0],Ha[1],Math.abs(t))),Nv=V.CANONICAL_FACE_POSITIONS[234*3+1],mp=e=>{let t=1/0,n=-1/0;for(const a of e){if(a.part==="follow")continue;const s=a.canonical,r=a.binding.distance;for(let o=0;o<r.length;o+=1)Math.abs(r[o])<Ha[0]||Math.abs(s[o*3+1]-Nv)>1||(t=Math.min(t,s[o*3]),n=Math.max(n,s[o*3]))}return n>t?n-t:0},gp=1.5,Sp=e=>{const t=ei(),n=r=>{const o=e.find(h=>h.eye===r);if(!o)return null;const c=new d.Box3().setFromArray(o.canonical).getCenter(new d.Vector3),u=r==="left"?t.leftEye:t.rightEye,l=Math.hypot(c.x-u[0],c.y-u[1]);return l>gp?null:{at:[c.x,c.y,u[2]],d:l}},a=n("left"),s=n("right");return!a||!s||Math.max(a.d,s.d)<.05?null:{leftEye:a.at,rightEye:s.at,mouth:t.mouth,nose:t.nose,chin:t.chin}},Ov=-.3,Pv=(e,t,n,a)=>{const s=e.getAttribute("position"),r=new Float32Array(s.count*3);for(let l=0;l<s.count;l+=1)r[l*3]=s.getX(l),r[l*3+1]=s.getY(l),r[l*3+2]=s.getZ(l);const o=new Float32Array(r.length),i=new d.Vector3;for(let l=0;l<s.count;l+=1)i.fromArray(r,l*3).applyMatrix4(t).toArray(o,l*3);const c=e.getAttribute("uv");let u=null;if(c){u=new Float32Array(c.count*2);for(let l=0;l<c.count;l+=1)u[l*2]=c.getX(l),u[l*2+1]=c.getY(l)}return{rest:r,canonical:o,uvs:u,binding:ta(o,u,{mode:n,falloff:a})}},dl=e=>{const n=new d.Box3().setFromArray(e).getCenter(new d.Vector3);return ta([n.x,n.y,n.z],null,{mode:"surface",falloff:[1e6,1000001]})},Ep=(e,{mode:t="auto",falloff:n=[.8,2.5],parts:a,align:s="auto"}={})=>{e.updateMatrixWorld(!0);const r=e.matrixWorld.clone().invert(),o=[],i=new Map;e.traverse(u=>{if(!(u instanceof d.Mesh))return;const l=u.geometry,h=l.clone();u.geometry=h,u.frustumCulled=!1;const f=new d.Matrix4().multiplyMatrices(r,u.matrixWorld),{rest:p,canonical:m,uvs:E,binding:S}=vt(l,[f.elements.join(),t,n.join()].join("|"),()=>Pv(h,f,t,n)),g=new d.BufferAttribute(p.slice(),3);g.setUsage(d.DynamicDrawUsage),h.setAttribute("position",g);let A=a==null?void 0:a[u.name];if(!A){const P=Float32Array.from(S.distance).sort();A=P[P.length>>1]<Ov?"follow":"surface"}const v=A==="follow"?dl(m):null,M=new d.Matrix3().setFromMatrix4(f),y=P=>{const G=P.elements;return Float32Array.from([G[0],G[3],G[6],G[1],G[4],G[7],G[2],G[5],G[8]])},x=y(M.clone().invert()),F=[];for(const[P,G]of Object.entries(u.morphTargetDictionary??{})){const U=T.faceMorphChannel(P);U>=0&&F.push({index:G,channel:U,region:T.faceMorphRegion(U)})}const k=new d.Box3().setFromArray(p).getCenter(new d.Vector3),R=k.clone().applyMatrix4(f),b=A==="follow"&&/eye/i.test(u.name)?R.x>=0?"left":"right":null,N={mesh:u,part:A,binding:S,rest:p,position:g,toLocal:x,toModel:y(M),centre:v,morphs:F,eye:b,pivot:k,canonical:m,aligned:m,widen:pl(S)};i.set(N,E),o.push(N)});const c=s==="auto"?Sp(o):s||null;if(c)for(const u of o){const l=ns(u.canonical,c);u.aligned=l,u.binding=vt(l,[t,n.join()].join("|"),()=>ta(l,i.get(u)??null,{mode:t,falloff:n})),u.part==="follow"&&(u.centre=dl(l)),u.widen=pl(u.binding)}return o},Uv=["eyes","brows","mouth","tongue"],Ap=(e,t)=>{const n=new Set(e.flatMap(o=>o.morphs.map(i=>i.region))),a=t!=="auto"?t:n.has("mouth")?"morphs":n.has("eyes")||n.has("brows")?"hybrid":"landmarks",s=a==="morphs"?Uv:a==="hybrid"?["eyes","brows","tongue"].filter(o=>n.has(o)):[];let r=null;if(a==="hybrid")for(const o of["eyes","brows"]){if(!s.includes(o))continue;const i=T.FACE_REGION_MASKS[o];r??(r=new Float32Array(i.length));for(let c=0;c<i.length;c+=1)r[c]=Math.max(r[c],i[c])}return{mode:a,landmarks:a==="landmarks"||a==="hybrid",morphRegions:new Set(s),mask:r,gaze:s.includes("eyes")}},Dv=new Float32Array(ni),Wr=new WeakSet,ml=(e,t,n)=>{if(n===1){Wr.delete(e);return}Wr.add(e);const a=n-1,s=e.toLocal,r=e.widen,o=e.canonical;for(let i=0;i<r.length;i+=1){if(r[i]===0)continue;const c=a*r[i]*o[i*3];t[i*3]+=s[0]*c,t[i*3+1]+=s[3]*c,t[i*3+2]+=s[6]*c}},Ma=new Float32Array(ni),kt=new Float32Array(3),Gv=new Float32Array(3),gl=new d.Matrix3,Sl=new d.Matrix3,El=new d.Matrix3,Al=new d.Matrix3,$v=new d.Euler(0,0,0,"YXZ"),vl=new d.Matrix4,ya=new d.Vector3,Ml=(e,t)=>e.set(t[0],t[1],t[2],t[3],t[4],t[5],t[6],t[7],t[8]),vp=(e,t,n,{expression:a=1,morphGain:s,gazeDegrees:r=[25,20],headWidth:o=1}={})=>{const i=n&&n.tracking!=="lost"?n:null,c=i?a:0;let u=Dv;if(i&&t.landmarks)if(t.mask){const l=t.mask;for(let h=0;h<l.length;h+=1){const f=1-l[h];Ma[h*3]=i.residual[h*3]*f,Ma[h*3+1]=i.residual[h*3+1]*f,Ma[h*3+2]=i.residual[h*3+2]*f}u=Ma}else u=i.residual;for(const l of e){const h=l.mesh.morphTargetInfluences;if(h)for(const p of l.morphs){if(!t.morphRegions.has(p.region))continue;const m=(s==null?void 0:s[p.channel])??1;h[p.index]=i?i.morphs[p.channel]*c*m:0}const f=l.position.array;if(l.part==="rigid"){if(o===1&&!Wr.has(l))continue;f.set(l.rest),ml(l,f,o)}else if(l.part==="surface")Vr(l.binding,l.rest,u,f,c,l.toLocal),ml(l,f,o);else if(l.centre){Vr(l.centre,Gv,u,kt,c,l.toLocal);const p=t.gaze&&i&&l.eye?T.FACE_GAZE_CHANNELS[l.eye]:null;if(p&&i){const E=(l.eye==="left"?1:-1)*(i.morphs[p.out]-i.morphs[p.in])*d.MathUtils.degToRad(r[0]),S=(i.morphs[p.up]-i.morphs[p.down])*d.MathUtils.degToRad(r[1]);vl.makeRotationFromEuler($v.set(-S*c,E*c,0)),gl.setFromMatrix4(vl),Ml(El,l.toModel),Ml(Al,l.toLocal),Sl.multiplyMatrices(Al,gl).multiply(El);const g=l.pivot;for(let A=0;A<f.length;A+=3)ya.set(l.rest[A]-g.x,l.rest[A+1]-g.y,l.rest[A+2]-g.z).applyMatrix3(Sl),f[A]=g.x+ya.x+kt[0],f[A+1]=g.y+ya.y+kt[1],f[A+2]=g.z+ya.z+kt[2]}else for(let m=0;m<f.length;m+=3)f[m]=l.rest[m]+kt[0],f[m+1]=l.rest[m+1]+kt[1],f[m+2]=l.rest[m+2]+kt[2]}l.position.needsUpdate=!0}},Mp=1.2,yl=[.8,1.3],yp=(e,t,n=1)=>{const a=V.CANONICAL_FACE_POSITIONS,r=(a[454*3]+e[454*3]-(a[234*3]+e[234*3]))*Mp*n;return Math.min(yl[1],Math.max(yl[0],r/t))},ai=_.createContext(null),wp=()=>_.useContext(ai),wl=({model:e,drive:t="auto",binding:n="auto",falloff:a=[.8,2.5],parts:s,align:r="auto",headFit:o=!1,expression:i=1,morphGain:c,gazeDegrees:u,onBind:l,children:h})=>{const f=ge(),p=a.join(),m=JSON.stringify(s??{}),E=JSON.stringify(r),{clone:S,meshes:g}=_.useMemo(()=>{const k=cu.clone(e);return le.markFaceSurface(k),{clone:k,meshes:Ep(k,{mode:n,falloff:a,parts:s,align:r})}},[e,n,p,m,E]);_.useEffect(()=>(l==null||l(g.map(({mesh:k,part:R,binding:b})=>({mesh:k,part:R,binding:b}))),()=>g.forEach(({mesh:k})=>k.geometry.dispose())),[g]);const A=_.useMemo(()=>Ap(g,t),[g,t]),v=JSON.stringify(c??{}),M=_.useMemo(()=>c?Float32Array.from(T.FACE_MORPH_NAMES,k=>c[k]??1):null,[v]),y=_.useMemo(()=>mp(g),[g]),x=o?o===!0?1:o.width??1:0,F=_.useRef({expression:i,gains:M,gazeDegrees:u,fitWidth:x});F.current={expression:i,gains:M,gazeDegrees:u,fitWidth:x};const w=_.useRef(!0);return J.useFrame(()=>{const k=(f==null?void 0:f.current)??null,R=!!k&&k.tracking!=="lost"&&A.mode!=="none";if(!R&&w.current)return;w.current=!R;const{fitWidth:b}=F.current;vp(g,A,R?k:null,{expression:F.current.expression,morphGain:F.current.gains,gazeDegrees:F.current.gazeDegrees,headWidth:b&&k&&y>0?yp(k.neutral,y,b):1})}),L.jsxs(ai.Provider,{value:g,children:[L.jsx("primitive",{object:S}),h]})},Bv=({faceIndex:e,smoothing:t,expressionSmoothing:n,holdMs:a,neutral:s,neutralMs:r,leadMs:o,neutralKey:i,onTrackingChange:c,...u})=>ge()?L.jsx(wl,{...u}):L.jsx(yt,{faceIndex:e,smoothing:t,expressionSmoothing:n,holdMs:a,neutral:s,neutralMs:r,leadMs:o,neutralKey:i,onTrackingChange:c,children:L.jsx(wl,{...u})}),Hv=new Map(T.FACE_MORPH_NAMES.map((e,t)=>[e,t])),zv=new Set(T.FACE_ACTION_NAMES),_l=new Set,_p=e=>{_l.has(e)||(_l.add(e),console.warn(`[FaceExpression] ${e}`))},Fl=e=>{const t=Hv.get(e);return t===void 0?(_p(`unknown blendshape "${e}" reads 0. Names: ${T.FACE_MORPH_NAMES.join(", ")}.`),()=>0):n=>n.morphs[t]??0},Fp=e=>{if(typeof e=="function")return a=>e(a);if(typeof e=="string")return Fl(e);if("action"in e)return zv.has(e.action)?a=>a.face?T.getFaceActionValue(a.face,e.action):0:(_p(`unknown Face Action "${e.action}" reads 0. Actions: ${T.FACE_ACTION_NAMES.join(", ")}.`),()=>0);const t=e.channels.map(Fl),n=e.combine??"max";return a=>{if(t.length===0)return 0;let s=n==="min"?1/0:n==="max"?-1/0:0;for(const r of t){const o=r(a);n==="max"?s=Math.max(s,o):n==="min"?s=Math.min(s,o):s+=o}return n==="avg"?s/t.length:s}},xp=(e,t={})=>{const[n,a]=t.range??[0,1];let s=a>n?(e-n)/(a-n):e>=a?1:0;s=d.MathUtils.clamp(s,0,1);const r=t.curve??1;r!==1&&(s**=r);const o=t.multiplier??1;s*=o;const[i,c]=t.clamp??[0,Math.max(1,o)];return d.MathUtils.clamp(s,i,c)},qr=e=>({values:e.map(t=>({value:t.rest??0,target:t.rest??0,active:!1}))}),Cp=(e,t)=>{t.forEach((n,a)=>{var r;const s=e.values[a];s.value=s.target=n.rest??0,s.active&&(s.active=!1,(r=n.onEnd)==null||r.call(n))})},Tp=(e,t,n,a)=>{var s,r;for(let o=0;o<t.length;o+=1){const i=t[o],c=e.values[o];a.live?c.target=xp(n[o](a),i):(i.onLost??"rest")==="rest"&&(c.target=i.rest??0);const u=i.smoothing??.6,l=typeof u=="number"?u:c.target>c.value?u.attack:u.release;c.value+=(c.target-c.value)*d.MathUtils.clamp(l,.01,1),Math.abs(c.target-c.value)<1e-4&&(c.value=c.target);const[h,f]=i.trigger??[.5,.35];!c.active&&c.value>=h?(c.active=!0,(s=i.onStart)==null||s.call(i)):c.active&&c.value<=f&&(c.active=!1,(r=i.onEnd)==null||r.call(i))}return e},Xr=(e,t={morphs:new Float32Array(T.FACE_MORPH_NAMES.length),face:null,live:!1})=>(t.live=!!e&&e.tracking!=="lost",t.morphs=(e==null?void 0:e.morphs)??t.morphs,t.face=t.live?(e==null?void 0:e.face)??null:null,t),xl=new Set,ur=e=>{xl.has(e)||(xl.add(e),console.warn(`[FaceExpressionController] ${e}`))},Kv=(e,t)=>e===t||T.faceMorphChannel(e)>=0&&T.faceMorphChannel(e)===T.faceMorphChannel(t),jv=(e,t)=>{const n=t.target?e.getObjectByName(t.target)??null:e,a={root:n,morphs:[],properties:[]};if(!n)return a;const s=t.morph?typeof t.morph=="string"?[t.morph]:t.morph:[];return n.traverse(r=>{if(r instanceof d.Mesh){if(s.length&&r.morphTargetDictionary&&r.morphTargetInfluences)for(const[o,i]of Object.entries(r.morphTargetDictionary))s.some(c=>Kv(c,o))&&a.morphs.push({influences:r.morphTargetInfluences,index:i});if(t.property){const o=Array.isArray(r.material)?r.material:[r.material];for(const i of o){const c=i.uniforms;c!=null&&c[t.property]?a.properties.push({material:i,name:t.property,uniform:!0}):typeof i[t.property]=="number"&&a.properties.push({material:i,name:t.property,uniform:!1})}}}}),a},hr=d.MathUtils.DEG2RAD,wa={q:new d.Quaternion,e:new d.Euler,v:new d.Vector3},kp=e=>{let t=[];const n=new Map,a=new Set;return{resolve(s,r=!1){t=s.map(o=>jv(e,o)),r&&s.forEach((o,i)=>{const c=t[i];o.target&&!c.root&&ur(`no object named "${o.target}" under the controller.`),o.morph&&c.root&&c.morphs.length===0&&ur(`no morph target named ${JSON.stringify(o.morph)} under "${o.target??"the controller"}".`),o.property&&c.root&&c.properties.length===0&&ur(`no material uniform or numeric property "${o.property}" under "${o.target??"the controller"}".`)})},apply(s,r){a.clear(),s.forEach((o,i)=>{var l;const c=(l=t[i])==null?void 0:l.root;if(!o.transform||!c)return;let u=n.get(c);u||(u={position:c.position.clone(),quaternion:c.quaternion.clone(),scale:c.scale.clone()},n.set(c,u)),a.has(c)||(a.add(c),c.position.copy(u.position),c.quaternion.copy(u.quaternion),c.scale.copy(u.scale))}),s.forEach((o,i)=>{var l,h;const c=((l=r.values[i])==null?void 0:l.value)??0,u=t[i];if(u){for(const f of u.morphs)f.influences[f.index]=c;for(const f of u.properties)f.uniform?f.material.uniforms[f.name].value=c:f.material[f.name]=c;if(o.visible&&u.root){const{above:f,below:p}=o.visible;u.root.visible=f===void 0&&p===void 0?c>=.5:(f===void 0||c>=f)&&(p===void 0||c<=p)}if(o.transform&&u.root){const{position:f,rotation:p,scale:m}=o.transform;f&&u.root.position.add(wa.v.fromArray(f).multiplyScalar(c)),p&&(wa.e.set(p[0]*hr*c,p[1]*hr*c,p[2]*hr*c),u.root.quaternion.multiply(wa.q.setFromEuler(wa.e))),m!==void 0&&u.root.scale.multiplyScalar(1+(m-1)*c)}(h=o.set)==null||h.call(o,c)}})}}},Vv=e=>{const t=_.useRef(e);t.current=e;const n=e.map(r=>typeof r.input=="function"?"fn":JSON.stringify(r.input)).join("|"),a=_.useMemo(()=>e.map(r=>Fp(r.input)),[n]),s=_.useRef(qr(e));return s.current.values.length!==e.length&&(s.current=qr(e)),{rulesRef:t,readers:a,state:s}},Lp=(e,{resetKey:t}={})=>{const n=ge(),{rulesRef:a,readers:s,state:r}=Vv(e),o=_.useRef(Xr(null)),i=_.useMemo(()=>()=>Cp(r.current,a.current),[]),c=_.useRef(!0);return _.useEffect(()=>{if(c.current){c.current=!1;return}i()},[t,i]),J.useFrame(()=>{Xr((n==null?void 0:n.current)??null,o.current),Tp(r.current,a.current,s,o.current)}),_.useMemo(()=>({state:r,reset:i,get:u=>{var h;const l=typeof u=="number"?u:a.current.findIndex(f=>f.id===u);return((h=r.current.values[l])==null?void 0:h.value)??0}}),[])},Cl=60,Wv=({rules:e,resetKey:t,children:n})=>{const{state:a}=Lp(e,{resetKey:t}),s=_.useRef(e);s.current=e;const r=_.useRef(null),o=_.useRef(null),i=_.useRef(0),c=_.useRef(-1);return J.useFrame(()=>{const u=r.current;if(!u)return;o.current??(o.current=kp(u));const l=s.current;(i.current%Cl===0||c.current!==l.length)&&(o.current.resolve(l,i.current>=Cl*2),c.current=l.length),i.current+=1,o.current.apply(l,a.current)}),L.jsx("group",{ref:r,children:n})},qv=({rules:e,resetKey:t,children:n,faceIndex:a,smoothing:s,expressionSmoothing:r,holdMs:o,neutral:i,neutralMs:c,leadMs:u,neutralKey:l,onTrackingChange:h})=>{const f=ge(),p=L.jsx(Wv,{rules:e,resetKey:t,children:n});return f?p:L.jsx(yt,{faceIndex:a,smoothing:s,expressionSmoothing:r,holdMs:o,neutral:i,neutralMs:c,leadMs:u,neutralKey:l,onTrackingChange:h,children:p})},Rp={"face.center":[10,152,234,454],"face.leftEye":[263,362,387,373],"face.rightEye":[33,133,158,145]},bp=[...Object.keys(eo.FACE_LANDMARK_INDICES),...Object.keys(Rp)],ss=(e,t)=>typeof e=="string"?ee.feedSidedName(e,t):e,Ip=1.2,Xv=e=>{if(typeof e=="string"){const t=eo.FACE_LANDMARK_INDICES[e],n=t!==void 0?[t]:Rp[e];if(!n)return null;const a=[0,0,0];for(const s of n)for(let r=0;r<3;r+=1)a[r]+=V.CANONICAL_FACE_POSITIONS[s*3+r]/n.length;return a}if("landmark"in e){const t=e.landmark;return t>=0&&t<K.CANONICAL_FACE_LANDMARK_COUNT?[V.CANONICAL_FACE_POSITIONS[t*3],V.CANONICAL_FACE_POSITIONS[t*3+1],V.CANONICAL_FACE_POSITIONS[t*3+2]]:null}return"point"in e?[e.point[0],e.point[1],e.point[2]]:null},Np=(e,t)=>{for(let n=0;n<3;n+=1)t[n]=(V.CANONICAL_FACE_POSITIONS[K.CANONICAL_FACE_TRIANGLES[e*3]*3+n]+V.CANONICAL_FACE_POSITIONS[K.CANONICAL_FACE_TRIANGLES[e*3+1]*3+n]+V.CANONICAL_FACE_POSITIONS[K.CANONICAL_FACE_TRIANGLES[e*3+2]*3+n])/3;return t},rs=(e,{patchRadius:t=Ip}={})=>{let n,a,s=null;if(typeof e=="object"&&"triangle"in e){if(!(e.triangle>=0&&e.triangle<K.CANONICAL_FACE_TRIANGLES.length/3))throw new Error(`PinToFaceMesh: no canonical face triangle ${e.triangle}`);const u=e.weights[0]+e.weights[1]+e.weights[2]||1;n=e.triangle,a=[e.weights[0]/u,e.weights[1]/u,e.weights[2]/u]}else{if(s=Xv(e),!s)throw new Error(`PinToFaceMesh: unknown anchor ${JSON.stringify(e)} — use one of ${bp.join(", ")}, { landmark: 0–467 }, { point } or { triangle, weights }`);const u=ta(s,null,{mode:"surface"});n=u.triangle[0],a=[u.weights[0],u.weights[1],u.weights[2]]}const r=[0,0,0];for(let u=0;u<3;u+=1)r[u]=a[0]*V.CANONICAL_FACE_POSITIONS[K.CANONICAL_FACE_TRIANGLES[n*3]*3+u]+a[1]*V.CANONICAL_FACE_POSITIONS[K.CANONICAL_FACE_TRIANGLES[n*3+1]*3+u]+a[2]*V.CANONICAL_FACE_POSITIONS[K.CANONICAL_FACE_TRIANGLES[n*3+2]*3+u];const o=[],i=[0,0,0];for(let u=0;u<K.CANONICAL_FACE_TRIANGLES.length/3;u+=1)Np(u,i),Math.hypot(i[0]-r[0],i[1]-r[1],i[2]-r[2])<=t&&o.push(u);o.includes(n)||o.push(n);const c={triangle:n,weights:a,offset:[0,0,0],patch:Int32Array.from(o)};if(s){const u=os(c,Op,{},Pp),l=new d.Vector3(s[0],s[1],s[2]).sub(u.position).applyQuaternion(u.quaternion.clone().invert());l.lengthSq()>1e-10&&(c.offset=[l.x,l.y,l.z])}return c},Yv=(e,t=1/0)=>{const n=[0,0,0];if(e)for(let c=0;c<3;c+=1)for(let u=0;u<3;u+=1)n[c]+=e.weights[u]*V.CANONICAL_FACE_POSITIONS[K.CANONICAL_FACE_TRIANGLES[e.triangle*3+u]*3+c];const a=[],s=[0,0,0];for(let c=0;c<K.CANONICAL_FACE_TRIANGLES.length/3;c+=1)e&&(Np(c,s),Math.hypot(s[0]-n[0],s[1]-n[1],s[2]-n[2])>t)||a.push(c);const r=new Map;for(const c of a)for(let u=0;u<3;u+=1)r.set(K.CANONICAL_FACE_TRIANGLES[c*3+u],0);const o=Uint16Array.from([...r.keys()].sort((c,u)=>c-u));o.forEach((c,u)=>r.set(c,u));const i=new Uint16Array(a.length*3);return a.forEach((c,u)=>{for(let l=0;l<3;l+=1)i[u*3+l]=r.get(K.CANONICAL_FACE_TRIANGLES[c*3+l])}),{landmarks:o,index:i}},Op={residual:new Float32Array(K.CANONICAL_FACE_LANDMARK_COUNT*3),neutral:new Float32Array(K.CANONICAL_FACE_LANDMARK_COUNT*3)},Pp={position:new d.Vector3,quaternion:new d.Quaternion},Tl=new d.Vector3,St=new d.Vector3,_a=new d.Vector3,kl=new d.Vector3,Ll=new d.Vector3,Rl=new d.Vector3,Ke=new d.Vector3,Yt=new d.Vector3,bl=new d.Vector3,Il=new d.Matrix4,Nl=new d.Vector3(1,0,0),fr=new d.Quaternion,Qv=new d.Vector3,Rt=(e,t,n,a,s)=>{const r=a*3,o=t==="face"?e.neutral:null,i=t==="face"&&e.view&&e.local?e:null;return s.set(V.CANONICAL_FACE_POSITIONS[r]+(o?o[r]:0)+e.residual[r]+(n?n[r]:0)+(i?i.view[r]-i.local[r]:0),V.CANONICAL_FACE_POSITIONS[r+1]+(o?o[r+1]:0)+e.residual[r+1]+(n?n[r+1]:0)+(i?i.view[r+1]-i.local[r+1]:0),V.CANONICAL_FACE_POSITIONS[r+2]+(o?o[r+2]:0)+e.residual[r+2]+(n?n[r+2]:0)+(i?i.view[r+2]-i.local[r+2]:0))},os=(e,t,{surface:n="face",orient:a="surface",offsets:s=null}={},r)=>{const o=e.triangle,[i,c,u]=e.weights;Rt(t,n,s,K.CANONICAL_FACE_TRIANGLES[o*3],St),Rt(t,n,s,K.CANONICAL_FACE_TRIANGLES[o*3+1],_a),Rt(t,n,s,K.CANONICAL_FACE_TRIANGLES[o*3+2],kl),r.position.copy(St).multiplyScalar(i).addScaledVector(_a,c).addScaledVector(kl,u),Ke.set(0,0,0);for(const p of e.patch){Rt(t,n,s,K.CANONICAL_FACE_TRIANGLES[p*3],St),Rt(t,n,s,K.CANONICAL_FACE_TRIANGLES[p*3+1],_a),Rt(t,n,s,K.CANONICAL_FACE_TRIANGLES[p*3+2],Tl),Ll.subVectors(_a,St),Rl.subVectors(Tl,St);const m=Ll.cross(Rl);m.x*St.x+m.y*(St.y-.5)+m.z*(St.z+4)<0&&m.negate(),Ke.add(m)}Ke.lengthSq()<1e-12&&Ke.set(0,0,1),Ke.normalize(),Yt.copy(Nl).addScaledVector(Ke,-Nl.dot(Ke)),Yt.lengthSq()<1e-8&&Yt.set(0,1,0).addScaledVector(Ke,-Ke.y),Yt.normalize(),bl.crossVectors(Ke,Yt),Il.makeBasis(Yt,bl,Ke),fr.setFromRotationMatrix(Il);const[l,h,f]=e.offset;return(l!==0||h!==0||f!==0)&&r.position.add(Qv.set(l,h,f).applyQuaternion(fr)),a==="head"?r.quaternion.identity():r.quaternion.copy(fr),r},Ol=new d.Raycaster,pr=new d.Vector3,Pl=new d.Vector3,Ul=new d.Quaternion,dr=new d.Vector3,Up=(e,t,n,a=8)=>{const s=os(e,Op,{},Pp),r=new d.Vector3(0,0,1).applyQuaternion(s.quaternion);n.updateWorldMatrix(!0,!1),t.updateWorldMatrix(!0,!0),n.getWorldQuaternion(Ul);for(const o of[1,-1]){pr.copy(s.position).addScaledVector(r,a*o),n.localToWorld(pr),Pl.copy(r).multiplyScalar(-o).applyQuaternion(Ul).normalize(),Ol.set(pr,Pl);const i=Ol.intersectObject(t,!0)[0];if(i)return dr.copy(i.point),n.worldToLocal(dr),dr.sub(s.position).dot(r)}return null},Jv=300,mr=d.MathUtils.DEG2RAD,gr={position:new d.Vector3,quaternion:new d.Quaternion},Zv=({anchor:e,mirrored:t,surface:n="face",orient:a="surface",offset:s,smoothing:r=1,onto:o,children:i})=>{const c=ge(),u=le.useFaceSurface(),l=ae.useXRMirrored(),h=ss(e,t??l),f=JSON.stringify(h),p=_.useMemo(()=>rs(h),[f]),m=_.useRef(null),E=_.useRef({surface:n,orient:a,smoothing:r,offsets:null});E.current.surface=n,E.current.orient=a,E.current.smoothing=r;const S=_.useRef(!1),g=_.useRef({source:null,target:null,binding:p,tries:0,marked:0});J.useFrame(()=>{const v=m.current,M=c==null?void 0:c.current;if(!v||!M)return;const y=g.current,x=(o&&"current"in o?o.current:o)??null;if((y.source!==p||y.target!==x)&&Object.assign(y,{source:p,target:x,binding:p,tries:0}),x&&y.binding===p&&v.parent&&y.tries<Jv){y.tries+=1;const w=Up(p,x,v.parent);if(w!==null){const[k,R,b]=p.offset;y.binding={...p,offset:[k,R,b+w]}}}if(x&&(y.marked+=1)%30===1&&le.markFaceSurface(v),M.tracking==="lost"){S.current=!1;return}E.current.offsets=u!=null&&u.current.active?u.current.offsets:null,os(y.binding,M,E.current,gr);const F=S.current?d.MathUtils.clamp(E.current.smoothing,.01,1):1;v.position.lerp(gr.position,F),v.quaternion.slerp(gr.quaternion,F),S.current=!0});const A=s==null?void 0:s.rotation;return L.jsx("group",{ref:m,children:L.jsx("group",{position:s!=null&&s.position?[...s.position]:void 0,rotation:A?[A[0]*mr,A[1]*mr,A[2]*mr]:void 0,scale:s==null?void 0:s.scale,children:i})})},Dp=({faceIndex:e,expressionSmoothing:t,holdMs:n,neutral:a,neutralMs:s,leadMs:r,neutralKey:o,onTrackingChange:i,...c})=>{const u=ge(),l=L.jsx(Zv,{...c});return u?l:L.jsx(yt,{faceIndex:e,expressionSmoothing:t,holdMs:n,neutral:a,neutralMs:s,leadMs:r,neutralKey:o,onTrackingChange:i,children:l})},Gp=["nose.left","nose.right","septum","lip.centre","lip.left","lip.right","brow.left","brow.right"],eM=["stud","ring"],et=(e,t,n,a)=>({at:e,orient:t,offset:{position:n,rotation:a}}),Yr=e=>({at:[-e.at[0],e.at[1],e.at[2]],orient:e.orient,offset:{position:[-e.offset.position[0],e.offset.position[1],e.offset.position[2]],rotation:[e.offset.rotation[0],-e.offset.rotation[1],-e.offset.rotation[2]]}}),Dl={region:"nose",kind:"stud",size:{stud:.25,ring:.8},stud:et([1.28,-.95,6.25],"surface",[0,0,0],[0,0,0]),ring:et([1.28,-.95,6.25],"surface",[0,0,0],[0,0,0])},Gl={region:"lip",kind:"ring",size:{stud:.3,ring:.9},stud:et([1.1,-5.55,5.1],"surface",[0,0,0],[0,0,0]),ring:et([1.1,-5.55,5.1],"surface",[0,0,0],[30,0,180])},$l={region:"brow",kind:"ring",size:{stud:.3,ring:1},stud:et([4.6,4.6,4.05],"surface",[0,0,0],[0,0,0]),ring:et([4.6,4.9,4],"surface",[0,0,0],[-50,15,0])},Qt=(e,t,n,a)=>a==="left"?{...e,name:t,label:n,side:a}:{...e,name:t,label:n,side:a,stud:Yr(e.stud),ring:Yr(e.ring)},Qr={"nose.left":Qt(Dl,"nose.left","nostril (left)","left"),"nose.right":Qt(Dl,"nose.right","nostril (right)","right"),septum:{name:"septum",label:"septum",region:"nose",side:"centre",kind:"ring",size:{stud:.3,ring:1},stud:et([0,-1.72,6.6],"head",[0,-.15,-.1],[0,0,0]),ring:et([0,-1.72,6.6],"head",[0,.25,0],[-15,90,0])},"lip.centre":{name:"lip.centre",label:"labret (lip centre)",region:"lip",side:"centre",kind:"stud",size:{stud:.3,ring:.9},stud:et([0,-5.8,5.28],"surface",[0,0,0],[0,0,0]),ring:et([0,-5.8,5.28],"surface",[0,0,0],[30,0,180])},"lip.left":Qt(Gl,"lip.left","lip (left)","left"),"lip.right":Qt(Gl,"lip.right","lip (right)","right"),"brow.left":Qt($l,"brow.left","brow (left)","left"),"brow.right":Qt($l,"brow.right","brow (right)","right")},Bl=new Map,tM=e=>{const t=e.join(",");let n=Bl.get(t);if(!n){const a=rs({point:e});n={triangle:a.triangle,weights:a.weights},Bl.set(t,n)}return n},$p=(e,{kind:t,mirrored:n=!1}={})=>{const a=Qr[e];if(!a)throw new Error(`FacePiercing: unknown preset ${JSON.stringify(e)} — use one of ${Gp.join(", ")}`);const s=t??a.kind,o=Qr[ee.feedSidedName(e,n)][s];return{name:e,kind:s,anchor:tM(o.at),orient:o.orient,offset:o.offset,size:a.size[s],flip:o.at[0]<0}},Bp=e=>({...e,position:e.position&&[-e.position[0],e.position[1],e.position[2]],rotation:e.rotation&&[e.rotation[0],-e.rotation[1],-e.rotation[2]]}),nM=2.5,Fa=new d.Vector3,aM=(e,t,n)=>Yv(e===void 0?null:rs(ss(e,n)),t),Hp=({surface:e="face",around:t,mirrored:n,radius:a=nM,renderOrder:s=-1,debug:r=!1,faceIndex:o,expressionSmoothing:i,holdMs:c,neutral:u,neutralMs:l,leadMs:h,neutralKey:f,onTrackingChange:p})=>{const m=ge(),E=ae.useXRMirrored(),S=L.jsx(sM,{surface:e,around:t,mirrored:n??E,radius:a,renderOrder:s,debug:r});return m?S:L.jsx(yt,{faceIndex:o,expressionSmoothing:i,holdMs:c,neutral:u,neutralMs:l,leadMs:h,neutralKey:f,onTrackingChange:p,children:S})},sM=({surface:e,around:t,mirrored:n,radius:a,renderOrder:s,debug:r})=>{const o=ge(),i=le.useFaceSurface(),c=t===void 0?void 0:ss(t,n),u=c===void 0?"":JSON.stringify(c),l=_.useMemo(()=>aM(c,a,!1),[u,a]),h=_.useMemo(()=>{const p=new d.BufferGeometry;return p.setAttribute("position",new d.BufferAttribute(new Float32Array(l.landmarks.length*3),3)),p.setIndex(new d.BufferAttribute(l.index,1)),p},[l]);_.useEffect(()=>()=>h.dispose(),[h]);const f=_.useMemo(()=>r?new d.MeshBasicMaterial({color:"#22d3ee",wireframe:!0,transparent:!0,opacity:.5,depthWrite:!1}):new d.MeshBasicMaterial({colorWrite:!1,side:d.DoubleSide,polygonOffset:!0,polygonOffsetFactor:1,polygonOffsetUnits:2}),[r]);return _.useEffect(()=>()=>f.dispose(),[f]),J.useFrame(()=>{const p=o==null?void 0:o.current;if(!p||p.tracking==="lost")return;const m=i!=null&&i.current.active?i.current.offsets:null,E=h.getAttribute("position"),S=E.array,{landmarks:g}=l;for(let A=0;A<g.length;A+=1)Rt(p,e,m,g[A],Fa),S[A*3]=Fa.x,S[A*3+1]=Fa.y,S[A*3+2]=Fa.z;E.needsUpdate=!0}),L.jsx("mesh",{geometry:h,material:f,renderOrder:s,frustumCulled:!1})},rM=2,Sr=d.MathUtils.DEG2RAD;let oM=null;const Hl=()=>oM??(oM=new d.MeshStandardMaterial({color:"#e5e7eb",metalness:.85,roughness:.25})),iM=({kind:e,size:t})=>{if(e==="stud")return L.jsx("mesh",{material:Hl(),position:[0,0,t/2],children:L.jsx("sphereGeometry",{args:[t/2,16,12]})});const n=Math.max(.04,t*.06),a=t/2+n;return L.jsx("mesh",{material:Hl(),position:[0,-a,0],rotation:[0,Math.PI/2,0],children:L.jsx("torusGeometry",{args:[a,n,8,40]})})},cM=({preset:e,kind:t,mirrored:n,occlude:a=!0,surface:s="face",smoothing:r,onto:o,offset:i,children:c,faceIndex:u,expressionSmoothing:l,holdMs:h,neutral:f,neutralMs:p,leadMs:m,neutralKey:E,onTrackingChange:S})=>{const g=ge(),A=ae.useXRMirrored(),v=n??A,M=_.useMemo(()=>$p(e,{kind:t,mirrored:v}),[e,t,v]),y=i&&M.flip?Bp(i):i,x=y==null?void 0:y.rotation,F=L.jsxs(L.Fragment,{children:[a&&!o&&L.jsx(Hp,{around:M.anchor,radius:rM,surface:s}),L.jsx(Dp,{anchor:M.anchor,surface:s,orient:M.orient,offset:M.offset,smoothing:r,onto:o,children:L.jsx("group",{position:y!=null&&y.position?[...y.position]:void 0,rotation:x?[x[0]*Sr,x[1]*Sr,x[2]*Sr]:void 0,scale:y==null?void 0:y.scale,children:c??L.jsx(iM,{kind:M.kind,size:M.size})})})]});return g?F:L.jsx(yt,{faceIndex:u,expressionSmoothing:l,holdMs:h,neutral:f,neutralMs:p,leadMs:m,neutralKey:E,onTrackingChange:S,children:F})},zp=(e,t)=>{const n=ge(),a=J.useThree(S=>S.gl),s=ae.useXRModelNode(ee.XRModel.FACE_TRACKER),r=qa(),[o,i]=_.useState(null),c=_.useRef(e);_.useEffect(()=>{const S=new Ja(c.current);return i(S),()=>S.dispose()},[]);const{resolution:u,unwrapResolution:l,padding:h,facing:f,unwrapMipmaps:p}=e,m=f==null?void 0:f.join();_.useEffect(()=>{o==null||o.setOptions({resolution:u,unwrapResolution:l,padding:h,facing:f,unwrapMipmaps:p})},[o,u,l,h,m,p]);const E=_.useRef({landmarks:null,texture:null,version:-1,time:-1/0});return J.useFrame(()=>{var y,x;const S=n==null?void 0:n.current;if(!o||!S||!r||S.tracking!=="tracked")return;const g=(x=(y=s==null?void 0:s.detectionResults)==null?void 0:y.faceLandmarks)==null?void 0:x[S.faceIndex];if(!g||g.length<K.CANONICAL_FACE_LANDMARK_COUNT)return;const A=E.current,v=T.feedTextureVersion(r);if(g===A.landmarks&&r===A.texture&&v===A.version)return;const M=performance.now();t>0&&M-A.time<1e3/t-1||(A.landmarks=g,A.texture=r,A.version=v,A.time=M,o.render(a,r,g))}),o},lM=["leftEye","rightEye"],uM=["mouth"],hM=(e,t)=>(e??[]).filter(n=>t?t.includes(n.mesh.name):n.part==="surface"),Kp=({mesh:e,eye:t})=>{if(t)return!0;const n=Array.isArray(e.material)?e.material:[e.material];return[e.name,...n.map(a=>a.name)].some(a=>/eye|iris|pupil/i.test(a))},zl=new WeakMap,fM=e=>{let t=zl.get(e);return t||(t=e.distance.map(Math.abs),zl.set(e,t)),t},Kl=e=>Kp(e)?lM:uM,pM=({meshes:e,align:t,region:n="face",amount:a=1,shading:s="unlit",mask:r=null,canonicalMask:o=null,resolution:i=1024,unwrapResolution:c=512,padding:u=2,fps:l=30,facing:h=[.05,.3],falloff:f=[1,3],fill:p=!1,fillReach:m=Bo,apply:E=!0,onTexture:S})=>{const g=wp(),A=zp({resolution:i,unwrapResolution:c,padding:u,facing:h,unwrapMipmaps:p},l),v=e==null?void 0:e.join(`
|
|
2305
|
+
`),M=_.useMemo(()=>hM(g,e),[g,v]),y=f.join(),x=JSON.stringify(t??null),F=_.useMemo(()=>M.map(({canonical:N,aligned:P})=>t?ns(N,t):P),[M,x]),w=_.useMemo(()=>M.map((N,P)=>Ut(F[P],{falloff:f,openings:Kl(N)})),[M,F,y]),k=!E||!!S;_.useEffect(()=>{A&&(A.setOptions({falloff:f}),A.setTargets(k?M.map((N,P)=>({mesh:N,i:P})).filter(({mesh:N})=>N.mesh.geometry.getAttribute("uv")).map(({mesh:N,i:P})=>({geometry:N.mesh.geometry,canonical:F[P],openings:Kl(N)})):[]))},[A,M,F,k,y]),A==null||A.setRegion(n),A==null||A.setMasks(r,o);const R=_.useMemo($o,[]);R.faceReprojectionMap.value=(A==null?void 0:A.unwrapTexture)??null,R.faceReprojectionAmount.value=Math.min(1,Math.max(0,a)),R.faceReprojectionLit.value=s==="lit"?1:0,R.faceReprojectionFill.value=p&&n==="face"?1:0,R.faceReprojectionFillReach.value=Math.max(.1,m),R.faceReprojectionFillTexelsPerCm.value=Ho(c),_.useEffect(()=>{if(!E||!A)return;const N=M.map(({mesh:P},G)=>{const U=P.geometry;U.setAttribute("faceUv",new Ae.BufferAttribute(w[G].canonicalUv,2)),U.setAttribute("faceCoverage",new Ae.BufferAttribute(w[G].coverage,1));const H=!Kp(M[G]);H&&U.setAttribute("faceDistance",new Ae.BufferAttribute(fM(w[G]),1));const z=P.material,X=D=>{const $=D.clone();return zo($,R,{attributes:!0,fill:H}),$},j=Array.isArray(z)?z.map(X):X(z);return P.material=j,()=>{P.material=z,U.deleteAttribute("faceUv"),U.deleteAttribute("faceCoverage"),H&&U.deleteAttribute("faceDistance"),(Array.isArray(j)?j:[j]).forEach(Ce)}});return()=>N.forEach(P=>P())},[E,A,M,w,R]);const b=_.useRef(S);return b.current=S,_.useEffect(()=>{var N;A&&((N=b.current)==null||N.call(b,{texture:A.texture,unwrap:A.unwrapTexture}))},[A]),null},dM=-.3,mM=["leftEye","rightEye","mouth"],gM=["leftEye","rightEye"],SM=["mouth"],jl=(e,t)=>{const n=e.clone();return zo(n,t,{attributes:!0}),n},Vl=(e,t,n,a,s,r)=>{const o=e.geometry;o.setAttribute("faceUv",new d.BufferAttribute(s.canonicalUv,2)),o.setAttribute("faceCoverage",new d.BufferAttribute(s.coverage,1));const i=new d.BufferAttribute(new Float32Array(t.length),3);return i.setUsage(d.DynamicDrawUsage),o.setAttribute("position",i),o.deleteAttribute("normal"),e.frustumCulled=!1,{mesh:e,binding:s,shape:n,base:t,toLocal:a,frame:new Float32Array(t.length),position:i,owned:r}},EM=(e,t,n,a,s,r)=>{var E;const o=e.getAttribute("position"),i=o.count,c=new Float32Array(i*3),u=new Float32Array(i*3),l=n!==void 0?(E=e.morphAttributes.position)==null?void 0:E[n]:void 0,h=new d.Vector3,f=new d.Vector3;for(let S=0;S<i;S+=1)h.fromBufferAttribute(o,S),h.clone().applyMatrix4(t).toArray(c,S*3),l&&(f.fromBufferAttribute(l,S),e.morphTargetsRelative?h.add(f):h.copy(f)),h.applyMatrix4(t).toArray(u,S*3);const p=ns(c,r);let m=Ut(p,{falloff:s,openings:a?gM:SM});if(!a){const S=r?Ut(c,{falloff:s}).distance:m.distance,g=Float32Array.from(S).sort();g[g.length>>1]<dM&&(m={...m,coverage:new Float32Array(i)})}return{bindBase:p,target:u,binding:m}},AM=(e,{morphKey:t,falloff:n,subdivisions:a,color:s,align:r},o)=>{if(typeof e=="string"){const l=Jf(e,{subdivisions:a}),h=l.geometry.getAttribute("position").array,f=jl(new d.MeshStandardMaterial({color:s,roughness:.85,vertexColors:!0,...le.faceSurfaceBlending,depthWrite:!1}),o),p=new d.Mesh(l.geometry,f),m=Ut(l.base,{falloff:n,openings:mM}),E=Vl(p,l.base,h.slice(),new d.Matrix4,m,[f]);return le.markFaceSurface(p),{root:p,parts:[E]}}const i=cu.clone(e);i.updateMatrixWorld(!0);const c=i.matrixWorld.clone().invert(),u=[];return i.traverse(l=>{var w;if(!(l instanceof d.Mesh))return;const h=l.geometry,f=h.clone();l.geometry=f;const p=new d.Matrix4().multiplyMatrices(c,l.matrixWorld),m=(w=l.morphTargetDictionary)==null?void 0:w[t],E=Array.isArray(l.material)?l.material:[l.material],S=[l.name,...E.map(k=>k.name)].some(k=>/eye|iris|pupil/i.test(k)),g=vt(h,[p.elements.join(),t,n.join(),JSON.stringify(r??null),S].join("|"),()=>EM(f,p,m,S,n,r));m!==void 0&&l.morphTargetInfluences&&(l.morphTargetInfluences[m]=0);const{bindBase:A,target:v,binding:M}=g,y=l.material,x=(Array.isArray(y)?y:[y]).map(k=>jl(k,o));l.material=Array.isArray(y)?x:x[0];const F=p.clone().invert();u.push(Vl(l,A,v,F,M,x))}),le.markFaceSurface(i),{root:i,parts:u}},vM=(e,t=4)=>Array.from({length:K.CANONICAL_FACE_LANDMARK_COUNT},(n,a)=>{const s=V.CANONICAL_FACE_POSITIONS;let r=null,o=t*t;return e.forEach((i,c)=>{for(let u=0;u<i.base.length/3;u+=1){if(i.binding.triangle[u]<0||i.binding.coverage[u]===0)continue;const l=(i.base[u*3]-s[a*3])**2+(i.base[u*3+1]-s[a*3+1])**2+(i.base[u*3+2]-s[a*3+2])**2;l<o&&(o=l,r={part:c,vertex:u})}}),r}),Wl=({shape:e,weight:t=1,expression:n=1,scale:a=1,morphKey:s="morph",align:r,faceTexture:o=1,region:i="face",shading:c="unlit",color:u="#f1c6a8",subdivisions:l=2,falloff:h=[1,3],facing:f=[.05,.3],unwrapResolution:p=512,fps:m=30,children:E})=>{const S=ge(),g=zp({unwrapResolution:p,facing:f},m);g==null||g.setRegion(i);const A=_.useMemo($o,[]);A.faceReprojectionMap.value=(g==null?void 0:g.unwrapTexture)??null,A.faceReprojectionAmount.value=Math.min(1,Math.max(0,o)),A.faceReprojectionLit.value=c==="lit"?1:0;const v=h.join(),M=JSON.stringify(r??null),y=new d.Color(u).getHex(),x=_.useMemo(()=>AM(e,{morphKey:s,falloff:h,subdivisions:l,color:u,align:r},A),[e,s,v,l,y,M,A]);_.useEffect(()=>()=>x.parts.forEach(({mesh:N,owned:P})=>{N.geometry.dispose(),P.forEach(Ce)}),[x]);const F=_.useMemo(Zo,[]),w=_.useMemo(()=>x.parts.length?vt(x.parts[0].base,x.parts.map(N=>N.base.length).join(),()=>vM(x.parts)):[],[x]),k=_.useRef(le.createFaceSurfaceState()),R=_.useRef({weight:t,expression:n,scale:a});R.current={weight:t,expression:n,scale:a};const b=_.useMemo(()=>new d.Vector3,[]);return J.useFrame(()=>{const N=S==null?void 0:S.current;if(!N||N.tracking==="lost")return;Jo(N.view,N.residual,F.point,F.expression);for(const U of x.parts){const{weight:H,expression:z,scale:X}=R.current;Zf(U.binding,U.shape,F,{weight:Mt(H),expression:Mt(z),scale:X},U.frame);const j=U.position.array;for(let D=0;D<j.length;D+=3)b.fromArray(U.frame,D).applyMatrix4(U.toLocal).toArray(j,D);U.position.needsUpdate=!0,U.mesh.geometry.computeVertexNormals()}const P=k.current;P.active=!0;const G=pe().index;for(let U=0;U<K.CANONICAL_FACE_LANDMARK_COUNT;U+=1){const H=w[U];for(let z=0;z<3;z+=1){if(!H){P.offsets[U*3+z]=0;continue}const{binding:X,frame:j}=x.parts[H.part],D=X.triangle[H.vertex];let $=0;for(let q=0;q<3;q+=1)$+=X.weights[H.vertex*3+q]*F.point[G[D*3+q]*3+z];P.offsets[U*3+z]=j[H.vertex*3+z]-$}}},le.FACE_SURFACE_FRAME_PRIORITY),L.jsxs(le.FaceSurfaceContext.Provider,{value:k,children:[L.jsx("primitive",{object:x.root}),E]})},MM=({faceIndex:e,smoothing:t,expressionSmoothing:n,holdMs:a,neutral:s,neutralMs:r,leadMs:o,neutralKey:i,onTrackingChange:c,...u})=>ge()?L.jsx(Wl,{...u}):L.jsx(yt,{faceIndex:e,smoothing:t,expressionSmoothing:n,holdMs:a,neutral:s,neutralMs:r,leadMs:o,neutralKey:i,onTrackingChange:c,children:L.jsx(Wl,{...u})}),jp=1280,Vp=(e,t,n=jp)=>{const a=Math.max(1,Math.round(e)),s=Math.max(1,Math.round(t)),r=Math.max(1,Math.round(n)),o=Math.min(1,r/Math.max(a,s));return o===1?{width:a,height:s,scale:o}:{width:Math.min(r,Math.max(1,Math.round(a*o))),height:Math.min(r,Math.max(1,Math.round(s*o))),scale:o}},yM=e=>{let t=1/0,n=1/0,a=-1/0,s=-1/0;for(const r of e)r.x<t&&(t=r.x),r.x>a&&(a=r.x),r.y<n&&(n=r.y),r.y>s&&(s=r.y);return Number.isFinite(t)?{x:t,y:n,width:a-t,height:s-n}:{x:.5,y:.5,width:0,height:0}},Wp=e=>e.map((t,n)=>({index:n,x:t.box.x+t.box.width/2})).sort((t,n)=>t.x-n.x||t.index-n.index).map(t=>t.index),wM=(e,t="largest")=>{if(t==="largest"){const a=pi.faceCandidates(e.map(r=>r.landmarks)),{index:s}=pi.selectSubject(a,{selection:"largest"});return s===null?null:{detection:e[s],index:s}}if(!Number.isInteger(t)||t<0)return null;const n=Wp(e)[t];return n===void 0?null:{detection:e[n],index:n}},qp=["turned","eyesClosed","mouthOpen","small","severalFaces"],_M=Object.freeze({turnedDegrees:25,eyeBlink:.5,jawOpen:.3,interocularPixels:60}),FM=e=>{if(!e||e.length<16)return null;const t=e[8],n=e[10];if(!Number.isFinite(t)||!Number.isFinite(n)||t===0&&n===0)return null;const a=e[12],s=e[14],r=Number.isFinite(a)&&Number.isFinite(s)&&s!==0?Math.atan2(-a,-s):0,o=Math.atan2(t,n)-r;return Math.abs(Math.atan2(Math.sin(o),Math.cos(o))*180/Math.PI)},Er=[468,473],Jr=[[33,133],[263,362]],xM=Math.max(...Jr.flat()),CM=(e,t,n)=>{let a,s;if(e.length>Er[1])[a,s]=[e[Er[0]],e[Er[1]]];else if(e.length>xM){const r=([o,i])=>({x:(e[o].x+e[i].x)/2,y:(e[o].y+e[i].y)/2});[a,s]=[r(Jr[0]),r(Jr[1])]}else return 0;return Math.hypot((s.x-a.x)*t,(s.y-a.y)*n)},TM=(e,t,n)=>{const a=_M,s=FM(e.matrix),r=e.blendshapes,o=Math.max(r.eyeBlinkLeft??0,r.eyeBlinkRight??0),i={turned:s!==null&&s>a.turnedDegrees,eyesClosed:o>a.eyeBlink,mouthOpen:(r.jawOpen??0)>a.jawOpen,small:CM(e.landmarks,n.width,n.height)<a.interocularPixels,severalFaces:t.length>1};return qp.filter(c=>i[c])};class Se extends Error{constructor(n,a,s){super(a);C(this,"code");C(this,"cause");this.name="FaceTextureLoadError",this.code=n,this.cause=s}}const kM=e=>e instanceof Se?{code:e.code,message:e.message}:(e==null?void 0:e.name)==="AbortError"?{code:"aborted",message:e.message||"aborted"}:{code:"decode",message:e instanceof Error?e.message:String(e)},Zr=[512,1024],ql={facing:[.2,.5],unwrapPadding:8},Vn=()=>new Se("aborted","the face texture load was cancelled"),is=e=>{if(e!=null&&e.aborted)throw Vn()},si=(e,t)=>t?t.aborted?Promise.reject(Vn()):new Promise((n,a)=>{const s=()=>a(Vn());t.addEventListener("abort",s,{once:!0}),e.then(r=>{t.removeEventListener("abort",s),n(r)},r=>{t.removeEventListener("abort",s),a(r)})}):e,LM=`
|
|
2306
|
+
varying vec2 vUv;
|
|
2307
|
+
void main() {
|
|
2308
|
+
vUv = uv;
|
|
2309
|
+
gl_Position = vec4(position.xy, 0.0, 1.0);
|
|
2310
|
+
}
|
|
2311
|
+
`,RM=`
|
|
2312
|
+
uniform sampler2D source;
|
|
2313
|
+
uniform float premultiply;
|
|
2314
|
+
uniform float decodeSrgb;
|
|
2315
|
+
varying vec2 vUv;
|
|
2316
|
+
vec3 srgbToLinear(vec3 c) {
|
|
2317
|
+
return mix(c / 12.92, pow((c + 0.055) / 1.055, vec3(2.4)), step(vec3(0.04045), c));
|
|
2318
|
+
}
|
|
2319
|
+
void main() {
|
|
2320
|
+
vec4 c = texture2D(source, vUv);
|
|
2321
|
+
if (decodeSrgb > 0.5) c.rgb = srgbToLinear(max(c.rgb, vec3(0.0)));
|
|
2322
|
+
gl_FragColor = premultiply > 0.5 ? vec4(c.rgb * c.a, c.a) : c;
|
|
2323
|
+
}
|
|
2324
|
+
`,Xl=new d.Color,Xp=(e,t,n,a,s=!1)=>{const r=new d.WebGLRenderTarget(n,n,{colorSpace:d.SRGBColorSpace,depthBuffer:!1,generateMipmaps:!0,minFilter:d.LinearMipmapLinearFilter,magFilter:d.LinearFilter}),o=new d.ShaderMaterial({uniforms:{source:{value:t},premultiply:{value:a?1:0},decodeSrgb:{value:s?1:0}},vertexShader:LM,fragmentShader:RM,blending:d.NoBlending,depthTest:!1,depthWrite:!1,toneMapped:!1}),i=new d.Mesh(new d.PlaneGeometry(2,2),o);i.frustumCulled=!1;const c=new d.Scene;c.add(i);const u=new d.OrthographicCamera(-1,1,1,-1,0,1),l=e.getRenderTarget(),h=e.getActiveCubeFace(),f=e.getActiveMipmapLevel();e.getClearColor(Xl);const p=e.getClearAlpha(),m=e.autoClear,E=e.xr.enabled;try{e.xr.enabled=!1,e.autoClear=!1,e.setClearColor(0,0),e.setRenderTarget(r),e.clear(!0,!1,!1),e.render(c,u)}finally{e.setRenderTarget(l,h,f),e.setClearColor(Xl,p),e.autoClear=m,e.xr.enabled=E,i.geometry.dispose()}return r},bM=Object.freeze([]),Yp=({kind:e,target:t,stats:n,mirrored:a,landmarks:s,warnings:r,faceCount:o})=>{const i={kind:e,map:t.texture,low:n.low,mean:n.mean,mirrored:a,landmarks:s,faceIndex:null,version:1,ready:!0,warnings:r,faceCount:o,dispose:()=>{i.ready&&(i.ready=!1,t.dispose(),n.dispose())}};return i},Qp=e=>{e.width=0,e.height=0},IM=async(e,t,n,a)=>{const{detectFacePhoto:s}=await Promise.resolve().then(()=>cy);is(a);const r=await s(t.src,{maxSize:t.maxSize,pick:t.pick,mirrored:t.mirrored,signal:a});if(a!=null&&a.aborted)throw Qp(r.canvas),Vn();return NM(e,r,n)},NM=(e,t,n=1024)=>{const{landmarks:a}=t.detection,s=new d.CanvasTexture(t.canvas);s.colorSpace=d.SRGBColorSpace,s.needsUpdate=!0;const r=new Ja({uvs:T.FACE_ATLAS_UVS,unwrapResolution:n,facing:ql.facing,mirrorFill:!0,unwrapPadding:ql.unwrapPadding,resolution:1});let o=null,i=null;try{r.render(e,s,a),o=Xp(e,r.unwrapTexture,n,!1),i=new Vo,i.updateFromImage(e,s,a,{dtMs:0,reset:!0,aspect:t.width/t.height})}catch(c){throw o==null||o.dispose(),i==null||i.dispose(),c}finally{r.dispose(),s.dispose(),Qp(t.canvas)}return Yp({kind:"photo",target:o,stats:i,mirrored:t.mirrored,landmarks:a,warnings:t.warnings,faceCount:t.detections.length})};let Yl=0;const OM=e=>(e==null?void 0:e.name)==="AbortError",PM={timeoutMs:3e4,pollMs:50},UM=e=>e.naturalWidth??e.videoWidth??e.width??0,DM=(e,t)=>si(new Promise(n=>{setTimeout(n,e)}),t),GM=async(e,t)=>{const{timeoutMs:n,pollMs:a}=PM;for(let s=0;;s+=a){is(t);const r=e.image;if(r){if(r.complete===!1&&typeof r.decode=="function")try{await si(r.decode(),t)}catch(o){throw o instanceof Se?o:new Se("decode","the face texture's image could not be decoded",o)}if(UM(r)>0)return;if(r.complete===!0)throw new Se("decode","the face texture's image is broken or empty")}if(s>=n)throw new Se("decode",`the face texture got no image within ${n} ms (pass a loaded texture, e.g. from TextureLoader.loadAsync)`);await DM(a,t)}},$M=async(e,t,n,a,s)=>{let r,o=()=>{};if(typeof t.src=="string"){const u=s??Pn.getDefaultAssetCache(),l=Pn.defineTextureAsset(t.src);Yl+=1;const h=`face-texture-${Yl}`;o=()=>u.release(l.key,h);try{r=await si(u.acquire(l,h),a)}catch(f){throw o(),f instanceof Se?f:OM(f)?Vn():f instanceof Pn.AssetFetchError?new Se("cors",`the face texture could not be fetched: ${t.src}`,f):new Se("decode",`the face texture could not be decoded: ${t.src}`,f)}}else r=t.src,await GM(r,a);let i=null,c=null;try{is(a),i=Xp(e,r,n,!r.premultiplyAlpha,r.colorSpace===d.NoColorSpace),c=new Vo,c.update(e,i.texture,{dtMs:0,reset:!0,mask:!0,lod:iE(n)})}catch(u){throw i==null||i.dispose(),c==null||c.dispose(),u}finally{o()}return Yp({kind:"canonical",target:i,stats:c,mirrored:t.mirrored??!1,landmarks:null,warnings:bM,faceCount:1})},Jp=async(e,t,n={})=>{const a=n.resolution??1024;if(!Zr.includes(a))throw new RangeError(`createFaceTexture: resolution must be one of ${Zr.join(", ")}, got ${a}`);if(is(n.signal),t.kind==="photo")return IM(e,t,a,n.signal);if(t.kind==="canonicalTexture")return $M(e,t,a,n.signal,n.assetCache);throw new TypeError(`createFaceTexture: unknown source kind ${String(t.kind)}`)},Ql=new WeakMap;let Jl=1;const BM=e=>{let t=Ql.get(e);return t===void 0&&(t=Jl,Jl+=1,Ql.set(e,t)),`#${t}`},HM=(e,t=1024)=>{if(!e)return null;const n=typeof e.src=="string"?`url:${e.src}`:BM(e.src),a=e.kind==="photo"?`${String(e.pick??"largest")}|${e.maxSize??""}`:"";return`${e.kind}|${n}|${e.mirrored?1:0}|${a}|${t}`},ri=Object.freeze([]),Zl=Object.freeze({face:null,status:"idle",warnings:ri,error:null,faceCount:0}),zM=Object.freeze({face:null,status:"loading",warnings:ri,error:null,faceCount:0}),Zp=(e,t={})=>{const n=J.useThree(c=>c.gl),a=t.resolution??1024,s=HM(e,a),r=_.useRef(e);r.current=e;const[o,i]=_.useState(Zl);return _.useEffect(()=>{const c=r.current;if(!c||s===null){i(Zl);return}const u=new AbortController;let l=null;return i(zM),Jp(n,c,{resolution:a,signal:u.signal}).then(h=>{if(u.signal.aborted){h.dispose();return}l=h,i({face:h,status:"ready",warnings:h.warnings,error:null,faceCount:h.faceCount})},h=>{u.signal.aborted||i({face:null,status:"error",warnings:ri,error:kM(h),faceCount:0})}),()=>{u.abort(),l==null||l.dispose()}},[n,s,a]),o},KM=-.6,jM=Object.freeze({required:1,frames:1}),VM=Object.freeze([]),WM=({numFaces:e,quality:t,smoothing:n,settings:a,ranks:s,amount:r})=>{const o={mirrorFill:!0,quality:t,smoothing:n,numFaces:e},i=jn(0,o),c=jn(1,o);return L.jsxs(L.Fragment,{children:[L.jsx(fn,{...a,smoothing:n,face:c,faceIndex:0,numFaces:e,quality:t,amount:r,renderOrder:$r(s[0]??0)}),L.jsx(fn,{...a,smoothing:n,face:i,faceIndex:1,numFaces:e,quality:t,amount:r,renderOrder:$r(s[1]??0)})]})},qM=({source:e=vf,amount:t=1,faceIndex:n,numFaces:a,quality:s="auto",active:r=!0,onStatus:o,...i})=>{const c=Te.useTrackerContext(),u=ge(),l=ae.useXRModelNode(ee.XRModel.FACE_TRACKER),h=ae.useXRCameraTexture(),f=e.kind==="eachOther",p=l==null?void 0:l.numFaces,{numFaces:m,targets:E,checkFace:S}=_.useMemo(()=>ts({eachOther:f,faceIndex:n,numFaces:a,modelFaces:p}),[f,n,a,p]);dn(r&&(c==null?void 0:c.type)!=="face"&&!u,m),_.useLayoutEffect(()=>{r&&ja(l,S,"FaceSwap")},[r,l,S]);const g=Zp(UE(e)),A=e.kind==="faceTexture"?e.face:g.face,v=O.resolveFaceSwapSettings(i,{source:PE(e)}),M=Mf(v),{smoothing:y}=i,[x,F]=_.useState([]),w=_.useMemo(()=>({current:0}),[]),k=_.useRef([]),R=_.useRef({nowMs:0,inference:!1,faces:0,ready:!1}),b=_.useRef({sizes:[],previous:[],next:[],entries:[],lastResults:void 0,faces:0,eachOther:f,status:null}),N=_.useRef({active:r,amount:t,eachOther:f,targets:E,face:A,photo:g,source:e,node:l,cameraTexture:h,onStatus:o,ranks:x});Object.assign(N.current,{active:r,amount:t,eachOther:f,targets:E,face:A,photo:g,source:e,node:l,cameraTexture:h,onStatus:o,ranks:x});const P=G=>{const U=b.current,{entries:H,sizes:z,previous:X,next:j}=U,D=G==null?void 0:G.image,$=(D==null?void 0:D.width)??1,q=(D==null?void 0:D.height)??1;z.length=H.length;let Q=0,se=-1,Z=-1;for(let te=0;te<H.length;te+=1){const ie=H[te];z[te]=ie!=null&&ie.track.tracked&&ie.positionsReady?Ef(ie.landmarks,$,q):0,(ie==null?void 0:ie.track.update.reason)==="jump"&&(Q+=1,se<0?se=te:Z=te)}const B=N.current.ranks;X.length=H.length;for(let te=0;te<H.length;te+=1)X[te]=B[te]??0;if(Q===2&&Z>=0){const te=X[se];X[se]=X[Z],X[Z]=te}PA(z,X,j);let Y=j.length!==B.length;for(let te=0;!Y&&te<j.length;te+=1)Y=j[te]!==B[te];Y&&F(j.slice())};return J.useFrame(G=>{var Y,te,ie,_e;const U=N.current,H=b.current,z=(Y=U.node)==null?void 0:Y.detectionResults,X=z!==H.lastResults;if(H.lastResults=z,X&&(H.faces=((te=z==null?void 0:z.faceLandmarks)==null?void 0:te.length)??0),H.eachOther!==U.eachOther){H.eachOther=U.eachOther;for(let ne=0;ne<k.current.length;ne+=1)sr(k.current[ne])}const j=U.eachOther?1:U.targets.length;for(;k.current.length<j;)k.current.push(Wf());const{entries:D}=H;D.length=U.targets.length;for(let ne=0;ne<U.targets.length;ne+=1)D[ne]=U.active?Af(G.gl,U.targets[ne]):void 0;const $=R.current;$.nowMs=performance.now(),$.inference=X;let q=!1,Q;if(U.eachOther){const[ne,ue]=D;$.faces=(ne!=null&&ne.track.tracked?1:0)+(ue!=null&&ue.track.tracked?1:0),$.ready=!!(ne!=null&&ne.face.ready)&&!!(ue!=null&&ue.face.ready);const Me=k.current[0];U.active?Kr(Me,$):sr(Me),w.current=Mt(U.amount)*Me.fade,q=Me.fade>0,Q=$.faces>=2&&$.ready?"ready":"waiting"}else{const ne=!!((ie=U.face)!=null&&ie.ready);for(let ue=0;ue<U.targets.length;ue+=1){const Me=D[ue],wt=k.current[ue];$.faces=Me!=null&&Me.track.tracked?1:0,$.ready=ne&&!!(Me!=null&&Me.statsReady),U.active?Kr(wt,$,jM):sr(wt),q||(q=wt.fade>0)}U.source.kind==="faceTexture"?Q=ne?"ready":"waiting":Q=DE(U.photo.status)}U.active&&X&&U.targets.length>1&&P(U.cameraTexture);const se=U.eachOther?VM:U.photo.warnings,Z=U.eachOther?null:U.photo.error,B=H.status;if(!B||B.active!==q||B.faces!==H.faces||B.source!==Q||B.warnings!==se||B.error!==Z){const ne={active:q,faces:H.faces,source:Q,warnings:se,error:Z},ue=!HE(B,ne);H.status=ne,ue&&((_e=U.onStatus)==null||_e.call(U,ne))}},KM),r?L.jsx("group",{children:f?L.jsx(WM,{numFaces:m,quality:s,smoothing:y,settings:M,ranks:x,amount:w}):E.map((G,U)=>L.jsx(fn,{...M,smoothing:y,face:A,faceIndex:G,numFaces:m,quality:s,amount:t,renderOrder:$r(x[U]??0)},G))}):null},XM=({target:e,variant:t,numFaces:n,quality:a,smoothing:s,amount:r,settings:o})=>{const i=jn(e,{quality:a,smoothing:s,numFaces:n});return L.jsx(fn,{...o,smoothing:s,face:i,faceIndex:e,layout:t,numFaces:n,quality:a,amount:r})},YM=({variant:e,amount:t=1,faceIndex:n,numFaces:a,quality:s="auto",active:r=!0,...o})=>{const i=Te.useTrackerContext(),c=ge(),u=ae.useXRModelNode(ee.XRModel.FACE_TRACKER),l=u==null?void 0:u.numFaces,{numFaces:h,targets:f,checkFace:p}=_.useMemo(()=>ts({faceIndex:n,numFaces:a,modelFaces:l}),[n,a,l]);dn(r&&(i==null?void 0:i.type)!=="face"&&!c,h),_.useLayoutEffect(()=>{r&&ja(u,p,"FaceMirror")},[r,u,p]);const m=O.resolveFaceMirrorSettings({...o,variant:e}),E=Mf(O.faceMirrorTransferSettings(m)),{smoothing:S}=o;return r?L.jsx("group",{children:f.map(g=>L.jsx(XM,{target:g,variant:m.variant,numFaces:h,quality:s,smoothing:S,amount:t,settings:E},g))}):null},za=4,ed=3e4,oi=e=>e instanceof Error?e.message:String(e),Ka=()=>new Se("aborted","the face photo load was aborted"),Wn=e=>{if(e!=null&&e.aborted)throw Ka()},QM=(e,t)=>t?new Promise((n,a)=>{const s=()=>a(Ka());if(t.aborted){s();return}t.addEventListener("abort",s,{once:!0}),e.then(r=>{t.removeEventListener("abort",s),n(r)},r=>{t.removeEventListener("abort",s),a(r)})}):e,td=e=>(e.faceLandmarks??[]).map((t,n)=>{var o,i,c,u;const a=t.map(l=>({x:l.x,y:l.y,z:l.z})),s={};for(const l of((i=(o=e.faceBlendshapes)==null?void 0:o[n])==null?void 0:i.categories)??[])s[l.categoryName]=l.score;const r=(u=(c=e.facialTransformationMatrixes)==null?void 0:c[n])==null?void 0:u.data;return{landmarks:a,blendshapes:s,matrix:r&&r.length>=16?Array.from(r):null,box:yM(a)}});let ut=null,Gn=null,Ra=0,nn=null;const JM=async e=>{try{const t=await di.FilesetResolver.forVisionTasks(new URL(ee.VISION_WASM_PATH,ee.libConfig.assetStorageEndpoint).toString()),[n]=await Promise.all([e,ee.warmVisionWasm(t)]);return await di.FaceLandmarker.createFromOptions(t,{baseOptions:{modelAssetBuffer:n,delegate:"CPU"},runningMode:"IMAGE",numFaces:za,outputFaceBlendshapes:!0,outputFacialTransformationMatrixes:!0})}catch(t){throw new Se("model",`the face model could not be loaded: ${oi(t)}`,t)}},ZM=()=>{if(!ut){const e=ee.acquireVerifiedBytes(new URL(ee.FACE_TRACKING_MODEL_PATH,ee.libConfig.assetStorageEndpoint).toString()),t=JM(e.bytes);ut=t,nn=e,t.catch(()=>{e.release(),ut===t&&(ut=null,nn=null)})}return ut},ii=()=>{Gn!==null&&(clearTimeout(Gn),Gn=null)},ci=()=>{ii();const e=ut;ut=null,nn==null||nn.release(),nn=null,e&&e.then(t=>{try{t.close()}catch{}},()=>{})},ey=()=>{ii(),Gn=setTimeout(()=>{Gn=null,Ra===0&&ci()},ed)},nd=(e,t)=>{const n=t!==void 0&&Number.isFinite(t)?Math.min(za,Math.max(1,Math.floor(t))):za,a=e.length>n?e.map((s,r)=>({d:s,index:r})).sort((s,r)=>r.d.box.width-s.d.box.width||s.index-r.index).slice(0,n).map(s=>s.d):e;return Wp(a).map(s=>a[s])},li=async(e,t={})=>{const{signal:n}=t;Wn(n),ii(),Ra+=1;try{const a=ZM(),s=await QM(a,n);if(ut!==a)throw new Se("aborted","the face image detector was disposed");Wn(n);let r;try{r=s.detect(e)}catch(o){const i=(o==null?void 0:o.name)==="SecurityError";throw new Se(i?"cors":"model",i?"the photo is cross-origin and cannot be read (serve it with CORS)":`face detection failed: ${oi(o)}`,o)}return nd(td(r),t.numFaces)}finally{Ra-=1,Ra===0&&ut&&ey()}},eu=()=>{},ad=e=>({image:e,width:e.width,height:e.height,close:()=>e.close()}),ty=e=>typeof Image>"u"||typeof URL>"u"||typeof URL.createObjectURL!="function"?Promise.resolve(null):new Promise(t=>{const n=URL.createObjectURL(e),a=new Image,s=r=>{a.onload=null,a.onerror=null,URL.revokeObjectURL(n),t(r)};a.onload=()=>s(a.naturalWidth>0&&a.naturalHeight>0?{width:a.naturalWidth,height:a.naturalHeight}:null),a.onerror=()=>s(null),a.decoding="async",a.src=n}),ny=async(e,t)=>{const n=await ty(e);if(!n)return null;const a=Vp(n.width,n.height,t);if(a.scale===1)return null;let s;try{s=await createImageBitmap(e,{imageOrientation:"from-image",resizeWidth:a.width,resizeHeight:a.height,resizeQuality:"high"})}catch{return null}const r=s.width===a.width&&s.height===a.height,o=s.width===n.width&&s.height===n.height;return r||o?ad(s):(s.close(),null)},tu=async(e,t)=>{const n=await ny(e,t);if(n)return n;let a;try{a=await createImageBitmap(e,{imageOrientation:"from-image"})}catch(s){throw new Se("decode",`the photo could not be decoded: ${oi(s)}`,s)}return ad(a)},ay=e=>"naturalWidth"in e&&"decode"in e,sy=async(e,t,n)=>{if(typeof e=="string"){let s;try{s=await fetch(e,n?{signal:n}:void 0)}catch(o){throw n!=null&&n.aborted?Ka():new Se("cors","the photo could not be fetched (CORS or network error)",o)}if(!s.ok)throw new Se("cors",`the photo could not be fetched (HTTP ${s.status})`);let r;try{r=await s.blob()}catch(o){throw n!=null&&n.aborted?Ka():new Se("cors","the photo download failed",o)}return Wn(n),tu(r,t)}if(typeof Blob<"u"&&e instanceof Blob)return tu(e,t);if(ay(e)){if(!e.complete||e.naturalWidth===0)try{await e.decode()}catch(s){throw new Se("decode","the photo <img> could not be decoded",s)}return{image:e,width:e.naturalWidth,height:e.naturalHeight,close:eu}}const a=e;return{image:a,width:a.width,height:a.height,close:eu}},ry=(e,t)=>{if(typeof document<"u"){const n=document.createElement("canvas");return n.width=e,n.height=t,n}return new OffscreenCanvas(e,t)},oy=e=>e.getContext("2d"),sd=async(e,t={})=>{const{signal:n}=t,a=t.maxSize??jp;Wn(n);const s=await sy(e,a,n);try{if(Wn(n),!(s.width>0&&s.height>0))throw new Se("decode","the photo is empty (0 × 0)");const r=Vp(s.width,s.height,a),o=ry(r.width,r.height),i=oy(o);if(!i)throw new Se("decode","no 2D canvas context for the photo");return i.imageSmoothingEnabled=!0,i.imageSmoothingQuality="high",i.drawImage(s.image,0,0,r.width,r.height),{canvas:o,width:r.width,height:r.height}}finally{s.close()}},iy=async(e,t={})=>{const{pick:n="largest",signal:a}=t,s=await sd(e,{maxSize:t.maxSize,signal:a}),r=await li(s.canvas,{signal:a}),o=wM(r,n);if(!o)throw new Se("noFace",r.length?`the photo has ${r.length} face(s); there is no face ${n} from the left`:"no face was found in the photo");return{...s,detection:o.detection,pickedIndex:o.index,detections:r,warnings:TM(o.detection,r,s),mirrored:t.mirrored??!1}},cy=Object.freeze(Object.defineProperty({__proto__:null,FACE_IMAGE_LANDMARKER_IDLE_MS:ed,FACE_IMAGE_MAX_FACES:za,detectFaceImage:li,detectFacePhoto:iy,disposeFaceImageLandmarker:ci,limitFaceImageDetections:nd,loadFacePhoto:sd,toFaceImageDetections:td},Symbol.toStringTag,{value:"Module"})),rd={outline:"#0f172a",fade:"#dc2626",band:"#ea580c",own:"#2563eb",midline:"#475569",grid:"#e2e8f0",gridText:"#94a3b8"},W=e=>Number(e.toFixed(2)).toString(),ly=e=>e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">"),an=e=>[T.FACE_ATLAS_UVS[e*2],T.FACE_ATLAS_UVS[e*2+1]],uy=720,Ar=16,hy=4,fy=1,xa=(e,t)=>{const n=V.CANONICAL_FACE_POSITIONS,a=e.length,s=a*t,r=new Float64Array(s*3),o=new Float64Array(s*2),i=u=>e[(u+a)%a],c=(u,l)=>Math.sqrt(Math.hypot(n[u*3]-n[l*3],n[u*3+1]-n[l*3+1],n[u*3+2]-n[l*3+2]))||1e-6;for(let u=0;u<a;u+=1){const l=[i(u-1),i(u),i(u+1),i(u+2)],h=c(l[0],l[1]),f=h+c(l[1],l[2]),p=f+c(l[2],l[3]);for(let m=0;m<t;m+=1){const E=h+(f-h)*m/t,S=[(h-E)/h,E/h,0,0],g=[0,(f-E)/(f-h),(E-h)/(f-h),0],A=[0,0,(p-E)/(p-f),(E-f)/(p-f)],v=S.map((x,F)=>(f-E)/f*x+E/f*g[F]),M=g.map((x,F)=>(p-E)/(p-h)*x+(E-h)/(p-h)*A[F]),y=u*t+m;for(let x=0;x<4;x+=1){const F=(f-E)/(f-h)*v[x]+(E-h)/(f-h)*M[x];for(let w=0;w<3;w+=1)r[y*3+w]+=F*n[l[x]*3+w];for(let w=0;w<2;w+=1)o[y*2+w]+=F*T.FACE_ATLAS_UVS[l[x]*2+w]}}}return{xyz:r,uv:o,count:s}},nu=(e,t,n,a)=>{const s=[0,1,2].map(c=>t[a*3+c]-t[n*3+c]),r=[0,1,2].map(c=>e[c]-t[n*3+c]),o=s[0]*s[0]+s[1]*s[1]+s[2]*s[2],i=o>0?Math.min(1,Math.max(0,(r[0]*s[0]+r[1]*s[1]+r[2]*s[2])/o)):0;return(r[0]-i*s[0])**2+(r[1]-i*s[1])**2+(r[2]-i*s[2])**2},vr=(e,{xyz:t,count:n})=>{let a=0,s=1/0;for(let r=0;r<n;r+=1){const o=(e[0]-t[r*3])**2+(e[1]-t[r*3+1])**2+(e[2]-t[r*3+2])**2;o<s&&(s=o,a=r)}return Math.sqrt(Math.min(nu(e,t,(a+n-1)%n,a),nu(e,t,a,(a+1)%n)))},py=(e,t,{uv:n,count:a})=>{let s=!1;for(let r=0,o=a-1;r<a;o=r,r+=1){const i=n[r*2],c=n[r*2+1],u=n[o*2],l=n[o*2+1];c>t!=l>t&&e<(u-i)*(t-c)/(l-c)+i&&(s=!s)}return s},dy=()=>{const e=hy,t=T.FACE_ATLAS_SOURCE.vertexCount,n=[],a=[];for(let v=0;v<t;v+=1)n.push(v,v,v),a.push(1,0,0);const s=new Map,r=(v,M,y)=>{const[x,F,w]=v<M?[v,M,y]:[M,v,e-y],k=(x*t+F)*(e+1)+w;let R=s.get(k);return R===void 0&&(R=n.length/3,s.set(k,R),n.push(x,F,F),a.push(1-w/e,w/e,0)),R},o=[],i=new Int32Array((e+1)*(e+1)),c=(v,M)=>i[v*(e+1)+M];for(let v=0;v<T.FACE_ATLAS_SOURCE.triangleCount;v+=1){const M=T.FACE_ATLAS_TRIANGLES[v*3],y=T.FACE_ATLAS_TRIANGLES[v*3+1],x=T.FACE_ATLAS_TRIANGLES[v*3+2];for(let F=0;F<=e;F+=1)for(let w=0;w<=e-F;w+=1){const k=e-F-w;let R;F===0&&w===0?R=M:F===e?R=y:w===e?R=x:w===0?R=r(M,y,F):F===0?R=r(M,x,w):k===0?R=r(y,x,w):(R=n.length/3,n.push(M,y,x),a.push(k/e,F/e,w/e)),i[F*(e+1)+w]=R}for(let F=0;F<e;F+=1)for(let w=0;w<e-F;w+=1)o.push(c(F,w),c(F+1,w),c(F,w+1)),F+w<e-1&&o.push(c(F+1,w),c(F+1,w+1),c(F,w+1))}const u=xa(T.FACE_ATLAS_OVAL_RING,uy/T.FACE_ATLAS_OVAL_RING.length),l=[xa(T.FACE_ATLAS_EYE_RINGS.negX,Ar),xa(T.FACE_ATLAS_EYE_RINGS.posX,Ar)],h=xa(T.FACE_ATLAS_LIP_RINGS.inner,Ar),f=(v,M,y,x,F)=>v>=fy?v:(py(M,y,x)?F:-F)*v,p=n.length/3,m=new Float64Array(p*2),E=new Float64Array(p),S=new Float64Array(p),g=new Float64Array(p),A=[0,0,0];for(let v=0;v<p;v+=1){A.fill(0);let M=0,y=0;for(let w=0;w<3;w+=1){const k=n[v*3+w],R=a[v*3+w];for(let b=0;b<3;b+=1)A[b]+=R*V.CANONICAL_FACE_POSITIONS[k*3+b];M+=R*T.FACE_ATLAS_UVS[k*2],y+=R*T.FACE_ATLAS_UVS[k*2+1]}m[v*2]=M,m[v*2+1]=y,E[v]=f(vr(A,u),M,y,u,1);const x=l.map(w=>vr(A,w)),F=x[0]<=x[1]?0:1;S[v]=f(x[F],M,y,l[F],-1),g[v]=f(vr(A,h),M,y,h,-1)}return{uv:m,values:{edge:E,eye:S,mouth:g},triangles:Uint32Array.from(o),outline:u.uv}};let au=null;const od=()=>(au??(au=dy()),au),my=(e,t)=>{const{uv:n,values:a,triangles:s}=od(),r=a[e],o=r.length,i=new Map,c=[],u=(m,E)=>{const S=m<E?m*o+E:E*o+m;if(!i.has(S)){const g=(r[m]-t)/(r[m]-r[E]);i.set(S,[n[m*2]+(n[E*2]-n[m*2])*g,n[m*2+1]+(n[E*2+1]-n[m*2+1])*g])}return S};for(let m=0;m<s.length;m+=3){const E=[];for(let S=0;S<3;S+=1){const g=s[m+S],A=s[m+(S+1)%3];r[g]<t!=r[A]<t&&E.push(u(g,A))}E.length===2&&c.push([E[0],E[1]])}const l=new Map;c.forEach(([m,E],S)=>{l.set(m,[...l.get(m)??[],S]),l.set(E,[...l.get(E)??[],S])});const h=new Uint8Array(c.length),f=(m,E)=>{const S=[m];let g=m,A=E;for(;A>=0;){h[A]=1;const[v,M]=c[A];g=v===g?M:v,S.push(g),A=(l.get(g)??[]).find(y=>!h[y])??-1}return S.flatMap(v=>i.get(v))},p=[];return l.forEach((m,E)=>{m.length===1&&!h[m[0]]&&p.push(f(E,m[0]))}),c.forEach(([m],E)=>{h[E]||p.push(f(m,E))}),p},gy=()=>od().outline,$n=(e,t)=>`${e.map((n,a)=>{const[s,r]=an(n),{x:o,y:i}=st(s,r,t);return`${a===0?"M":"L"}${W(o)},${W(i)}`}).join("")}Z`,su=(e,t,n=!1)=>e.map(a=>{const s=a.length-2,r=n||a[0]===a[s]&&a[1]===a[s+1],o=r&&!n?s:a.length;let i="";for(let c=0;c<o;c+=2){const{x:u,y:l}=st(a[c],a[c+1],t);i+=`${c===0?"M":"L"}${W(u)},${W(l)}`}return r?`${i}Z`:i}).join(""),Mr=(e,t)=>{const n=[];for(let a=0;a<e.length;a+=1){const s=[0,1,2].map(r=>{const[o,i]=an(T.FACE_ATLAS_TRIANGLES[e[a]*3+r]),{x:c,y:u}=st(o,i,t);return`${W(c)},${W(u)}`});n.push(`M${s[0]}L${s[1]}L${s[2]}Z`)}return n.join("")},ui=(e={})=>{const{size:t=1024,background:n,wireframe:a=!0,labels:s=!0,grid:r=.1,preset:o="keepColors",edgeInset:i=O.DEFAULT_FACE_SWAP_SETTINGS.edgeInset,featureSoftness:c=O.DEFAULT_FACE_SWAP_SETTINGS.featureSoftness}=e,u=e.edgeSoftness??O.FACE_SWAP_PRESETS[o].edgeSoftness,l=rd,h=t/100,f=h*.25,p=h*1.35,m='font-family="ui-monospace, SFMono-Regular, Menlo, monospace"',E=(b,N,P,G="start",U="",H=1,z=Ge.text)=>`<text x="${W(b)}" y="${W(N)}" text-anchor="${G}" ${m} font-size="${W(p*H)}" fill="${z}"${U}>${ly(P)}</text>`,S=(b,N)=>su(my(b,N),t),g=(b,N,P,G="")=>`<path d="${b}" fill="none" stroke="${N}" stroke-width="${W(P)}" stroke-linecap="round" stroke-linejoin="round"${G?` stroke-dasharray="${G}"`:""}/>`,A=`${W(h*.9)} ${W(h*.6)}`,v=`${W(h*.15)} ${W(h*.6)}`,M=`${W(h*.5)} ${W(h*.4)}`,y=[];if(n&&y.push(`<rect width="${t}" height="${t}" fill="${n}"/>`),r>0){const b=[];for(let N=1;N*r<1-1e-9;N+=1)b.push(N*r);y.push(g(b.map(N=>`M${W(N*t)},0V${t}M0,${W((1-N)*t)}H${t}`).join(""),l.grid,f*.5)),s&&b.forEach(N=>{const P=W(N);y.push(E(N*t+h*.3,p*.75,`u ${P}`,"start","",.65,l.gridText),E(h*.3,(1-N)*t-h*.3,`v ${P}`,"start","",.65,l.gridText))})}y.push(Jn({size:t,regions:["skin","lips","eyes","mouth"],wireframe:a,labels:!1}));const x=st(.5,T.FACE_ATLAS_UVS[10*2+1]+.015,t).y,F=st(.5,T.FACE_ATLAS_UVS[152*2+1]-.015,t).y;y.push(g(`M${t/2},${W(x)}V${W(F)}`,l.midline,f*.6,`${W(h)} ${W(h*.8)}`));const w=i+u,k=i+jo*u;y.push(g(S("edge",k),l.band,f*.8,v),g(S("edge",w),l.fade,f),g(S("edge",i),l.fade,f*.8,A));const R=gy().filter((b,N)=>N%4<2);if(y.push(g(su([R],t,!0),l.outline,f*1.4)),y.push(g($n(T.FACE_ATLAS_EYE_RINGS.negX,t)+$n(T.FACE_ATLAS_EYE_RINGS.posX,t)+$n(T.FACE_ATLAS_LIP_RINGS.inner,t),l.own,f*1.2),g(S("eye",c)+S("mouth",c),l.own,f*.7,M)),s){const b=h*2.5,N=p*1.3,P=[`${t}×${t}: FACE_ATLAS_UVS, the face atlas. Paint upright, as on an`,"unmirrored photo: image LEFT = the person's RIGHT. Neutral face, eyes","open, lips closed, flat even light. Opaque 3–5 mm past the outline."];y.push(E(b,b+p,"Face texture template (face swap)","start",' font-weight="bold"'),...P.map((D,$)=>E(b,b+p+N*($+1),D)));const G=u===O.FACE_SWAP_PRESETS[o].edgeSoftness?o:"custom",U=h*3,H=(D,$,q,Q)=>`<g transform="translate(${W(D)},${W($-p*.35)})">${q}</g>`+E(D+U+h,$,Q);[[g(`M0,0H${W(U)}`,l.outline,f*1.4),"face outline"],[g(`M0,0H${W(U)}`,l.fade,f*.8,A),`${G}: fade starts ${W(i)} cm in`],[g(`M0,0H${W(U)}`,l.fade,f),`${G}: opaque from ${W(w)} cm`],[g(`M0,0H${W(U)}`,l.band,f*.8,v),`${G}: colour band to ${W(k)} cm`]].forEach(([D,$],q)=>{y.push(H(t*.63,b+p+N*q,D,$))});const X=t-b-p*1.2,j=[[`<rect x="0" y="${W(-h*.6)}" width="${W(U)}" height="${W(h*1.2)}" fill="${Ge.skin}" fill-opacity="0.35"/>`,"skin statistics area"],[g(`M0,0H${W(U)}`,l.own,f*1.2),"wearer's own eyes, mouth"],[g(`M0,0H${W(U)}`,l.own,f*.7,M),`paint fades in ${W(c)} cm to here`]];j.forEach(([D,$],q)=>{y.push(H(b,X-N*(j.length-q),D,$))}),["Keep liner and lip lines","outside the dashed blue rims."].forEach((D,$)=>{y.push(E(t-b,X-N*(3-$),D,"end"))}),y.push(E(t*.25,t-b,"◂ person's RIGHT","middle",' font-weight="bold"'),E(t*.75,t-b,"person's LEFT ▸","middle",' font-weight="bold"'))}return`<svg xmlns="http://www.w3.org/2000/svg" width="${t}" height="${t}" viewBox="0 0 ${t} ${t}">${y.join("")}</svg>`},Sy=e=>`data:image/svg+xml;charset=utf-8,${encodeURIComponent(ui(e))}`,Ey=(e={})=>mo(ui(e),e.size??1024,"face texture guide"),Ay={skin:"#dcae92",brows:"#5b4034",lips:"#b4535e",sclera:"#f4f0ea",iris:"#3f2c22",mouth:"#3a1c1f",left:"#1d4ed8",right:"#c81e1e"},ru=263,vy=33,My="M0,0H0.28V0.78H0.9V1H0Z",yy="M0,0H0.6A0.3,0.28 0 0 1 0.6,0.56L0.95,1H0.66L0.36,0.6H0.26V1H0ZM0.26,0.2H0.58A0.1,0.08 0 0 1 0.58,0.36H0.26Z",wy=(e,t,n,a,s)=>e.replace(/([MLHVA])([^MLHVAZ]*)/g,(r,o,i)=>{const c=i.split(/[\s,]+/).filter(Boolean).map(Number),u=h=>W(t+h*a),l=h=>W(n+h*s);switch(o){case"H":return`H${u(c[0])}`;case"V":return`V${l(c[0])}`;case"A":return`A${W(c[0]*a)},${W(c[1]*s)} ${c[2]} ${c[3]} ${c[4]} ${u(c[5])},${l(c[6])}`;default:return`${o}${u(c[0])},${l(c[1])}`}}),_y=(e={})=>{const{size:t=1024}=e,n=Ay,a=(x,F,w="")=>`<path d="${x}" fill="${F}"${w}/>`,s=(x,F)=>st(x,F,t),r=[`<rect width="${t}" height="${t}" fill="${n.skin}"/>`];r.push(a(Mr(T.getFaceAtlasRegionTriangles("brows"),t),n.brows,' fill-opacity="0.85"'),a(Mr(T.getFaceAtlasRegionTriangles("lips"),t),n.lips),a(Mr(T.getFaceAtlasRegionTriangles("mouth"),t),n.mouth)),["negX","posX"].forEach(x=>{const F=T.FACE_ATLAS_EYE_RINGS[x];let w=0,k=0;F.forEach(N=>{w+=T.FACE_ATLAS_UVS[N*2]/F.length,k+=T.FACE_ATLAS_UVS[N*2+1]/F.length});const R=s(w,k),b=`side-test-eye-${x}`;r.push(`<clipPath id="${b}"><path d="${$n(F,t)}"/></clipPath>`,a($n(F,t),n.sclera),`<ellipse cx="${W(R.x)}" cy="${W(R.y)}" rx="${W(t*.028)}" ry="${W(t*.034)}" fill="${n.iris}" clip-path="url(#${b})"/>`)});const o=t*.1,i=t*.15,c=x=>Math.sign(x-.5)||1,u=(x,F,w,k)=>{const[R,b]=an(F),{x:N,y:P}=s(R+.02*c(R),b-.2);return a(wy(x,N-o/2,P-i/2,o,i),w,` id="${k}" fill-rule="evenodd"`)};r.push(u(My,ru,n.left,"person-left"),u(yy,vy,n.right,"person-right"));const l=c(an(ru)[0]),h=[un.browUpper,Iu(un.browUpper)].find(x=>c(an(x.landmarks[0])[0])===l),f=((h==null?void 0:h.landmarks)??[]).map(x=>an(x)[0]),p=x=>Math.abs(x-.5),m=f.reduce((x,F)=>p(F)<p(x)?F:x),E=f.reduce((x,F)=>p(F)>p(x)?F:x),S=.795,g=s(m,S),A=s(E+.03*l,S),v=t*.012,M=t*.035,y=A.x-l*M;return r.push(a(`M${W(g.x)},${W(g.y-v)}H${W(y)}V${W(A.y-M)}L${W(A.x)},${W(A.y)}L${W(y)},${W(A.y+M)}V${W(g.y+v)}H${W(g.x)}Z`,n.left,' id="person-left-arrow"')),`<svg xmlns="http://www.w3.org/2000/svg" width="${t}" height="${t}" viewBox="0 0 ${t} ${t}">${r.join("")}</svg>`};exports.FACE_ATLAS_MIRROR=T.FACE_ATLAS_MIRROR;exports.FACE_ATLAS_REGIONS=T.FACE_ATLAS_REGIONS;exports.FACE_ATLAS_SOURCE=T.FACE_ATLAS_SOURCE;exports.FACE_ATLAS_TRIANGLES=T.FACE_ATLAS_TRIANGLES;exports.FACE_ATLAS_UVS=T.FACE_ATLAS_UVS;exports.FACE_GAZE_CHANNELS=T.FACE_GAZE_CHANNELS;exports.FACE_MORPH_COUNT=T.FACE_MORPH_COUNT;exports.FACE_MORPH_NAMES=T.FACE_MORPH_NAMES;exports.FACE_REGION_MASKS=T.FACE_REGION_MASKS;exports.FACE_RIG_FAST_MOVE_CM=T.FACE_RIG_FAST_MOVE_CM;exports.FACE_RIG_FAST_TURN_DEG=T.FACE_RIG_FAST_TURN_DEG;exports.HEAD_OCCLUDER_DEFAULT_OPACITY=T.HEAD_OCCLUDER_DEFAULT_OPACITY;exports.HEAD_OCCLUDER_DEFAULT_POSITION=T.HEAD_OCCLUDER_DEFAULT_POSITION;exports.HEAD_OCCLUDER_DEFAULT_SCALE=T.HEAD_OCCLUDER_DEFAULT_SCALE;exports.HEAD_OCCLUDER_DEFAULT_SMOOTHING=T.HEAD_OCCLUDER_DEFAULT_SMOOTHING;exports.HEAD_OCCLUDER_RENDER_ORDER=T.HEAD_OCCLUDER_RENDER_ORDER;exports.HEAD_OCCLUDER_V2_PATH=T.HEAD_OCCLUDER_V2_PATH;exports.HEAD_OCCLUDER_V3_PATH=T.HEAD_OCCLUDER_V3_PATH;exports.HeadOccluder=T.HeadOccluder;exports.MADE_UP_CAMERA_LAYER=T.MADE_UP_CAMERA_LAYER;exports.NECK_BUST_TORSO_POSITION=T.NECK_BUST_TORSO_POSITION;exports.NECK_OCCLUDER_BUST_PATH=T.NECK_OCCLUDER_BUST_PATH;exports.NECK_OCCLUDER_FOLLOWS=T.NECK_OCCLUDER_FOLLOWS;exports.NECK_OCCLUDER_SHOULDER_TURN=T.NECK_OCCLUDER_SHOULDER_TURN;exports.NECK_OCCLUDER_TYPES=T.NECK_OCCLUDER_TYPES;exports.NeckOccluder=T.NeckOccluder;exports.SegmentationOverlay=T.SegmentationOverlay;exports.createFaceRigState=T.createFaceRigState;exports.faceMorphChannel=T.faceMorphChannel;exports.faceMorphRegion=T.faceMorphRegion;exports.feedTextureVersion=T.feedTextureVersion;exports.getFaceAtlasAttributes=T.getFaceAtlasAttributes;exports.getFaceAtlasRegionBounds=T.getFaceAtlasRegionBounds;exports.getFaceAtlasRegionIndices=T.getFaceAtlasRegionIndices;exports.getFaceAtlasRegionTriangles=T.getFaceAtlasRegionTriangles;exports.headOccluderUrl=T.headOccluderUrl;exports.neckBoneTwist=T.neckBoneTwist;exports.neckOccluderUrl=T.neckOccluderUrl;exports.recalibrateFaceRig=T.recalibrateFaceRig;exports.stepFaceRig=T.stepFaceRig;exports.FaceTrackMemory=ee.FaceTrackMemory;exports.clearSemanticMask=ee.clearSemanticMask;exports.createSemanticMask=ee.createSemanticMask;exports.DEFAULT_FACE_MIRROR_SETTINGS=O.DEFAULT_FACE_MIRROR_SETTINGS;exports.DEFAULT_FACE_SWAP_SETTINGS=O.DEFAULT_FACE_SWAP_SETTINGS;exports.DEFAULT_IRIS_EFFECT_SETTINGS=O.DEFAULT_IRIS_EFFECT_SETTINGS;exports.DEFAULT_LIP_EFFECT_SETTINGS=O.DEFAULT_LIP_EFFECT_SETTINGS;exports.FACE_MIRROR_SETTINGS_FIELDS=O.FACE_MIRROR_SETTINGS_FIELDS;exports.FACE_MIRROR_VARIANTS=O.FACE_MIRROR_VARIANTS;exports.FACE_MIRROR_VARIANT_LABELS=O.FACE_MIRROR_VARIANT_LABELS;exports.FACE_RETOUCH_DEFAULT_CONTROLS=O.FACE_RETOUCH_DEFAULT_CONTROLS;exports.FACE_RETOUCH_SETTINGS_FIELDS=O.FACE_RETOUCH_SETTINGS_FIELDS;exports.FACE_SWAP_PAINTED_FEATURE_SOFTNESS=O.FACE_SWAP_PAINTED_FEATURE_SOFTNESS;exports.FACE_SWAP_PRESETS=O.FACE_SWAP_PRESETS;exports.FACE_SWAP_PRESET_KEYS=O.FACE_SWAP_PRESET_KEYS;exports.FACE_SWAP_SETTINGS_FIELDS=O.FACE_SWAP_SETTINGS_FIELDS;exports.FACE_SWAP_SETTINGS_RANGES=O.FACE_SWAP_SETTINGS_RANGES;exports.FACE_SWAP_SOURCE_KINDS=O.FACE_SWAP_SOURCE_KINDS;exports.FaceRetouch=O.FaceRetouch;exports.IRIS_EFFECT_EYES=O.IRIS_EFFECT_EYES;exports.IRIS_EFFECT_MODES=O.IRIS_EFFECT_MODES;exports.IRIS_EFFECT_SETTINGS_FIELDS=O.IRIS_EFFECT_SETTINGS_FIELDS;exports.LIP_EFFECT_COLOR_MODES=O.LIP_EFFECT_COLOR_MODES;exports.LIP_EFFECT_GRADIENT_DIRECTIONS=O.LIP_EFFECT_GRADIENT_DIRECTIONS;exports.LIP_EFFECT_PRESETS=O.LIP_EFFECT_PRESETS;exports.LIP_EFFECT_PRESET_KEYS=O.LIP_EFFECT_PRESET_KEYS;exports.LIP_EFFECT_SETTINGS_FIELDS=O.LIP_EFFECT_SETTINGS_FIELDS;exports.MAKEUP_AUTO_SHADE_REGIONS=O.MAKEUP_AUTO_SHADE_REGIONS;exports.MAKEUP_FINISHES=O.MAKEUP_FINISHES;exports.MAKEUP_FINISH_DEFAULTS=O.MAKEUP_FINISH_DEFAULTS;exports.MAKEUP_REGIONS=O.MAKEUP_REGIONS;exports.MAKEUP_SHADES=O.MAKEUP_SHADES;exports.MAKEUP_SHADE_NAMES=O.MAKEUP_SHADE_NAMES;exports.MAKEUP_SIDES=O.MAKEUP_SIDES;exports.alphaMapOptions=O.alphaMapOptions;exports.blendModeOptions=O.blendModeOptions;exports.createLipTextureTransform=O.createLipTextureTransform;exports.defaultFaceSwapPreset=O.defaultFaceSwapPreset;exports.faceMirrorTransferSettings=O.faceMirrorTransferSettings;exports.isFaceMirrorVariant=O.isFaceMirrorVariant;exports.isFaceSwapPresetKey=O.isFaceSwapPresetKey;exports.isLipEffectPresetKey=O.isLipEffectPresetKey;exports.isMakeupShadeName=O.isMakeupShadeName;exports.materialTypeOptions=O.materialTypeOptions;exports.patchFaceMirrorSettings=O.patchFaceMirrorSettings;exports.patchFaceRetouchControls=O.patchFaceRetouchControls;exports.patchFaceSwapSettings=O.patchFaceSwapSettings;exports.patchIrisEffectSettings=O.patchIrisEffectSettings;exports.patchLipEffectSettings=O.patchLipEffectSettings;exports.resolveFaceMirrorSettings=O.resolveFaceMirrorSettings;exports.resolveFaceRetouchControls=O.resolveFaceRetouchControls;exports.resolveFaceSwapSettings=O.resolveFaceSwapSettings;exports.resolveIrisEffectSettings=O.resolveIrisEffectSettings;exports.resolveLipEffectSettings=O.resolveLipEffectSettings;exports.resolveMakeupShade=O.resolveMakeupShade;exports.shaderPresetOptions=O.shaderPresetOptions;exports.sideOptions=O.sideOptions;exports.supportsAutoMakeupShade=O.supportsAutoMakeupShade;exports.textureMapOptions=O.textureMapOptions;exports.CANONICAL_FACE_POSITIONS=V.CANONICAL_FACE_POSITIONS;exports.CANONICAL_HEAD_ANCHOR=V.CANONICAL_HEAD_ANCHOR;exports.CANONICAL_HEAD_FIT_DEFAULT_SMOOTHING=V.CANONICAL_HEAD_FIT_DEFAULT_SMOOTHING;exports.CANONICAL_RIGID_INDICES=V.CANONICAL_RIGID_INDICES;exports.CANONICAL_RIGID_LANDMARKS=V.CANONICAL_RIGID_LANDMARKS;exports.CANONICAL_RIGID_POINTS=V.CANONICAL_RIGID_POINTS;exports.CanonicalHeadFrame=V.CanonicalHeadFrame;exports.solveCanonicalHeadPose=V.solveCanonicalHeadPose;exports.useCanonicalHeadFit=V.useCanonicalHeadFit;exports.solveSimilarity=iu.solveSimilarity;exports.CANONICAL_FACE_LANDMARK_COUNT=K.CANONICAL_FACE_LANDMARK_COUNT;exports.CANONICAL_FACE_TRIANGLES=K.CANONICAL_FACE_TRIANGLES;exports.CANONICAL_FACE_UVS=K.CANONICAL_FACE_UVS;exports.FACE_SURFACE_RENDER_ORDER=le.FACE_SURFACE_RENDER_ORDER;exports.faceSurfaceBlending=le.faceSurfaceBlending;exports.markFaceSurface=le.markFaceSurface;exports.useFaceSurface=le.useFaceSurface;exports.LANDMARK_POSE_FIT_DEFAULT_SMOOTHING=Gt.LANDMARK_POSE_FIT_DEFAULT_SMOOTHING;exports.LANDMARK_POSE_FIT_SNAP_CM=Gt.LANDMARK_POSE_FIT_SNAP_CM;exports.stepLandmarkPoseSmoothing=Gt.stepLandmarkPoseSmoothing;exports.useLandmarkPoseFit=Gt.useLandmarkPoseFit;exports.SEMANTIC_SEGMENTATION_PRESETS=hd.SEMANTIC_SEGMENTATION_PRESETS;exports.CANONICAL_FACE_MESH_GEOMETRY_SPECS=oe.CANONICAL_FACE_MESH_GEOMETRY_SPECS;exports.CanonicalFaceMeshRenderer=oe.CanonicalFaceMeshRenderer;exports.DEFAULT_APPEARANCE=oe.DEFAULT_APPEARANCE;exports.DEFAULT_FACE_MESH_RENDERER=oe.DEFAULT_FACE_MESH_RENDERER;exports.DEFAULT_FACE_MESH_TRANSFORM=oe.DEFAULT_FACE_MESH_TRANSFORM;exports.DEFAULT_MASKING=oe.DEFAULT_MASKING;exports.FACE_MESH_ALPHA_MAPS=oe.FACE_MESH_ALPHA_MAPS;exports.FACE_MESH_BLEND_MODES=oe.FACE_MESH_BLEND_MODES;exports.FACE_MESH_MASK_TEXTURE_SOURCES=oe.FACE_MESH_MASK_TEXTURE_SOURCES;exports.FACE_MESH_MATERIAL_TYPES=oe.FACE_MESH_MATERIAL_TYPES;exports.FACE_MESH_SHADER_PRESETS=oe.FACE_MESH_SHADER_PRESETS;exports.FACE_MESH_SIDES=oe.FACE_MESH_SIDES;exports.FACE_MESH_TEXTURE_MAPS=oe.FACE_MESH_TEXTURE_MAPS;exports.FaceMeshMaterial=oe.FaceMeshMaterial;exports.FaceMeshRenderer=oe.FaceMeshRenderer;exports.blendModeIndices=oe.blendModeIndices;exports.canonicalFaceAlphaMaskUrl=oe.canonicalFaceAlphaMaskUrl;exports.canonicalFaceTextureStyle2Url=oe.canonicalFaceTextureStyle2Url;exports.canonicalFaceTextureUrl=oe.canonicalFaceTextureUrl;exports.mapFaceMeshRendererProps=oe.mapFaceMeshRendererProps;exports.mapFaceMeshRendererSettingsToProps=oe.mapFaceMeshRendererSettingsToProps;exports.parseCanonicalFaceModel=oe.parseCanonicalFaceModel;exports.resolveFaceMeshEyeVisibility=oe.resolveFaceMeshEyeVisibility;exports.resolveFaceMeshRendererSettings=oe.resolveFaceMeshRendererSettings;exports.supportsBlendMode=oe.supportsBlendMode;exports.supportsTexturePanel=oe.supportsTexturePanel;exports.useCanonicalFaceMesh=oe.useCanonicalFaceMesh;exports.FACE_ATLAS_STENCIL=de.FACE_ATLAS_STENCIL;exports.FACE_RETOUCH_RENDER_ORDER=de.FACE_RETOUCH_RENDER_ORDER;exports.MAKEUP_BLENDING=de.MAKEUP_BLENDING;exports.MAKEUP_RENDER_ORDER=de.MAKEUP_RENDER_ORDER;exports.DEFAULT_SEGMENTATION_OVERLAY_SETTINGS=tt.DEFAULT_SEGMENTATION_OVERLAY_SETTINGS;exports.SEGMENTATION_OVERLAY_BLEND_MODES=tt.SEGMENTATION_OVERLAY_BLEND_MODES;exports.SEGMENTATION_OVERLAY_SETTINGS_FIELDS=tt.SEGMENTATION_OVERLAY_SETTINGS_FIELDS;exports.SEMANTIC_MASK_LABELS=tt.SEMANTIC_MASK_LABELS;exports.parseOverlayLabels=tt.parseOverlayLabels;exports.patchSegmentationOverlaySettings=tt.patchSegmentationOverlaySettings;exports.resolveSegmentationOverlaySettings=tt.resolveSegmentationOverlaySettings;exports.FACE_REGION_LABELS=pn.FACE_REGION_LABELS;exports.PERSON_MASK_LABELS=pn.PERSON_MASK_LABELS;exports.useFaceRegionMask=pn.useFaceRegionMask;exports.useHairMask=pn.useHairMask;exports.usePersonMask=pn.usePersonMask;exports.useSemanticSegmentationMask=pn.useSemanticSegmentationMask;exports.Blush=H0;exports.Brows=W0;exports.CANONICAL_LIP_UV_BOUNDS=dg;exports.Contour=z0;exports.DEFAULT_IRIS_EFFECT_RENDER_ORDER=Fu;exports.DEFAULT_LIP_EFFECT=xm;exports.DEFAULT_LIP_EFFECT_RENDER_ORDER=Wa;exports.DEFAULT_MAKEUP_DESIGN_SETTINGS=Fo;exports.DEFAULT_MAKEUP_SETTINGS=Xa;exports.Earrings=_d;exports.ExternalFaceMesh=Bv;exports.ExternalFaceMeshContext=ai;exports.Eyeliner=V0;exports.Eyeshadow=j0;exports.FACELESS_DEFAULTS=at;exports.FACELESS_FRAGMENT=zf;exports.FACELESS_FRAME_PRIORITY=Xf;exports.FACELESS_MAX_FACES=Yf;exports.FACELESS_REGIONS=Hf;exports.FACELESS_STYLES=CA;exports.FACE_ATLAS_ANCHORS=Fr;exports.FACE_ATLAS_GUIDE_COLORS=Ge;exports.FACE_ATLAS_POLYLINES=un;exports.FACE_ATLAS_POLYLINE_NAMES=bu;exports.FACE_AUTO_ALIGN_MAX=gp;exports.FACE_HEAD_FIT_RAMP=Ha;exports.FACE_HEAD_WIDTH_RATIO=Mp;exports.FACE_INSET_BOXES=on;exports.FACE_INSET_HOLD_MS=Gh;exports.FACE_INSET_PARTS=cS;exports.FACE_INSET_PLACEMENTS=vS;exports.FACE_INSET_RENDER_ORDER=zh;exports.FACE_LIQUIFY_DEFAULT_SMOOTHING=Bf;exports.FACE_LIQUIFY_FACE_HEIGHT=Br;exports.FACE_LIQUIFY_FADE=Of;exports.FACE_LIQUIFY_FAR_SIDE=yf;exports.FACE_LIQUIFY_FRAME_PRIORITY=Gf;exports.FACE_LIQUIFY_KINDS=qo;exports.FACE_LIQUIFY_KIND_CODE=Nt;exports.FACE_LIQUIFY_KIND_LIMITS=Xo;exports.FACE_LIQUIFY_MAX_FACES=$f;exports.FACE_LIQUIFY_MAX_OPS=hn;exports.FACE_LIQUIFY_MAX_WEIGHT=$a;exports.FACE_LIQUIFY_OP_FLOATS=Dt;exports.FACE_LIQUIFY_POINTS=ea;exports.FACE_LIQUIFY_PRESETS=Rf;exports.FACE_LIQUIFY_PRESET_NAMES=Lf;exports.FACE_LIQUIFY_RENDER_ORDER=Yo;exports.FACE_LIQUIFY_WEIGHT_EXPONENT=xf;exports.FACE_PHOTO_WARNINGS=qp;exports.FACE_PIERCINGS=Qr;exports.FACE_PIERCING_KINDS=eM;exports.FACE_PIERCING_NAMES=Gp;exports.FACE_PIN_PATCH_RADIUS=Ip;exports.FACE_PIN_TARGETS=bp;exports.FACE_REPROJECTION_FILL_REACH=Bo;exports.FACE_RESIDUAL_LENGTH=ni;exports.FACE_SKIN_PROBE=ve;exports.FACE_SKIN_PROBE_TIERS=bt;exports.FACE_SKIN_QUALITIES=Dd;exports.FACE_SKIN_STATS=re;exports.FACE_SKIN_STATS_GLSL=Pu;exports.FACE_SWAP_EACH_OTHER=vf;exports.FACE_SWAP_QUALITIES=xE;exports.FACE_TEXTURE_GUIDE_COLORS=rd;exports.FACE_TEXTURE_LAYOUTS=JS;exports.FACE_TEXTURE_RESOLUTIONS=Zr;exports.FACE_TRANSFER_FRAGMENT_SHADER=of;exports.FACE_TRANSFER_VERTEX_SHADER=rf;exports.FACE_UNWRAP_MIRROR=qh;exports.FACE_WARP_MAX_KEYS=Ot;exports.FaceAtlasLayer=Cr;exports.FaceExpressionController=qv;exports.FaceInset=wS;exports.FaceLiquify=xA;exports.FaceMirror=YM;exports.FaceMorph=MM;exports.FacePiercing=cM;exports.FaceReprojection=pM;exports.FaceReprojector=Ja;exports.FaceRig=yt;exports.FaceRigContext=io;exports.FaceSkinProbe=Bu;exports.FaceSurfaceOccluder=Hp;exports.FaceSwap=qM;exports.FaceTextureLayer=fn;exports.FaceTransfer=cf;exports.FaceWarp3D=rv;exports.Faceless=HA;exports.FacelessTexture=Vf;exports.HAIR_LOCK_DEFAULTS=On;exports.HAIR_LOCK_SPRING=pp;exports.HEAD_ATTACHMENT_POINTS=to;exports.HEAD_ATTACHMENT_POINT_NAMES=pd;exports.HairLock=xv;exports.HeadAttachment=gd;exports.HeadBinding=uv;exports.HeadBindingOccluder=wv;exports.Highlighter=K0;exports.IRIS_IMAGE_FRAGMENT=Mu;exports.IRIS_SHADER_FRAGMENT=vu;exports.IRIS_VERTEX_SHADER=oo;exports.IrisEffect=Cd;exports.LIP_EFFECT_FRAGMENT_SHADER=Yu;exports.LIP_EFFECT_VERTEX_SHADER=Xu;exports.LIP_UV_GUIDE_COLORS=kr;exports.LipEffect=sh;exports.LipEffectMaterial=nh;exports.LipEffects=Cg;exports.MAKEUP_DESIGN_SETTINGS_FIELDS=Yg;exports.MAKEUP_GLSL=fe;exports.MAKEUP_LOOKS=mh;exports.MAKEUP_LOOK_NAMES=dh;exports.MAKEUP_SETTINGS_FIELDS=Hg;exports.MAKEUP_SHAPES=yo;exports.MAKEUP_SHAPE_NAMES=Mo;exports.MAKEUP_SKIN_DEPTHS=Q0;exports.MAKEUP_SKIN_READY=Nh;exports.MAKEUP_SKIN_TONE=$e;exports.MAKEUP_UNDERTONES=J0;exports.MadeUpCamera=Lg;exports.MakeupDesign=Y0;exports.NECKLACE_SWING_DEFAULTS=up;exports.NECKLACE_SWING_NODES=lp;exports.Necklace=_v;exports.PinToFaceMesh=Dp;exports.SPRING_DEFAULTS=no;exports.SPRING_MAX_FRAME=fu;exports.SPRING_MAX_JUMP=pu;exports.SPRING_MAX_SUBSTEP=hu;exports.SPRING_SETTINGS_RANGES=yr;exports.SPRING_SWING_LENGTH=wr;exports.SpringChain=du;exports.SpringJoint=so;exports.SpringSwing=gu;exports.SpringSwingDriver=ro;exports.alignFaceFeatures=ns;exports.applyFaceLiquifyOp=Tf;exports.autoFaceModelAlignment=Sp;exports.bindFaceMesh=ta;exports.bindFaceModel=Ep;exports.bindFacePin=rs;exports.bindFaceReprojection=Ut;exports.bindFaceWarpDeformation=tp;exports.canonicalFaceFeatures=ei;exports.classifyMakeupSkinDepth=Rh;exports.classifyMakeupUndertone=bh;exports.compileExpressionInput=Fp;exports.computeAdaptiveVerticalFit=vv;exports.computeHeadBindingCubePose=cp;exports.computeHeadBindingDebugMetrics=yv;exports.computeHeadBindingShape=ip;exports.computeMakeupSkinTone=Oh;exports.computeUniversalHeadDepthOffset=Av;exports.computeUniversalOccluderScale=gv;exports.computeUniversalPitchOffsetY=Ev;exports.computeUniversalYawOffsetX=Sv;exports.createCanonicalFaceGeometry=ov;exports.createClosestPointSearch=Qa;exports.createExpressionOutputs=kp;exports.createExpressionState=qr;exports.createFaceAtlasGuideDataUrl=fg;exports.createFaceAtlasGuidePngBlob=pg;exports.createFaceAtlasGuideSvg=Jn;exports.createFaceAtlasMask=Xn;exports.createFaceAtlasMaskTexture=Ru;exports.createFaceAtlasPolylineGlsl=qd;exports.createFaceInsetFrame=Io;exports.createFaceLiquifyFrame=wf;exports.createFaceLiquifyPresence=Pf;exports.createFaceMorphLive=Zo;exports.createFaceMorphShape=Jf;exports.createFaceReprojectionUniforms=$o;exports.createFaceTexture=Jp;exports.createFaceTextureGuideDataUrl=Sy;exports.createFaceTextureGuidePngBlob=Ey;exports.createFaceTextureGuideSvg=ui;exports.createFaceTextureSideTestSvg=_y;exports.createFaceWarpGpuData=np;exports.createFaceWarpMesh=ep;exports.createFacelessMask=Kf;exports.createFacelessStretchMask=jf;exports.createFeatureWarp=sp;exports.createIrisImageMaterial=_u;exports.createIrisShaderMaterial=wu;exports.createIrisUniforms=Eu;exports.createLipEffectMaterial=So;exports.createLipUvGuideDataUrl=Eg;exports.createLipUvGuidePngBlob=Ag;exports.createLipUvGuideSvg=go;exports.createLockGeometry=hp;exports.createMakeupMaterial=kh;exports.deformFaceMesh=Vr;exports.detectFaceImage=li;exports.disposeFaceImageLandmarker=ci;exports.driveFaceModel=vp;exports.expressionFrame=Xr;exports.faceAtlasAnchorPosition=Vd;exports.faceAtlasMaskToRgba=zd;exports.faceAtlasUvToPixel=st;exports.faceHeadWidth=yp;exports.faceInsetAspect=bo;exports.faceLiquifyAmount=zr;exports.faceLiquifyBounds=kf;exports.faceLiquifyFalloff=Cf;exports.faceLiquifyLandmarkPoint=Ff;exports.faceLiquifySideVisibility=Hr;exports.faceLiquifyWarpSide=If;exports.facePinAnchorForFeed=ss;exports.faceReprojectionRegionEllipses=Go;exports.faceReprojectionRegionMask=Or;exports.faceTransferGain=QS;exports.faceUnwrapTexelsPerCm=Ho;exports.getFaceUnwrapMesh=pe;exports.getFaceUnwrapUvs=Hn;exports.getHeadAttachmentPoint=md;exports.getLipUvBounds=gn;exports.insertSwingPivots=mu;exports.isMakeupLookName=gh;exports.isMakeupShape=wo;exports.lipEffectDesignDecode=Lr;exports.lipUvToPixel=Ca;exports.measureFaceModelEarWidth=mp;exports.mirrorFaceAtlasPolyline=Iu;exports.mirrorFaceAtlasUv=rg;exports.mirrorFaceLandmarks=HS;exports.mirrorFacePiercingOffset=Bp;exports.mirrorFacePiercingPlacement=Yr;exports.nearestMakeupShades=Ih;exports.patchFaceReprojectionMaterial=zo;exports.patchMakeupDesignSettings=Ah;exports.patchMakeupSettings=_o;exports.planFaceDrive=Ap;exports.projectFacePinOnto=Up;exports.readFaceSkinStats=lo;exports.readLiveNumber=Mt;exports.readLiveRecord=Wo;exports.resetExpressions=Cp;exports.resetFaceLiquifyPresence=Uf;exports.resolveFaceLiquifyWarps=bf;exports.resolveFacePiercing=$p;exports.resolveFaceSourceMirror=Xh;exports.resolveHeadAttachmentPoint=qn;exports.resolveLipEffectFaceConfig=oh;exports.resolveMakeupDesignSettings=To;exports.resolveMakeupLook=zg;exports.resolveMakeupSettings=rt;exports.resolveSpringSettings=ao;exports.sampleFaceLiquify=VE;exports.sampleResidual=dp;exports.setMakeupDesignTexture=vh;exports.shapeExpressionValue=xp;exports.solveHeadBinding=ti;exports.stepExpressions=Tp;exports.stepFaceLiquifyPresence=Df;exports.stepFaceMorph=Zf;exports.stepFacePin=os;exports.stepFaceWarp3D=nv;exports.subdivideFaceUnwrap=Qo;exports.updateIrisUniforms=Au;exports.updateLipEffectMaterial=Eo;exports.updateMakeupMaterial=L0;exports.useExpressionValues=Lp;exports.useExternalFaceMesh=wp;exports.useFaceAtlasSurface=fo;exports.useFaceInsetTexture=Hh;exports.useFaceRig=ge;exports.useFaceSkin=Va;exports.useFaceTexture=Zp;exports.useFacelessTexture=Qf;exports.useLipDesignTextures=Ao;exports.useLipEffectMaterial=th;exports.useLiveFaceTexture=jn;exports.useMadeUpCamera=lh;exports.useMadeUpCameraTexture=qa;exports.useMakeupSkinTone=iS;exports.writeFaceFacing=Uo;exports.writeFaceInsetFrame=No;exports.writeFaceLiquifyFrame=_f;exports.writeFaceLiquifyOps=Nf;exports.writeFaceMorphLive=Jo;exports.writeFaceReprojectionLayoutUv=jh;exports.writeFaceUnwrapFrame=Do;exports.writeFaceWarpLiveTexels=ap;exports.writeLock=fp;
|