iOS向けにビルドしたUnityアプリで WebCamTexture を使ってカメラを扱う方法や注意点について説明します。
これまでAndroidでWebCamTextureを使って映像を出力する方法やGetPixcel32()でメモリリークを防ぐ方法などをまとめてきました。
今回、iOSでWebCamTextureを使にあたり、Androidでは不要だったiOS独自の対応が必要になりましたのでその辺りを説明していきたいと思います。
WebCamTextureの基本的な使い方についてはこちらの記事を参考にしていただければと思います。
カメラの使用許可を要求する方法
iOSでもAndroid同様にカメラの使用許可を要求する必要があります。その処理がAndroidとは異なり、以下のようなスクリプトで処理します。
IEnumerator Start()
{
yield return Application.RequestUserAuthorization(UserAuthorization.WebCam);
if (Application.HasUserAuthorization(UserAuthorization.WebCam)) {
// UnityのWebCamTextureで処理
}
}
Androidで使用していたPermission.Cameraは使用せず、UserAuthorization.WebCamを使用する点に注意してください。
また、Xcodeでも以下の通り、info.plistにPrivacy – Camera Usage Descriptionへの設定が必要になります。
このカメラの設定はUnityのPostbuildスクリプトでUnityのビルド時に自動で生成することも可能です。詳しくはこちらの記事をご参考ください。
カメラの起動方法
カメラ起動がAndroidの挙動と異なる
Androidでは特に気にしていなかったカメラの起動待ちですが、iOSではPlay()を実行してからすぐには起動してこないようです。
というのも、Play()による起動直後にwidthパラメータを参照したところ、requestedWidthとは全く異なる値(16)が読み出せてしまいました。
時間がたつと、requestedWidthでリクエストした値に変化することから、起動が完了するまで正しいwidthとが取得できないと判断しました。
これをケアするために、コルーチンでカメラを起動させることで対応しました。
コルーチンとはStartCoroutine()で実行できるタスクのようなものです。コルーチンは処理を途中で抜けることができ、処理の続きを次のフレームや指定時間後に処理できるというものです。
iOSのカメラ起動スクリプト
以下にカメラ起動のコードを示します。
// カメラを起動させる
public void StartCamera()
{
// 処理はコルーチンで実行する
StartCoroutine(_startCamera());
}
IEnumerator _startCamera()
{
// 指定カメラを起動させる
webCam = new WebCamTexture(WebCamTexture.devices[0].name, 640, 480);
// RawImageのテクスチャにWebCamTextureのインスタンスを設定
RawImage.texture = webCam;
// カメラ起動
webCam.Play();
while (webCam.width != webCam.requestedWidth)
{
// widthが指定したものになっていない場合は処理を抜けて次のフレームで再開
yield return null;
}
yield break;
}
_startCameraがコルーチンで処理するためにIEnumeratorで定義されているのに注意してください。yield return nullはここは一旦引いて、次のフレームでまた続きを処理することを意味します。コルーチンはyield breakで終了します。
WebCamTextureのwidthをが要求した値であるrequestedWidthになったことでカメラが起動したと判断し、処理を抜けています。
カメラのプレビュー画像を正しく表示する方法
カメラの表示はAndroidと同じなのですが、以前の記事でvideoVerticallyMirroredの取り扱いを間違っているところがあったので、ここで訂正させていただきます。
カメラの表示を正しい向きで取り込むためのコードは以下になります。
if (webCam.videoVerticallyMirrored)
{
//左右反転しているのを戻す
Vector3 scaletmp = RawImage.GetComponent<RectTransform>().localScale;
scaletmp.y = -1;
RawImage.GetComponent<RectTransform>().localScale = scaletmp;
}
// 起動させて初めてvideoRotationAngle、width、heightに値が入り、
// アスペクト比、何度回転させれば正しく表示されるかがわかる
// 表示するRawImageを回転させる
Vector3 angles = RawImage.GetComponent<RectTransform>().eulerAngles;
angles.z = -webCam.videoRotationAngle;
RawImage.GetComponent<RectTransform>().eulerAngles = angles;
// widthはx、heightはyでサイズ調整
// 全体を表示させるように、大きい方のサイズを表示枠に合わせる
float scaler;
Vector2 sizetmp = RawImage.GetComponent<RectTransform>().sizeDelta;
if (webCam.width > webCam.height)
{
scaler = sizetmp.x / webCam.width;
}
else
{
scaler = sizetmp.y / webCam.height;
}
// サイズ調整
sizetmp.x = webCam.width * scaler;
sizetmp.y = webCam.height * scaler;
// 表示領域サイズ設定
RawImage.GetComponent<RectTransform>().sizeDelta = sizetmp;
if (WebCamTexture.devices[0].isFrontFacing ) {
// Face Cameraの場合は反転表示させる回転の向きによって、どの軸で回転させるかが異なる
Vector3 scaletmp = RawImage.GetComponent<RectTransform>().localScale;
if ((webCam.videoRotationAngle == 90) || (webCam.videoRotationAngle == 270))
{
scaletmp.y *= -1;
} else
{
scaletmp.x *= -1;
}
RawImage.GetComponent<RectTransform>().localScale = scaletmp;
}
以前はisFrontFacingがTrueでvideoVerticallyMirroredもTrueだったら、反転させる必要ないと思っていましたが間違っていました。
videoVerticallyMirroredは回転する前の映像が反転しているかどうかなので、まず最初に反転なしの正しい映像に戻してやる必要があります。
その上でisFrontFacingがTrueの時は回転後の正しい軸で反転させてあげます。Androidの時はvideoVerticallyMirroredがTrueなデバイスに当たっていなかったので、たまたま正しく表示できていましたが、iOSはTrueで来たので気づくことができました。
おわりに
iOS、Android共にNativeライブラリを用いることなく、カメラの映像を正しく表示させることができました。
WebCamTextureのパラメータは実際に触ってみないとわかならいものが多かったり、カメラの起動待ちなど振る舞いも動かしてみないとわからないものが多いと感じました。
iOSやAndroidで実際にカメラを動かしてWebCamTextureやNativeのパラメータを確認するアプリをリリースしています。手軽に手持ちのデバイスでカメラの動きやパラメータを確認できるアプリになっています。ご参考まで。
コメント
[…] 【Unity】WebCamTextureでiOSのカメラを使いこなす これまでAndroid、Wondows PCでWe… […]