Erstellen eines Snapchat-ähnlichen Filters mit Jeeliz 'FaceFilter-API: Teil 2, Benutzerinteraktionen und Partikel

Mit der FaceFilter-API können Sie mühelos Snapchat-ähnliche Filter in Ihren Web-Apps erstellen. Es basiert auf unserem neuronalen Gesichtserkennungsnetzwerk und kombiniert die Leistungsfähigkeit des Deep Learning mit der Vielseitigkeit von WebGL / Three.js.

Rückblick auf den vorherigen Teil: Im ersten Teil dieser Serie haben wir erstmals gesehen, wie ein 3D-Modell mit Blender nach JSON exportiert wird. Wir haben dann unseren Hut zu unserer Three.js-Szene hinzugefügt und sind so ein wahrer Pirat der Grand Line geworden! Ziemlich ordentlich, oder?

In diesem Tutorial verwenden wir eine Benutzerinteraktion, um das Hinzufügen einer großartigen Fliege zu unserem Filter auszulösen. Wir werden gleichzeitig animierte Partikel hinzufügen, um einen coolen Erscheinungseffekt zu erzielen. Shazaa!

Voraussetzungen: Wie im vorherigen Tutorial benötigen Sie gute Kenntnisse in Javascript und gute Kenntnisse der Grundlagen von Three.j.

Bereit, einen Kick-Ass-Filter zu bauen?!

Erstellen unseres Projektordners

Wir beginnen am selben Punkt wie beim ersten Tutorial dieser Serie. Duplizieren wir den Ordner "cube" und nennen ihn "bowtie".

NB: Zum Ausführen der FaceFilter-API müssen unsere Assets über einen lokalen Server bereitgestellt werden. Starten Sie in der Befehlszeile im Stammverzeichnis unseres Projektordners das Skript httpServer.py und besuchen Sie localhost: 8455, um die Demos zu überprüfen.

Erstellen Sie unser Bowtie-Objekt

Okay, Zeit unsere Fliege zu kreieren. Wir suchen zuerst im Web nach einem 3D-Modell und exportieren es dann mit Blender nach JSON. Wenn Sie den ersten Artikel dieser Reihe noch nicht gelesen haben, wird der gesamte Vorgang hier beschrieben.

Unsere prächtige Fliege, visualisiert in Blender

Okay, jetzt, da wir unser Modell im richtigen Format haben, können wir mit dem Codieren beginnen. In demo.js erstellen wir eine Funktion, initListeners (), in der wir den gesamten Code in Bezug auf Benutzerinteraktionen einfügen - in diesem Fall das "Klicken" oder "Berühren" auf Mobilgeräten.

// hier initialisieren wir alle Listener für Benutzerinteraktionen
Funktion initListeners () {
  // Dein Code geht hierher!
}}

Wir erstellen dann unser Bowtie-Netz, indem wir unser Modell laden, ein Material erstellen und dann beide zu einem Netz mischen:

// hier initialisieren wir alle Listener für Benutzerinteraktionen
Funktion initListeners () {
  // Wir erstellen unseren Loader
  const loader = new THREE.BufferGeometryLoader ()
  // Wir laden dann unser Modell
  loader.load (
    'models / bowtie.json',
    Funktion (Geometrie) {
      // Dann erstellen wir im Rückruf unseres Loaders zuerst ein Material
      // Wir wählen ein MeshPhongMaterial, um realistischer zu werden
      // Ergebnis (siehe: https://threejs.org/docs/#api/materials/MeshPhongMaterial)
      const material = new THREE.MeshPhongMaterial ({
      // Hier laden wir eine Textur für unser Modell
        map: new THREE.TextureLoader (). load ('models / texture.jpg'),
        Glanz: 3,
        Spiegel: 0xffffff
      });
      // Hier erstellen wir unser Netz mit der neu geladenen Geometrie und dem Material, das wir gerade erstellt haben
     const bowtieMesh = new THREE.Mesh (Geometrie, Matte);
   )
}}

Unsere Partikel erschaffen

Der nächste Schritt besteht darin, unser Partikelobjekt zu erstellen. Beim Klicken breiten sich die Partikel in zufällige Richtungen aus, um einen coolen magischen Erscheinungseffekt zu erzielen. Wir werden einen Teil unseres Codes aus diesem Beispiel von three.js erhalten.

Insgesamt werden diese Beispiele oder meine Anlaufstelle, wenn ich irgendwo in einem three.js-Projekt festsitze, behandelt, da die meisten Grundlagen und noch komplexeren Funktionen behandelt werden.

Wir werden diese Art von Partikeln erzeugen:

Schön, nicht wahr? Lass uns eintauchen!

