Hi everyone
Recently I started a project where I’m basically creating makeup try-ons using FaceMeshTexture filters, but I wanted to implement a comparison slider where I could see the difference between the filter being applied and not applied at the same time.
I’ve tried adding an intensity field on the shaderMaterial of the FaceMeshTexture but it ended up breaking the texture so I just reverted back to the original shaderMaterial.
Does anyone know how I could implement this slider?
Any help is appreciated.
Thanks!
A common approach for a comparison slider – showing one half of your face with the FaceMeshTexture filter and the other half without – is to duplicate your face mesh so that you have two versions: one with the filter applied and the original one. Then, you can use clipping planes (or masks) to “cut” each instance along a vertical line that’s controlled by a slider value.
For example, you can have two components:
• One that applies a clipping plane to reveal only the filtered side.
• One that applies the inverse clipping plane to show only the original (unfiltered) side.
When you move the slider (an HTML range input), you update both clipping planes so their boundaries adjust seamlessly.
Here’s a simplified Needle Engine component (written in TypeScript) that demonstrates the idea:
import { Behaviour, serializable } from "@needle-tools/engine";
import { Plane, Vector3 } from "three";
export class FaceMeshComparison extends Behaviour {
// Assign your two face mesh objects in the editor or via script
@serializable(Object3D)
faceMeshWithFilter: any = null;
@serializable(Object3D)
faceMeshOriginal: any = null;
private filterPlane!: Plane;
private originalPlane!: Plane;
awake() {
// Initialize the clipping planes along the vertical axis.
// The normals are set so the plane clips away one side.
this.filterPlane = new Plane(new Vector3(-1, 0, 0), 0);
this.originalPlane = new Plane(new Vector3(1, 0, 0), 0);
// Apply local clipping to the filtered face mesh
if (this.faceMeshWithFilter) {
this.faceMeshWithFilter.traverse((child: any) => {
if (child.material) {
child.material.clippingPlanes = [this.filterPlane];
child.material.clipShadows = true;
child.material.needsUpdate = true;
}
});
}
// Apply local clipping to the original face mesh
if (this.faceMeshOriginal) {
this.faceMeshOriginal.traverse((child: any) => {
if (child.material) {
child.material.clippingPlanes = [this.originalPlane];
child.material.clipShadows = true;
child.material.needsUpdate = true;
}
});
}
// Listen to slider input from your HTML element (make sure its id is "comparisonSlider")
const slider = document.getElementById("comparisonSlider") as HTMLInputElement;
if (slider) {
slider.addEventListener("input", () => {
const value = parseFloat(slider.value); // Assuming a value between 0 and 1
this.updateClipping(value);
});
}
}
updateClipping(value: number) {
// Adjust the clipping constant based on the slider value.
// The relationship here is simplistic – you might need to adjust it
// based on how your scene and camera are set up.
this.filterPlane.constant = -value;
this.originalPlane.constant = value;
}
}
In this solution the slider’s value directly remaps where the clipping happens, letting you “slide” between versions. This avoids messing with shader properties on the FaceMeshTexture filter (which you noted was breaking the texture) by leveraging scene setup instead.
You can review similar techniques in other Needle Engine sample components, such as the face filter samples at facefilter—FaceSticker.ts.md. This strategy should give you smooth control over what portion of your face shows the filter versus the unfiltered version.
I hope this helps, and feel free to ask for more details if needed!
1 replies left - Become PRO for more replies. thread_jeAvQuYPTAZ9ibd77FMoWa8J Reply to this post directly if you need further help (bottom right button)
Hi,
I used the original code from the FaceMeshBehaviour class under the Sample Face Filter Scene and displayed the wrong colors at the wrong spots along the texture.
I added these lines to the faceMeshTexture fragment:
uniform float intensity;
texColor.a *= intensity;
And this line to the createMaterial() function:
intensity: { value: this.intensity },
Everything else is the original code that was present already when I first created the project.
I’m extending the FaceTexture class and modify the created material with the intensity and fragment shader.
It sounds like you’re using the FaceFilter example from samples - we have since then moved the code into it’s own npm package. The samples Unity package needs to be updated to reflect that. I’ll create an issue to prioritize this.
Hi
Thank you so much for your help, this worked!
Maybe it was broken because I was modifying the sample file?
Anyway, extending base class fixed my issue.