【Unity】スクリプトからMaterialをオブジェクトごとに変更
Unity触りはじめてしばらくたったが、本当に今更な事に気づいたのでメモ。アタシってほんとバカ。。。
いままで、スクリプトからMaterialのColorとかEmissionとかを変更したいとなった時、変更したいMaterialを直接宣言してました。しかし、この方法では同じMaterialのオブジェクトの色がすべて変わってしまいます。
かと言って、オブジェクトの個数分Materialを用意するのもスムーズではありません。更にはMaterialの設定を実行中に変更して停止すると変更がもとに戻りません。
そこで、オブジェクトのMaterialをオブジェクト1つずつ個別に設定する方法について記載します。
1,とりあえずMaterialの色を変えてみる
下の画像のように、スクリプトを貼り付けた空のGameObjectと、自分で作ったMaterialをCubeたちのMaterialに設定し配置しました。
「ChangeMaterial 」のスクリプトは下記とおり。
public class ChangeMaterial : MonoBehaviour {
public Material testMat;void Start()
{
SetMatColor(Color.red);
}void SetMatColor(Color col )
{
testMat.color = col; //Materialの色を変える
}
}
実行すると、両方のCubeの色が変わりました。
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を設定して実行すると、個別に色が変わります。
3、仕組みについて
MaterialはMeshごとにInstanceされます。そのInstanceされたMaterialにアクセスするにはRenderer.materialからアクセスします。
逆にInstanceされる前(ベースとなるMaterial)を変更したいのであればMaterial
から直接アクセスします。(伝われ)
使い所によってどちらが良いか見極めてから実装するほうがいいですね。
追記
描画処理を軽くする方法
【Unity】StartとかUpdateについて
unityに慣れてしまっていたので記憶から消えていた疑問なんですが
「UnityってなんでStart()とかUpdate()とかだけ勝手に実行されんの?」
「UnityのStratとかUpdateって、どのスクリプトのUpdate(Start)がどの順番で実行されてんの?」
うーん...わからん
Unityが作りやすいように魔法の呪文を用意してくれていて、実行順が重要な作り方でない限り、毎フレーム必要な処理はUpdateに、起動時に必要な処理はStartに書いておけばおk!
と、いう感じで使っている人多いですよね。でも、モヤモヤが無くならない人も多いハズ。
ってことで、調べたらモヤモヤの正体がわかるとてもわかり易い記事がありました。
要は「MonoBehaviourが設定した魔法の呪文メソッドが、各魔法の呪文リストにランダムな順番でaddされて、決まった順番で魔法の呪文リストが実行される」からモヤモヤするみたいっすね。(日本語ムズイ
って、ことで上記記事からも分かる通り、むやみにスクリプトを増やしまくってUpadeなりを実行させるとかなり負荷がかかるみたい。
個人的には、毎フレーム実行したい関数はUpdateAction()みたいな名前にして、それらクラスを参照したSceneManagerクラスのUpdate()でUpdateAction()をすべて呼び出したら実行順も決めやすいし、わかりやすいし、良いような気がする。
public class SceneManager : MonoBehaviour {
DataManager dataManager;
TimerManager timerManager;
DebugManager debugManager;
void Awake() {
dataManager.Awake_Action();
timerManager.Awake_Action();
debugManager.Awake_Action();
}
void Start () {
dataManager.Start_Action();
timerManager.Start_Action();
debugManager.Start_Action();
}
void Update () {
dataManager.Update_Action();
timerManager.Update_Action();
debugManager.Update_Action();
}
}
【Unity】無名関数とかラムダ式とかいうやつ
C#でintとかstringみたいにSystem.Actionってのを引数にすれば関数を呼べるってことを最近知ったので使ってみてる。
例えば、下記の1と2は同じ処理だが1は引数の関数を実行するので、呼びたい関数を突っ込めばよい。
string log;
void Awake(){
SendLog(SetLog); //1
ActionLog(); //2
}
void SendLog(System.Action act){
act();
Debug.Log(log);
}
void SetLog(){
log="Action!";
}
void ActionLog(){
SetLog();
Debug.Log(log);
}
ただ、困ったことにSetLogに引数がつけられない。
string log;
void Awake(){
SendLog(SetLog("無理")); //エラー
}
void SendLog(System.Action act){
act();
Debug.Log(log);
}
void SetLog(string str){
log=str;
}
で、無名関数とかラムダ式使うやつを使おうとおもった。
(引数)=>{処理}と書けば大丈夫らしい。
string log;
void Awake(){
SendLog(()=>{log="ShimaRin"});
}
void SendLog(System.Action act){
act();
Debug.Log(log);
}
書き方が独特なので覚えるのに時間かかったが、すごく便利なので多用していきたい。
が、これ処理のせいで動作が重くなったりしないかな。。。というとこだけ疑問。
おかしなことしなければ大丈夫だとは思う。
【Unity】unityちゃんをつかってVtuberテスト!マジ卍!
過去記事にもあるけど、去年作りかけていたプロジェクトを掘り起こしたのでテストした。
去年の今頃はVtuberなんて言葉もなかったのに、気づけば600人以上のVtuberがいるとか。
あー俺が言いだしたことになんねーかn(例のコラ割愛
忙しさにかまけてやりたいことやらなくなると時代において行かれるね。。。
ってことで下記に現状アップ
マジ卍!
次はモーフあたりをいじるかな
モデルもオリジナルにしたいからc4d頑張る
輝夜月としのめぐに会いに行くことを目標に暇を見つけてブラッシュアップするか!
【Unity】LightingやQualitySettingをいじっても影がちらつく
大きな街のモデルを配置してその中をプレイヤーが動く時、なぜだか影がちらつき出した。
解決方法を探していたらありました。
No hack, no work • サバティカるブログ 第13話「影がチラつく」
右の建物の影に注目
これが
こう
どうやらカメラの「Clipping Planes」のNearの数値を0.1以上にすれば直るっぽい。
近くを描画しない時は全体の処理が軽そうだからと言ってむやみにNearの値を小さくしないほうが良い。贅沢は敵。
奥の木がちらついてるのはTerrainの設定っぽい。直さないと。。。