// Wir erstellen ein leeres Array, in dem wir unsere Partikel verehren
// um sie später zu animieren
const PARTICLES = [];
// Wir instanziieren unser Partikelobjekt 3D und setzen seine "sichtbare" Eigenschaft auf false
// Wir werden diese Eigenschaft verwenden, um dieses Objekt auszublenden, das durch unsere Animation benötigt wurde
const PARTICLESOBJ3D = new THREE.Object3D ();
PARTICLESOBJ3D.visible = false;
// füge das Objekt zu unserem Gesichtsobjekt 3D hinzu
THREEFACEOBJ3D.add (PARTICLESOBJ3D);
// ein Material erstellen
// Wir verwenden die Hilfsmethode generateSprite aus dem Beispiel von threejs
const PartikelMaterial = neues THREE.SpriteMaterial ({
  map: new THREE.CanvasTexture (generateSprite ()),
  Blending: THREE.AdditiveBlending
});
// Wir erzeugen dann 200 Partikel, die wir beim Klicken anzeigen
für (sei i = 0; i <= 200; i ++) {
  Partikel = neu THREE.Sprite (Partikelmaterial);
  PARTICLES.push (Partikel);
  PARTICLESOBJ3D.add (Partikel);
}}

Ich habe die generateSprite () -Methode aus dem Beispiel von three.js ein wenig angepasst:

Funktion generateSprite () {
  var canvas = document.createElement ('canvas');
  canvas.width = 8;
  canvas.height = 8;
  var context = canvas.getContext ('2d');
  var gradient = context.createRadialGradient (canvas.width / 2, canvas.height / 2, 0, canvas.width / 2, canvas.height / 2, canvas.width / 2);
  gradient.addColorStop (0, 'rgba (255,255,255,0,5)');
  gradient.addColorStop (0,2, 'rgba (255,255,255,0,5)');
  gradient.addColorStop (1, 'rgba (0,0,0,0,5)');
  context.fillStyle = gradient;
  context.fillRect (0, 0, canvas.width, canvas.height);
  Leinwand zurückgeben;
}}

Erstellen Sie unseren Event Listener

Wir möchten erkennen, wann ein Benutzer auf unsere Leinwand klickt. Wir werden dann die Fliege an der Position der Maus hinzufügen, wenn der Benutzer klickt und unsere Partikelanimation startet. Beginnen wir mit der Erstellung eines Ereignis-Listeners.

In unserem Loader-Rückruf:

// Wir erstellen einen Verweis auf unsere Zeichenfläche und fügen unseren Ereignis-Listener hinzu
const canvas = document.getElementById ('jeeFaceFilterCanvas');
canvas.addEventListener ('click', (event) => {
  // Wir positionieren unser Netz mithilfe unserer Hilfsfunktion setPosition
  bowtieMesh = setPosition (bowtieMesh, Ereignis);
  // Wir setzen .frustumCulled auf false, um Elemente zu rendern, die einen Teil ihres Körpers haben
  // aus dem Kegelstumpf
  bowtieMesh.frustumCulled = false;
  // Setze den RenderOrder hoch, um unsere Fliege über unsere Videotextur zu legen
  bowtieMesh.renderOrder = 100000;
  // Wir erstellen ein Bowtie-Objekt in 3D und fügen unser Netz hinzu
  const BOWTIE = new THREE.Object3D ();
  BOWTIE.add (bowtieMesh);
  // Wir setzen dann die sichtbare Eigenschaft des Partikels object3D auf "true", damit sie gerendert wird, und positionieren das Objekt mit unserem setPosition-Helfer
  PARTICLESOBJ3D.visible = true;
  setPosition (PARTICLESOBJ3D, Ereignis);
  // Wir rufen dann die animateParticle-Methode auf, die wir direkt danach für jedes Element aus unserem PARTICLES-Array erstellen
  // Diese Methode übernimmt die Animation unserer Partikel
  PARTICLES.forEach ((Partikel, Index) => {
    animateParticle (Partikel, 50 * Index);
  });
  // Wir fügen ein setTimeout hinzu, um die sichtbare Eigenschaft unseres Partikelobjekts festzulegen
  // auf false, nachdem die Animation beendet ist
  setTimeout (function () {
     PARTICLESOBJ3D.visible = false;
  }, 50 * PARTICLES.length);
  // Wir fügen endlich unser Bowtie-Objekt hinzu
  THREEFACEOBJ3D.add (BOWTIE);
});

Puh! Das war eine große Sache, aber wir sind hier fast fertig! Wir müssen noch unsere Hilfsmethoden setPosition () und animateParticles () hinzufügen.

Erstellen Sie unseren setPosition-Helfer

Ich werde nur setPosition einfügen, da Sie die zugrunde liegenden Konzepte nicht verstehen müssen. Wenn Sie jedoch bereit sind, etwas mehr über die Funktionsweise zu verstehen, lade ich Sie ein, das folgende Tutorial auf WebGLAcademy.com durchzuführen.

Hier ist unsere Funktion:

