おもちゃラボ

Unityで遊びを作っていきます

【Unity】樹木を作る

Unityには様々な形の木を作ることができるツールが付属しています(知りませんでした)。ただ、このツール、設定しなくてはいけないパラメータがめちゃくちゃ多いので、1本の木を作るまでが大変です。そこで、ここではUnity2019を使って、最小限のパラメータだけで木を作る方法を説明します。

f:id:nn_hokuson:20200331185250p:plain:w600

Unityを使って木を作る流れは次のとおりです。

木を作成する

ヒエラルキーウインドウでCreate→3D→Treeを選択してください。シーンウインドウに一本の木が表示されます。これが、これから作っていく木の幹になります。

f:id:nn_hokuson:20200331185307p:plain:w220 f:id:nn_hokuson:20200331185317p:plain:w350

幹の設定

作成した木の幹の設定を行います。設定と言っても幹で必要になるパラメータは次の2つぐらいです。

  • Length
  • Crinkness

Lengthは木の幹の長さ(そのままですね・・)です。また、Crinknessは木のねじれ具合を表します。盆栽の松みたいにくねくねした木を作りたいときにはこのパラメータを調節してください。

これらのパラメータを操作するために、シーンウインドウで木のモデルを選択した状態でインスペクタを見てください。インスペクタのTreeパネルに表示された木の幹の画像をクリックすると、幹のパラメータが表示されます。表示されたパラメータのうちLengthとCrinknessを調整します。

f:id:nn_hokuson:20200331185329g:plain:w600

いい感じの幹ができたら、次は枝の設定をしていきましょう。

枝の設定

次に幹から枝を生やします。Treeパネルの幹を選択した状態で、パネル右下のAdd Brunch Groupボタンをクリックしてください。一本だけ木から枝が生えると思います。

この枝の調整には次の3つのパラメータを使います。

  • Freqency
  • Grown Angle
  • Length

Frequencyは親の木(ここでは幹)から何本の枝を生やすかを指定します。GrownAngleは枝が成長する向きを決めます。Lengthではスライダを使って長さのばらつきを決めます。ここではFrequencyに「5」、Grown Angleに「0.93」を設定しました。

f:id:nn_hokuson:20200331185349g:plain:w600

いま生やした枝から更に枝を生やします。そのためTreeパネルの一番上の木のパネルを選択して、先程と同様にパネル右下のAdd Brunch Groupボタンをクリックしてください。今回は先程よりも枝の本数を増やしたいのでFreqencyを「15」、Grown Angleを「0.53」に設定しています。

f:id:nn_hokuson:20200331185415g:plain

また、木の枝の形状を上向けに反らせるために「Seek Sun」のパラメータを大きくしています。この値を大きくすることで枝が太陽の方向を向くように変形します。

葉の設定

木に葉っぱを付ける

最後に木に葉っぱを生やしましょう。葉っぱも先程と同様にTreeパネルから設定できます。Treeパネルの一番上の木のパネルを選択した状態で、Treeパネル右下のAdd Leaf Groupボタンをクリックしてください。

葉っぱの設定に必要なパラメータは次のようになります。

  • Frequency
  • Distribution

Frequencyは葉っぱの枚数を表すので、値を大きくすればそれだけ葉っぱの数が増えます。ここでは「10」に設定しました。

f:id:nn_hokuson:20200331185443g:plain

また、ここでは操作していませんが、Distributionは葉っぱの付き方(葉っぱのばらつき方)を変えるパラメータです。Random、Alternate、Opposite、Whorledが選択でき、それぞれの意味は次のようになります。それぞれどのように見え方が変わるか試してみてください。

パラメータ 意味
Random ランダムに生成
Alternate 交互に生成
Opposite 対になるように生成
Whorled 螺旋状に生成

葉のマテリアルの作成

今のままでは葉っぱが平面モデルのままなので、ここにマテリアルを割り当てます。そのマテリアルを作りましょう。

プロジェクトウィンドウで右クリックして、Crate→Materialを選択してください。Unityには葉っぱ用のシェーダがすでに用意されているので、それを利用します。作成したマテリアルを選択して、インスペクタからNature/Tree Creator Leaves Fastを選択してください。また、葉っぱのテクスチャは次のものを使いました。
f:id:nn_hokuson:20200331190814p:plain:w100
マテリアルのシェーダを変更した上で、マテリアルのテクスチャ欄には上記の葉っぱのテクスチャを設定してください

f:id:nn_hokuson:20200331185506j:plain:w650

いま作成したマテリアルを、葉っぱのモデルに反映しましょう。シーンウインドウで木を選択した状態で、インスペクタのTreeパネルから葉っぱのパネルを選択してください。

f:id:nn_hokuson:20200331185517p:plain:w200

葉っぱの設定画面が表示されるので、GeometryのMaterialの欄に作成したマテリアルをドラッグ&ドロップしてください。

f:id:nn_hokuson:20200331165427j:plain:w650

木の幹にも茶色のマテリアルを作成して適応すれば完成です。

f:id:nn_hokuson:20200331185540p:plain:w650

まとめ

ここではUnityを使って木のモデルを作る方法を紹介しました。一見、設定しなくてはいけないパラメータが多いので大変そうですが、実際には数個のパラメータを調整するだけでそれっぽい木を作ることができました。

【ARFoundation】カメラ映像を取得する

ARKitを使っていると、ARとは別にカメラからの映像を取得したい場合があります。そこで、この記事ではARFoundationを使ってカメラ映像を取得する方法を紹介したいと思います。目次は次のとおりです。

ARFoundationのセットアップ

まずはARFoundationを使うため、ARSessionとARSessionOriginをインスペクタから追加します。ヒエラルキーウインドウから「Create→XR→ARSession」と「Create→XR→AR Session Origin」を追加します。

f:id:nn_hokuson:20200129213752p:plain:w230

ヒエラルキーウインドウから「Create→3D Object→Plane」を選択して、カメラ(AR Camera)の映像を映すための平面を作ります。常にカメラに映るように、カメラに正対するように配置して、カメラの子要素にしておきます。

f:id:nn_hokuson:20200129214111p:plain

また、このPlaneがライティングの影響を受けないように、プロジェクトウィンドウで右クリックしてCreate→Materialを選択してマテリアルを作ります。マテリアルのShaderをUnlit→Textureに設定してからPlaneにドラッグしておきましょう。

f:id:nn_hokuson:20200129214741j:plain

カメラ映像をフックするスクリプトを作る

続いて、ARFoundationで使用しているカメラ映像をフックするスクリプトを作成します。ARFounationでカメラ映像を取得する流れは次のようになります。

  1. カメラの更新イベントを登録
  2. カメラフレームが更新されたタイミングでフレーム取得
  3. 必要に応じて回転・フリップを行う

プロジェクトウインドウで右クリックして、Create→C# Scriptでスクリプトを作成し、CamerImageControllerという名前で保存してください。保存できたら先程のPlaneにアタッチしておきましょう。

アタッチできたら、CameraImageControllerに次のスクリプトを入力します。

using System;
using Unity.Collections.LowLevel.Unsafe;
using UnityEngine;
using UnityEngine.XR.ARFoundation;
using UnityEngine.XR.ARSubsystems;

public class CamerImageController : MonoBehaviour
{
    public ARCameraManager cameraManager;

    private Texture2D mTexture;
    private MeshRenderer mRenderer;

    private void Start()
    {
        mRenderer = GetComponent<MeshRenderer>();
    }

    void OnEnable()
    {
        cameraManager.frameReceived += OnCameraFrameReceived;
    }

    void OnDisable()
    {
        cameraManager.frameReceived -= OnCameraFrameReceived;
    }

    unsafe void OnCameraFrameReceived(ARCameraFrameEventArgs eventArgs)
    {
        XRCameraImage image;
        if (!cameraManager.TryGetLatestImage(out image))
            return;

        var conversionParams = new XRCameraImageConversionParams
        (
            image,
            TextureFormat.RGBA32,
            CameraImageTransformation.None
        );
      
        if (mTexture == null || mTexture.width != image.width || mTexture.height != image.height)
        {            
            mTexture = new Texture2D(conversionParams.outputDimensions.x,
                                     conversionParams.outputDimensions.y,
                                     conversionParams.outputFormat, false);
        }

        var buffer = mTexture.GetRawTextureData<byte>();
        image.Convert(conversionParams, new IntPtr(buffer.GetUnsafePtr()), buffer.Length);
        
        mTexture.Apply();
        mRenderer.material.mainTexture = mTexture;

        buffer.Dispose();
        image.Dispose();
    }
}

このスクリプトではframeReceivedイベントにOnCameraFrameReceivedメソッドを追加しています。これにより、カメラのフレームが更新されるたびにOnCameraFrameReceivedメソッドが呼び出されるようになります。OnCameraFrameReceivedメソッドではTryGetLatestImageメソッドを使ってカメラ映像をXRCameraImage型のimage変数に代入しています。

続いて、XRCameraImageクラスのConvertメソッドを使って取得したカメラ映像をTexture2D型に変換しています。変換後の画像フォーマットはXRCameraImageConversionParamsで指定します。ここではカラーフォーマットはRGBA32、回転フォーマットは無しで映像を取得しています。カラーフォーマットには次のような値を指定できます。

フォーマット名 意味
TextureFormat.R8 1チャネルで8bitの画像
TextureFormat.Alpha8 アルファチャネルのみ
TextureFormat.RGB24 RGBの3チャネルで各8bitの画像
TextureFormat.RGBA32 RGBAの4チャネルで各8bit画像
TextureFormat.ARGBA32 ARGBの4チャネルで各8bit画像
TextureFormat.BGRA32 BGRAの4チャネルで各8bit画像

また、回転フォーマットには次の値を指定できます。

フォーマット 意味
MirrorX X軸でフリップ
MirrorY Y軸でフリップ
None 回転しない

最後にTexture2DをApplyして変更を反映した後に、PlaneのMesh Rendererに設定してPlaneにカメラ映像を表示しています。

unsafeコードの設定

上記のスクリプトではunsafeコードを使っているため、そのままではコンパイルエラーになってしまいます。メニューバーからEdit→Project Settings→Playerを選択して、Allow unsafe codeにチェックを入れます。

f:id:nn_hokuson:20200129215259p:plain

アウトレット接続

スクリプト中で宣言したARCameraManagerに値を代入します。UnityのインスペクタにCamerImageControllerを表示し、ARCameraManagerの欄にヒエラルキーウインドウのAR Cameraをドラッグ&ドロップしてください。

f:id:nn_hokuson:20200129215637j:plain

これでカメラ映像がPlaneにも映るようになっているはずです。ビルドして確かめてみてください。

Visual Studio for Macでタブ幅・インデント幅を変える

ソリューションウインドウ(表示されていない場合はメニューバーから「表示」→「パッド」→「ソリューション」)のプロジェクト名の上で右クリックして「オプション」を選択します。

f:id:nn_hokuson:20200125204458j:plain:w600

ソースコード→コードのフォーマット→C#のソースコードを選択します。
ポリシーの欄で「Default」を選択するか、またはテキストファイルの規定の設定を使用のチェックを外して、タブ幅、インデント幅を設定してから、右下の「OK」ボタンを押します。

f:id:nn_hokuson:20200125204533p:plain