Feel Physics Backyard

HoloLensの出張授業をする会社で、教材を開発しています

HoloLensで撮った写真をUnityからスクリプトでテクスチャとして使う

注:原題は「HoloLensにデバイスポータル経由でアップロードした画像をUnityからスクリプトでテクスチャとして使う」でした

「HoloMagnetには笑い要素がないって言われたんだ」

「まあ、真面目なアプリだよね」

「で、棒磁石にHoloLensを操作する生徒の顔を貼り付けたら、ギャラリーにもウケるんじゃないか、というんだよね」

「それは面白そうだけど、大変そうだね」

「いやー、やりきったよ」

f:id:weed_7777:20180217160450j:plain

f:id:weed_7777:20180217160458j:plain

f:id:weed_7777:20180217160459j:plain

「いいの、これ?」

「聞かないで…」

「HoloMagnetには笑い要素がない」というご指摘をいただき、棒磁石に本人のを貼り付けるという暴挙に出ました。Windows10のカメラアプリで撮影した写真をデバイスポータル経由でHoloLensに入れます。カメラロールのファイルリストを取得し、PNG/JPGファイルをテクスチャに取り込みます。テクスチャを正方形にクロップし、Planeに貼ります。

Windows10のカメラアプリで撮影した写真をデバイスポータル経由でHoloLensに入れる

注:実はHoloLensで撮った写真はカメラロールに保存され、そのまま使えます。音量ボタン同時押しでパシャパシャ撮って即使えます。

f:id:weed_7777:20180217163318p:plain

EdgeやChromeだとJavaScriptエラーが出ますがIEだと出ません(いいのか)。

以下のページを参考にしました:

bluebirdofoz.hatenablog.com

Windows10でIE11を起動する方法 (IE11が見つからない) - ぼくんちのTV 別館

スクリプトでカメラロールのファイルリストを取得する

    async void SetTextureFromCameraRollToPlane(GameObject planeNorth, GameObject planeSouth)
    {
        // カメラロールフォルダは以下のように取得する
        StorageFolder CameraFolder = Windows.Storage.KnownFolders.CameraRoll;
        // GetFilesAsync()でファイルのリストを取得する
        var filesInFolder = await CameraFolder.GetFilesAsync();
        
        // await後の処理ここから
        int count = filesInFolder.Count;
        // 最後から2番目の写真をN極に貼り付けるために取得する
        string filePathNorth = filesInFolder[count - 2].Path;
        // 最後の写真をS極に貼り付けるために取得する
        string filePathSouth = filesInFolder[count - 1].Path;

        // 2枚の写真をそれぞれ貼り付ける
        SetTextureToPlane(filePathNorth, planeNorth);
        SetTextureToPlane(filePathSouth, planeSouth);
        // await後の処理ここまで
    }

ちなみに上のコードは下のプリプロセッサで囲まなければなりません。

#if !UNITY_EDITOR

...

#endif

プリプロセッサで囲むとVisual Studioの補完が効かないし大変だな、と思っていたらアドバイスを頂きました。

なるほど…これは必須テクニックですね。

あと以下の設定も必要です:

f:id:weed_7777:20180217211234p:plain

以下のページを参考にしました:

forums.hololens.com

スクリプトで任意のパスのPNG/JPGファイルをテクスチャとして取り込む

    public static Texture2D LoadJPGorPNG(string filePath)
    {

        Texture2D tex = null;
        byte[] fileData;

        if (File.Exists(filePath))
        {
            fileData = File.ReadAllBytes(filePath);
            tex = new Texture2D(2, 2);
            tex.LoadImage(fileData);  // 配列からテクスチャへ変換し PNG/JPG 画像を読み込みます
        }
        return tex;
    }

以下のページを参考にしました:

answers.unity.com

docs.unity3d.com

スクリプトでテクスチャを正方形にクロップする

    Texture2D GetSquareCroppedTexture(Texture2D textureOriginal)
    {
        int length = textureOriginal.height;
        int margin = (textureOriginal.width - length) / 2;
        Color[] c = textureOriginal.GetPixels(margin, 0, length, length);
        Texture2D textureCropped = new Texture2D(length, length);
        textureCropped.SetPixels(c);
        textureCropped.Apply();
        return textureCropped;
    }

スクリプトでテクスチャをPlaneに貼る

    void SetTextureToPlane(string filePath, GameObject plane)
    {
        Texture2D texture = LoadJPGorPNG(filePath);  // ファイルパスからテクスチャを取得する

        texture = GetSquareCroppedTexture(texture);  // 正方形にする

        Material material = new Material(Shader.Find("HoloToolkit/StandardFast"));
        material.EnableKeyword("_EMISSION");
        material.SetTexture("_EmissionMap", texture);
        material.SetColor("_EmissionColor", Color.gray);
        plane.GetComponent<Renderer>().material = material;
    }

以下のページを参考にしました:

https://forum.unity.com/threads/solved-apply-image-to-plane-primitive.320489/

answers.unity.com

さあ、明日の反応は吉と出るか凶と出るか…