diff --git a/example/assets/pages/facemesh-with-machine-learning/shaders/fragmentShader.frag b/example/assets/pages/facemesh-with-machine-learning/shaders/fragmentShader.frag
index e615831b..63401e98 100644
--- a/example/assets/pages/facemesh-with-machine-learning/shaders/fragmentShader.frag
+++ b/example/assets/pages/facemesh-with-machine-learning/shaders/fragmentShader.frag
@@ -1,15 +1,20 @@
-// VSCode Frag
-#pragma vscode_glsllint_stage : frag
-
// Const
const float PI = 3.1415926535897932384626433832795;
// Varying
-varying vec3 vPos;
+varying vec4 vPos;
+varying vec2 vUv;
// Main
void main () {
- gl_FragColor = vec4( gl_PointCoord, 1., 1. ) * vec4( vPos, 1. );
+ // Make point rounded
+ float dist = length( gl_PointCoord - vec2( 0.5 ) );
+ float alpha = 1. - smoothstep( 0.45, 0.5, dist );
+
+ // Bring back pixels
+ // gl_FragColor = vec4( gl_PointCoord, 1., alpha ) * vPos;
+ // gl_FragColor = vec4( vPos.xyz, alpha );
+ gl_FragColor = vec4( vUv, 1., alpha );
}
diff --git a/example/assets/pages/facemesh-with-machine-learning/shaders/vertexShader.vert b/example/assets/pages/facemesh-with-machine-learning/shaders/vertexShader.vert
index 47b84c2b..5f7e17ff 100644
--- a/example/assets/pages/facemesh-with-machine-learning/shaders/vertexShader.vert
+++ b/example/assets/pages/facemesh-with-machine-learning/shaders/vertexShader.vert
@@ -2,16 +2,18 @@
#pragma vscode_glsllint_stage : vert
// Varying
-varying vec3 vPos;
+varying vec4 vPos;
+varying vec2 vUv;
// Main
void main () {
- vPos = position.xyz;
+ vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
- vec4 mvPosition = modelViewMatrix * vec4( position.xyz, 1.0 );
+ vUv = uv;
+ vPos = mvPosition;
- gl_PointSize = 2. * ( 1. / - mvPosition.z );
+ gl_PointSize = 10. * ( 1. / - mvPosition.z );
gl_Position = projectionMatrix * mvPosition;
diff --git a/example/assets/style.css b/example/assets/style.css
index e91efbe3..0e3b159f 100644
--- a/example/assets/style.css
+++ b/example/assets/style.css
@@ -60,6 +60,34 @@ video {
}
+button {
+
+ width: 100%;
+ max-width: 354px;
+ margin: 16px auto;
+ padding: 8px;
+ color: #f05;
+ font-weight: bold;
+ line-height: 1.36;
+ text-align: center;
+ background-color: #f3f0f1;
+ border: 0;
+ border-radius: 6px;
+ cursor: pointer;
+ opacity: .9;
+ transition: all .27s ease-in-out;
+ appearance: none;
+
+}
+
+button:hover,
+button:active,
+button:focus {
+
+ opacity: 1;
+
+}
+
.opacity-50 {
opacity: .5;
diff --git a/example/pages/experiments/facemesh-with-machine-learning.vue b/example/pages/experiments/facemesh-with-machine-learning.vue
index fe08b44c..e85fe0b7 100644
--- a/example/pages/experiments/facemesh-with-machine-learning.vue
+++ b/example/pages/experiments/facemesh-with-machine-learning.vue
@@ -3,7 +3,7 @@
-
- Click on the video to see your face
- (allow access to camera and microphone)
-
+
@@ -33,7 +42,7 @@
Points,
Scene,
ShaderMaterial,
- PlaneBufferGeometry,
+ BufferGeometry,
// Camera
PerspectiveCamera,
// Utils
@@ -43,7 +52,6 @@
DoubleSide,
// Buffers
Float32BufferAttribute,
- BufferAttribute,
DynamicDrawUsage,
} from 'three';
@@ -59,10 +67,23 @@
// Page
export default {
name: 'three-js-starter',
+ data: () => (
+ {
+ width: 500,
+ height: 500,
+ isWebcamReady: false,
+ }
+ ),
created() {
this.$sketchManager = null;
+ // Faces and geometry utils
+ this.$facemesh = null;
+ this.$geometry = null;
+ this.$camera = null;
+ this.$scene = null;
+
},
async mounted() {
@@ -100,23 +121,35 @@
},
methods: {
createRenderer(
- context
+ {
+ context,
+ width,
+ height,
+ color = '#111',
+ }
) {
// Renderer
const renderer = new WebGLRenderer(
{
context,
+ depth: false,
+ antialias: true,
}
);
renderer.setClearColor(
new Color(
- '#121212'
+ color
),
1
);
+ renderer.setSize(
+ width,
+ height
+ );
+
renderer.outputEncoding = sRGBEncoding;
renderer.physicallyCorrectLights = true;
@@ -133,10 +166,10 @@
// Camera
const camera = new PerspectiveCamera(
- 45,
+ 70,
width / height,
- 0.1,
- 100
+ 0.001,
+ 1000
);
camera.position.set(
@@ -145,10 +178,6 @@
3
);
- camera.lookAt(
- new Vector3()
- );
-
// Controls
const { OrbitControls } = await orbitControlsLoader()
, controls = new OrbitControls(
@@ -163,26 +192,22 @@
};
},
- createSceneAndPointsMaterialGeometry(
- {
- width,
- height,
- }
- ) {
+ createSceneAndPointsMaterialGeometry() {
// Scene
const scene = new Scene()
- , geometry = new PlaneBufferGeometry(
- width / height,
- 1,
- 21,
- 22
- )
+ , geometry = new BufferGeometry()
, material = new ShaderMaterial(
{
+ depthTest: false,
+ depthWrite: false,
+ transparent: true,
vertexShader,
fragmentShader,
side: DoubleSide,
+ extensions: {
+ derivatives: '#extension GL_OES_standard_derivatives : enable',
+ },
uniforms: {
time: {
type: 'f',
@@ -195,19 +220,29 @@
},
}
)
- , points = new Points(
- geometry,
- material
- )
;
+ geometry.name = 'face';
+
return {
scene,
- points,
geometry,
material,
};
+ },
+ createPoints(
+ material,
+ geometry,
+ ) {
+
+ const points = new Points(
+ geometry,
+ material
+ );
+
+ return points;
+
},
// Attributes
addAttributes(
@@ -216,101 +251,48 @@
const number = 468
, numberOfCoords = 3
+ , arrayOfPoints = Array.from(
+ {
+ length: number * numberOfCoords,
+ },
+ Math.random
+ )
, points = new Float32BufferAttribute(
- new Array(
- number * numberOfCoords
- ).fill(
- 0
- ),
+ arrayOfPoints,
numberOfCoords,
).setUsage(
DynamicDrawUsage
)
+ , attributeName = 'position'
;
+ points.name = attributeName;
+
geometry.setAttribute(
- 'facesPoints',
- new BufferAttribute(
- points,
- numberOfCoords
- )
+ attributeName,
+ points
);
},
// Faces
- async findFaces() {
+ async face(
+ width = this.width,
+ height = this.height,
+ ) {
- // if( ! this.facemesh )
- // return;
-
- // const faces = await this.facemesh.estimateFaces(
- // this.$refs.video,
- // );
-
- // if( ! faces.length )
- // return;
-
- // Each face object contains a `scaledMesh` property,
- // which is an array of 468 landmarks.
- // faces.forEach(
- // face => {
-
- // if( ! face.mesh )
- // return;
-
- // face.mesh.forEach(
- // (
- // [
- // x,
- // y,
- // z,
- // ],
- // index
- // ) => pointsPositions.setXYZ(
- // index,
- // x,
- // y,
- // z,
- // )
- // );
-
- // // pointsGeometry.attributes.position.needsUpdate = true;
-
- // // console.info(
- // // 'Face updated',
- // // {
- // // pointsGeometry,
- // // }
- // // );
-
- // }
- // );
+ if( ! this.$refs.video )
+ return;
- },
- async webcamReady() {
+ if( this.isWebcamReady || this.$facemesh ) {
- // Video loading
- this.facemesh = await load(
- {
- maxFaces: 1,
- }
- );
+ await this.findFaces();
- await this.findFaces();
+ return;
- },
- async videoInitialization(
- {
- width,
- height,
}
- ) {
try {
- if( ! this.$refs.video )
- return;
-
// Video
this.$refs.video.width = width;
this.$refs.video.height = height;
@@ -329,7 +311,127 @@
await this.$refs.video.play();
- await this.webcamReady();
+ // Start the recognition
+ await this.facemeshInit();
+
+ this.isWebcamReady = true;
+
+ await this.findFaces();
+
+ } catch( e ) {
+
+ console.error(
+ e
+ );
+
+ }
+
+ },
+ async facemeshInit() {
+
+ this.$nuxt.$loading.start();
+
+ try {
+
+ // Load the Face library
+ this.$facemesh = await load(
+ {
+ maxFaces: 1,
+ }
+ );
+
+ } catch( e ) {
+
+ console.error(
+ e
+ );
+
+ }
+
+ this.$nuxt.$loading.finish();
+
+ },
+ async findFaces() {
+
+ if( ! this.$facemesh )
+ return;
+
+ try {
+
+ const faces = await this.$facemesh.estimateFaces(
+ this.$refs.video,
+ );
+
+ if( ! faces.length )
+ return;
+
+ console.info(
+ 'Faces found',
+ faces
+ );
+
+ // Each face object contains a `scaledMesh` property,
+ // which is an array of 468 landmarks.
+ faces.forEach(
+ face => {
+
+ if( ! face.mesh )
+ return;
+
+ const {
+ mesh: points,
+ // boundingBox,
+ } = face
+ , position = []
+ ;
+
+ points.forEach(
+ (
+ [
+ x,
+ y,
+ z,
+ ]
+ ) => {
+
+ const {
+ x: xN,
+ y: yN,
+ z: zN,
+ } = new Vector3(
+ x,
+ y,
+ z
+ ).normalize();
+
+ position.push(
+ xN,
+ yN,
+ zN
+ );
+
+ }
+ );
+
+ this.$geometry.attributes.position.array = new Float32Array(
+ position
+ );
+
+ this.$geometry.attributes.position.needsUpdate = true;
+
+ this.$geometry.computeBoundingSphere();
+
+ console.info(
+ 'Face updated',
+ {
+ position,
+ geometry: this.$geometry,
+ scene: this.$scene,
+ }
+ );
+
+ }
+ );
} catch( e ) {
@@ -349,40 +451,57 @@
}
) {
+ this.width = width;
+ this.height = height;
+
const renderer = this.createRenderer(
- context
+ {
+ context,
+ width,
+ height,
+ }
)
, {
camera,
controls,
} = await this.createCameraAndControls(
{
- width,
- height,
+ width: window.innerWidth,
+ height: window.innerHeight,
context,
}
)
, {
scene,
- points,
material,
geometry,
- } = this.createSceneAndPointsMaterialGeometry(
- {
- width,
- height,
- }
- )
+ } = this.createSceneAndPointsMaterialGeometry()
;
this.addAttributes(
geometry
);
+ const points = this.createPoints(
+ material,
+ geometry
+ );
+
scene.add(
points
);
+ this.$geometry = geometry;
+ this.$camera = camera;
+ this.$scene = scene;
+
+ console.info(
+ 'Sketch ready',
+ {
+ geometry: this.$geometry,
+ }
+ );
+
// Render
return {
render(
diff --git a/example/pages/single/three-js-starter.vue b/example/pages/single/three-js-starter.vue
index fd275185..084feec8 100644
--- a/example/pages/single/three-js-starter.vue
+++ b/example/pages/single/three-js-starter.vue
@@ -19,7 +19,6 @@
PerspectiveCamera,
// Utils
Color,
- Vector3,
sRGBEncoding,
DoubleSide,
} from 'three';
@@ -79,7 +78,12 @@
},
methods: {
createRenderer(
- context
+ {
+ context,
+ width,
+ height,
+ color = '#111',
+ }
) {
// Renderer
@@ -91,11 +95,16 @@
renderer.setClearColor(
new Color(
- '#121212'
+ color
),
1
);
+ renderer.setSize(
+ width,
+ height
+ );
+
renderer.outputEncoding = sRGBEncoding;
renderer.physicallyCorrectLights = true;
@@ -112,20 +121,16 @@
// Camera
const camera = new PerspectiveCamera(
- 45,
+ 70,
width / height,
- 0.1,
- 100
+ 0.001,
+ 1000
);
camera.position.set(
0,
0,
- 6
- );
-
- camera.lookAt(
- new Vector3()
+ 4.5
);
// Controls
@@ -172,12 +177,14 @@
};
},
- async createLights() {
+ async createLights(
+ color = '#f05'
+ ) {
const { PointLight } = await pointLightLoader()
, light = new PointLight(
new Color(
- '#f05'
+ color
),
500,
100,
@@ -206,15 +213,19 @@
) {
const renderer = this.createRenderer(
- context
+ {
+ context,
+ width,
+ height,
+ }
)
, {
camera,
controls,
} = await this.createCameraAndControls(
{
- width,
- height,
+ width: window.innerWidth,
+ height: window.innerHeight,
context,
}
)