2017年06月20日

[Unity] Viveフロントカメラで疑似AR表示を実装する方法

arcamera2.png

HTC Viveのフロントカメラの映像を、カメラの向きと画角を考慮して配置したビルボードポリゴンに表示する方法をご紹介したいと思います。

まず、新規プロジェクトを作成し、アセットストアからSteamVR Pluginをインポートし、「Assets/SteamVR/Prefabs/[CameraRig]」をHierarchyに追加します。

また、Unity 5.6ではViveコントローラが認識しないので、「Camera (eye)」に「SteamVR_UpdatePoses」をアタッチします。

詳しくは、以下のサイトを参考にして下さい。


まず、不要なので「Main Camera」を削除します。

次に、スクリーンを表示するための「3D Object/Quad」を[CameraRig]の下に作成します。とりあえず名前を「ARScreen」に変更します。

「Mesh Collider」は不要なので削除します。

「Mesh Renderer」の「Light Probes」「Reflection Probes」「Cast Shadows」「Receive Shadows」は不要なのでオフにします。

「ARScreen」に「Assets/SteamVR/Extras/SteamVR_TestTrackedCamera.cs」を追加し、「Material」に「Assets/SteamVR/Extras/Assets/SteamVR/Extras/SteamVR_TestTrackedCamera.mat」を設定し、「Target」に自分自身の「ARScreen」を設定します。

また、「Materials」の「Element 0」にも同じマテリアルを設定します。

次に、「Assets/SteamVR/Extras/SteamVR_TestTrackedCamera.cs」を開き、コードを書き替えます。直接編集するのが嫌な場合はコピーしてから書き替えて下さい。

「SteamVR_TestTrackedCamera」クラスの最後に、以下のメソッドを追加します。
// プロジェクションのスケールを取得する
static Vector2 GetProjectionScale(SteamVR_TrackedCamera.VideoStreamTexture source)
{
    Valve.VR.CVRTrackedCamera trackedCamera = Valve.VR.OpenVR.TrackedCamera;
    if (trackedCamera == null) return Vector2.one;

    // スケール値を取得するだけなので、Near/Farの値は何でも構わない
    const float Near = 1.0f;
    const float Far = 100.0f;
    Valve.VR.HmdMatrix44_t ProjectionMatrix = new Valve.VR.HmdMatrix44_t();

    if (trackedCamera.GetCameraProjection(source.deviceIndex, source.frameType, Near, Far, ref ProjectionMatrix) !=
        Valve.VR.EVRTrackedCameraError.None)
    {
        return Vector2.one;
    }

    return new Vector2(ProjectionMatrix.m0, ProjectionMatrix.m5);
}
次に、Update()メソッドの、
target.localScale = new Vector3(1, 1.0f / aspect, 1);

// Apply the pose that this frame was recorded at.
if (source.hasTracking)
{
    var t = source.transform;
    target.localPosition = t.pos;
    target.localRotation = t.rot;
}
この部分を、

// Apply the pose that this frame was recorded at.
if (source.hasTracking)
{
    const float ProjectionZ = 1.0f;
    Vector2 ProjectionScale = GetProjectionScale(source);
    Vector2 LocalScale = new Vector2(2.0f * ProjectionZ / ProjectionScale.x, 2.0f * ProjectionZ / ProjectionScale.y);

    target.localScale = new Vector3(LocalScale.x, LocalScale.y, 1.0f);

    //
    var t = source.transform;
    target.localPosition = t.TransformPoint(new Vector3(0.0f, 0.0f, ProjectionZ));
    target.localRotation = t.rot;
}
このように書き替えてビルドします。

この段階で実行すると、視界のやや下にカメラ映像のスクリーンが表示されると思います。

ただ、この状態だと、スクリーンより向こう側にあるオブジェクトが隠れて見えなくなるので、専用のシェーダを作成します。

とりあえず、「Assets」のルートで右クリックし、Create→Shader→Unlit Shaderを選択します。とりあえず、シェーダファイルの名前を「ARBackground」に変更しておきます。

その「ARBackground.shader」を開き、1行目を、

Shader "Custom/ARBackground"
に書き替え、Tagsブロックを、
Tags { "RenderType"="Opaque" "Queue"="Background" }

このように書き替え、Passブロックの先頭に、

Pass
{
    ZWrite Off

    CGPROGRAM
このように「Zwrite Off」を追加します。

ビルドして再びUnityに戻り、「ARScreen」の「SteamVR_TestTrackedCamera」の「Shader」を「Custom/ARBackground」に変更します。

「ARScreen」のインスペクタは最終的にこのようになります。

arcamera4.png

最後に、「[CameraRig]/Camera (head)/Camera (eye)」のインスペクタを開き、「Camera」の「Clear Flags」を「Solid Color」に変更し、「Background」の色を#00000000に変更します。

arcamera3.png

これで、「ARScreen」より向こうにあるオブジェクトも手前に表示されるようになります。

なお、もし実行時に画面が白くなって何も表示されない等の不具合が発生した場合は、以下を参考にして下さい。



posted by 妹尾雄大 at 17:28| Comment(0) | Unity | このブログの読者になる | 更新情報をチェックする