はらけんログ

unity触ったりバイクに乗ったり

【Unity】値をループさせたいときはMathf.Repeat

こんな便利なAPIがあったなんて。。。

docs.unity3d.com

 

Mathf.Repeatは第1引数が、0を下回る場合は第2引数を、第2引数を上回る場合は0を返してくれます。

 

値をループさせたいときに特に重宝します。

 

値を0~10でループさせたい場合、単純に書くと下記のようになると思います。

float currentValue;

 

void Update{

    if(currentValue > targetValue ){

        currentValue= 0f;

    }

    if(currentValue < 0f){

        currentValue = 10f;

    }

}

 

 

それを下記のようにできます。

float currentValue;

 

void Update{

    currentValue = Mathf.Repeat(currentTime,10f)

 

}

 すごいすっきりしましたね。

 

注意すべき点は、負の数を第2引数に設定できないことです。

 

それでも使える場面は多々あると思うので参考までに。

【Unity】続・スクリプトからMaterialをオブジェクトごとに変更ーMaterialPropertyBlock編

久しぶりに更新します。

 

今回は以前の記事についての補足、応用編です。

haraken.hatenablog.com

 

haraken.hatenablog.com

 

 

前回の記事では、スクリプトから任意のMeshごとにMaterialの情報をSetする方法を記載しました。

 

この方法より処理が軽くする方法がありました。

複数のMeshのMaterial情報を、毎フレーム更新するような場合には特に効果が見られます。

 

 

複数のcubeをMaterialのEmissionの値を変えて光らせたいと思います。

※光っていることが分かりやすいようにPostProcessのBloomを設定しておきます。

f:id:HarakeN:20190227185009p:plain

 

 

1.前回までの方法で光らせてみる

下記のようなスクリプトになると思います。

public class SetMaterialPropertyManager : MonoBehaviour
{
    [SerializeField] MeshRenderer objMesh;

    int emissionID;

    [SerializeField] float emissionValue;

    void Start()
    {
        emissionID = Shader.PropertyToID("_EmissionColor");
    }

    void Update()
    {
    Color emissionColor = new Color(emissionValue, emissionValue, emissionValue);

    for (int i = 0; i < objMesh.Length; i++) {

        objMesh[i].material.SetColor(emissionID, emissionColor);
    }
}

 

実行して emissionValueの値を変えてみると、、、

f:id:HarakeN:20190227190043p:plain

光りましたね。Batchesは102でした。

 

 

2.MaterialPropertyBlockを使用する

 「Material.Set~」は新しくMaterialを生成しているので、レンダリングパスが増えて描画処理が重くななるようです。しかし、MaterialPropertyBlockを使用すると、新しくMaterialを生成せず、そのまま情報を流し込めるようです。

※詳しくは参考ページより

 

MaterialPropertyBlockを使う場合は、下記のようなスクリプトになります。

public class SetMaterialPropertyManager : MonoBehaviour
{
    [SerializeField] MeshRenderer objMesh;

    MaterialPropertyBlock block = null;
    int emissionID;

    [SerializeField] float emissionValue;

 

    void Start()
    {
        block = new MaterialPropertyBlock(); //初期化
        emissionID = Shader.PropertyToID("_EmissionColor");
    }

    void Update()
    {
        Color emissionColor = new Color(emissionValue, emissionValue, emissionValue);


        block.SetColor(emissionID, emissionColor); //materialにSetしたい処理

        for (int i = 0; i < objMesh.Length; i++) {
            objMesh[i].SetPropertyBlock(block);
        }
    }
}

 

実行してみると、、、

f:id:HarakeN:20190227192017p:plain

光りました。

先ほどとやっていることは変わりませんが、Batchesは20になり先ほどの5分の1の処理で済んでいます。

 

 

 

 

まとめ

Meshごと個別にMaterialの情報を頻繁に変えたい場合はMaterialPropertyBlockを使うと格段に処理が速くなります。使用してみてください。

 

 

 

参考ページ

tsubakit1.hateblo.jp

【Unity】MaterialのPropertyIDについて

UnityのMaterialはEmissionの値やMainTextureのデータなど、様々な値を外部からセットできます。

その時に使うのが、material.Set〇〇みたいな関数です。

SetInt

SetFloat

SetColor

SetTexture

などなど

 

例えば、色を変えたいとなった時、

material.SetColor("_Color",new Color(1,1,1));

