ハンドポーズを認識してシャッターを切ろう!
プレビュー表示欄を作成
シャッターを切った時に撮影イメージを確認するプレビュー表示欄を作成します。
(1) Imageオブジェクトを作成して設定します。
- メニュー: GameObject / UI / Image
- 名前: OverlayImage
- Inspectorの設定:
Rect Transform / Anchor Presets: stretch - stretch
Rect Transform / Left: 0
Rect Transform / Top: 0
Rect Transform / Right: 0
Rect Transform / Bottom: 0
Image / Color: 0, 0, 0, 224 ( R, G, B, A )
(2) 上記で作成したOverlayImageの中にImageオブジェクトを作成します。
- メニュー: (Hierarchy) / シーン / Canvas / OverlayImage を右クリック / UI / Image
- 名前: PreviewImage
(3) Gameウィンドウで確認しながら PreviewImage のサイズを調整します。
- Inspectorの設定:
Rect Transform / Anchors / Min / X: 0.15
Rect Transform / Anchors / Min / Y: 0.15
Rect Transform / Anchors / Max / X: 0.85
Rect Transform / Anchors / Max / Y: 0.85
Rect Transform / Left: 0
Rect Transform / Top: 0
Rect Transform / Right: 0
Rect Transform / Bottom: 0
スクリプトを作成
フレーム毎に手のポーズを確認して、決まったポーズであれば撮影を行うスクリプトを作成します。撮影は、カメラ映像を取得してImageオブジェクトに表示します。
※ UnityでiOS端末のアルバム保存を行うにはプラグインが必要となるため、今回は表示のみとしています。
(1) Scriptsフォルダを作成します。
- メニュー: (Project) / Assets を右クリック / Create / Folder
- 名前: Scripts
(2) スクリプトファイルを作成します。
- メニュー: (Project) / Assets / Scripts を右クリック / Create / C# Script
- 名前: PoseShutter
(3) 作成したスクリプトファイルをダブルクリックしてスクリプトを記述します。
- スクリプト: (Project) / Assets / Scripts / PoseShutter
- スクリプト内容:
using System.Collections;
using TofAr.V0.Hand;
using UnityEngine;
using UnityEngine.UI;
public class PoseShutter : MonoBehaviour
{
// 撮影時にキャプチャーするカメラ
public Camera captureCamera;
// プレビューをオーバーレイ表示にするImageオブジェクト
public Image overlayImage;
// プレビューを表示するImageオブジェクト
public Image previewImage;
// シャッターポーズ
private const PoseIndex SHUTTER_POSE = PoseIndex.Peace;
// Start is called before the first frame update
void Start()
{
// プレビュー表示を閉じる
this.overlayImage.gameObject.SetActive(false);
}
// Update is called once per frame
void Update()
{
// プレビューの表示状態で処理を切り替え
if (this.overlayImage.gameObject.activeSelf == true)
{
// 表示時は、タップ操作でプレビュー表示を閉じる
if (Input.GetMouseButtonDown(0))
{
this.overlayImage.gameObject.SetActive(false);
}
}
else
{
// 非表示時は、Handデータを取得してポーズを判定
StartCoroutine("CheckHandPose");
}
}
// Handデータを取得してポーズを判定
private IEnumerator CheckHandPose()
{
// 1回目で撮影するとポーズの途中でも認識されて撮影されるため、
// 時間をあけて2回判定する
var loopCount = 2;
for (var cnt = 0; cnt < loopCount; cnt++)
{
// Handデータを取得
var handData = TofArHandManager.Instance.HandData;
if (handData == null)
{
yield break;
}
// 認識したポーズを取得
handData.GetPoseIndex(out var leftPose, out var rightPose);
// シャッターポーズ以外の場合、判定は終了
if (leftPose != SHUTTER_POSE && rightPose != SHUTTER_POSE)
{
yield break;
}
// 最終ループ以外は1秒待機
if (cnt < loopCount - 1)
{
yield return new WaitForSeconds(1);
}
}
// 判定を通過してプレビューが表示されていない場合、プレビューを表示
if (this.overlayImage.gameObject.activeSelf == false)
{
this.ShowPreview();
}
}
// カメラ映像を取得して、プレビューを表示する
private void ShowPreview()
{
// カメラと映像サイズを取得
var camera = this.captureCamera;
var cameraW = camera.pixelWidth;
var cameraH = camera.pixelHeight;
// 既存の設定をバックアップ
var backupActiveRenderTexture = RenderTexture.active;
var backupCameraTargetTexture = camera.targetTexture;
// レンダーテクスチャを一時的に変更して、カメラ映像を取得
var rect = new Rect(0, 0, cameraW, cameraH);
var renderTexture = new RenderTexture(cameraW, cameraH, 24);
try
{
var texture2D = new Texture2D(cameraW, cameraH, TextureFormat.RGB24, false);
RenderTexture.active = renderTexture;
camera.targetTexture = renderTexture;
camera.Render();
texture2D.ReadPixels(rect, 0, 0);
texture2D.Apply();
// カメラ映像からSpriteを作成し、プレビューイメージとして設定
this.previewImage.sprite = Sprite.Create(texture2D, rect, new Vector2(0.5f, 0.5f));
this.previewImage.preserveAspect = true;
}
finally
{
RenderTexture.active = backupActiveRenderTexture;
camera.targetTexture = backupCameraTargetTexture;
Destroy(renderTexture);
}
// プレビューを表示
this.overlayImage.gameObject.SetActive(true);
}
}
スクリプトをアタッチ
スクリプトを設定して、Unityから実行されるようにします。
(1) スクリプトをアタッチするために「空のオブジェクト」を作成して設定します。
- メニュー: GameObject / Create Empty
- 名前: PoseShutter
- Inspectorの設定:
Add Component: Pose Shutter ※ 上記で作成したスクリプト
(2) 上記で追加したコンポーネント(Pose Shutter)を設定します。
- Inspectorの設定:
Capture Camera: Hierarchyウィンドウの Main Camera を設定
Overlay Image: Hierarchyウィンドウの OverlayImage を設定
Preview Image: Hierarchyウィンドウの PreviewImage を設定
これでハンドポーズを認識してシャッターが切れるようになりました。フロントカメラで自分を映して、ピースサインをしてみましょう!
ToF ARでは、他にも色々なポーズを認識します。
使用できるポーズを確認して、シャッターポーズを変えてみましょう。
API references - TofAr.V0.Hand.PoseIndex
また、ポーズ以外に ToF AR はジェスチャーを認識する事もできます。
API references - TofAr.V0.Hand.GestureIndex
但し、ポーズと違って、ジェスチャーの認識結果は static のイベント形式になっています。リファレンスの TofArHandManager からジェスチャーが推定された時に発生するイベントとジェスチャー推定を開始するメソッドを調べて、ジェスチャーでシャッターを切れるようにしてみましょう!
API references - TofAr.V0.Hand.TofArHandManager