[SWIFT] Essayez de vous serrer la main avec ARKit + Metal

Je vais vous montrer comment utiliser ARKit et Metal pour vous serrer la main.

La finition ressemble à ceci. 20201015_qiita用_ショート.gif

Façon de penser

Utilisez l'Occlusion de personnes d'ARKit.

People Occlusion vous donne une texture de masque humanoïde qui déforme le masque et l'image de la caméra en même temps pour obtenir une image composite déformée. On a l'impression de couper tout en étant déformé.

Vous pouvez obtenir une image comme celle-ci (elle est plus déformée que la vidéo pour plus de clarté)

Vous pouvez réaliser la vidéo ci-dessus en superposant l'image de la main déformée et l'image d'origine.

procédure

** 1. Obtenez l'échantillon officiel d'Apple **

L'exemple officiel d'Apple décrit le processus d'obtention d'une texture de masque humanoïde à l'aide de l'Occlusion de personnes, donc j'écrirai sur cette base.

Effecting People Occlusion in Custom Renderers

** 2. Passez le temps écoulé au shader **

Pour le faire balancer, il faut donner le temps écoulé à la formule de transformation.

Déclarez la structure à passer au shader.

Renderer.swift


struct Uniforms {
    var time: Float = 0
}

Ensuite, déclarez les variables de gestion du temps écoulé et de l'heure de début.

Renderer.swift


class Renderer {
    var uniforms = Uniforms()
    private var startDate: Date = Date()
    var uniformsBuffer: MTLBuffer! //Tampon à passer au shader

Ensuite, dans la méthode compositeImagesWithEncoder qui transmet les informations au shader, nous passerons ensemble le temps écoulé.

Renderer.swift


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

Préparez la même structure côté shader que côté Swift et recevez-la comme argument de la fonction. Le nom de l'argument est 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. Réécrire le shader **

Dans l'exemple officiel, réécrivez la fonction compositeImageFragmentShader de Shaders.metal comme suit.

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); //Formule de transformation
     half4 cameraColor = half4(rgb);
-    half alpha = half(alphaTexture.sample(s, cameraTexCoord).r);
+    half alpha = half(alphaTexture.sample(s, cameraTexCoord + modifier).r); //Transformez le masque humanoïde

     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; //Transformez l'image

-    half4 occluderResult = mix(sceneColor, cameraColor, alpha);
+    half4 displacedCol = half4(sceneColorTexture.sample(s, displacedUV)); //Acquisition d'une image humanoïde déformée
+    half4 occluderResult = mix(sceneColor, displacedCol, alpha); //Combinez l'image déformée avec l'image d'origine
     half4 mattingResult = mix(sceneColor, occluderResult, showOccluder);
     return mattingResult;
 }

C'est là que ça compte.

Shaders.metal


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

La coordonnée y de l'image d'entrée plus le temps écoulé est donnée à la fonction sin, et elle est affectée au modificateur. Le modificateur est une variable à ajouter à la caméra ou au masque humanoïde, et cette fois la formule n'est contenue que dans x, donc seule la direction de l'axe x fluctuera.

De plus, comme la vidéo réelle fluctue dans le sens vertical, cela contredit la formule ci-dessus, mais c'est parce que l'iPhone enregistré en mode paysage a été converti verticalement avec un logiciel de retouche d'image.

J'ai écrit sur la transformation de la figure dans cet article, alors veuillez également le voir ici.

Comment transformer des figurines ARKit et SceneKit avec un shader Metal

terminer

J'ai également mis en ligne une vidéo sur Youtube. Vidéo terminée (Youtube)

Le code source est ici.

finalement

Note publie régulièrement sur le développement iOS, alors suivez-nous. https://note.com/tokyoyoshida

Nous envoyons des conseils simples sur Twitter. https://twitter.com/jugemjugemjugem

Recommended Posts

Essayez de vous serrer la main avec ARKit + Metal
Camouflage optique avec ARKit + SceneKit + Metal ①
Navigation Web avec ARKit + SceneKit + Metal
Camouflage optique avec ARKit + SceneKit + Metal ②
Tout le monde est super Saiyan avec ARKit + Metal
Essayez DI avec Micronaut
Essayez de créer avec Trailblazer
Essayez WebSocket avec jooby