 みたいに書くと思います。

 

実は上記のようなSet〇〇の第1引数はintでも可能なんです。

docs.unity3d.com

で、引数をstringにしていると、それを内部的にintに変換するようで、要はintで指定したほうが処理が早いみたいなんですね。

 

じゃあ、自分が設定したいPropertyNameのintはどう取得するの?

こちらです。

 

int propertyID = Shader.PropertyToID("_Color"); //取得したいPropertyName

 

一回記録しておくだけで良いので、Start関数などで代入しておいて、それを使い回せばおk!

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PropertyIdTest: MonoBehaviour {

  int colorID;

  int emissionID;

  void Start(){

    colorID = Shader.PropertyToID("_Color");

    emissionID = Shader.PropertyToID("_Emission");

  }

 

  void SetMaterialColor(Material mat, Color col){

    mat.SetColor(colorID,col);

  }

  

  void SetMaterialEmission(Material mat, Color col){

    mat.SetColor(emissionID ,col);

  }

}

 

 

書いてる途中で、いい記事を見つけたので、こちらを参考にしたほうがイイかもです。。。

 

 

www.shibuya24.info

以上。

【Unity】Meshどうしの頂点をピッタリくっつけたい時

Unityさんでなぁ!MeshとMeshの頂点をなぁ!ピッタリくっつけたいときはなぁ!

 

Vキーを押しながらドラックアンドドロップ!

 

youtu.be

 

以上。

【Unity】スクリプトからMaterialをオブジェクトごとに変更

Unity触りはじめてしばらくたったが、本当に今更な事に気づいたのでメモ。アタシってほんとバカ。。。

 

いままで、スクリプトからMaterialのColorとかEmissionとかを変更したいとなった時、変更したいMaterialを直接宣言してました。しかし、この方法では同じMaterialのオブジェクトの色がすべて変わってしまいます。

 

かと言って、オブジェクトの個数分Materialを用意するのもスムーズではありません。更にはMaterialの設定を実行中に変更して停止すると変更がもとに戻りません。

 

そこで、オブジェクトのMaterialをオブジェクト1つずつ個別に設定する方法について記載します。

 

1,とりあえずMaterialの色を変えてみる

下の画像のように、スクリプトを貼り付けた空のGameObjectと、自分で作ったMaterialをCubeたちのMaterialに設定し配置しました。

f:id:HarakeN:20180703184038p:plain

 

「ChangeMaterial 」のスクリプトは下記とおり。

public class ChangeMaterial : MonoBehaviour {
 public Material testMat;

 void Start()
 {
  SetMatColor(Color.red);
 }

 void SetMatColor(Color col )
 {
  testMat.color = col; //Materialの色を変える
 }
}

 

 

 実行すると、両方のCubeの色が変わりました。

f:id:HarakeN:20180703184228p:plain

 

 

2,Cubeごとに色を変える

さて、本題です。オブジェクトの色を個別に設定する場合は、Materialを宣言するのではなく設定したいオブジェクトのMeshRendererを宣言します。

スクリプトは下記のように変更してください。

public class ChangeMaterial : MonoBehaviour {
 public MeshRenderer cube1;
 public MeshRenderer cube2;

 void Start()
 {
  SetMatColor(cube1,Color.red);
  SetMatColor(cube2, Color.blue);
 }

 void SetMatColor(MeshRenderer mesh,Color col )
 {
  mesh.material.color = col; //meshのmaterialの色を変える
 }
}

 

下図のようにInspectorでスクリプトにCubeを設定して実行すると、個別に色が変わります。

f:id:HarakeN:20180703190122p:plain

 

 

3、仕組みについて

MaterialはMeshごとにInstanceされます。そのInstanceされたMaterialにアクセスするにはRenderer.materialからアクセスします。

f:id:HarakeN:20180703191506p:plain

 

 

逆にInstanceされる前(ベースとなるMaterial)を変更したいのであればMaterial

から直接アクセスします。(伝われ)

docs.unity3d.com

docs.unity3d.com

 

 

使い所によってどちらが良いか見極めてから実装するほうがいいですね。

 

 

 追記

描画処理を軽くする方法

haraken.hatenablog.com