let MOUSEVECTOR = new THREE.Vector3 () let DIRECTIONVECTOR = new THREE.Vector3 () let VIEWPORTVECTOR = new THREE.Vector3 () // Diese Funktion positioniert das Bowtie-Netz auf unserer THREEFACEOBJ3D-Funktion setBowtiePosition (mesh, event) {// we Berechnen Sie die Position der Maus innerhalb der Leinwand
// Sie müssen möglicherweise damit herumspielen, je nachdem, ob Ihre Zeichenfläche absolut / normal positioniert ist. var x = - (2 * (event.clientX - canvas.offsetLeft + canvas.offsetWidth / 2) / canvas.offsetWidth - 1); var y = - (2 * (event.clientY - canvas.offsetTop + canvas.offsetHeight / 2) / canvas.offsetHeight - 1);
// Dies wird verwendet, um den Punkt zu finden, an dem das Netz hinzugefügt werden soll. Klicken Sie auf MOUSEVECTOR.set (x, y). VIEWPORTVECTOR.set (x, y, 1);
  DIRECTIONVECTOR.copy (VIEWPORTVECTOR);
  DIRECTIONVECTOR.unproject (THREECAMERA);
  DIRECTIONVECTOR (THREECAMERA.position);
  DIRECTIONVECTOR.normalize ();
  // Wir berechnen den Koeffizienten, mit dem wir die Position unseres Netzes ermitteln können. const k = _headCenterZ / DIRECTIONVECTOR.z;
mesh.position.copy (DIRECTIONVECTOR) .multiplyScalar (k); mesh.position (THREEFACEOBJ3D.position); }}

Animieren Sie unsere Partikel mit animateParticle

Perfekt. Wir können jetzt jedes Element, das wir beim Klicken hinzufügen, an der Mausposition positionieren. Lassen Sie uns unsere animateParticle-Methode erstellen. Diese Methode akzeptiert zwei Argumente:

  1. Das Partikelnetz, das wir animieren möchten
  2. Der Verzögerungswert, dh die Zeit bis zum Abschluss der Animation

Wir werden Tween.js verwenden, um unsere Partikel zu animieren. Noch einmal, ich werde die mathematische Logik dieser Animation nicht erklären. Der beste Weg, um besser zu verstehen, was vor sich geht, besteht darin, mit den Parametern zu spielen und den Effekt zu beobachten, den sie erzeugt.

Funktion animateParticle (Partikel, Verzögerung) {
  // Zwischenposition:
  var radiusEnd = 100;
  Partikel.Position.set (0,0,0)
var theta = Math.random () * 2 * Math.PI; // Winkel in der Ebene XY
var phi = (Math.random () * 2–1) * Math.PI / 4 // Winkel zwischen Ebene XY und Partikel. 0-> in der Ebene XY
  neues TWEEN.Tween (Partikelposition)
  .to ({x: 0,008 * radiusEnd * Math.cos (Theta) * Math.cos (phi),
    y: 0,008 * radiusEnd * Math.sin (Theta) * Math.cos (phi),
  }, verzögern)
  .Start();
  // Tween-Skala:
  Partikel.Skala.x = Partikel.Skala.y = Math.Random () * 0,15
  neues TWEEN.Tween (Partikel.Skala)
  .to ({x: 0,0001, y: 0,0001}, Verzögerung)
  .Start();
}}

Der letzte Schritt besteht darin, eine Codezeile in unsere Renderschleife einzufügen, um unsere Tweens im Laufe der Zeit zu aktualisieren. In der main () -Funktion im callbackTrack:

if (ISDETECTED) {
  // Wir fügen unsere Codezeile im ISDETECTED if-Block hinzu
  TWEEN.update ()
}}

Und da ist es! Jedes Mal, wenn der Benutzer an der Position seiner Maus auf die Leinwand klickt, wird eine fabelhafte Fliege hinzugefügt, zusammen mit einem coolen Erscheinungseffekt, der durch die Animation unserer Partikel erzeugt wird. Wie großartig ist das?!

Übungen:

  1. Spielen Sie ein bisschen mehr mit den Partikeln: Lassen Sie sie wie Regen vom Himmel fallen oder ändern Sie ihre Farben im Laufe der Zeit, ändern Sie ihre Bewegung
  2. Wählen Sie andere 3D-Modelle aus und fügen Sie sie zu Ihrem Projekt hinzu, die sich gut zum virtuellen Anprobieren eignen: Ohrringe, T-Shirts…

Zusammenfassen:

Der zweite Teil dieser Reihe zum Erstellen von Snapchat-ähnlichen Filtern ist abgeschlossen! Ja!

In diesem Tutorial haben wir gesehen, wie ein 3D-Objekt bei Benutzerinteraktion hinzugefügt wird. Wir haben auch gesehen, wie man Partikel erzeugt und animiert, um einen schönen Effekt zu erzielen!

Im nächsten Teil werden wir visuelle Deformationen im Gesicht des Benutzers erzeugen. Das wird lustig, ich garantiere es; Außerdem können wir tiefer in Three.js eintauchen und komplexere 3D-Techniken studieren. Also seid gespannt auf diese aufregende Folge!