shaderpad 1.0.0-beta.24 → 1.0.0-beta.25
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/README.md +18 -16
- package/dist/plugins/pose.js +5 -4
- package/dist/plugins/pose.js.map +1 -1
- package/dist/plugins/pose.mjs +5 -4
- package/dist/plugins/pose.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -297,13 +297,14 @@ ShaderPad supports plugins to add additional functionality. Plugins are imported
|
|
|
297
297
|
|
|
298
298
|
The `helpers` plugin provides convenience functions and constants. See [helpers.glsl](./src/plugins/helpers.glsl) for the implementation.
|
|
299
299
|
|
|
300
|
-
|
|
300
|
+
```typescript
|
|
301
301
|
import ShaderPad from 'shaderpad';
|
|
302
302
|
import helpers from 'shaderpad/plugins/helpers';
|
|
303
303
|
|
|
304
304
|
const shader = new ShaderPad(fragmentShaderSrc, {
|
|
305
305
|
plugins: [helpers()],
|
|
306
306
|
});
|
|
307
|
+
```
|
|
307
308
|
|
|
308
309
|
**Note:** The `helpers` plugin automatically injects the `u_resolution` uniform into your shader. Do not declare it yourself.
|
|
309
310
|
|
|
@@ -339,15 +340,15 @@ const shader = new ShaderPad(fragmentShaderSrc, {
|
|
|
339
340
|
|
|
340
341
|
**Uniforms:**
|
|
341
342
|
|
|
342
|
-
| Uniform | Type | Description
|
|
343
|
-
| -------------- | -------------- |
|
|
344
|
-
| `u_maxFaces` | int | Maximum number of faces to detect
|
|
345
|
-
| `u_nFaces` | int | Current number of detected faces
|
|
346
|
-
| `
|
|
347
|
-
| `
|
|
348
|
-
| `
|
|
349
|
-
| `
|
|
350
|
-
| `
|
|
343
|
+
| Uniform | Type | Description |
|
|
344
|
+
| -------------- | -------------- | ------------------------------------------------ |
|
|
345
|
+
| `u_maxFaces` | int | Maximum number of faces to detect |
|
|
346
|
+
| `u_nFaces` | int | Current number of detected faces |
|
|
347
|
+
| `u_leftEye` | vec2[maxFaces] | Left eye positions |
|
|
348
|
+
| `u_rightEye` | vec2[maxFaces] | Right eye positions |
|
|
349
|
+
| `u_noseTip` | vec2[maxFaces] | Nose tip positions |
|
|
350
|
+
| `u_faceMask` | sampler2D | Face mask texture (R: mouth, G: face, B: eyes) |
|
|
351
|
+
| `u_faceCenter` | vec2[maxFaces] | Center positions of the face mask bounding boxes |
|
|
351
352
|
|
|
352
353
|
**Helper functions:** `getFace(vec2 pos)`, `getEye(vec2 pos)`, `getMouth(vec2 pos)`
|
|
353
354
|
|
|
@@ -368,12 +369,13 @@ const shader = new ShaderPad(fragmentShaderSrc, {
|
|
|
368
369
|
|
|
369
370
|
**Uniforms:**
|
|
370
371
|
|
|
371
|
-
| Uniform | Type | Description
|
|
372
|
-
| ----------------- | ------------------- |
|
|
373
|
-
| `u_maxPoses` | int | Maximum number of poses to track
|
|
374
|
-
| `u_nPoses` | int | Current number of detected poses
|
|
375
|
-
| `u_poseLandmarks` | vec2[maxPoses * 33] | Landmark positions in UV space
|
|
376
|
-
| `u_poseMask` | sampler2D | Pose mask texture (G: body, B: skeleton)
|
|
372
|
+
| Uniform | Type | Description |
|
|
373
|
+
| ----------------- | ------------------- | ------------------------------------------------ |
|
|
374
|
+
| `u_maxPoses` | int | Maximum number of poses to track |
|
|
375
|
+
| `u_nPoses` | int | Current number of detected poses |
|
|
376
|
+
| `u_poseLandmarks` | vec2[maxPoses * 33] | Landmark positions in UV space |
|
|
377
|
+
| `u_poseMask` | sampler2D | Pose mask texture (G: body, B: skeleton) |
|
|
378
|
+
| `u_poseCenter` | vec2[maxPoses] | Center positions of the pose mask bounding boxes |
|
|
377
379
|
|
|
378
380
|
**Helper functions:** `poseLandmark(int poseIndex, int landmarkIndex)`, `getBody(vec2 pos)`, `getSkeleton(vec2 pos)`
|
|
379
381
|
|
package/dist/plugins/pose.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
"use strict";var
|
|
1
|
+
"use strict";var U=Object.create;var x=Object.defineProperty;var A=Object.getOwnPropertyDescriptor;var H=Object.getOwnPropertyNames;var F=Object.getPrototypeOf,R=Object.prototype.hasOwnProperty;var V=(r,c)=>{for(var s in c)x(r,s,{get:c[s],enumerable:!0})},v=(r,c,s,P)=>{if(c&&typeof c=="object"||typeof c=="function")for(let m of H(c))!R.call(r,m)&&m!==s&&x(r,m,{get:()=>c[m],enumerable:!(P=A(c,m))||P.enumerable});return r};var j=(r,c,s)=>(s=r!=null?U(F(r)):{},v(c||!r||!r.__esModule?x(s,"default",{value:r,enumerable:!0}):s,r)),W=r=>v(x({},"__esModule",{value:!0}),r);var $={};V($,{default:()=>Y});module.exports=W($);var C=33;function X(r){let{textureName:c,options:s}=r,P="https://storage.googleapis.com/mediapipe-models/pose_landmarker/pose_landmarker_lite/float16/1/pose_landmarker_lite.task";return function(m,I){let{injectGLSL:S}=I,f=null,y=null,M=-1,_=new Map,g=s?.maxPoses??1,D=512,O=512,i=document.createElement("canvas");i.width=D,i.height=O;let l=i.getContext("2d"),h=document.createElement("canvas"),w=h.getContext("2d");l.globalCompositeOperation=w.globalCompositeOperation="lighten";let b=[];async function z(){try{let{FilesetResolver:n,PoseLandmarker:o}=await import("@mediapipe/tasks-vision");y=await n.forVisionTasks("https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@latest/wasm"),b.push(...o.POSE_CONNECTIONS),f=await o.createFromOptions(y,{baseOptions:{modelAssetPath:s?.modelPath||P},runningMode:"VIDEO",numPoses:s?.maxPoses??1,minPoseDetectionConfidence:s?.minPoseDetectionConfidence??.5,minPosePresenceConfidence:s?.minPosePresenceConfidence??.5,minTrackingConfidence:s?.minTrackingConfidence??.5,outputSegmentationMasks:s?.outputSegmentationMasks??!0})}catch(n){throw console.error("[Pose Plugin] Failed to initialize Pose Landmarker:",n),n}}function E(n){let o=1/0,e=-1/0,t=1/0,a=-1/0;for(let u of n)o=Math.min(o,u.x),e=Math.max(e,u.x),t=Math.min(t,u.y),a=Math.max(a,u.y);let d=(o+e)/2,p=(t+a)/2;return[d,p]}async function N(n,o){if(!f){console.warn("[Pose Plugin] Cannot update mask: poseLandmarker missing");return}try{if(l.clearRect(0,0,i.width,i.height),o&&o.length>0&&o.forEach(e=>{if(!e)return;let{width:t,height:a}=e,d=e.getAsUint8Array(),p=t*a,u=new Uint8ClampedArray(p*4);for(let k=0;k<p;k++)u[k*4+1]=d[k],u[k*4+3]=255;let T=new ImageData(u,t,a);t===i.width&&a===i.height?l.putImageData(T,0,0):(h.width!==t&&(h.width=t),h.height!==a&&(h.height=a),w.putImageData(T,0,0),l.drawImage(h,0,0,i.width,i.height))}),b.length){let e=Math.max(2,i.width/256);l.lineWidth=e,l.lineCap="round",l.strokeStyle="#00f",n.forEach(t=>{b.forEach(({start:a,end:d})=>{let p=t[a],u=t[d];!p||!u||(p.visibility??1)<.3||(u.visibility??1)<.3||(l.beginPath(),l.moveTo(p.x*i.width,p.y*i.height),l.lineTo(u.x*i.width,u.y*i.height),l.stroke())})})}m.updateTextures({u_poseMask:i})}catch(e){console.error("[Pose Plugin] Failed to generate mask texture:",e)}}function L(n){if(!n.landmarks)return;N(n.landmarks,n.segmentationMasks).catch(t=>{console.warn("[Pose Plugin] Mask texture update error:",t)});let o=n.landmarks.length,e={u_nPoses:o};if(o){e.u_poseLandmarks=n.landmarks.flatMap(a=>a.map(d=>[d.x,1-d.y]));let t=[];for(let a of n.landmarks){let d=E(a);t.push([d[0],1-d[1]])}e.u_poseCenter=t}m.updateUniforms(e)}m.registerHook("init",async()=>{m.initializeTexture("u_poseMask",i),m.initializeUniform("u_maxPoses","int",g),m.initializeUniform("u_nPoses","int",0);let n=Array.from({length:g*C},()=>[.5,.5]);m.initializeUniform("u_poseLandmarks","float",n,{arrayLength:g*C});let o=Array.from({length:g},()=>[.5,.5]);m.initializeUniform("u_poseCenter","float",o,{arrayLength:g}),await z()}),m.registerHook("updateTextures",n=>{Object.entries(n).forEach(([o,e])=>{if(o===c&&(_.set(o,e),!!f))try{if(e instanceof HTMLVideoElement){if(e.currentTime!==M){M=e.currentTime;let t=performance.now(),a=f.detectForVideo(e,t);L(a)}}else if(e instanceof HTMLImageElement){let t=f.detect(e);L(t)}}catch(t){console.error("[Pose Plugin] Pose detection error:",t)}})}),m.registerHook("destroy",()=>{f&&(f.close(),f=null),y=null,_.clear(),i.remove()}),S(`
|
|
2
2
|
uniform int u_maxPoses;
|
|
3
3
|
uniform int u_nPoses;
|
|
4
|
-
uniform vec2 u_poseLandmarks[${
|
|
4
|
+
uniform vec2 u_poseLandmarks[${g*C}];
|
|
5
5
|
uniform sampler2D u_poseMask;
|
|
6
|
+
uniform vec2 u_poseCenter[${g}];
|
|
6
7
|
vec2 poseLandmark(int poseIndex, int landmarkIndex) {
|
|
7
|
-
return u_poseLandmarks[poseIndex * ${
|
|
8
|
+
return u_poseLandmarks[poseIndex * ${C} + landmarkIndex];
|
|
8
9
|
}
|
|
9
10
|
float getBody(vec2 pos) { return texture(u_poseMask, pos).g; }
|
|
10
|
-
float getSkeleton(vec2 pos) { return texture(u_poseMask, pos).b; }`)}}var
|
|
11
|
+
float getSkeleton(vec2 pos) { return texture(u_poseMask, pos).b; }`)}}var Y=X;
|
|
11
12
|
//# sourceMappingURL=pose.js.map
|
package/dist/plugins/pose.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/plugins/pose.ts"],"sourcesContent":["import ShaderPad, { PluginContext, TextureSource } from '../index';\nimport type { PoseLandmarker, NormalizedLandmark } from '@mediapipe/tasks-vision';\n\nexport interface PosePluginOptions {\n\tmodelPath?: string;\n\tmaxPoses?: number;\n\tminPoseDetectionConfidence?: number;\n\tminPosePresenceConfidence?: number;\n\tminTrackingConfidence?: number;\n\toutputSegmentationMasks?: boolean;\n}\n\nconst LANDMARK_COUNT = 33; // See https://ai.google.dev/edge/mediapipe/solutions/vision/pose_landmarker#pose_landmarker_model.\n\nfunction pose(config: { textureName: string; options?: PosePluginOptions }) {\n\tconst { textureName, options } = config;\n\tconst defaultModelPath =\n\t\t'https://storage.googleapis.com/mediapipe-models/pose_landmarker/pose_landmarker_lite/float16/1/pose_landmarker_lite.task';\n\n\treturn function (shaderPad: ShaderPad, context: PluginContext) {\n\t\tconst { injectGLSL } = context;\n\n\t\tlet poseLandmarker: PoseLandmarker | null = null;\n\t\tlet vision: any = null;\n\t\tlet lastVideoTime = -1;\n\t\tconst textureSources = new Map<string, TextureSource>();\n\t\tconst maxPoses = options?.maxPoses ?? 1;\n\t\tconst maskWidth = 512;\n\t\tconst maskHeight = 512;\n\t\tconst poseMaskCanvas = document.createElement('canvas');\n\t\tposeMaskCanvas.width = maskWidth;\n\t\tposeMaskCanvas.height = maskHeight;\n\t\tconst poseMaskCtx = poseMaskCanvas.getContext('2d')!;\n\t\tposeMaskCtx.globalCompositeOperation = 'lighten'; // Keep the highest value of each channel.\n\t\tconst poseConnections: { start: number; end: number }[] = [];\n\n\t\tasync function initializePoseLandmarker() {\n\t\t\ttry {\n\t\t\t\tconst { FilesetResolver, PoseLandmarker } = await import('@mediapipe/tasks-vision');\n\t\t\t\tvision = await FilesetResolver.forVisionTasks(\n\t\t\t\t\t'https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@latest/wasm'\n\t\t\t\t);\n\t\t\t\tposeConnections.push(...PoseLandmarker.POSE_CONNECTIONS);\n\t\t\t\tposeLandmarker = await PoseLandmarker.createFromOptions(vision, {\n\t\t\t\t\tbaseOptions: {\n\t\t\t\t\t\tmodelAssetPath: options?.modelPath || defaultModelPath,\n\t\t\t\t\t},\n\t\t\t\t\trunningMode: 'VIDEO',\n\t\t\t\t\tnumPoses: options?.maxPoses ?? 1,\n\t\t\t\t\tminPoseDetectionConfidence: options?.minPoseDetectionConfidence ?? 0.5,\n\t\t\t\t\tminPosePresenceConfidence: options?.minPosePresenceConfidence ?? 0.5,\n\t\t\t\t\tminTrackingConfidence: options?.minTrackingConfidence ?? 0.5,\n\t\t\t\t\toutputSegmentationMasks: options?.outputSegmentationMasks ?? false,\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error('[Pose Plugin] Failed to initialize Pose Landmarker:', error);\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\n\t\tasync function updateMaskTexture(poses: NormalizedLandmark[][], segmentationMasks?: ImageData[]) {\n\t\t\tif (!poseLandmarker) {\n\t\t\t\tconsole.warn('[Pose Plugin] Cannot update mask: poseLandmarker missing');\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tposeMaskCtx.clearRect(0, 0, poseMaskCanvas.width, poseMaskCanvas.height);\n\n\t\t\t\t// Draw the segmentation masks.\n\t\t\t\tif (segmentationMasks && segmentationMasks.length > 0) {\n\t\t\t\t\t// Combine all segmentation masks (for multiple poses).\n\t\t\t\t\tsegmentationMasks.forEach(mask => {\n\t\t\t\t\t\t// Resize mask to canvas size if needed.\n\t\t\t\t\t\tif (mask.width !== poseMaskCanvas.width || mask.height !== poseMaskCanvas.height) {\n\t\t\t\t\t\t\tconst tempCanvas = document.createElement('canvas');\n\t\t\t\t\t\t\ttempCanvas.width = mask.width;\n\t\t\t\t\t\t\ttempCanvas.height = mask.height;\n\t\t\t\t\t\t\tconst tempCtx = tempCanvas.getContext('2d')!;\n\t\t\t\t\t\t\ttempCtx.putImageData(mask, 0, 0);\n\t\t\t\t\t\t\tposeMaskCtx.drawImage(tempCanvas, 0, 0, poseMaskCanvas.width, poseMaskCanvas.height);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tposeMaskCtx.putImageData(mask, 0, 0);\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\t// Draw the skeleton.\n\t\t\t\tif (poseConnections.length) {\n\t\t\t\t\tconst lineWidth = Math.max(2, poseMaskCanvas.width / 256);\n\t\t\t\t\tposeMaskCtx.lineWidth = lineWidth;\n\t\t\t\t\tposeMaskCtx.lineCap = 'round';\n\t\t\t\t\tposeMaskCtx.strokeStyle = '#00f';\n\n\t\t\t\t\tposes.forEach(landmarks => {\n\t\t\t\t\t\tposeConnections.forEach(({ start, end }) => {\n\t\t\t\t\t\t\tconst a = landmarks[start];\n\t\t\t\t\t\t\tconst b = landmarks[end];\n\t\t\t\t\t\t\tif (!a || !b) return;\n\t\t\t\t\t\t\tif ((a.visibility ?? 1) < 0.3 || (b.visibility ?? 1) < 0.3) return;\n\t\t\t\t\t\t\tposeMaskCtx.beginPath();\n\t\t\t\t\t\t\tposeMaskCtx.moveTo(a.x * poseMaskCanvas.width, a.y * poseMaskCanvas.height);\n\t\t\t\t\t\t\tposeMaskCtx.lineTo(b.x * poseMaskCanvas.width, b.y * poseMaskCanvas.height);\n\t\t\t\t\t\t\tposeMaskCtx.stroke();\n\t\t\t\t\t\t});\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tshaderPad.updateTextures({ u_poseMask: poseMaskCanvas });\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error('[Pose Plugin] Failed to generate mask texture:', error);\n\t\t\t}\n\t\t}\n\n\t\tfunction processPoseResults(result: any) {\n\t\t\tif (!result.landmarks) return;\n\n\t\t\tupdateMaskTexture(result.landmarks, result.segmentationMasks).catch(error => {\n\t\t\t\tconsole.warn('[Pose Plugin] Mask texture update error:', error);\n\t\t\t});\n\n\t\t\tconst nPoses = result.landmarks.length;\n\t\t\tconst updates: Parameters<typeof shaderPad.updateUniforms>[0] = { u_nPoses: nPoses };\n\t\t\tif (nPoses) {\n\t\t\t\tupdates.u_poseLandmarks = result.landmarks.flatMap((landmarks: NormalizedLandmark[]) =>\n\t\t\t\t\tlandmarks.map(landmark => [landmark.x, 1.0 - landmark.y])\n\t\t\t\t);\n\t\t\t}\n\t\t\tshaderPad.updateUniforms(updates);\n\t\t}\n\n\t\tshaderPad.registerHook('init', async () => {\n\t\t\tshaderPad.initializeTexture('u_poseMask', poseMaskCanvas);\n\t\t\tshaderPad.initializeUniform('u_maxPoses', 'int', maxPoses);\n\t\t\tshaderPad.initializeUniform('u_nPoses', 'int', 0);\n\t\t\tconst defaultPoseData: [number, number][] = Array.from({ length: maxPoses * LANDMARK_COUNT }, () => [\n\t\t\t\t0.5, 0.5,\n\t\t\t]);\n\t\t\tshaderPad.initializeUniform('u_poseLandmarks', 'float', defaultPoseData, {\n\t\t\t\tarrayLength: maxPoses * LANDMARK_COUNT,\n\t\t\t});\n\n\t\t\tawait initializePoseLandmarker();\n\t\t});\n\n\t\tshaderPad.registerHook('updateTextures', (updates: Record<string, TextureSource>) => {\n\t\t\tObject.entries(updates).forEach(([name, source]) => {\n\t\t\t\tif (name !== textureName) return;\n\t\t\t\ttextureSources.set(name, source);\n\t\t\t\tif (!poseLandmarker) return;\n\t\t\t\ttry {\n\t\t\t\t\tif (source instanceof HTMLVideoElement) {\n\t\t\t\t\t\tif (source.currentTime !== lastVideoTime) {\n\t\t\t\t\t\t\tlastVideoTime = source.currentTime;\n\t\t\t\t\t\t\tconst timestamp = performance.now();\n\t\t\t\t\t\t\tconst result = poseLandmarker.detectForVideo(source, timestamp);\n\t\t\t\t\t\t\tprocessPoseResults(result);\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (source instanceof HTMLImageElement) {\n\t\t\t\t\t\tconst result = poseLandmarker.detect(source);\n\t\t\t\t\t\tprocessPoseResults(result);\n\t\t\t\t\t}\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconsole.error('[Pose Plugin] Pose detection error:', error);\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\n\t\tshaderPad.registerHook('destroy', () => {\n\t\t\tif (poseLandmarker) {\n\t\t\t\tposeLandmarker.close();\n\t\t\t\tposeLandmarker = null;\n\t\t\t}\n\t\t\tvision = null;\n\t\t\ttextureSources.clear();\n\t\t\tposeMaskCanvas.remove();\n\t\t});\n\n\t\tinjectGLSL(`\nuniform int u_maxPoses;\nuniform int u_nPoses;\nuniform vec2 u_poseLandmarks[${maxPoses * LANDMARK_COUNT}];\nuniform sampler2D u_poseMask;\nvec2 poseLandmark(int poseIndex, int landmarkIndex) {\n\treturn u_poseLandmarks[poseIndex * ${LANDMARK_COUNT} + landmarkIndex];\n}\nfloat getBody(vec2 pos) { return texture(u_poseMask, pos).g; }\nfloat getSkeleton(vec2 pos) { return texture(u_poseMask, pos).b; }`);\n\t};\n}\n\nexport default pose;\n"],"mappings":"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","names":["pose_exports","__export","pose_default","__toCommonJS","LANDMARK_COUNT","pose","config","textureName","options","defaultModelPath","shaderPad","context","injectGLSL","poseLandmarker","vision","lastVideoTime","textureSources","maxPoses","maskWidth","maskHeight","poseMaskCanvas","poseMaskCtx","poseConnections","initializePoseLandmarker","FilesetResolver","PoseLandmarker","error","updateMaskTexture","poses","segmentationMasks","mask","tempCanvas","lineWidth","landmarks","start","end","a","b","processPoseResults","result","nPoses","updates","landmark","defaultPoseData","name","source","timestamp"]}
|
|
1
|
+
{"version":3,"sources":["../../src/plugins/pose.ts"],"sourcesContent":["import ShaderPad, { PluginContext, TextureSource } from '../index';\nimport type { PoseLandmarker, NormalizedLandmark } from '@mediapipe/tasks-vision';\n\nexport interface PosePluginOptions {\n\tmodelPath?: string;\n\tmaxPoses?: number;\n\tminPoseDetectionConfidence?: number;\n\tminPosePresenceConfidence?: number;\n\tminTrackingConfidence?: number;\n\toutputSegmentationMasks?: boolean;\n}\n\nconst LANDMARK_COUNT = 33; // See https://ai.google.dev/edge/mediapipe/solutions/vision/pose_landmarker#pose_landmarker_model.\n\nfunction pose(config: { textureName: string; options?: PosePluginOptions }) {\n\tconst { textureName, options } = config;\n\tconst defaultModelPath =\n\t\t'https://storage.googleapis.com/mediapipe-models/pose_landmarker/pose_landmarker_lite/float16/1/pose_landmarker_lite.task';\n\n\treturn function (shaderPad: ShaderPad, context: PluginContext) {\n\t\tconst { injectGLSL } = context;\n\n\t\tlet poseLandmarker: PoseLandmarker | null = null;\n\t\tlet vision: any = null;\n\t\tlet lastVideoTime = -1;\n\t\tconst textureSources = new Map<string, TextureSource>();\n\t\tconst maxPoses = options?.maxPoses ?? 1;\n\t\tconst maskWidth = 512;\n\t\tconst maskHeight = 512;\n\t\tconst poseMaskCanvas = document.createElement('canvas');\n\t\tposeMaskCanvas.width = maskWidth;\n\t\tposeMaskCanvas.height = maskHeight;\n\t\tconst poseMaskCtx = poseMaskCanvas.getContext('2d')!;\n\t\tconst segmentationCanvas = document.createElement('canvas');\n\t\tconst segmentationCtx = segmentationCanvas.getContext('2d')!;\n\t\tposeMaskCtx.globalCompositeOperation = segmentationCtx.globalCompositeOperation = 'lighten'; // Keep the highest value of each channel.\n\t\tconst poseConnections: { start: number; end: number }[] = [];\n\n\t\tasync function initializePoseLandmarker() {\n\t\t\ttry {\n\t\t\t\tconst { FilesetResolver, PoseLandmarker } = await import('@mediapipe/tasks-vision');\n\t\t\t\tvision = await FilesetResolver.forVisionTasks(\n\t\t\t\t\t'https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@latest/wasm'\n\t\t\t\t);\n\t\t\t\tposeConnections.push(...PoseLandmarker.POSE_CONNECTIONS);\n\t\t\t\tposeLandmarker = await PoseLandmarker.createFromOptions(vision, {\n\t\t\t\t\tbaseOptions: {\n\t\t\t\t\t\tmodelAssetPath: options?.modelPath || defaultModelPath,\n\t\t\t\t\t},\n\t\t\t\t\trunningMode: 'VIDEO',\n\t\t\t\t\tnumPoses: options?.maxPoses ?? 1,\n\t\t\t\t\tminPoseDetectionConfidence: options?.minPoseDetectionConfidence ?? 0.5,\n\t\t\t\t\tminPosePresenceConfidence: options?.minPosePresenceConfidence ?? 0.5,\n\t\t\t\t\tminTrackingConfidence: options?.minTrackingConfidence ?? 0.5,\n\t\t\t\t\toutputSegmentationMasks: options?.outputSegmentationMasks ?? true,\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error('[Pose Plugin] Failed to initialize Pose Landmarker:', error);\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\n\t\tfunction calculatePoseCenter(landmarks: NormalizedLandmark[]): [number, number] {\n\t\t\tlet minX = Infinity,\n\t\t\t\tmaxX = -Infinity,\n\t\t\t\tminY = Infinity,\n\t\t\t\tmaxY = -Infinity;\n\n\t\t\t// Calculate bounding box center from all landmarks.\n\t\t\tfor (const landmark of landmarks) {\n\t\t\t\tminX = Math.min(minX, landmark.x);\n\t\t\t\tmaxX = Math.max(maxX, landmark.x);\n\t\t\t\tminY = Math.min(minY, landmark.y);\n\t\t\t\tmaxY = Math.max(maxY, landmark.y);\n\t\t\t}\n\n\t\t\tconst centerX = (minX + maxX) / 2;\n\t\t\tconst centerY = (minY + maxY) / 2;\n\t\t\treturn [centerX, centerY];\n\t\t}\n\n\t\tasync function updateMaskTexture(poses: NormalizedLandmark[][], segmentationMasks?: any[]) {\n\t\t\tif (!poseLandmarker) {\n\t\t\t\tconsole.warn('[Pose Plugin] Cannot update mask: poseLandmarker missing');\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tposeMaskCtx.clearRect(0, 0, poseMaskCanvas.width, poseMaskCanvas.height);\n\n\t\t\t\t// Draw the segmentation masks.\n\t\t\t\tif (segmentationMasks && segmentationMasks.length > 0) {\n\t\t\t\t\tsegmentationMasks.forEach(mask => {\n\t\t\t\t\t\tif (!mask) return;\n\n\t\t\t\t\t\tconst { width, height } = mask;\n\t\t\t\t\t\tconst maskData = mask.getAsUint8Array();\n\t\t\t\t\t\tconst pixelCount = width * height;\n\t\t\t\t\t\tconst outputData = new Uint8ClampedArray(pixelCount * 4);\n\n\t\t\t\t\t\tfor (let i = 0; i < pixelCount; i++) {\n\t\t\t\t\t\t\toutputData[i * 4 + 1] = maskData[i]; // G (body mask)\n\t\t\t\t\t\t\toutputData[i * 4 + 3] = 255; // A (required for compositing)\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst rgbaMask = new ImageData(outputData, width, height);\n\n\t\t\t\t\t\t// Resize mask to canvas size if needed.\n\t\t\t\t\t\tif (width === poseMaskCanvas.width && height === poseMaskCanvas.height) {\n\t\t\t\t\t\t\tposeMaskCtx.putImageData(rgbaMask, 0, 0);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tif (segmentationCanvas.width !== width) segmentationCanvas.width = width;\n\t\t\t\t\t\t\tif (segmentationCanvas.height !== height) segmentationCanvas.height = height;\n\t\t\t\t\t\t\tsegmentationCtx.putImageData(rgbaMask, 0, 0);\n\t\t\t\t\t\t\tposeMaskCtx.drawImage(\n\t\t\t\t\t\t\t\tsegmentationCanvas,\n\t\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t\tposeMaskCanvas.width,\n\t\t\t\t\t\t\t\tposeMaskCanvas.height\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\t// Draw the skeleton.\n\t\t\t\tif (poseConnections.length) {\n\t\t\t\t\tconst lineWidth = Math.max(2, poseMaskCanvas.width / 256);\n\t\t\t\t\tposeMaskCtx.lineWidth = lineWidth;\n\t\t\t\t\tposeMaskCtx.lineCap = 'round';\n\t\t\t\t\tposeMaskCtx.strokeStyle = '#00f';\n\n\t\t\t\t\tposes.forEach(landmarks => {\n\t\t\t\t\t\tposeConnections.forEach(({ start, end }) => {\n\t\t\t\t\t\t\tconst a = landmarks[start];\n\t\t\t\t\t\t\tconst b = landmarks[end];\n\t\t\t\t\t\t\tif (!a || !b) return;\n\t\t\t\t\t\t\tif ((a.visibility ?? 1) < 0.3 || (b.visibility ?? 1) < 0.3) return;\n\t\t\t\t\t\t\tposeMaskCtx.beginPath();\n\t\t\t\t\t\t\tposeMaskCtx.moveTo(a.x * poseMaskCanvas.width, a.y * poseMaskCanvas.height);\n\t\t\t\t\t\t\tposeMaskCtx.lineTo(b.x * poseMaskCanvas.width, b.y * poseMaskCanvas.height);\n\t\t\t\t\t\t\tposeMaskCtx.stroke();\n\t\t\t\t\t\t});\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tshaderPad.updateTextures({ u_poseMask: poseMaskCanvas });\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error('[Pose Plugin] Failed to generate mask texture:', error);\n\t\t\t}\n\t\t}\n\n\t\tfunction processPoseResults(result: any) {\n\t\t\tif (!result.landmarks) return;\n\n\t\t\tupdateMaskTexture(result.landmarks, result.segmentationMasks).catch(error => {\n\t\t\t\tconsole.warn('[Pose Plugin] Mask texture update error:', error);\n\t\t\t});\n\n\t\t\tconst nPoses = result.landmarks.length;\n\t\t\tconst updates: Parameters<typeof shaderPad.updateUniforms>[0] = { u_nPoses: nPoses };\n\t\t\tif (nPoses) {\n\t\t\t\tupdates.u_poseLandmarks = result.landmarks.flatMap((landmarks: NormalizedLandmark[]) =>\n\t\t\t\t\tlandmarks.map(landmark => [landmark.x, 1.0 - landmark.y])\n\t\t\t\t);\n\n\t\t\t\tconst poseCenters: [number, number][] = [];\n\t\t\t\tfor (const landmarks of result.landmarks) {\n\t\t\t\t\tconst poseCenter = calculatePoseCenter(landmarks);\n\t\t\t\t\t// Invert Y-axis to match WebGL coordinate system.\n\t\t\t\t\tposeCenters.push([poseCenter[0], 1.0 - poseCenter[1]]);\n\t\t\t\t}\n\t\t\t\tupdates.u_poseCenter = poseCenters;\n\t\t\t}\n\t\t\tshaderPad.updateUniforms(updates);\n\t\t}\n\n\t\tshaderPad.registerHook('init', async () => {\n\t\t\tshaderPad.initializeTexture('u_poseMask', poseMaskCanvas);\n\t\t\tshaderPad.initializeUniform('u_maxPoses', 'int', maxPoses);\n\t\t\tshaderPad.initializeUniform('u_nPoses', 'int', 0);\n\t\t\tconst defaultPoseData: [number, number][] = Array.from({ length: maxPoses * LANDMARK_COUNT }, () => [\n\t\t\t\t0.5, 0.5,\n\t\t\t]);\n\t\t\tshaderPad.initializeUniform('u_poseLandmarks', 'float', defaultPoseData, {\n\t\t\t\tarrayLength: maxPoses * LANDMARK_COUNT,\n\t\t\t});\n\t\t\tconst defaultPoseCenterData: [number, number][] = Array.from({ length: maxPoses }, () => [0.5, 0.5]);\n\t\t\tshaderPad.initializeUniform('u_poseCenter', 'float', defaultPoseCenterData, {\n\t\t\t\tarrayLength: maxPoses,\n\t\t\t});\n\n\t\t\tawait initializePoseLandmarker();\n\t\t});\n\n\t\tshaderPad.registerHook('updateTextures', (updates: Record<string, TextureSource>) => {\n\t\t\tObject.entries(updates).forEach(([name, source]) => {\n\t\t\t\tif (name !== textureName) return;\n\t\t\t\ttextureSources.set(name, source);\n\t\t\t\tif (!poseLandmarker) return;\n\t\t\t\ttry {\n\t\t\t\t\tif (source instanceof HTMLVideoElement) {\n\t\t\t\t\t\tif (source.currentTime !== lastVideoTime) {\n\t\t\t\t\t\t\tlastVideoTime = source.currentTime;\n\t\t\t\t\t\t\tconst timestamp = performance.now();\n\t\t\t\t\t\t\tconst result = poseLandmarker.detectForVideo(source, timestamp);\n\t\t\t\t\t\t\tprocessPoseResults(result);\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (source instanceof HTMLImageElement) {\n\t\t\t\t\t\tconst result = poseLandmarker.detect(source);\n\t\t\t\t\t\tprocessPoseResults(result);\n\t\t\t\t\t}\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconsole.error('[Pose Plugin] Pose detection error:', error);\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\n\t\tshaderPad.registerHook('destroy', () => {\n\t\t\tif (poseLandmarker) {\n\t\t\t\tposeLandmarker.close();\n\t\t\t\tposeLandmarker = null;\n\t\t\t}\n\t\t\tvision = null;\n\t\t\ttextureSources.clear();\n\t\t\tposeMaskCanvas.remove();\n\t\t});\n\t\t// TODO: getBody and getSkeleton shouldn't rely on alpha. Do they? Seems so in the example...\n\t\tinjectGLSL(`\nuniform int u_maxPoses;\nuniform int u_nPoses;\nuniform vec2 u_poseLandmarks[${maxPoses * LANDMARK_COUNT}];\nuniform sampler2D u_poseMask;\nuniform vec2 u_poseCenter[${maxPoses}];\nvec2 poseLandmark(int poseIndex, int landmarkIndex) {\n\treturn u_poseLandmarks[poseIndex * ${LANDMARK_COUNT} + landmarkIndex];\n}\nfloat getBody(vec2 pos) { return texture(u_poseMask, pos).g; }\nfloat getSkeleton(vec2 pos) { return texture(u_poseMask, pos).b; }`);\n\t};\n}\n\nexport default pose;\n"],"mappings":"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","names":["pose_exports","__export","pose_default","__toCommonJS","LANDMARK_COUNT","pose","config","textureName","options","defaultModelPath","shaderPad","context","injectGLSL","poseLandmarker","vision","lastVideoTime","textureSources","maxPoses","maskWidth","maskHeight","poseMaskCanvas","poseMaskCtx","segmentationCanvas","segmentationCtx","poseConnections","initializePoseLandmarker","FilesetResolver","PoseLandmarker","error","calculatePoseCenter","landmarks","minX","maxX","minY","maxY","landmark","centerX","centerY","updateMaskTexture","poses","segmentationMasks","mask","width","height","maskData","pixelCount","outputData","i","rgbaMask","lineWidth","start","end","a","b","processPoseResults","result","nPoses","updates","poseCenters","poseCenter","defaultPoseData","defaultPoseCenterData","name","source","timestamp"]}
|
package/dist/plugins/pose.mjs
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
var
|
|
1
|
+
var h=33;function E(_){let{textureName:w,options:d}=_,L="https://storage.googleapis.com/mediapipe-models/pose_landmarker/pose_landmarker_lite/float16/1/pose_landmarker_lite.task";return function(c,T){let{injectGLSL:v}=T,l=null,k=null,x=-1,C=new Map,p=d?.maxPoses??1,I=512,S=512,i=document.createElement("canvas");i.width=I,i.height=S;let s=i.getContext("2d"),f=document.createElement("canvas"),y=f.getContext("2d");s.globalCompositeOperation=y.globalCompositeOperation="lighten";let P=[];async function D(){try{let{FilesetResolver:n,PoseLandmarker:o}=await import("@mediapipe/tasks-vision");k=await n.forVisionTasks("https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@latest/wasm"),P.push(...o.POSE_CONNECTIONS),l=await o.createFromOptions(k,{baseOptions:{modelAssetPath:d?.modelPath||L},runningMode:"VIDEO",numPoses:d?.maxPoses??1,minPoseDetectionConfidence:d?.minPoseDetectionConfidence??.5,minPosePresenceConfidence:d?.minPosePresenceConfidence??.5,minTrackingConfidence:d?.minTrackingConfidence??.5,outputSegmentationMasks:d?.outputSegmentationMasks??!0})}catch(n){throw console.error("[Pose Plugin] Failed to initialize Pose Landmarker:",n),n}}function O(n){let o=1/0,e=-1/0,t=1/0,a=-1/0;for(let r of n)o=Math.min(o,r.x),e=Math.max(e,r.x),t=Math.min(t,r.y),a=Math.max(a,r.y);let m=(o+e)/2,u=(t+a)/2;return[m,u]}async function z(n,o){if(!l){console.warn("[Pose Plugin] Cannot update mask: poseLandmarker missing");return}try{if(s.clearRect(0,0,i.width,i.height),o&&o.length>0&&o.forEach(e=>{if(!e)return;let{width:t,height:a}=e,m=e.getAsUint8Array(),u=t*a,r=new Uint8ClampedArray(u*4);for(let g=0;g<u;g++)r[g*4+1]=m[g],r[g*4+3]=255;let M=new ImageData(r,t,a);t===i.width&&a===i.height?s.putImageData(M,0,0):(f.width!==t&&(f.width=t),f.height!==a&&(f.height=a),y.putImageData(M,0,0),s.drawImage(f,0,0,i.width,i.height))}),P.length){let e=Math.max(2,i.width/256);s.lineWidth=e,s.lineCap="round",s.strokeStyle="#00f",n.forEach(t=>{P.forEach(({start:a,end:m})=>{let u=t[a],r=t[m];!u||!r||(u.visibility??1)<.3||(r.visibility??1)<.3||(s.beginPath(),s.moveTo(u.x*i.width,u.y*i.height),s.lineTo(r.x*i.width,r.y*i.height),s.stroke())})})}c.updateTextures({u_poseMask:i})}catch(e){console.error("[Pose Plugin] Failed to generate mask texture:",e)}}function b(n){if(!n.landmarks)return;z(n.landmarks,n.segmentationMasks).catch(t=>{console.warn("[Pose Plugin] Mask texture update error:",t)});let o=n.landmarks.length,e={u_nPoses:o};if(o){e.u_poseLandmarks=n.landmarks.flatMap(a=>a.map(m=>[m.x,1-m.y]));let t=[];for(let a of n.landmarks){let m=O(a);t.push([m[0],1-m[1]])}e.u_poseCenter=t}c.updateUniforms(e)}c.registerHook("init",async()=>{c.initializeTexture("u_poseMask",i),c.initializeUniform("u_maxPoses","int",p),c.initializeUniform("u_nPoses","int",0);let n=Array.from({length:p*h},()=>[.5,.5]);c.initializeUniform("u_poseLandmarks","float",n,{arrayLength:p*h});let o=Array.from({length:p},()=>[.5,.5]);c.initializeUniform("u_poseCenter","float",o,{arrayLength:p}),await D()}),c.registerHook("updateTextures",n=>{Object.entries(n).forEach(([o,e])=>{if(o===w&&(C.set(o,e),!!l))try{if(e instanceof HTMLVideoElement){if(e.currentTime!==x){x=e.currentTime;let t=performance.now(),a=l.detectForVideo(e,t);b(a)}}else if(e instanceof HTMLImageElement){let t=l.detect(e);b(t)}}catch(t){console.error("[Pose Plugin] Pose detection error:",t)}})}),c.registerHook("destroy",()=>{l&&(l.close(),l=null),k=null,C.clear(),i.remove()}),v(`
|
|
2
2
|
uniform int u_maxPoses;
|
|
3
3
|
uniform int u_nPoses;
|
|
4
|
-
uniform vec2 u_poseLandmarks[${
|
|
4
|
+
uniform vec2 u_poseLandmarks[${p*h}];
|
|
5
5
|
uniform sampler2D u_poseMask;
|
|
6
|
+
uniform vec2 u_poseCenter[${p}];
|
|
6
7
|
vec2 poseLandmark(int poseIndex, int landmarkIndex) {
|
|
7
|
-
return u_poseLandmarks[poseIndex * ${
|
|
8
|
+
return u_poseLandmarks[poseIndex * ${h} + landmarkIndex];
|
|
8
9
|
}
|
|
9
10
|
float getBody(vec2 pos) { return texture(u_poseMask, pos).g; }
|
|
10
|
-
float getSkeleton(vec2 pos) { return texture(u_poseMask, pos).b; }`)}}var E
|
|
11
|
+
float getSkeleton(vec2 pos) { return texture(u_poseMask, pos).b; }`)}}var N=E;export{N as default};
|
|
11
12
|
//# sourceMappingURL=pose.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/plugins/pose.ts"],"sourcesContent":["import ShaderPad, { PluginContext, TextureSource } from '../index';\nimport type { PoseLandmarker, NormalizedLandmark } from '@mediapipe/tasks-vision';\n\nexport interface PosePluginOptions {\n\tmodelPath?: string;\n\tmaxPoses?: number;\n\tminPoseDetectionConfidence?: number;\n\tminPosePresenceConfidence?: number;\n\tminTrackingConfidence?: number;\n\toutputSegmentationMasks?: boolean;\n}\n\nconst LANDMARK_COUNT = 33; // See https://ai.google.dev/edge/mediapipe/solutions/vision/pose_landmarker#pose_landmarker_model.\n\nfunction pose(config: { textureName: string; options?: PosePluginOptions }) {\n\tconst { textureName, options } = config;\n\tconst defaultModelPath =\n\t\t'https://storage.googleapis.com/mediapipe-models/pose_landmarker/pose_landmarker_lite/float16/1/pose_landmarker_lite.task';\n\n\treturn function (shaderPad: ShaderPad, context: PluginContext) {\n\t\tconst { injectGLSL } = context;\n\n\t\tlet poseLandmarker: PoseLandmarker | null = null;\n\t\tlet vision: any = null;\n\t\tlet lastVideoTime = -1;\n\t\tconst textureSources = new Map<string, TextureSource>();\n\t\tconst maxPoses = options?.maxPoses ?? 1;\n\t\tconst maskWidth = 512;\n\t\tconst maskHeight = 512;\n\t\tconst poseMaskCanvas = document.createElement('canvas');\n\t\tposeMaskCanvas.width = maskWidth;\n\t\tposeMaskCanvas.height = maskHeight;\n\t\tconst poseMaskCtx = poseMaskCanvas.getContext('2d')!;\n\t\tposeMaskCtx.globalCompositeOperation = 'lighten'; // Keep the highest value of each channel.\n\t\tconst poseConnections: { start: number; end: number }[] = [];\n\n\t\tasync function initializePoseLandmarker() {\n\t\t\ttry {\n\t\t\t\tconst { FilesetResolver, PoseLandmarker } = await import('@mediapipe/tasks-vision');\n\t\t\t\tvision = await FilesetResolver.forVisionTasks(\n\t\t\t\t\t'https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@latest/wasm'\n\t\t\t\t);\n\t\t\t\tposeConnections.push(...PoseLandmarker.POSE_CONNECTIONS);\n\t\t\t\tposeLandmarker = await PoseLandmarker.createFromOptions(vision, {\n\t\t\t\t\tbaseOptions: {\n\t\t\t\t\t\tmodelAssetPath: options?.modelPath || defaultModelPath,\n\t\t\t\t\t},\n\t\t\t\t\trunningMode: 'VIDEO',\n\t\t\t\t\tnumPoses: options?.maxPoses ?? 1,\n\t\t\t\t\tminPoseDetectionConfidence: options?.minPoseDetectionConfidence ?? 0.5,\n\t\t\t\t\tminPosePresenceConfidence: options?.minPosePresenceConfidence ?? 0.5,\n\t\t\t\t\tminTrackingConfidence: options?.minTrackingConfidence ?? 0.5,\n\t\t\t\t\toutputSegmentationMasks: options?.outputSegmentationMasks ?? false,\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error('[Pose Plugin] Failed to initialize Pose Landmarker:', error);\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\n\t\tasync function updateMaskTexture(poses: NormalizedLandmark[][], segmentationMasks?: ImageData[]) {\n\t\t\tif (!poseLandmarker) {\n\t\t\t\tconsole.warn('[Pose Plugin] Cannot update mask: poseLandmarker missing');\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tposeMaskCtx.clearRect(0, 0, poseMaskCanvas.width, poseMaskCanvas.height);\n\n\t\t\t\t// Draw the segmentation masks.\n\t\t\t\tif (segmentationMasks && segmentationMasks.length > 0) {\n\t\t\t\t\t// Combine all segmentation masks (for multiple poses).\n\t\t\t\t\tsegmentationMasks.forEach(mask => {\n\t\t\t\t\t\t// Resize mask to canvas size if needed.\n\t\t\t\t\t\tif (mask.width !== poseMaskCanvas.width || mask.height !== poseMaskCanvas.height) {\n\t\t\t\t\t\t\tconst tempCanvas = document.createElement('canvas');\n\t\t\t\t\t\t\ttempCanvas.width = mask.width;\n\t\t\t\t\t\t\ttempCanvas.height = mask.height;\n\t\t\t\t\t\t\tconst tempCtx = tempCanvas.getContext('2d')!;\n\t\t\t\t\t\t\ttempCtx.putImageData(mask, 0, 0);\n\t\t\t\t\t\t\tposeMaskCtx.drawImage(tempCanvas, 0, 0, poseMaskCanvas.width, poseMaskCanvas.height);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tposeMaskCtx.putImageData(mask, 0, 0);\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\t// Draw the skeleton.\n\t\t\t\tif (poseConnections.length) {\n\t\t\t\t\tconst lineWidth = Math.max(2, poseMaskCanvas.width / 256);\n\t\t\t\t\tposeMaskCtx.lineWidth = lineWidth;\n\t\t\t\t\tposeMaskCtx.lineCap = 'round';\n\t\t\t\t\tposeMaskCtx.strokeStyle = '#00f';\n\n\t\t\t\t\tposes.forEach(landmarks => {\n\t\t\t\t\t\tposeConnections.forEach(({ start, end }) => {\n\t\t\t\t\t\t\tconst a = landmarks[start];\n\t\t\t\t\t\t\tconst b = landmarks[end];\n\t\t\t\t\t\t\tif (!a || !b) return;\n\t\t\t\t\t\t\tif ((a.visibility ?? 1) < 0.3 || (b.visibility ?? 1) < 0.3) return;\n\t\t\t\t\t\t\tposeMaskCtx.beginPath();\n\t\t\t\t\t\t\tposeMaskCtx.moveTo(a.x * poseMaskCanvas.width, a.y * poseMaskCanvas.height);\n\t\t\t\t\t\t\tposeMaskCtx.lineTo(b.x * poseMaskCanvas.width, b.y * poseMaskCanvas.height);\n\t\t\t\t\t\t\tposeMaskCtx.stroke();\n\t\t\t\t\t\t});\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tshaderPad.updateTextures({ u_poseMask: poseMaskCanvas });\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error('[Pose Plugin] Failed to generate mask texture:', error);\n\t\t\t}\n\t\t}\n\n\t\tfunction processPoseResults(result: any) {\n\t\t\tif (!result.landmarks) return;\n\n\t\t\tupdateMaskTexture(result.landmarks, result.segmentationMasks).catch(error => {\n\t\t\t\tconsole.warn('[Pose Plugin] Mask texture update error:', error);\n\t\t\t});\n\n\t\t\tconst nPoses = result.landmarks.length;\n\t\t\tconst updates: Parameters<typeof shaderPad.updateUniforms>[0] = { u_nPoses: nPoses };\n\t\t\tif (nPoses) {\n\t\t\t\tupdates.u_poseLandmarks = result.landmarks.flatMap((landmarks: NormalizedLandmark[]) =>\n\t\t\t\t\tlandmarks.map(landmark => [landmark.x, 1.0 - landmark.y])\n\t\t\t\t);\n\t\t\t}\n\t\t\tshaderPad.updateUniforms(updates);\n\t\t}\n\n\t\tshaderPad.registerHook('init', async () => {\n\t\t\tshaderPad.initializeTexture('u_poseMask', poseMaskCanvas);\n\t\t\tshaderPad.initializeUniform('u_maxPoses', 'int', maxPoses);\n\t\t\tshaderPad.initializeUniform('u_nPoses', 'int', 0);\n\t\t\tconst defaultPoseData: [number, number][] = Array.from({ length: maxPoses * LANDMARK_COUNT }, () => [\n\t\t\t\t0.5, 0.5,\n\t\t\t]);\n\t\t\tshaderPad.initializeUniform('u_poseLandmarks', 'float', defaultPoseData, {\n\t\t\t\tarrayLength: maxPoses * LANDMARK_COUNT,\n\t\t\t});\n\n\t\t\tawait initializePoseLandmarker();\n\t\t});\n\n\t\tshaderPad.registerHook('updateTextures', (updates: Record<string, TextureSource>) => {\n\t\t\tObject.entries(updates).forEach(([name, source]) => {\n\t\t\t\tif (name !== textureName) return;\n\t\t\t\ttextureSources.set(name, source);\n\t\t\t\tif (!poseLandmarker) return;\n\t\t\t\ttry {\n\t\t\t\t\tif (source instanceof HTMLVideoElement) {\n\t\t\t\t\t\tif (source.currentTime !== lastVideoTime) {\n\t\t\t\t\t\t\tlastVideoTime = source.currentTime;\n\t\t\t\t\t\t\tconst timestamp = performance.now();\n\t\t\t\t\t\t\tconst result = poseLandmarker.detectForVideo(source, timestamp);\n\t\t\t\t\t\t\tprocessPoseResults(result);\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (source instanceof HTMLImageElement) {\n\t\t\t\t\t\tconst result = poseLandmarker.detect(source);\n\t\t\t\t\t\tprocessPoseResults(result);\n\t\t\t\t\t}\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconsole.error('[Pose Plugin] Pose detection error:', error);\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\n\t\tshaderPad.registerHook('destroy', () => {\n\t\t\tif (poseLandmarker) {\n\t\t\t\tposeLandmarker.close();\n\t\t\t\tposeLandmarker = null;\n\t\t\t}\n\t\t\tvision = null;\n\t\t\ttextureSources.clear();\n\t\t\tposeMaskCanvas.remove();\n\t\t});\n\n\t\tinjectGLSL(`\nuniform int u_maxPoses;\nuniform int u_nPoses;\nuniform vec2 u_poseLandmarks[${maxPoses * LANDMARK_COUNT}];\nuniform sampler2D u_poseMask;\nvec2 poseLandmark(int poseIndex, int landmarkIndex) {\n\treturn u_poseLandmarks[poseIndex * ${LANDMARK_COUNT} + landmarkIndex];\n}\nfloat getBody(vec2 pos) { return texture(u_poseMask, pos).g; }\nfloat getSkeleton(vec2 pos) { return texture(u_poseMask, pos).b; }`);\n\t};\n}\n\nexport default pose;\n"],"mappings":"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","names":["LANDMARK_COUNT","pose","config","textureName","options","defaultModelPath","shaderPad","context","injectGLSL","poseLandmarker","vision","lastVideoTime","textureSources","maxPoses","maskWidth","maskHeight","poseMaskCanvas","poseMaskCtx","poseConnections","initializePoseLandmarker","FilesetResolver","PoseLandmarker","error","updateMaskTexture","poses","segmentationMasks","mask","tempCanvas","lineWidth","landmarks","start","end","a","b","processPoseResults","result","nPoses","updates","landmark","defaultPoseData","name","source","timestamp","pose_default"]}
|
|
1
|
+
{"version":3,"sources":["../../src/plugins/pose.ts"],"sourcesContent":["import ShaderPad, { PluginContext, TextureSource } from '../index';\nimport type { PoseLandmarker, NormalizedLandmark } from '@mediapipe/tasks-vision';\n\nexport interface PosePluginOptions {\n\tmodelPath?: string;\n\tmaxPoses?: number;\n\tminPoseDetectionConfidence?: number;\n\tminPosePresenceConfidence?: number;\n\tminTrackingConfidence?: number;\n\toutputSegmentationMasks?: boolean;\n}\n\nconst LANDMARK_COUNT = 33; // See https://ai.google.dev/edge/mediapipe/solutions/vision/pose_landmarker#pose_landmarker_model.\n\nfunction pose(config: { textureName: string; options?: PosePluginOptions }) {\n\tconst { textureName, options } = config;\n\tconst defaultModelPath =\n\t\t'https://storage.googleapis.com/mediapipe-models/pose_landmarker/pose_landmarker_lite/float16/1/pose_landmarker_lite.task';\n\n\treturn function (shaderPad: ShaderPad, context: PluginContext) {\n\t\tconst { injectGLSL } = context;\n\n\t\tlet poseLandmarker: PoseLandmarker | null = null;\n\t\tlet vision: any = null;\n\t\tlet lastVideoTime = -1;\n\t\tconst textureSources = new Map<string, TextureSource>();\n\t\tconst maxPoses = options?.maxPoses ?? 1;\n\t\tconst maskWidth = 512;\n\t\tconst maskHeight = 512;\n\t\tconst poseMaskCanvas = document.createElement('canvas');\n\t\tposeMaskCanvas.width = maskWidth;\n\t\tposeMaskCanvas.height = maskHeight;\n\t\tconst poseMaskCtx = poseMaskCanvas.getContext('2d')!;\n\t\tconst segmentationCanvas = document.createElement('canvas');\n\t\tconst segmentationCtx = segmentationCanvas.getContext('2d')!;\n\t\tposeMaskCtx.globalCompositeOperation = segmentationCtx.globalCompositeOperation = 'lighten'; // Keep the highest value of each channel.\n\t\tconst poseConnections: { start: number; end: number }[] = [];\n\n\t\tasync function initializePoseLandmarker() {\n\t\t\ttry {\n\t\t\t\tconst { FilesetResolver, PoseLandmarker } = await import('@mediapipe/tasks-vision');\n\t\t\t\tvision = await FilesetResolver.forVisionTasks(\n\t\t\t\t\t'https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@latest/wasm'\n\t\t\t\t);\n\t\t\t\tposeConnections.push(...PoseLandmarker.POSE_CONNECTIONS);\n\t\t\t\tposeLandmarker = await PoseLandmarker.createFromOptions(vision, {\n\t\t\t\t\tbaseOptions: {\n\t\t\t\t\t\tmodelAssetPath: options?.modelPath || defaultModelPath,\n\t\t\t\t\t},\n\t\t\t\t\trunningMode: 'VIDEO',\n\t\t\t\t\tnumPoses: options?.maxPoses ?? 1,\n\t\t\t\t\tminPoseDetectionConfidence: options?.minPoseDetectionConfidence ?? 0.5,\n\t\t\t\t\tminPosePresenceConfidence: options?.minPosePresenceConfidence ?? 0.5,\n\t\t\t\t\tminTrackingConfidence: options?.minTrackingConfidence ?? 0.5,\n\t\t\t\t\toutputSegmentationMasks: options?.outputSegmentationMasks ?? true,\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error('[Pose Plugin] Failed to initialize Pose Landmarker:', error);\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\n\t\tfunction calculatePoseCenter(landmarks: NormalizedLandmark[]): [number, number] {\n\t\t\tlet minX = Infinity,\n\t\t\t\tmaxX = -Infinity,\n\t\t\t\tminY = Infinity,\n\t\t\t\tmaxY = -Infinity;\n\n\t\t\t// Calculate bounding box center from all landmarks.\n\t\t\tfor (const landmark of landmarks) {\n\t\t\t\tminX = Math.min(minX, landmark.x);\n\t\t\t\tmaxX = Math.max(maxX, landmark.x);\n\t\t\t\tminY = Math.min(minY, landmark.y);\n\t\t\t\tmaxY = Math.max(maxY, landmark.y);\n\t\t\t}\n\n\t\t\tconst centerX = (minX + maxX) / 2;\n\t\t\tconst centerY = (minY + maxY) / 2;\n\t\t\treturn [centerX, centerY];\n\t\t}\n\n\t\tasync function updateMaskTexture(poses: NormalizedLandmark[][], segmentationMasks?: any[]) {\n\t\t\tif (!poseLandmarker) {\n\t\t\t\tconsole.warn('[Pose Plugin] Cannot update mask: poseLandmarker missing');\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tposeMaskCtx.clearRect(0, 0, poseMaskCanvas.width, poseMaskCanvas.height);\n\n\t\t\t\t// Draw the segmentation masks.\n\t\t\t\tif (segmentationMasks && segmentationMasks.length > 0) {\n\t\t\t\t\tsegmentationMasks.forEach(mask => {\n\t\t\t\t\t\tif (!mask) return;\n\n\t\t\t\t\t\tconst { width, height } = mask;\n\t\t\t\t\t\tconst maskData = mask.getAsUint8Array();\n\t\t\t\t\t\tconst pixelCount = width * height;\n\t\t\t\t\t\tconst outputData = new Uint8ClampedArray(pixelCount * 4);\n\n\t\t\t\t\t\tfor (let i = 0; i < pixelCount; i++) {\n\t\t\t\t\t\t\toutputData[i * 4 + 1] = maskData[i]; // G (body mask)\n\t\t\t\t\t\t\toutputData[i * 4 + 3] = 255; // A (required for compositing)\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst rgbaMask = new ImageData(outputData, width, height);\n\n\t\t\t\t\t\t// Resize mask to canvas size if needed.\n\t\t\t\t\t\tif (width === poseMaskCanvas.width && height === poseMaskCanvas.height) {\n\t\t\t\t\t\t\tposeMaskCtx.putImageData(rgbaMask, 0, 0);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tif (segmentationCanvas.width !== width) segmentationCanvas.width = width;\n\t\t\t\t\t\t\tif (segmentationCanvas.height !== height) segmentationCanvas.height = height;\n\t\t\t\t\t\t\tsegmentationCtx.putImageData(rgbaMask, 0, 0);\n\t\t\t\t\t\t\tposeMaskCtx.drawImage(\n\t\t\t\t\t\t\t\tsegmentationCanvas,\n\t\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t\t0,\n\t\t\t\t\t\t\t\tposeMaskCanvas.width,\n\t\t\t\t\t\t\t\tposeMaskCanvas.height\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\t// Draw the skeleton.\n\t\t\t\tif (poseConnections.length) {\n\t\t\t\t\tconst lineWidth = Math.max(2, poseMaskCanvas.width / 256);\n\t\t\t\t\tposeMaskCtx.lineWidth = lineWidth;\n\t\t\t\t\tposeMaskCtx.lineCap = 'round';\n\t\t\t\t\tposeMaskCtx.strokeStyle = '#00f';\n\n\t\t\t\t\tposes.forEach(landmarks => {\n\t\t\t\t\t\tposeConnections.forEach(({ start, end }) => {\n\t\t\t\t\t\t\tconst a = landmarks[start];\n\t\t\t\t\t\t\tconst b = landmarks[end];\n\t\t\t\t\t\t\tif (!a || !b) return;\n\t\t\t\t\t\t\tif ((a.visibility ?? 1) < 0.3 || (b.visibility ?? 1) < 0.3) return;\n\t\t\t\t\t\t\tposeMaskCtx.beginPath();\n\t\t\t\t\t\t\tposeMaskCtx.moveTo(a.x * poseMaskCanvas.width, a.y * poseMaskCanvas.height);\n\t\t\t\t\t\t\tposeMaskCtx.lineTo(b.x * poseMaskCanvas.width, b.y * poseMaskCanvas.height);\n\t\t\t\t\t\t\tposeMaskCtx.stroke();\n\t\t\t\t\t\t});\n\t\t\t\t\t});\n\t\t\t\t}\n\n\t\t\t\tshaderPad.updateTextures({ u_poseMask: poseMaskCanvas });\n\t\t\t} catch (error) {\n\t\t\t\tconsole.error('[Pose Plugin] Failed to generate mask texture:', error);\n\t\t\t}\n\t\t}\n\n\t\tfunction processPoseResults(result: any) {\n\t\t\tif (!result.landmarks) return;\n\n\t\t\tupdateMaskTexture(result.landmarks, result.segmentationMasks).catch(error => {\n\t\t\t\tconsole.warn('[Pose Plugin] Mask texture update error:', error);\n\t\t\t});\n\n\t\t\tconst nPoses = result.landmarks.length;\n\t\t\tconst updates: Parameters<typeof shaderPad.updateUniforms>[0] = { u_nPoses: nPoses };\n\t\t\tif (nPoses) {\n\t\t\t\tupdates.u_poseLandmarks = result.landmarks.flatMap((landmarks: NormalizedLandmark[]) =>\n\t\t\t\t\tlandmarks.map(landmark => [landmark.x, 1.0 - landmark.y])\n\t\t\t\t);\n\n\t\t\t\tconst poseCenters: [number, number][] = [];\n\t\t\t\tfor (const landmarks of result.landmarks) {\n\t\t\t\t\tconst poseCenter = calculatePoseCenter(landmarks);\n\t\t\t\t\t// Invert Y-axis to match WebGL coordinate system.\n\t\t\t\t\tposeCenters.push([poseCenter[0], 1.0 - poseCenter[1]]);\n\t\t\t\t}\n\t\t\t\tupdates.u_poseCenter = poseCenters;\n\t\t\t}\n\t\t\tshaderPad.updateUniforms(updates);\n\t\t}\n\n\t\tshaderPad.registerHook('init', async () => {\n\t\t\tshaderPad.initializeTexture('u_poseMask', poseMaskCanvas);\n\t\t\tshaderPad.initializeUniform('u_maxPoses', 'int', maxPoses);\n\t\t\tshaderPad.initializeUniform('u_nPoses', 'int', 0);\n\t\t\tconst defaultPoseData: [number, number][] = Array.from({ length: maxPoses * LANDMARK_COUNT }, () => [\n\t\t\t\t0.5, 0.5,\n\t\t\t]);\n\t\t\tshaderPad.initializeUniform('u_poseLandmarks', 'float', defaultPoseData, {\n\t\t\t\tarrayLength: maxPoses * LANDMARK_COUNT,\n\t\t\t});\n\t\t\tconst defaultPoseCenterData: [number, number][] = Array.from({ length: maxPoses }, () => [0.5, 0.5]);\n\t\t\tshaderPad.initializeUniform('u_poseCenter', 'float', defaultPoseCenterData, {\n\t\t\t\tarrayLength: maxPoses,\n\t\t\t});\n\n\t\t\tawait initializePoseLandmarker();\n\t\t});\n\n\t\tshaderPad.registerHook('updateTextures', (updates: Record<string, TextureSource>) => {\n\t\t\tObject.entries(updates).forEach(([name, source]) => {\n\t\t\t\tif (name !== textureName) return;\n\t\t\t\ttextureSources.set(name, source);\n\t\t\t\tif (!poseLandmarker) return;\n\t\t\t\ttry {\n\t\t\t\t\tif (source instanceof HTMLVideoElement) {\n\t\t\t\t\t\tif (source.currentTime !== lastVideoTime) {\n\t\t\t\t\t\t\tlastVideoTime = source.currentTime;\n\t\t\t\t\t\t\tconst timestamp = performance.now();\n\t\t\t\t\t\t\tconst result = poseLandmarker.detectForVideo(source, timestamp);\n\t\t\t\t\t\t\tprocessPoseResults(result);\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (source instanceof HTMLImageElement) {\n\t\t\t\t\t\tconst result = poseLandmarker.detect(source);\n\t\t\t\t\t\tprocessPoseResults(result);\n\t\t\t\t\t}\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconsole.error('[Pose Plugin] Pose detection error:', error);\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\n\t\tshaderPad.registerHook('destroy', () => {\n\t\t\tif (poseLandmarker) {\n\t\t\t\tposeLandmarker.close();\n\t\t\t\tposeLandmarker = null;\n\t\t\t}\n\t\t\tvision = null;\n\t\t\ttextureSources.clear();\n\t\t\tposeMaskCanvas.remove();\n\t\t});\n\t\t// TODO: getBody and getSkeleton shouldn't rely on alpha. Do they? Seems so in the example...\n\t\tinjectGLSL(`\nuniform int u_maxPoses;\nuniform int u_nPoses;\nuniform vec2 u_poseLandmarks[${maxPoses * LANDMARK_COUNT}];\nuniform sampler2D u_poseMask;\nuniform vec2 u_poseCenter[${maxPoses}];\nvec2 poseLandmark(int poseIndex, int landmarkIndex) {\n\treturn u_poseLandmarks[poseIndex * ${LANDMARK_COUNT} + landmarkIndex];\n}\nfloat getBody(vec2 pos) { return texture(u_poseMask, pos).g; }\nfloat getSkeleton(vec2 pos) { return texture(u_poseMask, pos).b; }`);\n\t};\n}\n\nexport default pose;\n"],"mappings":"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","names":["LANDMARK_COUNT","pose","config","textureName","options","defaultModelPath","shaderPad","context","injectGLSL","poseLandmarker","vision","lastVideoTime","textureSources","maxPoses","maskWidth","maskHeight","poseMaskCanvas","poseMaskCtx","segmentationCanvas","segmentationCtx","poseConnections","initializePoseLandmarker","FilesetResolver","PoseLandmarker","error","calculatePoseCenter","landmarks","minX","maxX","minY","maxY","landmark","centerX","centerY","updateMaskTexture","poses","segmentationMasks","mask","width","height","maskData","pixelCount","outputData","i","rgbaMask","lineWidth","start","end","a","b","processPoseResults","result","nPoses","updates","poseCenters","poseCenter","defaultPoseData","defaultPoseCenterData","name","source","timestamp","pose_default"]}
|