@vincentt-xr/sdk 2.0.0-alpha.7 → 2.0.0-alpha.8
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 +1109 -13
- package/dist/{DebuggerUI-BjOMr8q_.js → DebuggerUI-C-ldiozL.js} +1 -1
- package/dist/{DebuggerUI-B6bP6P9r.cjs → DebuggerUI-CWX5EtQv.cjs} +1 -1
- package/dist/FaceMeshRenderer-BEEXZwS6.cjs +158 -0
- package/dist/FaceMeshRenderer-UuH5sTXG.js +1322 -0
- package/dist/FaceRetouch-C7h7x9kd.js +683 -0
- package/dist/FaceRetouch-DqftT26Y.cjs +134 -0
- package/dist/GLTFLoader-C5q63sKO.js +1633 -0
- package/dist/GLTFLoader-Cb_CRwmG.cjs +1 -0
- package/dist/SegmentationOverlay-DQuW3dsc.js +133 -0
- package/dist/SegmentationOverlay-aWVod8Kl.cjs +1 -0
- package/dist/assets/cache.d.ts +99 -0
- package/dist/assets/estimate.d.ts +11 -0
- package/dist/assets/index.d.ts +7 -0
- package/dist/assets/loaders.d.ts +28 -0
- package/dist/assets/react.d.ts +33 -0
- package/dist/calibration/calibration.d.ts +70 -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/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/BodyTracker/index.d.ts +9 -0
- package/dist/components/FaceMesh/canonical/CanonicalFaceMeshRenderer.d.ts +33 -3
- package/dist/components/FaceMesh/canonical/parseCanonicalFaceModel.d.ts +12 -0
- package/dist/components/FaceMesh/canonical/shaders.d.ts +1 -1
- package/dist/components/FaceMesh/index.d.ts +1 -1
- package/dist/components/GestureListener/index.d.ts +11 -0
- package/dist/components/HandTracker/index.d.ts +10 -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/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 +7 -1
- package/dist/components/LipEffect/LipEffectMaterial.d.ts +43 -7
- package/dist/components/LipEffect/LipEffects.d.ts +9 -0
- package/dist/components/LipEffect/defaults.d.ts +27 -4
- package/dist/components/LipEffect/index.d.ts +11 -3
- package/dist/components/LipEffect/settings.d.ts +271 -0
- package/dist/components/LipEffect/types.d.ts +56 -9
- package/dist/components/LipEffect/useLipDesignTextures.d.ts +11 -0
- package/dist/components/LipEffect/uvGuide.d.ts +59 -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/XRProvider/index.d.ts +16 -2
- 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 +3 -0
- package/dist/constants/index.d.ts +4 -1
- package/dist/contexts-CO0sd4JQ.cjs +1 -0
- package/dist/{contexts-ByhzppYl.js → contexts-FzlnnMYD.js} +252 -246
- package/dist/coordinates/feed.d.ts +52 -0
- package/dist/coordinates/index.d.ts +5 -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/gesture-settings/index.d.ts +14 -0
- package/dist/debug-ui/holistic-tracker-settings/index.d.ts +16 -0
- package/dist/debug-ui/index.d.ts +14 -0
- 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.cjs +1 -1
- package/dist/debug-ui/media-source.js +1 -1
- package/dist/debug-ui/product-hotspots/index.d.ts +24 -0
- package/dist/debug-ui/segmentation-overlay-settings/index.d.ts +12 -0
- package/dist/debug-ui/xr-diagnostics/index.d.ts +25 -0
- package/dist/debug-ui.cjs +3 -3
- package/dist/debug-ui.js +2057 -1687
- package/dist/detector-K8aej4MB.js +59 -0
- package/dist/detector-ijypGtse.cjs +1 -0
- package/dist/entries/core.d.ts +18 -1
- package/dist/entries/face-effects.d.ts +11 -3
- package/dist/entries/low-level.d.ts +22 -3
- package/dist/entries/product.d.ts +11 -0
- package/dist/entries/tracking.d.ts +24 -1
- package/dist/face-effects.cjs +155 -1
- package/dist/face-effects.js +1134 -2197
- package/dist/gestures/definitions.d.ts +85 -0
- package/dist/gestures/detector.d.ts +87 -0
- package/dist/gestures/index.d.ts +8 -0
- package/dist/gestures/measures.d.ts +101 -0
- package/dist/gestures/settings.d.ts +49 -0
- package/dist/{getFaceInfo-C4QpCQIY.js → getFaceInfo-BkZfaQs-.js} +5 -5
- package/dist/{getFaceInfo-fA1bFBub.cjs → getFaceInfo-ahPxQFGu.cjs} +1 -1
- package/dist/hooks/selectors.d.ts +68 -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/useGesture.d.ts +32 -0
- package/dist/hooks/useIrisTracking.d.ts +45 -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--RgGzZ6X.cjs +47 -0
- package/dist/{index-VJ0SJwmG.js → index-CHVbH0hz.js} +4 -4
- package/dist/index-CeVkgsag.cjs +1 -0
- package/dist/index-CnGox6Xr.js +3054 -0
- package/dist/{index-ByoNj0QP.js → index-CsUdQ-pn.js} +113 -111
- package/dist/{index-BjmTe9eM.cjs → index-DKBAh6hV.cjs} +1 -1
- package/dist/index-DsZwTfG0.cjs +1 -0
- package/dist/index-Dw6tj2Mi.js +144 -0
- package/dist/index-OCPjOaeP.cjs +1 -0
- package/dist/{index-DXT3WccE.js → index-s9pF4zkG.js} +1065 -1101
- package/dist/internal-BYza1h8_.cjs +1 -0
- package/dist/{internal-Dmk1cTXq.js → internal-vsfNQycj.js} +15 -16
- package/dist/internal.cjs +1 -1
- package/dist/internal.js +2 -2
- package/dist/iris/compute.d.ts +25 -0
- package/dist/iris/index.d.ts +4 -0
- package/dist/iris/lead.d.ts +19 -0
- package/dist/iris/types.d.ts +87 -0
- package/dist/landmarkMask-CbTFzBYG.js +224 -0
- package/dist/landmarkMask-u7es2k4X.cjs +1 -0
- package/dist/low-level.cjs +1 -1
- package/dist/low-level.js +1085 -634
- package/dist/main.cjs +1 -1
- package/dist/main.js +1519 -465
- package/dist/measures-9dQPdw96.js +154 -0
- package/dist/measures-KfJzpvod.cjs +1 -0
- package/dist/models/Base/index.d.ts +49 -0
- package/dist/models/Body/index.d.ts +1 -1
- package/dist/models/Face/index.d.ts +1 -1
- package/dist/models/Hand/GestureTracking.d.ts +1 -1
- package/dist/models/Hand/HandTracking.d.ts +1 -1
- package/dist/models/Holistic/index.d.ts +49 -0
- package/dist/models/Holistic/result.d.ts +68 -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/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-C0Dlhh9Z.js +365 -0
- package/dist/providers-YNwkmNeK.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/{renderGroups-KZk6eRiY.js → renderGroups-CN1cGFUo.js} +1 -1
- package/dist/{renderGroups-80H3DpTl.cjs → renderGroups-O4KmaMl9.cjs} +1 -1
- package/dist/renderPasses-Cg-zqmEz.cjs +21 -0
- package/dist/renderPasses-NnKZVfBy.js +1460 -0
- package/dist/scene-object.cjs +1 -1
- package/dist/scene-object.js +2 -2
- package/dist/screenTransform-BenfCtZt.js +44 -0
- package/dist/screenTransform-BiXdpVf0.cjs +1 -0
- package/dist/segmentation-9PhSvc-R.cjs +1 -0
- package/dist/segmentation-CeOTKemr.js +5 -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 +46 -0
- package/dist/selectors-C5G1PMYL.js +195 -0
- package/dist/selectors-Du_PsVnW.cjs +1 -0
- package/dist/{session-CpkiK5YA.cjs → session-BBr0yN8h.cjs} +7 -7
- package/dist/{session-DLFN_VII.js → session-Cy0m7l7-.js} +76 -76
- package/dist/settings-DRR7-snV.cjs +1 -0
- package/dist/settings-aQk845NJ.js +73 -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 +1 -1
- package/dist/tracking.js +1056 -383
- package/dist/types/compositor.d.ts +21 -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 +27 -2
- package/dist/types/segmentation.d.ts +19 -0
- package/dist/types/session.d.ts +41 -3
- package/dist/useFaceInfo-Blf7FCu3.js +303 -0
- package/dist/useFaceInfo-C5mO8NQY.cjs +1 -0
- package/dist/useXRCapabilities-B1R2ghy-.cjs +1 -0
- package/dist/useXRCapabilities-C68v__wB.js +30 -0
- package/dist/utils/fns.d.ts +6 -3
- package/dist/utils/integrity.d.ts +4 -1
- package/dist/utils/updateThrottle.d.ts +2 -0
- package/dist/utils/useStableUniforms.d.ts +18 -0
- package/docs/api/adaptive-quality.mdx +104 -0
- package/docs/api/asset-lifecycle.mdx +78 -0
- package/docs/api/camera-permission.mdx +142 -0
- package/docs/api/coordinate-spaces.mdx +165 -0
- package/docs/api/cross-camera.mdx +88 -0
- package/docs/api/diagnostics-calibration.mdx +97 -0
- package/docs/api/face-effects.mdx +6 -0
- package/docs/api/face-mesh.mdx +4 -2
- package/docs/api/gestures.mdx +173 -0
- package/docs/api/holistic-tracker.mdx +159 -0
- package/docs/api/iris-tracking.mdx +242 -0
- package/docs/api/multi-subject.mdx +95 -0
- package/docs/api/person-cutout.mdx +136 -0
- package/docs/api/product-ar.mdx +111 -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 +23 -1
- package/docs/examples/lip-shaders.mdx +224 -0
- package/docs/guides/lip-effect-textures.mdx +292 -0
- package/docs/guides/lip-uv-template.png +0 -0
- package/docs/guides/lip-uv-template.svg +1 -0
- package/package.json +13 -1
- 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/contexts-Dr62It_K.cjs +0 -1
- package/dist/index-9dlAQAhy.js +0 -1462
- package/dist/index-BpEf2BBb.cjs +0 -1
- package/dist/index-CyUUurQT.cjs +0 -1
- package/dist/index-DCiMbxC3.cjs +0 -1
- package/dist/index-DpI-qo5X.cjs +0 -17
- package/dist/index-DyVF4vEW.js +0 -111
- 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/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
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Lip Shader Examples"
|
|
3
|
+
description: "Custom material factories for LipEffect: animated gloss, noise texture, iridescence, and a time-based shimmer."
|
|
4
|
+
sidebarTitle: "Lip Shaders"
|
|
5
|
+
icon: "wand-magic-sparkles"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
{/* Generated by scripts/generate-lip-shader-docs.mjs from example/src/pages/LipEffect/customMaterials.tsx. Edit the source, then re-run. */}
|
|
9
|
+
|
|
10
|
+
`LipEffect`'s `material` prop accepts a factory. It receives a
|
|
11
|
+
`LipEffectMaterialContext` and returns a material node or a three.js material
|
|
12
|
+
instance. These four examples share one component shell and differ only in
|
|
13
|
+
their fragment shader. They are live on the example playground's `/lip-effect`
|
|
14
|
+
page under the material picker; the source is
|
|
15
|
+
`example/src/pages/LipEffect/customMaterials.tsx`.
|
|
16
|
+
|
|
17
|
+
## What every example relies on
|
|
18
|
+
|
|
19
|
+
- `LIP_EFFECT_VERTEX_SHADER` from `@vincentt-xr/sdk/face-effects` provides
|
|
20
|
+
`vUv` (canonical UV), `vFaceUv` (live camera UV), `vLipEdge` (0 at the outer
|
|
21
|
+
ring, 1 at the mouth line), `vNormal` and `vViewDir`.
|
|
22
|
+
- One `uniforms` object per material, created with `useMemo` and mutated on
|
|
23
|
+
each render. three.js binds the uniforms object when the program compiles,
|
|
24
|
+
so a new object per render would be ignored.
|
|
25
|
+
- `useFrame` advances `uTime` for the animated looks.
|
|
26
|
+
- The stencil test follows `context.maskMode`: `stencilWrite` must be true for
|
|
27
|
+
three.js to run the comparison at all, and the keep-ops stop the material
|
|
28
|
+
from altering the mouth stencil it tests against.
|
|
29
|
+
- Coverage is design alpha × opacity × a feather from `vLipEdge`, read from
|
|
30
|
+
`context.settings`, so the panel controls still apply.
|
|
31
|
+
|
|
32
|
+
```glsl
|
|
33
|
+
const COMMON_HEAD = `
|
|
34
|
+
uniform sampler2D cameraTexture;
|
|
35
|
+
uniform sampler2D designTexture;
|
|
36
|
+
uniform float useDesign;
|
|
37
|
+
uniform vec3 tint;
|
|
38
|
+
uniform float opacity;
|
|
39
|
+
uniform float edgeSoftness;
|
|
40
|
+
uniform float uTime;
|
|
41
|
+
varying vec2 vFaceUv;
|
|
42
|
+
varying vec2 vUv;
|
|
43
|
+
varying float vLipEdge;
|
|
44
|
+
varying vec3 vNormal;
|
|
45
|
+
varying vec3 vViewDir;
|
|
46
|
+
|
|
47
|
+
float hash(vec2 p) {
|
|
48
|
+
return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453123);
|
|
49
|
+
}
|
|
50
|
+
float noise(vec2 p) {
|
|
51
|
+
vec2 i = floor(p);
|
|
52
|
+
vec2 f = fract(p);
|
|
53
|
+
f = f * f * (3.0 - 2.0 * f);
|
|
54
|
+
return mix(
|
|
55
|
+
mix(hash(i), hash(i + vec2(1.0, 0.0)), f.x),
|
|
56
|
+
mix(hash(i + vec2(0.0, 1.0)), hash(i + vec2(1.0, 1.0)), f.x),
|
|
57
|
+
f.y
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
float coverage() {
|
|
61
|
+
vec4 design = mix(vec4(1.0), texture2D(designTexture, vUv), useDesign);
|
|
62
|
+
float fade = smoothstep(0.0, max(edgeSoftness, 1e-4), vLipEdge);
|
|
63
|
+
return design.a * opacity * fade;
|
|
64
|
+
}
|
|
65
|
+
vec3 facing() {
|
|
66
|
+
vec3 n = normalize(vNormal);
|
|
67
|
+
return gl_FrontFacing ? n : -n;
|
|
68
|
+
}
|
|
69
|
+
`;
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Animated gloss
|
|
73
|
+
|
|
74
|
+
The key light orbits, sweeping a pulsing highlight across the lips.
|
|
75
|
+
|
|
76
|
+
````glsl
|
|
77
|
+
void main() {
|
|
78
|
+
vec3 base = texture2D(cameraTexture, vFaceUv).rgb;
|
|
79
|
+
// The key light orbits slowly, so the highlight sweeps across the lips.
|
|
80
|
+
vec3 light = normalize(vec3(sin(uTime * 0.8), 0.6, cos(uTime * 0.8) * 0.5 + 0.8));
|
|
81
|
+
vec3 h = normalize(light + normalize(vViewDir));
|
|
82
|
+
float specular = pow(max(dot(facing(), h), 0.0), 48.0);
|
|
83
|
+
float pulse = 0.75 + 0.25 * sin(uTime * 2.0);
|
|
84
|
+
vec3 painted = tint * (0.6 + 0.8 * dot(base, vec3(0.333)));
|
|
85
|
+
float c = coverage();
|
|
86
|
+
gl_FragColor = vec4(mix(base, painted, c) + specular * pulse * c, c);
|
|
87
|
+
#include <colorspace_fragment>
|
|
88
|
+
}```
|
|
89
|
+
|
|
90
|
+
## Noise texture
|
|
91
|
+
|
|
92
|
+
Value noise breaks up the paint and a sparse hash adds glitter grains. No image
|
|
93
|
+
texture is needed.
|
|
94
|
+
|
|
95
|
+
```glsl
|
|
96
|
+
void main() {
|
|
97
|
+
vec3 base = texture2D(cameraTexture, vFaceUv).rgb;
|
|
98
|
+
// Fine value noise breaks up the paint; a sparse hash adds glitter grains.
|
|
99
|
+
float grain = noise(vUv * 420.0);
|
|
100
|
+
float glitter = step(0.985, hash(floor(vUv * 900.0)));
|
|
101
|
+
vec3 painted = tint * (0.75 + 0.5 * grain) + glitter * 0.6;
|
|
102
|
+
painted *= 0.5 + dot(base, vec3(0.333));
|
|
103
|
+
float c = coverage();
|
|
104
|
+
gl_FragColor = vec4(mix(base, painted, c), c);
|
|
105
|
+
#include <colorspace_fragment>
|
|
106
|
+
}```
|
|
107
|
+
|
|
108
|
+
## Iridescence
|
|
109
|
+
|
|
110
|
+
A cosine palette driven by the viewing angle (fresnel) and the band position,
|
|
111
|
+
drifting slowly over time.
|
|
112
|
+
|
|
113
|
+
```glsl
|
|
114
|
+
vec3 palette(float t) {
|
|
115
|
+
return 0.5 + 0.5 * cos(6.28318 * (vec3(1.0, 1.0, 1.0) * t + vec3(0.0, 0.33, 0.67)));
|
|
116
|
+
}
|
|
117
|
+
void main() {
|
|
118
|
+
vec3 base = texture2D(cameraTexture, vFaceUv).rgb;
|
|
119
|
+
vec3 n = facing();
|
|
120
|
+
vec3 v = normalize(vViewDir);
|
|
121
|
+
// Hue shifts with the viewing angle (fresnel) and drifts slowly with time.
|
|
122
|
+
float fresnel = pow(1.0 - max(dot(n, v), 0.0), 1.5);
|
|
123
|
+
vec3 sheen = palette(fresnel * 1.2 + vLipEdge * 0.25 + uTime * 0.05);
|
|
124
|
+
vec3 painted = mix(tint, sheen, 0.55 + 0.45 * fresnel) * (0.6 + 0.8 * dot(base, vec3(0.333)));
|
|
125
|
+
vec3 h = normalize(vec3(0.3, 0.6, 1.0) + v);
|
|
126
|
+
float specular = pow(max(dot(n, h), 0.0), 64.0) * 0.8;
|
|
127
|
+
float c = coverage();
|
|
128
|
+
gl_FragColor = vec4(mix(base, painted, c) + specular * c, c);
|
|
129
|
+
#include <colorspace_fragment>
|
|
130
|
+
}```
|
|
131
|
+
|
|
132
|
+
## Time-based shimmer
|
|
133
|
+
|
|
134
|
+
Per-cell twinkling grains with a slow bright band moving across the lips.
|
|
135
|
+
|
|
136
|
+
```glsl
|
|
137
|
+
void main() {
|
|
138
|
+
vec3 base = texture2D(cameraTexture, vFaceUv).rgb;
|
|
139
|
+
// Twinkling grains: each cell blinks on its own phase; a bright band sweeps across.
|
|
140
|
+
vec2 cell = floor(vUv * 520.0);
|
|
141
|
+
float seed = hash(cell);
|
|
142
|
+
float twinkle = 0.5 + 0.5 * sin(uTime * 6.0 + seed * 60.0);
|
|
143
|
+
float sparkle = smoothstep(0.96, 1.0, seed * twinkle);
|
|
144
|
+
float band = smoothstep(0.08, 0.0, abs(fract(vUv.x * 2.5 - uTime * 0.25) - 0.5));
|
|
145
|
+
vec3 painted = tint * (0.7 + 0.6 * dot(base, vec3(0.333))) + vec3(sparkle) + band * 0.25;
|
|
146
|
+
float c = coverage();
|
|
147
|
+
gl_FragColor = vec4(mix(base, painted, c), c);
|
|
148
|
+
#include <colorspace_fragment>
|
|
149
|
+
}```
|
|
150
|
+
|
|
151
|
+
## The factory component
|
|
152
|
+
|
|
153
|
+
```tsx
|
|
154
|
+
/** One factory component for every example; the shader key picks the look. */
|
|
155
|
+
export const CustomLipShader = ({
|
|
156
|
+
context,
|
|
157
|
+
shader,
|
|
158
|
+
}: {
|
|
159
|
+
context: LipEffectMaterialContext;
|
|
160
|
+
shader: CustomLipShaderKey;
|
|
161
|
+
}) => {
|
|
162
|
+
// One uniforms object for the material's lifetime; values are mutated.
|
|
163
|
+
const uniforms = useMemo(
|
|
164
|
+
() => ({
|
|
165
|
+
cameraTexture: { value: null as THREE.Texture | null },
|
|
166
|
+
designTexture: { value: null as THREE.Texture | null },
|
|
167
|
+
useDesign: { value: 0 },
|
|
168
|
+
tint: { value: new THREE.Color() },
|
|
169
|
+
opacity: { value: 1 },
|
|
170
|
+
edgeSoftness: { value: 0.12 },
|
|
171
|
+
uTime: { value: 0 },
|
|
172
|
+
}),
|
|
173
|
+
[],
|
|
174
|
+
);
|
|
175
|
+
uniforms.cameraTexture.value = context.cameraTexture;
|
|
176
|
+
uniforms.designTexture.value = context.designTexture;
|
|
177
|
+
uniforms.useDesign.value = context.designTexture ? 1 : 0;
|
|
178
|
+
uniforms.tint.value.set(context.settings.color);
|
|
179
|
+
uniforms.opacity.value = context.settings.opacity;
|
|
180
|
+
uniforms.edgeSoftness.value = context.settings.edgeSoftness;
|
|
181
|
+
useFrame((_, delta) => {
|
|
182
|
+
uniforms.uTime.value += delta;
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
return (
|
|
186
|
+
<shaderMaterial
|
|
187
|
+
key={shader}
|
|
188
|
+
uniforms={uniforms}
|
|
189
|
+
vertexShader={LIP_EFFECT_VERTEX_SHADER}
|
|
190
|
+
fragmentShader={SHADERS[shader]}
|
|
191
|
+
transparent
|
|
192
|
+
side={THREE.DoubleSide}
|
|
193
|
+
depthWrite={false}
|
|
194
|
+
toneMapped={false}
|
|
195
|
+
// The stencil test only runs while stencilWrite is true; keep-ops make
|
|
196
|
+
// it a pure comparison against the mouth stencil, writing nothing back.
|
|
197
|
+
stencilWrite
|
|
198
|
+
stencilRef={1}
|
|
199
|
+
stencilFunc={
|
|
200
|
+
context.maskMode === "outer-and-inner-lips"
|
|
201
|
+
? THREE.NotEqualStencilFunc
|
|
202
|
+
: THREE.AlwaysStencilFunc
|
|
203
|
+
}
|
|
204
|
+
stencilFail={THREE.KeepStencilOp}
|
|
205
|
+
stencilZFail={THREE.KeepStencilOp}
|
|
206
|
+
stencilZPass={THREE.KeepStencilOp}
|
|
207
|
+
/>
|
|
208
|
+
);
|
|
209
|
+
};
|
|
210
|
+
````
|
|
211
|
+
|
|
212
|
+
Use it like any other factory:
|
|
213
|
+
|
|
214
|
+
```tsx
|
|
215
|
+
<LipEffect
|
|
216
|
+
preset="gloss"
|
|
217
|
+
material={(context) => <CustomLipShader context={context} shader="iridescence" />}
|
|
218
|
+
/>
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
To share one custom material across several faces, build a
|
|
222
|
+
`THREE.ShaderMaterial` yourself, update its uniforms in `useFrame`, and return
|
|
223
|
+
the instance from the factory (or pass it as `sharedMaterial`); the renderer
|
|
224
|
+
sets a material instance on the mesh directly, so several meshes can use it.
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Lip Effect Textures"
|
|
3
|
+
description: "How to author a design texture for LipEffect: the canvas contract, the lip UV template, orientation, mask modes, and the custom material context."
|
|
4
|
+
sidebarTitle: "Lip Effect Textures"
|
|
5
|
+
icon: "palette"
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
`LipEffect` (from `@vincentt-xr/sdk/face-effects`) paints a design texture onto
|
|
9
|
+
the lips of a tracked face. The texture lives in the **canonical face UV
|
|
10
|
+
atlas**, but only the lip triangles are ever sampled. Everything this page
|
|
11
|
+
describes is derived from the canonical mesh's own `uv` attribute: the mesh is
|
|
12
|
+
the design contract, not a hand-drawn diagram.
|
|
13
|
+
|
|
14
|
+
## The canvas contract
|
|
15
|
+
|
|
16
|
+
- **Square image, any resolution.** 1024×1024 or 2048×2048 is plenty; the lips
|
|
17
|
+
cover a small part of it. The layout is the same atlas as
|
|
18
|
+
`Canonical_Face_Color.png`.
|
|
19
|
+
- **Only the lip region is used.** The outer lip ring spans roughly
|
|
20
|
+
**x 38–62 %** and **y 65–74 %** of the image. Pixels outside the lip
|
|
21
|
+
triangles are never sampled, so leave them transparent or use them for notes.
|
|
22
|
+
- **Transparent means untouched skin.** The alpha channel drives the blend
|
|
23
|
+
(`design.a × opacity`). Soft edges in alpha give soft lip edges.
|
|
24
|
+
- **RGB is tinted by `color`.** At `intensity={1}` the design's RGB is
|
|
25
|
+
multiplied by `color`; at `intensity={0}` the design colours show as painted.
|
|
26
|
+
Paint white or light grey for a pure tint, or paint real colour and lower
|
|
27
|
+
`intensity`.
|
|
28
|
+
- **Image top is `v = 1`.** Textures load with `flipY`, so the top row of the
|
|
29
|
+
image is the top of the UV atlas and the upper lip sits above the lower lip
|
|
30
|
+
in the image, as you would expect.
|
|
31
|
+
|
|
32
|
+
## The lip UV template
|
|
33
|
+
|
|
34
|
+
<img
|
|
35
|
+
src="/guides/lip-uv-template.svg"
|
|
36
|
+
alt="Lip UV template generated from the canonical face mesh"
|
|
37
|
+
/>
|
|
38
|
+
|
|
39
|
+
The template is generated from `canonical_face_model.obj`:
|
|
40
|
+
|
|
41
|
+
- **Solid pink ring** — the outer lip ring (MediaPipe `FACEMESH_LIPS` outer
|
|
42
|
+
contour). This is the painted edge.
|
|
43
|
+
- **Dashed blue ring and blue fill** — the inner lip ring and the mouth
|
|
44
|
+
interior. In the default `outer-and-inner-lips` mask mode this area is cut
|
|
45
|
+
out, so teeth and tongue stay clean when the mouth opens.
|
|
46
|
+
- **Grey wireframe** — the lip triangles that are actually sampled.
|
|
47
|
+
- **Orientation labels** — image **left** is the subject's **right** lip corner.
|
|
48
|
+
|
|
49
|
+
Regenerate it after the canonical OBJ changes on the CDN; the script verifies
|
|
50
|
+
the download against the hash pinned in `lib/utils/integrity.ts`:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
pnpm dlx tsx scripts/generate-lip-uv-guide.ts --png
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Mirrored camera behaviour
|
|
57
|
+
|
|
58
|
+
The design is always mapped in the **subject's** frame: the left edge of the
|
|
59
|
+
lip region is the subject's right lip corner, whatever is on screen.
|
|
60
|
+
|
|
61
|
+
- With the **webcam**, the session mirrors the feed once (selfie view), so the
|
|
62
|
+
subject's right appears on **screen right**. The left side of your design
|
|
63
|
+
therefore lands on the right side of the screen.
|
|
64
|
+
- With **image or video sources**, nothing is mirrored, so the subject's right
|
|
65
|
+
(and the left side of your design) appears on **screen left**.
|
|
66
|
+
|
|
67
|
+
Do not add a second mirror in CSS, canvas, or a shader; see "Camera, layout,
|
|
68
|
+
mirror, and capture parity" in `GROUNDING.md`.
|
|
69
|
+
|
|
70
|
+
### Generating the guide at runtime
|
|
71
|
+
|
|
72
|
+
The same renderer is exported, so an editor or a debug panel can draw the guide
|
|
73
|
+
from the live mesh:
|
|
74
|
+
|
|
75
|
+
```tsx
|
|
76
|
+
import {
|
|
77
|
+
createLipUvGuideDataUrl,
|
|
78
|
+
createLipUvGuideSvg,
|
|
79
|
+
getLipUvBounds,
|
|
80
|
+
useCanonicalFaceMesh,
|
|
81
|
+
} from "@vincentt-xr/sdk/face-effects";
|
|
82
|
+
|
|
83
|
+
const mesh = useCanonicalFaceMesh();
|
|
84
|
+
const svg = mesh ? createLipUvGuideSvg(mesh, { size: 1024 }) : null;
|
|
85
|
+
const zoomed = mesh ? createLipUvGuideDataUrl(mesh, { region: "lips" }) : null;
|
|
86
|
+
const bounds = mesh ? getLipUvBounds(mesh) : null; // { minU, maxU, minV, maxV }
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Options: `size` (canvas pixels), `region` (`"canvas"` or `"lips"`),
|
|
90
|
+
`wireframe`, `labels`, `background`. `lipUvToPixel(u, v, size)` converts a UV
|
|
91
|
+
to image pixels with the `flipY` convention.
|
|
92
|
+
|
|
93
|
+
The example playground's `/lip-effect` page has a **Texture preview / UV
|
|
94
|
+
guide** toggle: it overlays the guide on the current design texture, shows a
|
|
95
|
+
zoomed crop of the lip region, and paints the template itself onto the tracked
|
|
96
|
+
lips so the labelled rings can be checked against a real mouth.
|
|
97
|
+
|
|
98
|
+
## Presets and material controls
|
|
99
|
+
|
|
100
|
+
`LipEffect` takes flat, serializable settings (`LipEffectSettings`). Start from
|
|
101
|
+
a preset and override what you need; explicit props always win over the preset:
|
|
102
|
+
|
|
103
|
+
```tsx
|
|
104
|
+
<LipEffect preset="matte" color="#8b2635" designTexture="/lips/matte.png" />
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
| Preset | Look |
|
|
108
|
+
| ---------- | --------------------------------------------------------------- |
|
|
109
|
+
| `lipstick` | Opaque colour with a soft highlight |
|
|
110
|
+
| `gloss` | Translucent colour with a strong, tight highlight |
|
|
111
|
+
| `matte` | Opaque, no highlight, heavy skin shading |
|
|
112
|
+
| `tint` | Sheer wash of colour that keeps the natural lip |
|
|
113
|
+
| `metallic` | Full-strength, tight gold-tinted highlight |
|
|
114
|
+
| `gradient` | Ombre: strong colour at the mouth line fading at the outer edge |
|
|
115
|
+
|
|
116
|
+
Controls: `color`, `opacity`, `intensity` (0 shows the design as painted, 1
|
|
117
|
+
multiplies it by `color`), `shading` (how much the camera's own lip light and
|
|
118
|
+
shadow show through), `gloss` and `roughness` (highlight amount and spread),
|
|
119
|
+
`highlightColor`, and `gradientColor` with `gradientAmount`. Without a
|
|
120
|
+
`designTexture` the lips are filled with `color`, so every preset works on its
|
|
121
|
+
own.
|
|
122
|
+
|
|
123
|
+
The `LipEffectSettingsPanel` from `@vincentt-xr/sdk/debug-ui` edits all of these
|
|
124
|
+
live, including the mask mode and the texture transform, and the `/lip-effect`
|
|
125
|
+
example page mounts it next to the design-texture picker.
|
|
126
|
+
|
|
127
|
+
## Procedural colour, edges, inner lip and split lips
|
|
128
|
+
|
|
129
|
+
- **Procedural colour.** Leave `designTexture` out, or set
|
|
130
|
+
`colorMode="solid"` to ignore one, and the lips are filled with `color`.
|
|
131
|
+
Add `gradientColor` with `gradientAmount` and pick `gradientDirection`:
|
|
132
|
+
`outward` runs from the mouth line to the outer edge, `vertical` and
|
|
133
|
+
`horizontal` span the lip box.
|
|
134
|
+
- **Edge softness.** `edgeSoftness` feathers the outer lip boundary as a
|
|
135
|
+
fraction of the lip band (default `0.12`; `0` is a hard polygon edge). It
|
|
136
|
+
uses the mesh's own band position, so it follows the tracked lip shape.
|
|
137
|
+
- **Inner lip.** `innerLipColor` with `innerLipAmount` tints the inner part of
|
|
138
|
+
the lips next to the mouth line; `innerLipWidth` sets how far out it reaches.
|
|
139
|
+
In `outer-lips` mask mode the same tint fills the mouth interior.
|
|
140
|
+
- **Separate lower lip.** Turn on `splitLips` to give the lower lip its own
|
|
141
|
+
`lowerLipColor` and `lowerLipOpacity`, and pass `lowerDesignTexture` for a
|
|
142
|
+
separate texture (it falls back to `designTexture`). The split happens at the
|
|
143
|
+
mouth line of the canonical UV atlas with a thin blend at the corners.
|
|
144
|
+
|
|
145
|
+
## Texture transform
|
|
146
|
+
|
|
147
|
+
A design that does not line up can be fitted without repainting:
|
|
148
|
+
|
|
149
|
+
| Setting | Effect |
|
|
150
|
+
| ---------------------------------- | --------------------------------------------------------------------------------------------- |
|
|
151
|
+
| `textureScaleX`, `textureScaleY` | Multiplier about the lip centre; `2` makes the design twice as large |
|
|
152
|
+
| `textureOffsetX`, `textureOffsetY` | Fraction of the lip region's width/height; `0.5` moves half a lip width (positive y moves up) |
|
|
153
|
+
| `textureRotation` | Degrees, counter-clockwise as seen on the face |
|
|
154
|
+
| `textureFlipX`, `textureFlipY` | Mirror across the lip centre |
|
|
155
|
+
|
|
156
|
+
The transform is applied to the sampled UV, so the gradient and the mask are
|
|
157
|
+
unaffected. `createLipTextureTransform(settings, bounds)` returns the same
|
|
158
|
+
`Matrix3` the shader uses if a custom material wants it.
|
|
159
|
+
|
|
160
|
+
## Downloading the template
|
|
161
|
+
|
|
162
|
+
The `/lip-effect` page has **Download SVG** and **Download PNG** buttons that
|
|
163
|
+
export the guide at 2048 px straight from the loaded mesh. In code,
|
|
164
|
+
`createLipUvGuideSvg(mesh, { size })` returns the SVG string and
|
|
165
|
+
`createLipUvGuidePngBlob(mesh, { size })` resolves to a PNG `Blob` (browser
|
|
166
|
+
only). The shipped copies are `docs/guides/lip-uv-template.svg` and
|
|
167
|
+
`docs/guides/lip-uv-template.png`.
|
|
168
|
+
|
|
169
|
+
## Mask modes
|
|
170
|
+
|
|
171
|
+
```tsx
|
|
172
|
+
<LipEffect designTexture="/lips/gloss.png" maskMode="outer-and-inner-lips" />
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
- `outer-and-inner-lips` (default) — paint the lip surface only. The mouth
|
|
176
|
+
interior writes the shared stencil buffer and the lip material skips it.
|
|
177
|
+
- `outer-lips` — paint everything inside the outer ring, mouth interior
|
|
178
|
+
included.
|
|
179
|
+
|
|
180
|
+
## Several faces and performance
|
|
181
|
+
|
|
182
|
+
`LipEffects` renders one lip effect per face slot. Pass one config for every
|
|
183
|
+
face or a picker per face:
|
|
184
|
+
|
|
185
|
+
```tsx
|
|
186
|
+
<LipEffects maxFaces={2} faces={{ preset: "gloss", designTexture: "/lips/gloss.png" }} />
|
|
187
|
+
<LipEffects
|
|
188
|
+
maxFaces={2}
|
|
189
|
+
faces={(faceIndex) =>
|
|
190
|
+
faceIndex === 0 ? { preset: "matte", color: "#8b2635" } : { preset: "gloss" }
|
|
191
|
+
}
|
|
192
|
+
/>
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
With a single config the faces share one built-in material. The material is a
|
|
196
|
+
plain three.js object underneath: `useLipEffectMaterial(inputs)` returns one you
|
|
197
|
+
can pass as `sharedMaterial` to any number of `LipEffect`s, or return from a
|
|
198
|
+
`material` factory. `maxUpdateFps` caps how often the lip mesh follows the
|
|
199
|
+
landmarks, and `<XRProvider perf={{ targetFps, camRes }}>` lowers the tracking
|
|
200
|
+
rate and the analysed camera resolution for the whole session.
|
|
201
|
+
|
|
202
|
+
## Custom materials
|
|
203
|
+
|
|
204
|
+
`material` accepts a React material node or a factory. The factory receives a
|
|
205
|
+
stable context and is called once per lip geometry group (plus the mouth
|
|
206
|
+
interior in `outer-lips` mode), only after the canonical mesh has loaded:
|
|
207
|
+
|
|
208
|
+
```ts
|
|
209
|
+
type LipEffectMaterialContext = {
|
|
210
|
+
cameraTexture: THREE.Texture | null;
|
|
211
|
+
designTexture: THREE.Texture | null;
|
|
212
|
+
faceUv: THREE.BufferAttribute;
|
|
213
|
+
lipEdge: THREE.BufferAttribute;
|
|
214
|
+
lowerDesignTexture: THREE.Texture | null;
|
|
215
|
+
faceIndex: number;
|
|
216
|
+
maskMode: LipMaskMode;
|
|
217
|
+
lipUvBounds: LipUvBounds;
|
|
218
|
+
settings: LipEffectSettings;
|
|
219
|
+
};
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
`lipEdge` is a static per-vertex position across the lip band: `0` on the
|
|
223
|
+
outer ring, `1` on the mouth line. It is bound as `attribute float lipEdge`
|
|
224
|
+
and is what the built-in material uses for feathering, the outward gradient
|
|
225
|
+
and the inner-lip tint. `lipUvBounds.mouthV` is the mouth line in UV space.
|
|
226
|
+
|
|
227
|
+
`faceUv` is the live per-vertex camera-texture UV. It is already bound to the
|
|
228
|
+
geometry, so a custom vertex shader reads it as `attribute vec2 faceUv`; the
|
|
229
|
+
attribute object is exposed for uniforms, debugging, or readback.
|
|
230
|
+
|
|
231
|
+
```tsx
|
|
232
|
+
<LipEffect
|
|
233
|
+
designTexture={texture}
|
|
234
|
+
material={({ cameraTexture, designTexture, maskMode }) => (
|
|
235
|
+
<shaderMaterial
|
|
236
|
+
uniforms={{
|
|
237
|
+
cameraTexture: { value: cameraTexture },
|
|
238
|
+
designTexture: { value: designTexture },
|
|
239
|
+
}}
|
|
240
|
+
vertexShader={`
|
|
241
|
+
attribute vec2 faceUv;
|
|
242
|
+
varying vec2 vFaceUv; varying vec2 vUv;
|
|
243
|
+
void main() {
|
|
244
|
+
vUv = uv; vFaceUv = faceUv;
|
|
245
|
+
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
|
|
246
|
+
}`}
|
|
247
|
+
fragmentShader={`
|
|
248
|
+
uniform sampler2D cameraTexture; uniform sampler2D designTexture;
|
|
249
|
+
varying vec2 vFaceUv; varying vec2 vUv;
|
|
250
|
+
void main() {
|
|
251
|
+
vec4 design = texture2D(designTexture, vUv);
|
|
252
|
+
vec3 skin = texture2D(cameraTexture, vFaceUv).rgb;
|
|
253
|
+
gl_FragColor = vec4(skin * design.rgb, design.a);
|
|
254
|
+
}`}
|
|
255
|
+
transparent
|
|
256
|
+
depthWrite={false}
|
|
257
|
+
stencilWrite
|
|
258
|
+
stencilRef={1}
|
|
259
|
+
stencilFunc={
|
|
260
|
+
maskMode === "outer-and-inner-lips" ? THREE.NotEqualStencilFunc : THREE.AlwaysStencilFunc
|
|
261
|
+
}
|
|
262
|
+
stencilFail={THREE.KeepStencilOp}
|
|
263
|
+
stencilZFail={THREE.KeepStencilOp}
|
|
264
|
+
stencilZPass={THREE.KeepStencilOp}
|
|
265
|
+
/>
|
|
266
|
+
)}
|
|
267
|
+
/>
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
Four complete factories (animated gloss, noise texture, iridescence, time-based
|
|
271
|
+
shimmer) are documented in [Lip Shader Examples](/examples/lip-shaders) and run
|
|
272
|
+
on the `/lip-effect` page.
|
|
273
|
+
|
|
274
|
+
Honour `maskMode` with the stencil test shown above; that is exactly what the
|
|
275
|
+
built-in `LipEffectMaterial` does through its `subtractMouth` prop. Note that
|
|
276
|
+
three.js only evaluates `stencilFunc` while `stencilWrite` is true, so keep it
|
|
277
|
+
on and use the keep-ops: the material then compares against the mouth stencil
|
|
278
|
+
without ever writing to it. The lip triangles already exclude the mouth cavity,
|
|
279
|
+
so the stencil is the guard for anything that reaches past them. It is
|
|
280
|
+
exported so you can reuse the default shader with different settings:
|
|
281
|
+
|
|
282
|
+
```tsx
|
|
283
|
+
material={(context) => (
|
|
284
|
+
<LipEffectMaterial
|
|
285
|
+
cameraTexture={context.cameraTexture}
|
|
286
|
+
designTexture={context.designTexture}
|
|
287
|
+
settings={resolveLipEffectSettings({ ...context.settings, preset: "metallic" })}
|
|
288
|
+
lipUvBounds={context.lipUvBounds}
|
|
289
|
+
subtractMouth={context.maskMode === "outer-and-inner-lips"}
|
|
290
|
+
/>
|
|
291
|
+
)}
|
|
292
|
+
```
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="1024" height="1024" viewBox="0 0 1024 1024"><rect x="1.28" y="1.28" width="1021.44" height="1021.44" fill="none" stroke="#cbd5e1" stroke-width="2.56"/><path d="M540.93,666.01L511.98,668.19L539.77,682.19ZM483.07,666.01L484.23,682.19L511.98,668.19ZM512.02,682.22L539.77,682.19L511.98,668.19ZM512.02,682.22L511.98,668.19L484.23,682.19ZM540.93,666.01L539.77,682.19L573.66,673ZM483.07,666.01L450.34,673L484.23,682.19ZM566.45,684.57L573.66,673L539.77,682.19ZM457.55,684.57L484.23,682.19L450.34,673ZM573.66,673L566.45,684.57L599.43,682.54ZM450.34,673L424.57,682.54L457.55,684.57ZM591.09,690.06L599.43,682.54L566.45,684.57ZM432.91,690.06L457.55,684.57L424.57,682.54ZM591.09,690.06L613.64,697.41L599.43,682.54ZM432.91,690.06L424.57,682.54L410.36,697.41ZM622.18,693.97L599.43,682.54L613.64,697.41ZM401.82,693.97L410.36,697.41L424.57,682.54ZM584.94,699.08L582.49,708.98L607.44,702.13ZM439.06,699.08L416.55,702.13L441.51,708.98ZM600.69,708.98L607.44,702.13L582.49,708.98ZM423.31,708.98L441.51,708.98L416.55,702.13ZM611.29,723.5L618.39,727.26L626.58,710.62ZM412.71,723.5L397.42,710.62L405.61,727.26ZM632.86,711.38L626.58,710.62L618.39,727.26ZM391.14,711.38L405.61,727.26L397.42,710.62ZM590.68,728.93L595.65,737.34L611.29,723.5ZM433.32,728.93L412.71,723.5L428.35,737.34ZM618.39,727.26L611.29,723.5L595.65,737.34ZM405.61,727.26L428.35,737.34L412.71,723.5ZM568.49,748.33L595.65,737.34L566.16,732.99ZM455.51,748.33L457.84,732.99L428.35,737.34ZM590.68,728.93L566.16,732.99L595.65,737.34ZM433.32,728.93L428.35,737.34L457.84,732.99ZM511.98,754.71L540.34,753.9L511.98,736.65ZM511.98,754.71L511.98,736.65L483.66,753.9ZM539.56,735.09L511.98,736.65L540.34,753.9ZM484.44,735.09L483.66,753.9L511.98,736.65ZM604.54,718.67L622.17,710.86L600.88,712.09ZM419.46,718.67L423.12,712.09L401.81,710.86ZM610.68,710.61L600.88,712.09L622.17,710.86ZM413.32,710.61L401.81,710.86L423.12,712.09ZM626.58,710.62L622.17,710.86L611.29,723.5ZM397.42,710.62L412.71,723.5L401.81,710.86ZM604.54,718.67L611.29,723.5L622.17,710.86ZM419.46,718.67L401.81,710.86L412.71,723.5ZM539.77,682.19L538.47,696.52L566.45,684.57ZM484.23,682.19L457.55,684.57L485.53,696.52ZM562.82,697.2L566.45,684.57L538.47,696.52ZM461.18,697.2L485.53,696.52L457.55,684.57ZM566.45,684.57L562.82,697.2L591.09,690.06ZM457.55,684.57L432.91,690.06L461.18,697.2ZM584.94,699.08L591.09,690.06L562.82,697.2ZM439.06,699.08L461.18,697.2L432.91,690.06ZM591.09,690.06L584.94,699.08L613.64,697.41ZM432.91,690.06L410.36,697.41L439.06,699.08ZM607.44,702.13L613.64,697.41L584.94,699.08ZM416.55,702.13L439.06,699.08L410.36,697.41ZM587.29,720.42L590.68,728.93L604.54,718.67ZM436.71,720.42L419.46,718.67L433.32,728.93ZM611.29,723.5L604.54,718.67L590.68,728.93ZM412.71,723.5L433.32,728.93L419.46,718.67ZM566.16,732.99L590.68,728.93L565.23,721.54ZM457.84,732.99L458.77,721.54L433.32,728.93ZM587.29,720.42L565.23,721.54L590.68,728.93ZM436.71,720.42L433.32,728.93L458.77,721.54ZM511.98,736.65L539.56,735.09L511.98,722.88ZM511.98,736.65L511.98,722.88L484.44,735.09ZM539.52,721.54L511.98,722.88L539.56,735.09ZM484.48,721.54L484.44,735.09L511.98,722.88ZM511.98,722.88L539.52,721.54L511.98,711.96ZM511.98,722.88L511.98,711.96L484.48,721.54ZM539.61,711.96L511.98,711.96L539.52,721.54ZM484.39,711.96L484.48,721.54L511.98,711.96ZM564.57,711.96L565.23,721.54L585.79,711.96ZM459.43,711.96L438.21,711.96L458.77,721.54ZM587.29,720.42L585.79,711.96L565.23,721.54ZM436.71,720.42L458.77,721.54L438.21,711.96ZM600.88,712.09L585.79,711.96L604.54,718.67ZM423.12,712.09L419.46,718.67L438.21,711.96ZM587.29,720.42L604.54,718.67L585.79,711.96ZM436.71,720.42L438.21,711.96L419.46,718.67ZM562.82,697.2L560.97,708.98L584.94,699.08ZM461.18,697.2L439.06,699.08L463.03,708.98ZM582.49,708.98L584.94,699.08L560.97,708.98ZM441.51,708.98L463.03,708.98L439.06,699.08ZM538.47,696.52L537.2,708.98L562.82,697.2ZM485.53,696.52L461.18,697.2L486.8,708.98ZM560.97,708.98L562.82,697.2L537.2,708.98ZM463.03,708.98L486.8,708.98L461.18,697.2ZM607.44,702.13L600.69,708.98L622.17,710.86ZM416.55,702.13L401.81,710.86L423.31,708.98ZM610.68,710.61L622.17,710.86L600.69,708.98ZM413.32,710.61L423.31,708.98L401.81,710.86ZM512.02,682.22L512.02,695.53L539.77,682.19ZM512.02,682.22L484.23,682.19L512.02,695.53ZM538.47,696.52L539.77,682.19L512.02,695.53ZM485.53,696.52L512.02,695.53L484.23,682.19ZM512.02,695.53L512.02,708.96L538.47,696.52ZM512.02,695.53L485.53,696.52L512.02,708.96ZM537.2,708.98L538.47,696.52L512.02,708.96ZM486.8,708.98L512.02,708.96L485.53,696.52ZM539.52,721.54L565.23,721.54L539.61,711.96ZM484.48,721.54L484.39,711.96L458.77,721.54ZM564.57,711.96L539.61,711.96L565.23,721.54ZM459.43,711.96L458.77,721.54L484.39,711.96ZM539.56,735.09L566.16,732.99L539.52,721.54ZM484.44,735.09L484.48,721.54L457.84,732.99ZM565.23,721.54L539.52,721.54L566.16,732.99ZM458.77,721.54L457.84,732.99L484.48,721.54ZM540.34,753.9L568.49,748.33L539.56,735.09ZM483.66,753.9L484.44,735.09L455.51,748.33ZM566.16,732.99L539.56,735.09L568.49,748.33ZM457.84,732.99L455.51,748.33L484.44,735.09ZM613.64,697.41L607.44,702.13L626.58,710.62ZM410.36,697.41L397.42,710.62L416.55,702.13ZM622.17,710.86L626.58,710.62L607.44,702.13ZM401.81,710.86L416.55,702.13L397.42,710.62ZM613.64,697.41L626.58,710.62L622.18,693.97ZM410.36,697.41L401.82,693.97L397.42,710.62ZM632.86,711.38L622.18,693.97L626.58,710.62ZM391.14,711.38L397.42,710.62L401.82,693.97Z" fill="#e85d75" fill-opacity="0.08" stroke="#94a3b8" stroke-width="1.28" stroke-linejoin="round"/><path d="M610.68,710.61L600.69,708.98L600.88,712.09ZM413.32,710.61L423.12,712.09L423.31,708.98ZM511.98,711.96L539.61,711.96L512.02,708.96ZM511.98,711.96L512.02,708.96L484.39,711.96ZM537.2,708.98L512.02,708.96L539.61,711.96ZM486.8,708.98L484.39,711.96L512.02,708.96ZM539.61,711.96L564.57,711.96L537.2,708.98ZM484.39,711.96L486.8,708.98L459.43,711.96ZM560.97,708.98L537.2,708.98L564.57,711.96ZM463.03,708.98L459.43,711.96L486.8,708.98ZM564.57,711.96L585.79,711.96L560.97,708.98ZM459.43,711.96L463.03,708.98L438.21,711.96ZM582.49,708.98L560.97,708.98L585.79,711.96ZM441.51,708.98L438.21,711.96L463.03,708.98ZM585.79,711.96L600.88,712.09L582.49,708.98ZM438.21,711.96L441.51,708.98L423.12,712.09ZM600.69,708.98L582.49,708.98L600.88,712.09ZM423.31,708.98L423.12,712.09L441.51,708.98Z" fill="#2563eb" fill-opacity="0.25" stroke="none"/><polygon points="391.14,711.38 405.61,727.26 428.35,737.34 455.51,748.33 483.66,753.9 511.98,754.71 540.34,753.9 568.49,748.33 595.65,737.34 618.39,727.26 632.86,711.38 622.18,693.97 599.43,682.54 573.66,673 540.93,666.01 511.98,668.19 483.07,666.01 450.34,673 424.57,682.54 401.82,693.97" fill="none" stroke="#e85d75" stroke-width="2.56" stroke-linejoin="round"/><polygon points="413.32,710.61 423.12,712.09 438.21,711.96 459.43,711.96 484.39,711.96 511.98,711.96 539.61,711.96 564.57,711.96 585.79,711.96 600.88,712.09 610.68,710.61 600.69,708.98 582.49,708.98 560.97,708.98 537.2,708.98 512.02,708.96 486.8,708.98 463.03,708.98 441.51,708.98 423.31,708.98" fill="none" stroke="#2563eb" stroke-width="2.56" stroke-dasharray="7.68 5.12" stroke-linejoin="round"/><text x="378.85" y="710.36" text-anchor="end" font-family="ui-monospace, SFMono-Regular, Menlo, monospace" font-size="16.38" fill="#0f172a">subject's RIGHT ▸</text><text x="645.15" y="710.36" text-anchor="start" font-family="ui-monospace, SFMono-Regular, Menlo, monospace" font-size="16.38" fill="#0f172a">◂ subject's LEFT</text><text x="512" y="653.73" text-anchor="middle" font-family="ui-monospace, SFMono-Regular, Menlo, monospace" font-size="16.38" fill="#0f172a">upper lip (outer ring = painted edge)</text><text x="512" y="783.38" text-anchor="middle" font-family="ui-monospace, SFMono-Regular, Menlo, monospace" font-size="16.38" fill="#0f172a">lower lip · dashed ring = mouth interior, hidden in outer-and-inner-lips mode</text><text x="512" y="804.68" text-anchor="middle" font-family="ui-monospace, SFMono-Regular, Menlo, monospace" font-size="16.38" fill="#0f172a">lip region: u 0.38–0.62, v 0.26–0.35 (image x 38–62%, y 65–74%)</text><text x="25.6" y="41.98" text-anchor="start" font-family="ui-monospace, SFMono-Regular, Menlo, monospace" font-size="16.38" fill="#0f172a" font-weight="bold">Lip UV template — canonical face UV atlas</text><text x="25.6" y="63.28" text-anchor="start" font-family="ui-monospace, SFMono-Regular, Menlo, monospace" font-size="16.38" fill="#0f172a">1024×1024 canvas, same layout as Canonical_Face_Color.png.</text><text x="25.6" y="84.58" text-anchor="start" font-family="ui-monospace, SFMono-Regular, Menlo, monospace" font-size="16.38" fill="#0f172a">Only the lip triangles are sampled; transparent pixels leave the skin untouched.</text><text x="25.6" y="105.88" text-anchor="start" font-family="ui-monospace, SFMono-Regular, Menlo, monospace" font-size="16.38" fill="#0f172a">Image LEFT = subject's RIGHT (screen-right on a mirrored webcam view).</text><text x="25.6" y="998.4" text-anchor="start" font-family="ui-monospace, SFMono-Regular, Menlo, monospace" font-size="16.38" fill="#0f172a">generated from canonical_face_model.obj uv attributes</text></svg>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vincentt-xr/sdk",
|
|
3
|
-
"version": "2.0.0-alpha.
|
|
3
|
+
"version": "2.0.0-alpha.8",
|
|
4
4
|
"description": "XR SDK by Vincentt",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -63,6 +63,11 @@
|
|
|
63
63
|
"import": "./dist/internal.js",
|
|
64
64
|
"require": "./dist/internal.cjs"
|
|
65
65
|
},
|
|
66
|
+
"./product": {
|
|
67
|
+
"types": "./dist/entries/product.d.ts",
|
|
68
|
+
"import": "./dist/product.js",
|
|
69
|
+
"require": "./dist/product.cjs"
|
|
70
|
+
},
|
|
66
71
|
"./debug-ui": {
|
|
67
72
|
"types": "./dist/debug-ui/index.d.ts",
|
|
68
73
|
"import": "./dist/debug-ui.js",
|
|
@@ -80,6 +85,7 @@
|
|
|
80
85
|
}
|
|
81
86
|
},
|
|
82
87
|
"peerDependencies": {
|
|
88
|
+
"@google/model-viewer": "^4.0.0",
|
|
83
89
|
"@mediapipe/tasks-vision": "^0.10.18",
|
|
84
90
|
"@react-three/drei": "9.105.6",
|
|
85
91
|
"@react-three/fiber": "8.18.0",
|
|
@@ -89,6 +95,9 @@
|
|
|
89
95
|
"three": "0.173.0"
|
|
90
96
|
},
|
|
91
97
|
"peerDependenciesMeta": {
|
|
98
|
+
"@google/model-viewer": {
|
|
99
|
+
"optional": true
|
|
100
|
+
},
|
|
92
101
|
"@mediapipe/tasks-vision": {
|
|
93
102
|
"optional": false
|
|
94
103
|
},
|
|
@@ -98,7 +107,9 @@
|
|
|
98
107
|
},
|
|
99
108
|
"devDependencies": {
|
|
100
109
|
"@eslint/js": "^9.14.0",
|
|
110
|
+
"@google/model-viewer": "4.0.0",
|
|
101
111
|
"@mdx-js/rollup": "^3.1.1",
|
|
112
|
+
"@playwright/test": "1.47.2",
|
|
102
113
|
"@testing-library/dom": "^10",
|
|
103
114
|
"@testing-library/react": "^16",
|
|
104
115
|
"@types/node": "^22.9.0",
|
|
@@ -156,6 +167,7 @@
|
|
|
156
167
|
"format:check": "prettier --check 'lib/**/*.{ts,tsx}' 'example/**/*.{ts,tsx}' '*.{json,md,mjs,ts}' '.github/**/*.{md,yml}' 'docs/**/*.{md,mdx,json}'",
|
|
157
168
|
"format": "prettier --write 'lib/**/*.{js,jsx,ts,tsx}' 'example/**/*.{js,jsx,ts,tsx}'",
|
|
158
169
|
"test": "vitest run",
|
|
170
|
+
"smoke": "playwright test",
|
|
159
171
|
"test:watch": "vitest",
|
|
160
172
|
"lint:check": "eslint lib --max-warnings 0",
|
|
161
173
|
"example:build": "vite build --config example/vite.config.ts",
|