ARKit + Metalで手をゆらゆらさせてみる
ARKitとMetalを使って手をゆらゆらさせる方法を紹介します。
考え方
ARKitのPeople Occlusionを使用します。
People Occlusionを使用すると人型のマスクテクスチャが得られるので、そのマスクとカメラの画像を同時に歪ませて、歪んだ合成用画像を取得します。歪んだまま切り取る感じです。
こんな画像が取得できます(わかりやすくするために動画よりも強めに歪ませています)
この歪ませた手の映像と、元の映像を重ねることで上のような動画を作ることができます。
手順
1.Appleの公式サンプルを入手する
Appleの公式サンプルにPeople Occlusionを使用して人型のマスクテクスチャを得る処理が書かれているため、これをベースに書いていきます。
Effecting People Occlusion in Custom Renderers
2. シェーダーに経過時間を渡す
ゆらゆらさせるには、経過時間を変形式に与える必要があります。
シェーダーに渡すstructを宣言します。
struct Uniforms {
var time: Float = 0
}
次に、経過時間を管理するための変数と、開始時間を宣言します。
class Renderer {
var uniforms = Uniforms()
private var startDate: Date = Date()
var uniformsBuffer: MTLBuffer! // シェーダに渡すためのバッファ
そしてシェーダに情報を渡しているcompositeImagesWithEncoderメソッドの中で一緒に経過時間を渡してあげます。
uniforms.time = time
uniformsBuffer = device.makeBuffer(bytes: &uniforms, length: MemoryLayout<Uniforms>.stride, options: [])
uniformsBuffer.label = "UniformsBuffer"
シェーダー側でもSwift側と同じstructを用意しておき、関数の引数として受け取ります。
引数名はmyUniformsとしています。
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. シェーダーを書き換える
公式サンプルのうち、Shaders.metalのcompositeImageFragmentShader関数を次のように書き換えます。
@@ -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); // 変形の式
half4 cameraColor = half4(rgb);
- half alpha = half(alphaTexture.sample(s, cameraTexCoord).r);
+ half alpha = half(alphaTexture.sample(s, cameraTexCoord + modifier).r); // 人型マスクを変形させる
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; // 画像を変形させる
- half4 occluderResult = mix(sceneColor, cameraColor, alpha);
+ half4 displacedCol = half4(sceneColorTexture.sample(s, displacedUV)); // 変形した人型画像の取得
+ half4 occluderResult = mix(sceneColor, displacedCol, alpha); // 変形した画像と元の画像を合成
half4 mattingResult = mix(sceneColor, occluderResult, showOccluder);
return mattingResult;
}
重要なのはここです。
float2 modifier = float2(sin(cameraTexCoord.y + myUniforms.time*5)*0.2, 0); // 変形の式
sin関数に入力画像のy座標と、経過時間を足したものを与え、これをmodifyerに代入しています。
modifierはカメラや人型マスクに加算するための変数で、今回はxだけに式が入っているので、x軸方向だけがゆらめくことになります。
なお、実際の動画は縦方向にゆらいでいるので、上の式と矛盾しますがこれは、iPhoneをランドスケープの状態で録画したものを、画像編集ソフトで縦に変換したためです。
図形の変形については、こちらの記事に書きましたので、こちらもご覧ください。
ARKitやSceneKitの図形をMetalシェーダーで変形させる方法
仕上がり
Youtubeにも動画をアップしています。
仕上がりの動画(Youtube)
最後に
NoteではiOS開発について定期的に発信していますので、フォローしていただけますと幸いです。
https://note.com/tokyoyoshida
Twitterでは簡単なtipsを発信しています。
https://twitter.com/jugemjugemjugem
Author And Source
この問題について(ARKit + Metalで手をゆらゆらさせてみる), 我々は、より多くの情報をここで見つけました https://qiita.com/TokyoYoshida/items/7984c28d6f556f6cffe0著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .