うにty生活

UnityChanを生活させたい

Blenderで作成した孫以上の親子関係は他ソフトで位置ずれがおきる

 

今回はBlenderで出力したFBXをUnityにインポートしたところUnity側で位置ずれが起きていたのでメモ

 

 

はじめに

当記事は根本的なことが解決できるわけではなく、こういう問題があるよというメモ書き程度になります。

 

現象

3階層以上の親子関係がある場合Unity側で3階層目以降は位置がずれる。

以下のオブジェクトをBlenderで作成していました。

木箱のレンダリング画像

 

親子関係はこんな感じで多いところで最大4階層の親子関係があります。

Blenderの親子関係

 

これをUnityにインポートしたところ

Unityにインポートしたときの位置ずれ

 

親子関係は保たれていますが、孫以上の金具の部品は選択している位置までずれています。

この現象はBlender側で回転やスケールを適用して修正していても起こる問題です。

 

何故...?

 

解決方法

根本的な解決方法ではないですが、今回はBlender側で3階層以上の親子関係をやめることで解決しました。

 

解決した画像

 

3DSubstancePainter(SP)でも同様のことが起こっていました。

SPでは親子関係などいじれないため不便だと思ったので、今回はこの方法で解決しました。

 

調べ方が悪いのかこの問題に関する記事が一切でてこないので問題を共有するだけにとどめておきます。

時間があれば根本的な解決に向けてもっと詳しく調べた後追記しておきます。

 

 

簡単!両端から中心に向かって減るゲージUIの作り方【uGUI】

タイトル通り両端から減っていく(もしくは増えていく)ゲージを作成していきます。

 

完成形

 

 

作成方法

両端から減っていくゲージはImageコンポーネントだけでは作成不可能なので自作していきます。

※SliceタイプのSpriteを使えばwidthを変更するだけでそれっぽくは見える

 

やり方としてシェーダーでも作成可能なのですが、今回はRectMask2Dコンポーネントを使ってさくっと作っていきます。

 

ヒエラルキービューの状態

ヒエラルキービューの状態


BarBackgroundImage(背景)、BarFrontImage(増減ゲージ)はただのImageコンポーネントが付いたものです。

間にRectMaskがあり、ここにRectMask 2Dコンポーネントと後述するコード(BothSidesFill.cs)がアタッチされています。

width,heightは全て同じ

 

Sliderは動作確認用なのであってもなくても大丈夫です。

 

コード

public class BothSidesFill : MonoBehaviour
{
    private RectTransform _maskRectTransform;
    private float _defaultWidth;
    private float _fillAmount;
    public float fillAmount {
        get { return _fillAmount; }
        set { 
            _fillAmount = Mathf.Clamp01(value); //設定値を0~1に変更
            _maskRectTransform.sizeDelta = new Vector2(Mathf.Lerp(0, _defaultWidth, _fillAmount), _maskRectTransform.sizeDelta.y);
        } 
    }

    public void Init()
    {
        _maskRectTransform = transform as RectTransform;
        _defaultWidth = _maskRectTransform.sizeDelta.x;
    }

    // Start is called before the first frame update
    void Start()
    {
        Init();
    }
//以下は無くても動きます(動作確認用) public Slider fillSlider; public void OnChangeFillAmount() { fillAmount = fillSlider.value; } }

 

ImageタイプがSlice対応画像ならwidth変更するだけでいいと思うけど、これなら非Slice画像でもいけます!

 

[blog:g:12921228815717619800:banner]

AddressablesのGroupを新規作成する方法

右クリック>Create New Group>Packed Assets

※バージョンによってはCreate New Groupだけ押せばいい時もある

AddressablesのGroupを新規作成するときの画像

AddressablesのGroupが新規作成できた時の画像

名前も変更可能です。

 

みんな当たり前のようにやっているのか、たったこれだけなのに全然情報なくて何時間か無駄にしたのでメモです。(結局人に聞きましたが)

 

DefaultGroupで運用していると結構コンフリクトして面倒なので分けることをおすすめ。

 

おそらく最短記事笑

まあたまにはこんなのがあってもいいかな

BlenderとSubstancePainterとUnityを使ったモデル作成フロー

今回はBlenderでモデルを作成、SubstancePainterで色付け(Texture作成)

最後にUnityにimportするまでのソフト間ワークフローを実際にやってみました。

 

間にSubstancePainterがありますが、Blender→Unityへのフローだけが知りたい人でも見れるようになってます。ではどうぞ

 

 

環境

Unity 2021.3.16

HDRP 12.1.8

Blender 3.1.2

3DSubstance Painter 8.3.0(以下SP)

 

完成品

左:Blender後、右:SP後

左:Blender後、右:SP後

汚れや表面の凹凸もSubstance Painterで簡単に作成できました。

それでは手順を解説していきます。

※モデルの作成方法やSubstancePainterでのペイント方法は解説していないので注意。あくまでフローやimport/export設定のみ

 

まずはBlenderでモデル作成

今回の記事を書くにあたって題材となるモデルが必要だったのでこちらの動画を参考にしました。

まじで簡単にできたのでおすすめ。

 

完成(Blenderのレンダリング結果)

Blenderのレンダリングしたサッカーボールの結果

 

Blenderのレンダリング絵作り下手すぎる...

 

エクスポートするための準備

モデルを最終的にUnityで扱うためにやっておくことがいくつかあります。

 

実寸にあわせる

現実に存在するものであれば、実際のサイズに合わせて作りましょう。

まずはLength(単位)をメートルに変更します(2.9あたりからはデフォルトでメートルだった気がしますが一応)

Blenderで単位をメートルに変更する時の設定画像

 

object選択モードに変更>Nキー>Item>Dimensionsからサイズを調整します。

英語版を使っているのでわかりにくいですが場所は同じです。

サッカーボールは22cmなので「0.22m」に設定

Blenderでサッカーボールを実寸大に設定している様子

 

原点をオブジェクトの中心にする

原点が正しい位置にない場合があるので原点をそのオブジェクトの正しい場所に配置する必要があります。

今回はボールなので原点をオブジェクトの中心にします。

Object>Set Origin>Geometry to Origin

Blenderでオブジェクトの原点を中心にしている様子

 

合わせて読みたい記事

Blenderで変更した原点はUnityでどう変わるのか

→執筆中 

 

スケールを1にする

Unityではスケール1にしておいた方が扱いやすいので今のサッカーボールのスケールを1に変更します。

Object>Apply>Rotation & Scale

Blenderでスケールを1にしている様子

 

マテリアルを設定

もし動画を見ながら作成していたらマテリアルを用意する部分まで説明されているので大丈夫だと思いますが、マテリアルはSubstancePainte側で個別に設定するために部分ごとに分けて設定しておきます。

 

今回はサッカーボールの白い部分を「soccerWhite」、黒い部分を「soccerBlack」という名前でマテリアルを割り当てました。

Blenderでマテリアルを設定している様子

 

UV展開

SubstancePainterではUV展開したモデルの頂点などを編集することができないのであらかじめUV展開して調整をしておきます。

 

編集モード>全選択>Uキー>Unwrap

BlenderでUV展開するコマンドがどこにあるか映した画像

BlenderでサッカーボールをUV展開した画像

 

今回はシームつけなくてもUV展開うまくいきましたが、もう少し複雑な形のモデルの時はこちらを参考にしてみてください。

 

 

モデルをFBXでエクスポート

下図はBlenderからUnity向けにExportする出力内容になります。

Blenderでfbx形式でexportしている設定画像

 

一度Unityにインポートして大きさを確認してみました。

Unityでサッカーボールの大きさを確認している画像

 

 

うん!いい感じ!

 

 

先にUnityで確認していた方が手戻りが少なくて済むかも。

Blender→Unityだけが知りたい方はここでおしまいです。以降SubstancePainterの作業になります。

 

SubstancePainterにImport

これでも十分にサッカーボールなのですが、ここからさらにSubstancePainterで表面の凹凸や縫い目、汚れなどを表現していきます。(SubstancePainter練習したいだけ)

 

ファイル>新規>テンプレート>Blender

その後にファイルを選択して何も設定は変えずにOKボタン

SubstancePainterにBlenderで作成したfbxファイルをimportする画像

 

読み込まれると画面はこんな感じ

SubstancePainterにBlenderで作成したモデルが読み込まれた時の画像

画像右上で確認できますが、マテリアルもちゃんと分かれてる。

ここからSubstance Painterで作業を行っていきます。

 

SubstancePainterでTextureを作成したのがこちら(料理番組かな?)

SubstancePainterで作業する前のモデル

Before

SubstancePainterで作業した後のモデル

After

初めてのSubstancePainter作品ですが、ブラシでモデルをへこませたりしてNormalが簡単に作成できるのは超楽しいです。

ここからが本番。この状態をUnityでしっかり再現できるかどうかです。

 

Textureをエクスポート

ファイル>テクスチャを書き出し

SubstancePainterでTextureの書き出しをしている画像

 

ひとまず試しにUnityHDRP向けの出力テンプレートがあるのでそれで出力してみます。

結果からいうとHDRPならばこの出力方法で問題なく使えました。

SubstancePainterで出力テンプレートを設定している画像

簡単に説明すると

左側:テンプレートリスト(自分で新しく増やすことも可能)

中心:出力される名前とチャンネルのリスト

右側:書き出せるマップのリスト

となっていて中心の色と右側の色はリンクしています。色のついてあるマップを出力するということになります。

 

アルファ、メタリック、ラフネス、AOはグレースケールなので

RGBAにそれぞれ情報を持たせることができるみたいですね。UnityのLitShaderではこのまとまったTextureはMask mapと対応しています。

 

 

今回これが知れただけでもでかい

 

 

そして罠なのが設定に戻って出力テンプレートを指定の選択しないとさっきのUnity用だったり自分で作成したテンプレートが使えないということです。

SubstancePainterで出力テンプレートを設定している画像

 

右下の書き出しを押して書き出し後、以下のテクスチャが書き出されました!

SubstancePainterで出力したTextureの一覧をエクスプローラーで表示

 

UnityにTextureをimport

UnityにSubstancePainterで出力したTextureをimportしている様子

 

サッカーボールのMaterialにTextureを設定していきます。

Texture設定前のLitMaterial

Unityでマテリアルを設定している画像



そもそもFBXインポートしたときにマテリアルないんだけどって人はimportしたModelを選択>Materials>Extract Materialsを押せばマテリアルが作成されます。

Unityでマテリアルを設定している画像

 

読み込んだNormal mapのみInspectorからTexture Typeを「Normal map」にしてあげる必要があります。

Unityにimportしたnormalmapのタイプを変更している画像

 

各TextureをLitMaterialに設定

Unityでマテリアルを設定している画像

 

完成

Unityで完成前と完成後のサッカーボールを比較している画像

←Before After→

汚れとか表面の凹凸が再現できました!

 

モデルの隙間から若干床の色が見えているのは、LitShaderのDouble-Sidedを有効にするとわからなくなります。まあ今回そこまで気にならないので放置します。

 

これからもSubstancePaitner活用していきます!

それではまた

 

【Unity】textInfoの内容が取得できない時の対処法

今回はTextMeshProやTextMeshProUGUIで扱えるプロパティ、textInfoを使っていて困ったことと対処方法を書いていきます。

※TextMeshPro自体の使い方や説明は省きます。

 

 

環境

Windows 11

Unity 2021.3.16f1

URP 12.1.8

 

TMP_TextInfoとは

TMP_TextInfoとは、TextMeshProやTextMeshProGUIが継承しているTMP_Textクラスに存在するクラスの一つです。

このTextInfoクラスには文字数だったり、テキストメッシュの座標情報が格納されていて結構使い勝手が良いです。

 

ここからは使っていて困ったことと解決策を書いていきます。

 

ちなみにTextMeshのメッシュが板ポリだったってことに気が付くのは結構最近のお話笑

 

characterInfoやmeshInfoの中身が上手く取得できない

困ったことの1つ目です。Debug.LogでcharacterInfoを出力してみても文字が入ってなかったりクラス自体がNullだったりします。

 

準備としてTextMeshProUGUIを用意しました。

TextMeshProUGUIを用意したScene画像

 

NGコード×

public class TextInfoBlog : MonoBehaviour
{
    public TextMeshProUGUI uiText;// TextMeshをアタッチ済み
    
    // Start is called before the first frame update
    void Start()
    {
        TMP_TextInfo textInfo = uiText.textInfo;
        Debug.Log(textInfo.characterInfo[0].character); //出力:空
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

原因は呼び出しタイミングが早すぎることです。

 

対処法

AwakeやStartからの呼び出しで使わないこと

 

OKコード〇

public class TextInfoBlog : MonoBehaviour
{
    public TextMeshProUGUI uiText;// TextMeshをアタッチ済み
    
    // Start is called before the first frame update
    void Start()
    {

    }

    // Update is called once per frame
    void Update()
    {
        if (Input.GetKeyUp(KeyCode.G))
        {
            TMP_TextInfo textInfo = uiText.textInfo;
            Debug.Log(textInfo.characterInfo[0].character); //出力:N
        }   
    }
}

 

AwakeとStartから呼び出すとInspectorで文字が入っていたとしてもcharacterInfoやmeshInfoが正しく呼ばれることはありません。

必ず、Startよりあとのタイミングで呼び出すようにしましょう

 

新しく設定したtextのtextInfoが取得できない

2つ目の困ったことは新しくtextを設定したとき、最新のtextInfoを取得してこないという問題があります。

 

NGコード×

※他は同じなのでUpdateのみ記述

void Update()
{
    if (Input.GetKeyUp(KeyCode.G))
    {
        uiText.text = "Textinfo test";
        TMP_TextInfo textInfo = uiText.textInfo;
        Debug.Log(textInfo.characterInfo[0].character); //出力:N
    }   
}

「T」という文字が取得したいのにデフォルトの「New Text」の「N」が出力されます。

 

対処法

GetTextInfo(newText)関数を使う

 

OKコード〇

void Update()
{
    if (Input.GetKeyUp(KeyCode.G))
    {
        TMP_TextInfo textInfo = uiText.GetTextInfo("Textinfo test");
        Debug.Log(textInfo.characterInfo[0].character);
    }   
}

TMP_TextInfo textInfo = uiText.GetTextInfo(newText)とやると内部的にtextも「newText」にセットできるし、「newText」のtextInfoも取得できる。(Get関数なのに内部でtextをSetしているのは少しわかりにくいですが関数の中身を見たら気が付けます...)

 

他にも見つけた便利なプロパティ

1文字の中央座標を取得する

よく紹介されている手法として、textInfo.meshInfoから全てのvertex(頂点)情報を取得後4を掛けてn文字の中央座標を求めることができます。

以下のコードでは「New Text」の3文字目、「w」の中心座標を求めて上からspriteをかぶせています

 

コード

public class TextInfoBlog : MonoBehaviour
{
    public TextMeshProUGUI uiText;// TextMeshをアタッチ済み
    public Image imagePrefab;

    // Update is called once per frame
    void Update()
    {
        if (Input.GetKeyUp(KeyCode.G))
        {
            TMP_TextInfo textInfo = uiText.textInfo;
//※ここで取得した座標はuiTextのローカル座標なので注意            
var mesh = textInfo.meshInfo[0]; var vertices = mesh.vertices; //3文字目のメッシュを取得 var charMechStart = 2 * 4; var topleft = vertices[charMechStart]; var bottomRight = vertices[charMechStart + 2]; var center = (topleft + bottomRight) / 2; var image = Instantiate(imagePrefab, uiText.transform, false); image.transform.localPosition = center; } } }

参考:uGUI Textの文字の座標を取得してインライン画像を実現する - おもちゃラボ

 

上記コードはNGというわけではありませんがもっと簡単な方法があったので紹介します。

 

characterInfoのtopleftやbottomrightといった座標プロパティが存在するのでそこから計算すればok。

 

改善コード(Updateだけ)

やってることは同じです。

void Update()
    {
        if (Input.GetKeyUp(KeyCode.G))
        {
            TMP_TextInfo textInfo = uiText.textInfo;
            var topleft = textInfo.characterInfo[2].topLeft;
            var bottomRight = textInfo.characterInfo[2].bottomRight;
            var center = (topleft + bottomRight) / 2;
            var image = Instantiate(imagePrefab, uiText.transform, false);
            image.transform.localPosition = center;
        }   
    }

 

正しい文字数を表示する

textInfo.characterCountのカウントは残念ながら思った通りには返ってきません。

例えばhoge hoge¥nfuga fugaというtextが存在すると、このテキストの正確な文字数は16文字です。空白も改行も数えてしまいます。

TMP_TextInfo textInfo = uiText.GetTextInfo("hoge hoge\nfuga fuga");
Debug.Log(textInfo.characterCount); //19

 

なのでこういう時はスペース数を取得して引いたものが正しい文字数です。

TMP_TextInfo textInfo = uiText.GetTextInfo("hoge hoge\nfuga fuga");
Debug.Log(textInfo.characterCount - textInfo.spaceCount); //16

なぜ改行もスペースとして数えられるのかはわかりませんがこれで正しい文字数は出せました。これをループに使えば各文字に何らかの処理を行えます!

 

いかがだったでしょうか、textInfo便利なのでぜひ使ってみてください。

 

 

Rigidbodyを使わずにオブジェクトを反発させる表現方法

はじめに

今回はRigidbodyを使わずにSpriteが重ならないようにする方法を紹介します。

 

Spriteが重ならないようにしたい場面は頻繁にあるのですが、重ねないためだけにRigidbodyを使うとパフォーマンス的に心配ということもあり

今回はTransform移動だけでRigidbodyを使った時のようなSprite同士が反発しあう表現を行っていきます。

 

今回の記事ではTransform移動だけでこんな感じの反発表現ができるようになります。

 

表現の近いゲーム

・ヴァンパイアサバイバーの敵

・Stocklandsのカード

 

準備

検証するための簡単にステージを用意しました。

サンプルステージ画像

 

貝(敵)のモンスター画像は以下のサイトから拝借

七三ゆきのアトリエ
https://nanamiyuki.com/

 

今回はこの貝を敵として大量描画を行い、画面外から中央に向かって移動させます。画面中央に設置した判定に当たると敵は消えるようにしています。

※敵の出現方法のコードは割愛します。

RigidBodyを使った場合

まずはRigidBodyを使ってどんなことがしたいのか見せます。

Spriteを重ならないようにする方法で検索すると大体このRigidBodyのDynamicを利用しています。(そういう紹介をしている人がほとんど)

※ただRigidbodyを使うには物理挙動を理解していないといけないし、FixedUpdateが必須となってくるので導入難易度は少し高いです。

 

TargetMove.cs

public class TargetMove : MonoBehaviour
{
    public Vector3 targetPosition;
    private Rigidbody2D rigidbody2d;

    // Start is called before the first frame update
    void Start()
    {
        rigidbody2d = GetComponent();
    }

    private void FixedUpdate()
    {
        rigidbody2d.AddForce((targetPosition - transform.position).normalized * speed);
        rigidbody2d.velocity = new Vector3(rigidbody2d.velocity.x, rigidbody2d.velocity.y) / 1.1f;
    }
}

 

このスクリプト時の貝(敵)のコンポーネントはこんな設定です。

貝のコンポーネント

貝(Enemy)のコンポーネント(Rigidbodyあり)

 

プレイしてみる

 

これをTransform移動で表現していきます。

 

RigidBodyを使わない場合

TargetMoveスクリプトは以下です。

public class TargetMove : MonoBehaviour
{
    public Vector3 targetPosition;
    public float speed;
    public float repulsionCoefficient; //反発係数
    public Vector2 origin; //原点調整用
    public float radius; //検知半径
    public LayerMask layerMask;

    // Update is called once per frame
    void Update()
    {
        //通常移動
        var directionVector = (targetPosition - transform.position).normalized;
        transform.position += directionVector * Time.deltaTime * speed;
        
        //反発移動
        var collision = CheckOverlapCircle();
        if (collision != null)
        {
            Vector3 repulsionVector = (collision.gameObject.transform.position - transform.position) * Time.deltaTime * repulsionCoefficient;
            transform.position -= repulsionVector;
        }
    }

    private Collider2D CheckOverlapCircle()
    {
        var hit = Physics2D.OverlapCircle(transform.position + (Vector3)origin, radius, layerMask);
        return hit;
    }
}

 

解説

毎フレーム自身と同じobjectが重なっているかどうかチェックして、重なっていればそのobjectと反対方向に速さが加わります。

Physics2Dは物理挙動を一部利用、設定できるクラスです。

Unity - Scripting API: Physics2D

 

このコードで問題点があるとすれば進行方向と逆側で重なってしまうと少しスピードが上がります。

 

Inspectorの作業としては

・レイヤーを作成してEnemyObject本体とTargetMoveスクリプトに設定

・各種パラメーターを設定します

・Rigidbodyは必要ありません

貝(Enemy)のコンポーネント2

貝(Enemy)のコンポーネント(物理挙動なし)

 

この状態で実行するとSpriteが重ならず、お互いに反発しているように見えます!

(最初の動画と同じ)

 

 

パフォーマンスについて

どちらも似たような表現ができますが、大切なのはどちらがパフォーマンスがよいかということです。今回はシンプルに敵の数を増やして検証します!

 

結果から言うとパフォーマンス的にはほぼ同じに見て取れます。

ですのでFixedUpdateを使うことができないなど、ケースによって使い分ければよいかなと思います。

 

検証方法はProfilerで確認していきます。

 

Profiler(Rigidbodyなし)

Profiler(物理挙動なし)

 

Profiler(Rigidbodyあり)

Profiler(物理挙動あり)



検証結果

結局Transform移動といってもPhysics2Dは使っているので、双方FPSはそんなに差はなかったです。RigidbodyありのほうがPhysics(ピンク)の処理が大きいということはやっぱり反発以外の処理も行っているという予想は当たってました。

 

あと当たり前かもしれないですが、双方オブジェクト数が増えすぎるとFPSは下がるので、今回のセンターに集まったら消える処理のような全体数を一定にコントロールするようなコードがあってもいいと思います。

 

久々に技術系書いた、終わりー

 

【Unity】キャラクターに落ちた陰が暗すぎる問題をLight Probeで解決 #38

今回はせっかく配置したキャラクターがなんか暗いなーといった現象の解消方法を書きました。初心者向けです。

 

Before→After

結果から先に伝えると

こんな感じに変わります

比較画像

 

環境

Unity:2019.4.10f1

HDRP:7.4.1

 

現象

間接光の影響を受けていないUnityちゃん

 

上記画像はUnityちゃんを配置して真上からDirectional Lightを当てています。直接光が当たっていない部分がとても暗くなっていて少し怖いです。

今回これを適切な明るさに調節していきます。

 

原因

まずこの状態がなぜ起こっているかというとUnityちゃんが「間接光」(ベイクしたときに生成されるLightmap)の影響をほとんど受けていないためです。

 

※間接光はオブジェクトに光が当たって跳ね返った光のことです。今回この間接光がUnityちゃんに適用されてないことになります。

 

本来間接光が適用されたらUnityちゃんの横の壁のように、床から跳ね返った色なども反映されるようになります。

ではそれをするにはどうすればいいか?

 

動的オブジェクトに間接光の情報を与えるためにはLight Probeを利用します。

 

Light Probeとは

light probeの画像

Light Probeは配置した地点の間接光情報を持ち、近くのオブジェクトに影響を与える役割があります。

このLight Probeの範囲外に出るとLight Probeの恩恵は受けられません。

 

Light Probe生成方法

Hierarchyビューで右クリック> Light > Light Probe Group

シーンに配置しただけでは何も変わりません。

一度bakeしないとLight Probeが適用されないためLightting Settingビュー>Scene>Generate Lightingを押してbakeします。

 

UnityちゃんがLight Probeを受ける方法

今回はUnityちゃんにLight Probeを適用したいので、Unityちゃんにアタッチされている

Mesh RendererもしくはSkinned Mesh Renderer>Probes>Light ProbesをBlend Probesに変更します。

skinned mesh renderer component

 

 

 

解決

間接光が適用されたUnityちゃん

間接光が適用されました!Light Probe簡単だし効果絶大!

低壁と同じように床のバウンスした色と同じものが、Unityちゃんにもかかっているのがわかります。

 

動画も載せたかったのですが、キャプチャの調子が悪いのでまた用意できしだい追加します。

 

効率的にLight Probe Groupを配置する方法

一応生成したLight Probe GroupのコンポーネントのEdit Light Probeを押すことで数の調整ができます。

 light probe group component

 

ただ、 Light Probeも一つひとつ情報なので多いとメモリを圧迫します。

私は「Light Probeはとりあえずつけとけ!」くらいに思っていますが、闇雲に増やせばいいというわけでもないですし、コンポーネントから編集するとかなり大変です。

 

そこで便利アセット「Magic Light Probes」を使えば簡単に多くのLight Probe Groupを綺麗に配置してくれます。

 

是非使ってみてください!

 

いかがだったでしょうか。簡単ですが、以上になります。

それでは

【Unity HDRP】Lighting検証 表にまとめて考察してみた

f:id:tubakihimeLoveHate:20220407223958p:plain

今回はLightingの設定ごとにシーンやオブジェクトにどのような影響があるか調査して表にまとめていこうと思います。

 

 

環境

Unity:2020.3.31

HDRP:10.8.1

 

検証内容

今回は以下のような環境でテストを作成して、それぞれのLightingのType(発光側)とMeshRenderer(光を受ける側)の設定がどのように作用するか全てを表にまとめていきます。あとLight Probeの有無も含めます。

 

検証環境

lightテスト環境の画像

シーンには光が一切ない状態

シーン全体

Light Probeを配置したときのシーンはこんな感じ

Light Probeを置いたときのイメージ

 

その他全体の設定としては

・ベイクした情報は毎回クリアしてる

・Lightは全てShadowを有効

・Mesh Rendererはcast shadowをOn

 

以下の表にまとめているのでそこから気になった部分の考察や検証を行なっていきます。

ここから「specular反射」と「色にじみ」という単語が出てきます。簡単に説明するとspecular反射が鏡面反射で、色にじみ(カラーブリード)が近くのオブジェクトの色が他の色に影響を与えることです。

 

「色にじみ」に関しては本に載っていた単語なのでUnityでは別の呼び方をしているかもしれませんが、当記事では「色にじみ」の表現を使います。

 

Specular反射について詳しく知りたい方はこちらの記事が参考になります。

物理ベースレンダリングを柔らかく説明してみる(1) - Qiita

検証結果

  Type RealTime Mixed Baked

Static/

Light

map

Direct

ional

specular反射有(動的)

影有(動的)

specular反射有(動的)

影有(動的)

色にじみ有(固定)

specular反射有(固定)

影有(固定)

色にじみ有(固定)

Point

specular反射有(動的)

影有(動的)

specular反射有(動的)

影有(動的)

specular反射有(固定)

影有(固定)

Spot

specular反射有(動的)

影有(動的)

specular反射有(動的)

影有(動的)

specular反射有(固定)

影有(固定)

色にじみ有(固定)

Area

specular反射有(動的)

影有(動的)

specular反射有(動的)

影有(動的)

specular反射有(固定)

影有(固定)

Static/

Light

Probe

Direct

ional

specular反射有(動的)

影有(動的)

specular反射有(動的)

影有(動的)

色にじみ有(固定)

specular反射無

影有(固定・粗い)

色にじみ有(固定)

Point

specular反射有(動的)

影有(動的)

specular反射有(動的)

影有(動的)

specular反射無

影有(固定)

Spot

specular反射有(動的)

影有(動的)

specular反射有(動的)

影有(動的)

specular反射有(固定)

影有(固定)

色にじみ有(固定)

Area

specular反射有(動的)

影有(動的)

specular反射有(動的)

影有(動的)

specular反射無

影有(固定)

Dynamic

Direct

ional

specular反射有(動的)

影有(動的)

specular反射有(動的)

影有(動的)

色にじみ無

specular反射無

影無

色にじみ無

Point

specular反射有(動的)

影有(動的)

specular反射有(動的)

影有(動的)

specular反射無

影無

Spot

specular反射有(動的)

影有(動的)

specular反射有(動的)

影有(動的)

specular反射無

影無

Area

specular反射有(動的)

影有(動的)

specular反射有(動的)

影有(動的)

specular反射無

影無

 

考察&検証

何故contribute GIの表がないのか?

検証環境の画像にはcontribute GI/Lightmapが入っています。何故表にないかというと

実は私がcontribute GIを理解していなかったこともあり、最初一緒に検証しました。

後々ドキュメントを見るとcontribute GIをつけることこそがオブジェクトにLightmapとLight Probeの影響を与えるトリガーだったみたいです。

 

contribute GIはStaticと同じ

つまり画像左上(Static/Lightmap)と右下(contribute GI/LIghtmap)は同じ状態のオブジェクトということです笑

通りで何も変わらないと思いました。

 

RealTImeでは色にじみが表現できない?

RealTimeでは以下の画像のような、オブジェクトの色が他のオブジェクトに影響する色にじみが表現できませんでした

後述していますが、色にじみの結果はLightmapに一緒に書き込まれるので、Lightmapを生成しないRealTimeだけでは色にじみは表現できません。

Light Probeはとりあえずつけておくでよし

今回わかったこととしてLight Probeをつけることで、動的なオブジェクトがあるときにより正確なライティングが再現可能だったということです。

Light ProbeはそのポイントでのLight情報を持っていて他のオブジェクトに渡すので、計算コストを抑えた間接光の再現する手法かなと理解しました。

 

Light Probeついてないアセットあんまりみたことないし、とりあえずつけておくで良さそう。ただ、配置方法についてはもう少し研究する必要があるかなと思いました。

 

RealTimeとmixedで影の落ち方が異なる

RealTime

realtime

mixed

mixed

LightmapデータをクリアにすることでmixedはRealTimeの影に近づきます。

つまり、mixedでもベイク可能(Lightmapが生成される)ということ。

 

mixedでベイクをすることで間接光のLightmap Data情報を用意することが可能。Specular反射と影はRealTimeに近い形がとられ、間接光は予め用意したものを使っていた。それと比べてRealTimeではLightmap Dataが生成されないのでこういう現象が起こっていたのでした。

 

mixedを知るために少しやり方を変更

bakedのSpot Lightを用意してbakeした状態が以下です。この状態から反対側にmixedのDirectional Lightを用意したときにどうなるか検証します。

mixed用に検証し直し

 

Directional Lightを反対方向から当てる

Dynamic以外のオブジェクトには影が二つできた!

もちろんSpot Lightの方はbakedなのでSpot LIghtを動かしても影は動かない

 

ちなみにSpotLightをmixedに変更してみたらSpot Lightのon/offが動的に切り替えられた!この表現はよく使うので覚えておきたい

また、今回はLighting Modeはbakedで行いましたが、公式のmixedライティングの説明ではLighting Modeによって動作が変わるみたいです。それはまた別の機会に検証行おうかなと思います。

 

Light Probeが存在する状態でBaked Lightの影が正確に動的オブジェクトに反映されない

自分の考察ではLight Probeがあれば動的なオブジェクトにも影が落ちると考察していましたが、Light Probeは正確な影の情報は持っていないみたいでした。

 

正確な影は落ちないが、暗い場所なのでオブジェクトが暗くなるといったことは再現できるっぽい

 

LightProbeはベイクしないと効果を発揮しない

今回の検証では動的になくすなどはできなかった。

→LightProbeの情報をランタイムで更新する方法がないか調べてみます。

 

Area Lightのシャドウ変じゃない?

以下の画像を見てもらいたい(見にくいけどごめん)

area lightの状況

Area Lightがもし全面均一に発光しているのだとしたら、影は本来Sphereの真下に現れるはず

なのに影は明らかにArea Lightの中心からのみ発光されているように出ていた。

 

これは自分の仕様に対する勘違い。Directinal Lightのような挙動だと思っていた。皆さんも間違えないように注意

 

Lightmapデータを削除したのに照らされているのはなぜ?

bakedのライトのみが存在するシーンで一度ベイク、その後にベイクしたLightmap情報を削除してもシーンは明るいまま?どういうこと?

普通暗くなるのでは...?

Directional Light

 

Emissionは光源ではなかった

今回ついでにEmissionも使ってみました。今までEmissionも単体で光源になると思っていたが認識が違っていた。

Lightなどの光源に反応して発光する効果という意味で使われるものということがわかりました。

 

環境光は影を落とすのか検証

Lightが何もない状態でHDRI Skyのみ20000Luxにしてベイク

結果→落とさない

 

 

今回かなりLightに関して理解が深まりました。

他にも気になることがあれば検証していきたいと思うのでTwitterのDMかこの記事にコメントしていってください!

 

それでは

Unity HDRPを真っ暗にする方法

f:id:tubakihimeLoveHate:20220313124945p:plain

ライティングを勉強したいときにLightが全くないところから始めたいときありますよね

今回はUnityのHDRPで真っ暗にする方法に少し手間取ったのでメモします。

 

 

環境

Unity 2019.4.10

HDRP 7.4.1

 

状況としては以下のライティング要素が存在している状態です

ライトの状況を表した画像

・Directional Light(Lighting Mode: Mixed)

・PointLight(Lighting Mode: Mixed)

・HDRI Sky Volume

・Static Light Sky

・Exposure(Fixed)

・Reflection Probe

・Light Probe Group

・ベイク済み

これらの状態からなるべくオブジェクトを無効にせずに

真っ暗(ライトの影響が何もない状態)にしていきます

 

Directional Lightの光量を下げる

Directional Lightを上向きにしてベイク

ベイクされているので明るさは残っている

Directional Lightwo

 

Directional Lightを0Luxにしてベイク

 

環境光の光量を下げる

背景がまだ明るいので空の明るさ(環境光)を調整します。

HDRI Sky>Desired Lux Valueを0にします。

 

その他Lightの光量を下げる

Point LightのEmission>Intensityも下げておきます。

point lightのemission

 

この状態でベイクした物がこちら

baked2

大体暗くなったのですが、まだBox上側の輪郭が見えますね。

この状態でExposure Volumeなどの値を上げれば真っ暗にはなるのですが、逆に0にすると結構明るくなります。

Exposureは光を取り込む量を設定するVolumeなのでここを変更して明るさが変わるということはまだどこかにわずかな光量があるということになります。

 

環境光の設定を再度確認

static lighting sky

結構探しましたが、最後はLighing Settingで設定可能なStatic Lighting Skyの光量が効いていたみたいです。この値をNoneに変更してベイクしたところ

ようやく真っ暗になりました

 

真っ暗なエディター画像


Exposureを変更させても明るくはなりません。

これで完璧にUnityから光が消えたと言ってもいいでしょう

 

今回の疑問点

Static Lighting Skyとは何だったのか?

ReferenceをみるとStatic Lighting Skyはベイク用の環境光ということでした。

Static Lighting Skyで選択できるものはGlobal Profileの内容によって異なるみたいです。

同じGlobal ProfileをVolumeにも設定できます。

 

Lighting SettingとVolumeで設定できるHDRI Skyの違いはベイク用とランタイム用の違いです。

証拠に真っ暗な状態からVolumeのHDRI SkyのLuxだけ元の値(20000)に戻してベイクしてもLightmapに変更はありません。

HDRI Skyのみ20000Luxにしてベイク

この状態でHDRI SkyのLuxを再び0に戻したら真っ暗になります。(ベイクはしてない)

HDRI Skyを再び0Luxに変更

 

暗闇にしたいだけだったのに、また1つLightingに詳しくなれました笑

ということで簡単ですけど以上になります。

それではまた

 

【Unity】クリック先にオブジェクト生成する機能作ってみた #37

f:id:tubakihimeLoveHate:20220221145020p:plain

今回は「うにty生活」の世界にクリエイティブ要素を追加したいと思います

環境

Unity2019.4.10f1

HDRP7.4.1

 

構想

今回は単純にクリックした場所にオブジェクトの生成を行なっていく機能と配置プレビュー機能など実装していこうと考えています。

 

今回作成する機能は以下の4つです。

作成機能

・クリックした先を衝突検知してオブジェクトが生成されること

・Colliderに沿って生成されること

・配置プレビュー

・オブジェクト生成をスライスシェーダー で行う

 

クリック先にオブジェクト生成

とりあえずCubeオブジェクトを、カメラから発するRayがぶつかるところに生成できるか検証

床にめり込んではいますが、クリックした場所にオブジェクトを生成することができました。

以下のコードを使って実現可能です。

 

これは以前ピン差し記事を書いたときに汎用的に作成したものを変数名変えてそのまま使いました。

ピン/シグナル/マーカー設置システムを作ってみた #34 - うにty生活

上記コードのcloneにただのCubeオブジェクトのPrefabをアタッチして利用します。

 

他のColliderに沿って生成

このままでは床にCubeがめり込んでいます。

これをちゃんと床の上に生成されるように機能を改善していきます。

 

まずは以下のコードでCubeがめり込んでしまうことを回避します。

25行目のif内を以下のように変更します

Vector3 movement = Vector3.Scale(previewClone.transform.localScale, hit.normal) / 2;
target = Instantiate(clone, hit.point, Quaternion.identity)
target.transform.position = new Vector3(hit.point.x + movement.x, hit.point.y + movement.y, hit.point.z + movement.z);

上記コードを簡単に説明すると、

ヒットしたオブジェクトの法線ベクトルを取得。

法線ベクトルが1か−1の方向に、Cubeのスケールの半分をプラス。

そうすることで生成される原点をヒット先から半分ずらしています。

 

また、上記のコードではRayがヒットした先のオブジェクトに関してのみめり込まないようにするものなので、床と既に存在しているオブジェクトの境界あたりをタップするとめり込みます。

 

それを回避するために、生成するオブジェクトには新たにRigidbodyコンポーネントをアタッチしています(結局)。

rigidbodyコンポーネントのinspector

 

Rigidbodyを使わずにできる方法はこれから模索してみます。

 

 

配置プレビュー

今のところ、どこにCubeが置かれるか全然わからないので、配置プレビュー機能を作成します。

まずはマテリアルを作成します。

f:id:tubakihimeLoveHate:20220215080207p:plain

先ほどまでのコードを以下になるように修正した後previewMaterialに、作成したマテリアルをアタッチします。

 

オブジェクトが徐々に出てくるようにする

オブジェクトが生成されるときに下から徐々に表示されていくように変更します。

 

作成したシェーダー グラフはこんな感じです。

shader graphの画像

 

シェーダー は以下の動画を参考にしてます。

 

Faderのスライダーを動かすことで下から表示されます。

このスライダーをオブジェクト生成時に自動的に動かしたいので、生成するオブジェクトにFaderを−1から1にするアニメーションを追加します。

faderを−1から1に移動させるアニメーション

ループはしないので、作成したAnimationのLoop Timeのチェックは外しておきましょう。

これで完成です。

 

ブログ始めた当初からこのクリエイティブ機能は作成したかったので、嬉しいです!

これから他のオブジェクトも置けるように機能拡張していくつもりです!

 

それではまた

 

Physically Based Skyの全プロパティ紹介

f:id:tubakihimeLoveHate:20211220224948p:plain

今回はUnityのHDRPでPhysically Based Sky(物理ベースの空)で設定できる

プロパティを見ていきます。

Unity2020でこの記事を書いていたところPhysically Based Skyが大幅アップデートするUnity2021.2がでたということで2021.2で書き直しました!

Unity2020との違いも含めてPhisically Based Skyのプロパティを見ていこうと思います。

 

 

環境

Unity 2021.2.6f1

HDRP 12.1.2

※LTSではないので注意

 

Physically Based Skyとは

直訳すると物理ベースの空で、設定を行うと 太陽の角度によって昼/夕方/夜の再現が簡単にシミュレーションが可能になります

 

 

Physically Base Skyを設定した時の太陽です(Unity2020.x)

太陽を表示させた時の画像

今まではPhisically Based Skyといえばこれでした。

Unity2021.2.xからはこうなります!

↓↓↓↓!!!

f:id:tubakihimeLoveHate:20211220225204p:plain

 

やばくないですか!?

これはPhisically Based Skyだけの進化ではありませんが、雲とフレアが追加されたことによってなんとも美しいデモシーンになっています。

 

さらにUnity2020ではHDRI Skyでは太陽は描画されてなかったのですが、Unity2021.2ではHDRI Skyでも太陽が出てくるようになりました!

これからはHDRIでもPhysically Based Skyでもどちらでも高クオリティなライティングや絵作りが可能です

※HDRI Skyの場合、太陽の角度によって昼/夕方/夜のシミュレーションはできません。

 

それでは簡単にPhysically Based Skyの準備方法と基本操作からおさらいしていきましょう

 

設定方法

まずはデフォルトではHDRI SkyになっているのでPhysically Based Skyに変更します。

1. GlobalのVolumeを作成

以下の方法で作成可能です(既に存在している場合は新たに追加する必要なし)

ヒエラルキービュー>右クリック>Volume>Global Volume

多分初めに開いた時には既にこの状態だと思います。

 

2. 作成したVolumeのVisual EnvaironmentをPhysically Based Skyに変更する

 

3. Global VolumeにPhysically Based SkyのOverrideを追加する

 

4.Visual EnvaoronmentがHDRI SkyのときはHDRI SkyのVolumeを、

Physically Based SkyのときはPhysically Based SkyのVolumeをにチェックを入れます。今回はHDRI Sky Volumeのチェックは外します。

physically Based Skyを設定したときn

これで準備完了です。

 

基本操作方法

太陽はDirectional LightのRotationで移動可能

大きさはDirectional Light > Shape > Angular Diameterから設定可能です。

 

Physically Based Skyのプロパティ

ここからはプロパティを紹介

Physically Based Skyのプロパティ

パッと見プロパティについてはUnity2020とUnity2021.2で変化はありません

Model > Type

後続の設定のテンプレートを提供してくれています。

作成するシーンが地球である場合、Earthを選択します。それ以外の惑星を表現したい場合はCustom Planetを選択します。

 

EarthのSimpleとAdvanceの違いとしてAdvanceの方がより詳細にプロパティを調節可能です。

Earth normal

Earth Advanced

 

Planet

Spherical Mode(Earth-Advanced,custom only)

惑星が球面であるかを設定します。

球面モードにチェックが入っているとき、Planet Center Position

チェックが入ってないときは、Sea Level(後述)が設定できるようになります。

 

Sea Level(Not Spherical Mode only)

海面の高さを設定できます。値をマイナスしていくと地平線が下がり、増やしていくと上がっていきます。

また、海抜が高いほど大気の密度が低くなります。以下の画像はSea Level「0」と「-10000」の比較画像です。太陽の位置は変更していませんが、大気が薄くなっていることがわかります。

山の上を想定した場合はマイナス値を増やすことでよりそのシーンを再現することができます。

 

Planet Center Position(Spherical Mode only)

惑星のセンターポジションを設定。この設定は基本的にそのままで良いと思います。

 

Planetary Radius(Type = Custom Planet only)

惑星の海面からの半径です。

半径が大きくなるということは惑星の弧が真っ直ぐに近づくということなので、

地平線の位置が高くなっていきます。またデフォルトの「-6378100」は地球の半径である、6378kmのことです。


 

Planet Rotation

惑星の傾き具合。惑星の自転ということですが、変更しても別に太陽の位置が変わるわけではなかったです。

次に紹介するGround Color Textureと一緒に利用します。

 

Ground Color Texture

Ground Tint

Ground Emission Texture

Ground Emission Multplier

これらは地表の色を決めます。地表からの照り返しなどに影響します。

Ground Color Textureに地球儀のようなTextureを設定することで現在いる場所の正しいGround Colorが取得できます。海の位置にPlanet Rotationが設定されているならGround Colorは青色、地表なら茶色みたいな表現が可能です。

Ground Color Textureを設定したときの風景

 

この設定をして、どんどん画面を引いていくとなんと宇宙空間に飛び出て地球を確認することができます。

※宇宙空間に飛び出るにはVolumetric Clouds Volumeを無効にする必要があります。

Ground Color Textureを設定したときの宇宙空間

 

このような地球儀Cubemapを作成するには以下から画像を取得します。

December, Blue Marble Next Generation w/ Topography and Bathymetry

そして、取得したTextureを以下のように変更します。

・Texture Shape → Cube

・Mapping → Latitude-Longitude Layout

・Applyを押下

 

Space(Advance or Custom only)

f:id:tubakihimeLoveHate:20210724224132p:plain

Space Emission Texture

この項目は結構大事です。 この項目にcubemap Textureを設定することで、夜をシミュレーションで利用するEmissive効果を持ったTextureを設定することができます。

ここに星空を設定することで夜を星空に変更することができます。

星空のcubemapは以前作成したので参照して見てください。3分もあればできますよ!

夜のライティング設定と星空作成 #35 - うにty生活

 

Space Rotation

上記TextureのOffsetを調節可能です。

 

Space Emission Multiplier

上記テクスチャの発光の強さを設定します。 

星空は少しこの値を上げないと見えにくいと思います。

 

 

Air(custom only)

f:id:tubakihimeLoveHate:20210728074645p:plain

Air Maximum Altitude 

Sea Levelの項目で、「海抜が高くなるほど大気が薄くなっていく」という説明をしましたが、Air Maximum Altitudeはその割合を設定できます。

 

Air Density RGB

単一散乱アルベドの散乱設定項目です。値はRGBを0~1に正規化したもので値が小さいほど色は光を吸収し大きいほど散乱します。

どういうことかというとこのようにAir Tintに赤色を設定した状態でAir Density Rを1にすると赤色は吸収される(透過する)ということです。

f:id:tubakihimeLoveHate:20210728074745p:plain

 

この設定OrverrideしたVolumeをボックス配置しておくと、砂嵐に入ったような演出をすることが可能です。

 

Air Tint

単一性アルベドを設定できます。この色がベースカラーとなって上のAir Densityの影響を受けます。

 

Aerosols

気体中に浮遊する微小な液体または固体の粒子と周囲の気体の混合体をエアロゾル(aerosol)と言います。

https://www.jaast.jp/new/about_aerosol.html

 

エアロゾルが存在している範囲では、境界線付近の白いモヤのような現象を再現できます。これはミー散乱によるもので白っぽく見えます。

以下はそのエアロゾルに関する設定項目

f:id:tubakihimeLoveHate:20210728080521p:plain

 

Aerosol Maximum Altitude

Air Maximum Altitudeの説明と同じで、高度に応じた密度降下の割合をメートルで表しています。具体的にどうなるかというとミー散乱で白っぽく見えている部分の範囲が広くなります。

 

Aerosol Tint

Aerosol Density

 エアロゾルの単一散乱アルベドです。以下のAerosol Densityの割合によって透明度が変化します。

 

Aerosol Anisotropy

3種類の散乱方法が設定できます。

・1:前方散乱強め

・0:異方性なし

・−1:後方散乱強め

結果から先に言うとこの値は見た目に大きな影響はありません。

ミー散乱は、エアロゾルなどの大気中の大きい粒子に光がぶつかって散乱することです。地平線付近が白く見えるのはミー散乱の効果になります。

ミー散乱の前方散乱後方散乱

f:id:tubakihimeLoveHate:20210731185928p:plain

Unityでのミー散乱について、私が腑に落ちていない部分があるのでまた調査したいと思います。→ちょっと待ってね

とにかくこの値は0のままでいいということです。

Artisic Overrides

Artistic Overridesのinspector画像

空の色に関する微調節を行う設定項目です。

 

Color Saturation 

彩度の変更

 

Alpha Saturation

Alpha Multiplier

透明度の変更。0に近づけるとDirectional Lightが白くなります。

Multi plierは適用する透明度の倍率です。

あんまり変化はわからないです。

 

Horizon Tint

境界線の色が変化します。空の色がHorizon TinitとAir Tint(後述するZenith Tint)とのグラデーションになります。

 

Zenith Tint

Horizon Zenith Shift

Zenith Tintは空の頂点カラーを設定できます。Air Tintとは乗算されているような色合いになります。Horizon Zenith ShiftでZenith Tintの影響度を変更可能です。

Horizon Tint、Horizon Zenith Shift , Zenith Tintを設定した時の画像

 

Miscellaneous

MiscellaneousのInspector画像

Physically Based Skyを設定したときのLighting設定です

 

Number Of Bounces

光が散乱する回数

値を上げるとより現実に近い表現ができるが、ベイク時間も長くなる

 

Intensity Mode

空の環境光の明るさを調節するモードです

Exposure:Exposure Volumeの値の2乗の計算をします。なので0だと変化なし

Multiplier:環境光の倍率

 

Update Mode

環境を更新する頻度です。

On Change:設定が更新されるたびに変化

On Demand:スクリプトから更新を手動で呼び出すまで待つ

Realtime:このモードを選択して表示されるUpdate Periodの間隔で更新する

 

Include Sun In Baking

Reflection Probに空と一緒に太陽が表示されるかどうかの設定だそうですが、

違いがうまく現れなかったです。

 

ということで長くなりましたが、Physically Based Skyのプロパティ紹介は以上です。

2021年内に記事を投稿できるのは最後になると思います。

2022年もどうぞ、よろしくお願いします。それでは。

 

参考

単一散乱アルベド single scattering albedo - aerosolpedia エアロゾルペディア

大気はどこにあるの? | 科学の普及活動 | 公益財団法人日本科学協会

成層圏エアロゾルと対流圏エアロゾル Stratospheric and Troposphric aerosols - aerosolpedia エアロゾルペディア

レイリー散乱とミー散乱 Rayleigh and Mie scattering - aerosolpedia エアロゾルペディア

 

 

【Blender→Unity】Unity側のNormal mapの適用方法 #35.1

どうも、ラブヘイトです。

 

BlenderからUnityにモデルをインポートした際に、

・Normal mapはどうやって適用するの?

 

・Bleder側で割り当てていたUVmapはどこへ?など

いくつか疑問があったので、自分が行ってできた一例を紹介しようと思います。

 

利用するモデル

まずはBlender側から

今回はこちらのモデルを使います。

Blenderでの街灯モデル

街灯の窪んでいる部分が、Normal mapの適用されている箇所です。

これをUnity側に持っていった時も適用したいというのが、今回の課題です。

 

BlenderでのNormal mapの作成方法がわからない方は、過去記事に書いています。参考にしてみてください

【Blender】UV mapの一部にだけNormal mapを適用する方法 - うにty生活

 

作成したモデルの前提

オブジェクトの一部にNormal mapを割り当ててる(以下Normalオブジェクト)

つまり1つのオブジェクトの中でNormal mapを割り当てる部分のマテリアルは分けている状態

マテリアルを2つに分割している画像

また、全ての箇所に仮でもいいのでマテリアルを割り当てといてください。

Unity側でオリジナルのマテリアルを設定するのに必要です。

 

UV mapは二つ存在

UV mapが二つ存在している画像

 

一つはベタ塗り用、一つはNormal map用です。

 ※ 上側の画像背景はnormal mapですが本来は透明です

 

Normalオブジェクトのshaderはこんな感じ

 

エクスポート 

この状態のモデルをエクスポートします。

エクスポート設定は以下の通り

Blenderのエクスポート設定

 

ミニTips

エクスポート設定はいちいち覚えておくのも面倒なので、プリセットとして覚えさせておくことをお勧めします。

Blenderエクスポートのプリセット

 

そしてUnityにインポートします。

 

ミニTips

人によって違うとは思いますが、マテリアルはBlenderから運んできても、色味が違うので自分はそもそもBlender側では本気でShaderいじらないです。こんなもんかなーと確認が取れたらもう出力しちゃって、Unity側でガッツリShaderいじります。

 

 

 

Unity側の設定

 

インポートしたモデルのマテリアルをUnity側で設定する場合

インポートしたオブジェクト>Inspector>Materialからマテリアルを設定して

ApplyすることでUnity側のマテリアルをモデルに簡単に割り当てることが可能です。

Unity側のインポート設定


normal map用のマテリアルもここで割り当てます。

 

※Blender側でマテリアルが割り当てられてないまま、Unity側にインポートするとインポート設定で出てこなくなるので注意

 

normal map用のマテリアルを作成していきます。

と言ってもめちゃくちゃ簡単です。

 

Normal mapのShader作成

Blenderで作成したTextureはBlenderエクスポート時にCollectionとして一緒に出力してもいいし、画像を保存しているなら手動でインポートでもどちらでもいいと思います。

 

Create > Shader > HDRP > Lit Graphで新しいShader Graphを作成。選択した状態でCreate>MaterialからShader Graphが割り当てられたMaterialを作成します。

 

Sample Texture 2Dノードを利用する方法とNormal From Textureノードを利用する方法、2つあります。どちらもTextureにNormal mapを設定するのは同じです。

 

それぞれの結果を見てみましょう。まずはNormal From Textureから

 

近くで見た時

遠くで見た時



なぜかぼやける...

 

次にSample Texture 2D

 

近く

 

遠く

かなり遠くからでも窪んで見えるため、Sample Texture 2Dを採用

もしかしたら、Normal From Textureの使い方が悪いのかもしれないが今回は体験談ということでよしとしましょう。

 

今回はここまで、ここまで見てくださってありがとうございました。

夜のライティング設定と星空作成 #35

Unityで夜のLighting&星空作成!


明けましておめでとうございます。どうもラブヘイトです。

2021年もUnityで遊び尽くしていくので、よろしくお願いします。

 

以前街灯のモデルを作ってみたので、夜のライティングをしてみようと思います。

ついでに夜のライティングをするなら、星空も作成しよう!ってことで

今回は夜のライティング+星空を作ってみました。

 

 

夜のライティング設定

以前からHDRP環境ってどうやって夜にするんだろうと思ってましたが、HDRPのライティングはカメラと合わせてライティングなので、Exposure(絞り)を調節して光を取り込む量を調節します。

 

以下の動画で、その辺も含めて紹介されてます。


ライティングは基本この動画に沿って行っていきます。 

 

モデルインポート

こちらの記事で作成した、モデルをインポートして使っていきます。

【Blender】UV mapの一部にだけNormal mapを適用する方法 - うにty生活

 

街灯のモデル画像

 

Unity側でのNormal mapの設定方法などは今回やりたいこととは外れるので、別の記事で紹介します。

 → ちょっと待ってね

 

環境設定

まずはVolumeの設定から。デフォルト設定の影響を無くしたところから作業します。

デフォルトで作成している人は最初から存在する「Directional Light」「Sky and Fog Volume」のアクティブを切りましょう。

また、「Post Process Volume」はExposureとBloomも一旦切っておきます。

 

Create>Volume Profileで新しいVolumeを作成します。設定は以下の通りです。




これだけでは反映されなくて、Window>Lighting設定のEnvironment(HDRP)にProfileを設定する必要があります。

 

 

ライト設定

内側から発光する表現するためには街灯のカバーにあたる部分の、マテリアルのEmissioin項目を変更します。

Emissive Colorは配置するライトの色温度に近づけます。

Emissino Intensityは動画の通り791を設定。

791はLumenからカンデラに変換した値です。

 

カバーの中にポイントライトを設置します。設定は以下の通り

Lumenには現実の値を参照して10000〜40000の値を設定します。

 

こんな感じになりました 



 

星空作成

過去にskyboxを自作していますが、今回は再度紹介します。

skyboxについての基礎や詳細を知りたい人は以下のこちら↓

 

画像を用意

できるだけ綺麗な画像が欲しかったので、NASAの画像にしました。

 

 SVS: The Alternative Night Sky - Another Time - Another Place

8kの画像をダウンロードしました。

 

skybox作成

超簡単にskybox作成の解説します!

 

画像を取り込んで、取り込んだ画像のInspectorを以下のように変更します。

・Texture Type → Cube

・Mapping Type → Latitude - Longitude Layout

・Default > Compression → High Quality

・Apply

インポートした画像の設定

 

これだけでライティングの時に設定したHDRI skyの名前右側を押すと、先ほど取り込んだ画像がsky boxとして設定可能です。


 

星空はあっけないほど簡単に設定できました!

 

まとめ

一気に写実的な画面になって驚きです。以前UnityちゃんをHDRP環境に移行した時に予想していましたが、やはりHDRPでのLightは現実世界の数字を当てはめていくことがわかりましたね。

 

相変わらず、この世界何もないな笑

ピン/シグナル/マーカー設置システムを作ってみた #34

 

f:id:tubakihimeLoveHate:20201217020035j:plain

 

今回は最近の協力ゲームでは必須の機能!

仲間などに意思表示するためのシグナル(ピン立て)機能を作成します。

 

 

 

 

 

どんなピン/シグナル/マーカーにするか

みんな大好き(知らんけど)Fortniteの、シグナルシステムを参考にしようかなと考えてます。

余談ですが最近のfortniteは有名どころとコラボしまくって結構おもしろいです笑

 

色々呼び方あると思いますが、以下「ピン」に統一します。

見てわかる範囲ですが、Fortniteのピンの特徴としては以下の通りです。

fortniteでマーカーを設置している画像

マーカーが画面外に出た時



 

Fortniteのピン機能

・指定箇所にピンを立てる

・動かない(または動く)

・ピンを指したオブジェクトのアイコン表示させる

・どの距離でもピンの大きさが同じ

・アイテムの上にピンが表示される

・ピンが画面外に出た時に、画面の四角を移動する

・障害物で表示切り替え

・距離を表示etc...

 

いろいろ挙げましたが今回は以下の仕様を実装します

実装する機能

・指定箇所にピンを立てる

・ピンを指した場所から動かない

・障害物で表示切り替え

 

こんなイメージ

ピンを指すイメージ

 

準備

ピンを用意

適当に作成しました。以下の画像はご自由に使ってください。

グリーンバックにしているので、ご使用の際は背景を透過してから使用すること推奨

 


視点移動

クリックした場所にピンを立てるので、視点操作はあってもなくてもいいのですが一応

現在のUnityちゃんの視点や動きを紹介しておきます。

 

コード

 

gistcee3a5249862de6ecdec4929980c30b8

カメラは固定で、このコードは縦方向のみの視点移動を行います。

横方向はキャラクターの子にして、キャラクター移動に依存させています。

※動画内のズーム機能はついてません。

 

 

過去にもカメラ紹介してます

【改良版】追従+マウス視点移動のTPSカメラ #18.1 - うにty生活

 

Unityちゃん移動方法

キャラクターの動かし方を見直してみた #15 - うにty生活

 

個人的なことを言うとUnityちゃんの顔が見えなくなるカメラはあまり好きじゃないです。が、簡単に実装できるカメラを一つ作成しておきかたっかので作りました。

 

照準はOverlayのCanvasの中央にドットを配置しているだけです。


 

ピンを立てる

ピンを立てるためのイメージはこんな感じ

ピンを表示するまでの手順

 

①ユーザーからアクション(クリック)を受け取る

②PinPointを作成する

③PinPointからRayを飛ばして、位置情報や、物に隠れてないかを判断

④ピンの描画

 

※PinPointはUnityの単語ではありません。自分で適当につけた名前です。

  

コード解説

CreatePinPoint

 

CreatePinPointはカメラにアタッチします。クリックした場所からRayを飛ばして衝突検知した場所にPinPointオブジェクトを作成します。(PinPoint自体は透明で、見えるようなものではありません)

 

12行目 pinPoint

ピン情報を保持、発信するプレファブで構成は以下の通りです。

PinPointの設定

 

このPinPointにアタッチされているスクリプトはこちら↓↓↓

 

 PinSystemOverlay

 

簡単に概要を説明するとこのスクリプトがアタッチされたオブジェクトの、位置場所によってUIをCanvas上で移動させたり、障害物があれば非表示にする判定を行います。

 

 

11行目 pinPrefab

Canvas上に表示するピンのイメージプレファブで、OpenPrefabした時の構成は以下の通りです。

Cnavas(Overlay)
└ pinUI
    └ image

pinUIの設定

pinUI-imageの設定項目



上記プレファブのImageコンポーネントにアタッチされている画像はこちらで載せている画像を使ってます。

※ただここは任意で良いので、ピンっぽい画像ならなんでもいいです。

 

 

基本的な流れとして、Canvas上での「pinUI」の位置決定方法は、Start()内の手順で行います。

20行目 ScreenPositionの取得

21行目 Canvas上のlocalPositionを取得

22行目 Canvas上にピンのイメージを配置

 

衝突検知+表示制御+位置決定をLateUpdate()内で行っています。

30行目で障害物検知としてカメラに向かってRayを飛ばして、

カメラに到達しなかったものや、カメラとの間に障害物がある場合は表示されません。

 

次に画面内検知は二重で行っています。

33行目 Vector3.Dotでは、カメラベクトルとPinPointからカメラ方向へのベクトルの内積を取得。視野範囲を決定しています。

この範囲から外れたら、画面外と言うことなのでpinUIは非アクティブにしています。

 

OnBecameVisibleとOnBecameInvisible

最初はカメラフレームへのIn/Out判定に

OnBecameVisibleメソッドOnBecameInvisibleメソッドをセットで使用していました。

OnBecameVisibleメソッドは、オブジェクトがカメラフレームにInしたとき、

OnBecameInvisibleメソッドは、オブジェクトがカメラフレームからOutしたときを検知して動作します。

 

確かに、説明の通りに動いてはいるのですが、検証しているうちにカメラがPinPointの裏側を向いていても反応することが判明しました。

これによってカメラを挟んだPinPointと対角線にもUIが表示される問題があったため、今回の方法になりました。

 

視野範囲のコードはいろんなところで使えそうだし、応用が効きそう!

 

ピンシステムの完成!

 

まとめ

スクリーン座標からCanvasにUIを表示させて、さらにそれを動かし続けるのはまじで苦労しました。

座標を取得・変換する流れはこの通り

WorldPoint取得→ScreenPointに変換→配置したい親のlocalPositionに変換

 

2日間くらい悩んでいたので、Twitterで質問してできたコードです。

協力していただいた方々、どうもありがとうございます。

 

 やっとUnityちゃんを登場させることができました!

以前登場させたのが過去記事なので、8ヶ月ぶりです...笑

その間はshaderやparticleの学習に励んでいたので、表現力は豊かなUnityちゃんをこれからもお届けします!

 

【Shader Graphに入門してみた】HDRPで歪み表現 3日目

f:id:tubakihimeLoveHate:20200930065240p:plain

今回はHDRPでの歪み表現についてです。

 

URPから実装されたShader Graphですが、LWRPとHDRPで少し歪みShader表現の方法が違うみたいなので、対応策をまとめました。

 

 

歪みShader作成

以下の動画のシールドで紹介されたものを、HDRP用にカスタマイズしていきます

 

※当記事で扱うのは歪み表現だけです。シールド自体の作成は別の記事に書いたので、そちらを参考にしてください。

【Shader Graphに入門しました】衝突検知とフレネル 2日目 - うにty生活

 

環境

Unity 2019.4.10f1

HDRP 7.4.1

Shader Graph 7.4.1

 

特定のプロパティ名から直接特定の値を取得できる

f:id:tubakihimeLoveHate:20200930053455p:plain

Shader GraphはBlack boardでプロパティに特定の名前と型が一致すると、それに対応した値を取得することができます。

例えば冒頭に紹介した動画内では、Black boardに「_CameraOpaqueTexture」という名前でプロパティを作成することで、カメラの描画結果を取得することができるそうです。裏仕様みたいでわかりにくいですが、そういうことができるみたい。

 

HDRPでは「_CameraOpaqueTexture」プロパティは使えない

_CameraOpaqueTextureプロパティはHDRP環境では利用できません。その代わりにもっと簡単で分かりやすくノード化されています。

 

ノード構成

LitShader Graphで作成してみました。

f:id:tubakihimeLoveHate:20200930054105p:plain



HD Scene Color

f:id:tubakihimeLoveHate:20200930054546p:plain

このノードを利用することで、描画されている画面を映し出します。今回はそれに動画で紹介されたNoiseを加えることで歪みを表現しています。

 

Metallic:1

Smoothness:0

 

 

完成!!

f:id:tubakihimeLoveHate:20200930055040p:plain


 

問題点

・輪郭があるのが気に入らない

・おそらくHD Scene Colorで光を受けた描画結果にさらに光を加えているため、歪み越しにみたものの色味が違う

→シェーダー を適用するオブジェクトが光を受けないようにする必要がある?

 

Unlit Shaderにすればいいかもしれないと試したところ

成功しました!

普通のUnlit Shader GraphではなくHDRP>Unlitから選択したShader Graphです。

 

先ほどのdistortion(歪み)部分をConvert To Sub GraphでSub Graph化しました。

初めてSub Graphにしたのですが、こんなアイコンだったんですね!

f:id:tubakihimeLoveHate:20200930055702p:plain

f:id:tubakihimeLoveHate:20200930055541p:plain

 

そして、このSub GraphをUnlit Shader GraphのColorに突っ込んで、

Unlit ShaderのSurface TypeをTransparentに設定するだけ

f:id:tubakihimeLoveHate:20200930055830p:plain



 

f:id:tubakihimeLoveHate:20200930060522g:plain

 

輪郭も消えて、色味も同じです。

歪ませてみて気がついたのですが、結構ぼやけますね。またぼやけるのも直せたら追加しておきます。

 

面白い表現見つけた

Unlit ShaderのAlphaを1より低く設定すると面白い表現ができます。

f:id:tubakihimeLoveHate:20200930061841p:plain


Alphaを0.2にしてみました 

この設定でShader越しにみたものは全てぼやけて2つに見えるというShaderの完成!

強く頭を打って倒れる瞬間とか?に使えます(適当笑)

 

それではまた