3D Sensor Advent Calendar 2019 の13日目の記事です。
##はじめに
LIVを使ってBeatSaberのMR動画を撮影してるときに、「これ自分でも実装できるんじゃないか??」と思ったのをきっかけに挑戦してみました。
2時間くらい頑張ったらサクッと出来たので記事を書いてみます。
出来たこと
AzureKinectでグリーンバック無しのクロマキー合成的な何か pic.twitter.com/SuvWXWhAbf
— そいちろ@LookingGlass&AzureKinect (@asidys230) December 13, 2019
環境
・Unity 2019.2.11.f
・Azure Kinect (Amazonで買った)
手順(ざっくり)
###1.ポイントクラウド表示
こちらの素晴らしいブログを参照してください。
C#で始めるAzure Kinect開発⑥:Unity+C#でPoint Cloud表示
###2.クロマキー的な何か
今回のクロマキー的な何かはオブジェクトが重なった部分を描画しないようにして実現しました。
人物抽出ではなくて背景除去になります。
背景のみが映っている状態でポイントクラウドを複製、後述のシェーダーを適用したマテリアルに変更。
複製したポイントクラウドのPointSizeを少し大きくして、背景のポイントクラウドを覆うとこんな感じに。
シェーダー素人なので、こちらの記事を参考にしました。
【Unityシェーダ入門】オブジェクトが重なった部分をくり抜く
ポイントクラウド用に色々書き替えたのが以下です。
Shader "Custom/ColorutoutPoint" {
Properties{
_Size("ShaderSize", Float) = 1.000000
_PointSize("PointSize", Float) = 5.0
_Color("Color", Color) = (1,1,1,1)
}
SubShader{
Tags {"Queue" = "Geometry-1"}
Pass {
Zwrite On
ColorMask 0
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#pragma target 2.0
#include "UnityCG.cginc"
#pragma multi_compile_fog
#define USING_FOG (defined(FOG_LINEAR) || defined(FOG_EXP) || defined(FOG_EXP2))
float _Size;
float _PointSize;
// uniforms
// vertex shader input data
struct appdata {
float3 pos : POSITION;
half4 color : COLOR;
UNITY_VERTEX_INPUT_INSTANCE_ID
};
// vertex-to-fragment interpolators
struct v2f {
float psize : PSIZE;
fixed4 color : COLOR0;
#if USING_FOG
fixed fog : TEXCOORD0;
#endif
float4 pos : SV_POSITION;
UNITY_VERTEX_OUTPUT_STEREO
};
// vertex shader
v2f vert(appdata IN) {
IN.pos.xyz = IN.pos.xyz * _Size;
v2f o;
UNITY_SETUP_INSTANCE_ID(IN);
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
half4 color = IN.color;
float3 eyePos = mul(UNITY_MATRIX_MV, float4(IN.pos,1)).xyz;
half3 viewDir = 0.0;
o.color = saturate(color);
// compute texture coordinates
// fog
#if USING_FOG
float fogCoord = length(eyePos.xyz); // radial fog distance
UNITY_CALC_FOG_FACTOR_RAW(fogCoord);
o.fog = saturate(unityFogFactor);
#endif
// transform position
o.pos = UnityObjectToClipPos(IN.pos);
o.psize = _PointSize;
return o;
}
// fragment shader
fixed4 frag(v2f IN) : SV_Target {
fixed4 col;
col = IN.color;
// fog
#if USING_FOG
col.rgb = lerp(unity_FogColor.rgb, col.rgb, IN.fog);
#endif
return col;
}
ENDCG
}
}
}
//背景除去用メッシュ生成
if (Input.GetKeyDown(KeyCode.Space))
{
if (GameObject.Find("CutoutMesh"))
{
GameObject obj = GameObject.Find("CutoutMesh");
Destroy(obj);
}
verticesGreenBack = vertices;
greenBack = new GameObject();
greenBack.name = "CutoutMesh";
greenBack.AddComponent<MeshFilter>();
meshRendererG = greenBack.AddComponent<MeshRenderer>();
meshG = new Mesh();
//65535点以上描画する際に下記を記述
meshG.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32;
//頂点座標と色をmeshに渡す
meshG.vertices = verticesGreenBack;
//リストに格納した番号の頂点座標を点として描画
meshG.SetIndices(indices, MeshTopology.Points, 0);
//メッシュをこのオブジェクトのMeshFilterに適用
greenBack.GetComponent<MeshFilter>().mesh = meshG;
meshRendererG.material = materialG;
}
// 削除
if (Input.GetKey(KeyCode.Backspace))
{
GameObject obj = GameObject.Find("CutoutMesh");
Destroy(obj);
}
###3.おもむろにカメラの前へ。
いい感じに人だけ映る。
AzureKinectでグリーンバック無しのクロマキー合成的な何か pic.twitter.com/SuvWXWhAbf
— そいちろ@LookingGlass&AzureKinect (@asidys230) December 13, 2019
##さいごに
明日はtakminさんの「kalibrを使ってカメラ/IMUキャリブレーション」です。