[SWIFT] Schütteln Sie Ihre Hände mit ARKit + Metal

Ich werde Ihnen zeigen, wie Sie mit ARKit und Metal Ihre Hände schütteln können.

Das Finish sieht so aus. 20201015_qiita用_ショート.gif

Denkweise

Verwenden Sie ARKits People Occlusion.

People Occlusion bietet Ihnen eine humanoide Maskentextur, die das Masken- und Kamerabild gleichzeitig verzerrt, um ein verzerrtes zusammengesetztes Bild zu erhalten. Es fühlt sich an, als würde man verzerrt herausschneiden.

Sie können ein Bild wie dieses erhalten (es ist aus Gründen der Klarheit stärker verzerrt als das Video).

Sie können das obige Video erstellen, indem Sie das verzerrte Handbild und das Originalbild überlagern.

Verfahren

** 1. Holen Sie sich Apples offizielles Muster **

Apples offizielles Beispiel beschreibt den Prozess des Erhaltens einer humanoiden Maskentextur unter Verwendung von People Occlusion, daher werde ich darauf basierend schreiben.

Effecting People Occlusion in Custom Renderers

** 2. Übergeben Sie die verstrichene Zeit an den Shader **

Um es schwanken zu lassen, ist es notwendig, der Transformationsformel die verstrichene Zeit zu geben.

Deklarieren Sie die Struktur, die an den Shader übergeben werden soll.

Renderer.swift


struct Uniforms {
    var time: Float = 0
}

Als nächstes deklarieren Sie die Variablen für die Verwaltung der verstrichenen Zeit und der Startzeit.

Renderer.swift


class Renderer {
    var uniforms = Uniforms()
    private var startDate: Date = Date()
    var uniformsBuffer: MTLBuffer! //Puffer, der an den Shader übergeben werden soll

Dann übergeben wir in der Methode composImagesWithEncoder, die die Informationen an den Shader weitergibt, die verstrichene Zeit zusammen.

Renderer.swift


uniforms.time = time
uniformsBuffer = device.makeBuffer(bytes: &uniforms, length: MemoryLayout<Uniforms>.stride, options: [])
uniformsBuffer.label = "UniformsBuffer"

Bereiten Sie auf der Shader-Seite dieselbe Struktur vor wie auf der Swift-Seite, und erhalten Sie sie als Argument für die Funktion. Der Argumentname ist myUniforms.

Shaders.metal


struct Uniforms {
    float time;
};

fragment half4 compositeImageFragmentShader(CompositeColorInOut in [[ stage_in ]],
                                    texture2d<float, access::sample> capturedImageTextureY [[ texture(0) ]],
                                    texture2d<float, access::sample> capturedImageTextureCbCr [[ texture(1) ]],
                                    texture2d<float, access::sample> sceneColorTexture [[ texture(2) ]],
                                    depth2d<float, access::sample> sceneDepthTexture [[ texture(3) ]],
                                    texture2d<float, access::sample> alphaTexture [[ texture(4) ]],
                                    texture2d<float, access::sample> dilatedDepthTexture [[ texture(5) ]],
                                    constant SharedUniforms &uniforms [[ buffer(kBufferIndexSharedUniforms) ]],
                                    constant Uniforms &myUniforms [[buffer(kBufferIndexMyUniforms)]])
{

** 3. Schreibe den Shader neu **

Schreiben Sie im offiziellen Beispiel die CompositeImageFragmentShader-Funktion von Shaders.metal wie folgt um.

Shaders.metal


@@ -219,8 +397,9 @@ fragment half4 compositeImageFragmentShader(CompositeColorInOut in [[ stage_in ]
     half4 sceneColor = half4(sceneColorTexture.sample(s, sceneTexCoord));
     float sceneDepth = sceneDepthTexture.sample(s, sceneTexCoord);

+    float2 modifier = float2(sin(cameraTexCoord.y + myUniforms.time*5)*0.2, 0); //Transformationsformel
     half4 cameraColor = half4(rgb);
-    half alpha = half(alphaTexture.sample(s, cameraTexCoord).r);
+    half alpha = half(alphaTexture.sample(s, cameraTexCoord + modifier).r); //Transformiere die humanoide Maske

     half showOccluder = 1.0;

@@ -233,8 +412,11 @@ fragment half4 compositeImageFragmentShader(CompositeColorInOut in [[ stage_in ]
         showOccluder = (half)step(dilatedDepth, sceneDepth); // forwardZ case
     }

+    float2 displacedUV = sceneTexCoord + modifier; //Transformiere das Bild

-    half4 occluderResult = mix(sceneColor, cameraColor, alpha);
+    half4 displacedCol = half4(sceneColorTexture.sample(s, displacedUV)); //Aufnahme eines deformierten humanoiden Bildes
+    half4 occluderResult = mix(sceneColor, displacedCol, alpha); //Kombinieren Sie das deformierte Bild mit dem Originalbild
     half4 mattingResult = mix(sceneColor, occluderResult, showOccluder);
     return mattingResult;
 }

Hier kommt es darauf an.

Shaders.metal


float2 modifier = float2(sin(cameraTexCoord.y + myUniforms.time*5)*0.2, 0); //Transformationsformel

Die y-Koordinate des Eingabebildes plus die verstrichene Zeit wird der sin-Funktion gegeben, und diese wird dem Modifikator zugewiesen. Der Modifikator ist eine Variable, die der Kamera oder der humanoiden Maske hinzugefügt werden soll. Dieses Mal ist die Formel nur in x enthalten, sodass nur die Richtung der x-Achse schwankt.

Da das tatsächliche Video in vertikaler Richtung schwankt, widerspricht es der obigen Formel. Dies liegt jedoch daran, dass das im Querformat aufgenommene iPhone vertikal mit einer Bildbearbeitungssoftware konvertiert wurde.

Ich habe in diesem Artikel über die Transformation der Figur geschrieben, siehe auch hier.

So transformieren Sie ARKit- und SceneKit-Figuren mit Metal Shader

Fertig

Ich habe auch ein Video auf Youtube hochgeladen. Fertiges Video (Youtube)

Der Quellcode ist hier.

Schließlich

Hinweis veröffentlicht regelmäßig Informationen zur iOS-Entwicklung. Folgen Sie uns daher. https://note.com/tokyoyoshida

Wir senden einfache Tipps auf Twitter. https://twitter.com/jugemjugemjugem

Recommended Posts

Schütteln Sie Ihre Hände mit ARKit + Metal
Optische Tarnung mit ARKit + SceneKit + Metal ①
Surfen im Internet mit ARKit + SceneKit + Metal
Optische Tarnung mit ARKit + SceneKit + Metal ②
Jeder ist super Saiyajin mit ARKit + Metal
Versuchen Sie DI mit Micronaut
Versuchen Sie es mit Trailblazer
Probieren Sie WebSocket mit Jooby aus