20211224のUnityに関する記事は10件です。

Unityで音ゲーを作りたい

この記事は、木更津高専 Advent Calendar 2021 の25日目(最終日!)の記事です。 前→リア充にリア充を台無しにさせたい by @tos-up はじめに 私はプログラミング研究同好会に所属していますが、先日行われた祇園祭で「ゲームセンタープロ研」のスタッフをしているときに思いました。 音ゲー作って展示したら盛り上がるのでは? こうして、私は音ゲーを作ることを決心しました。 音ゲーとは? ご存知の方も多いと思いますが、音ゲーとは音楽ゲームの略称で、音楽に合わせて何らかのアクションを起こすゲームのことです。 有名なものには、 太鼓の達人 CHUNITHM プロジェクトセカイ カラフルステージ! feat. 初音ミク などがあります。 プレイ画面の作成 今回は縦画面の6レーンで、単押しの音符(以下、ノーツ)のみ上から下に降ってくるものを作ります。長押しノーツは実装が大変なので作りません。また、他のレイアウトに流用しやすくするため、3Dで作成します。 まずは、譜面が流れるためのレーンと判定の位置を示す判定ラインを用意します。これらの詳しい作り方については、レイアウトによりかなり異なるのでここでは説明しません。 このようにレーン等が用意できたら、背景がデフォルトなのも嫌なので後ろに背景のブロックを用意します。 一色塗りが嫌な場合は、ブロックに画像を貼ったり、立体的なオブジェクトを設置するのも良いと思います。この辺りは個人の好みに合わせて調整してください。 しかし、このままではノーツが判定ラインを通り過ぎてもそのまま下に行ってしまい、レーンを飛び出してしまうので、以下のように目隠し(兼HUD表示エリア)を設置しました。 以上が私の作ったプレイ画面です。 ちなみに、CHUNITHMやプロセカのようにノーツを画面奥から手前に来るようにしたいときは、カメラの角度を上向きにして、位置を調整するといい感じになると思います。レーン自体に角度をつける方法は、この後紹介するノーツを生成するスクリプトの実装が難しくなるので、あまりおすすめはしません。 CSVデータの読み取り 今回は譜面のデータをCSVで1行にノーツを叩く時間(s),ノーツが流れるレーンと記述し、それをノーツの個数分用意する形で管理しました。 score.csv 0.000000,1 0.370370,2 0.740741,3 1.111111,4 1.481481,5 1.851852,6 2.222222,1 2.592593,2 2.962963,3 まず、Assetsフォルダ内にResourcesフォルダを作成し、その中にこのファイルを入れます。 次に、GameController.csを作り以下のように編集します。 GameController.cs using System.Collections; using System.Collections.Generic; using UnityEngine; using System.IO; public class GameController : MonoBehaviour { public string filePass; TextAsset csvFile; private List<float> noteTiming = new List<float>(); private List<int> noteType = new List<int>(); private string[] csvDatas = new string[2]; void Start() { LoadScore(); } void LoadScore() { csvFile = Resources.Load(filePass) as TextAsset; StringReader reader = new StringReader(csvFile.text); while(reader.Peek() != -1) { string line = reader.ReadLine(); csvDatas = line.Split(','); noteTiming.Add(float.Parse(csvDatas[0])); noteType.Add(int.Parse(csvDatas[1])); } } } その後、空のGameObject GameController を作成してスクリプトを適用します。 すると、このオブジェクトのInspector画面にFile Passの項目が出現するので、先ほど作成したCSVファイルのファイル名を入力してください。 このスクリプトには特に出力は用意していませんが、変数noteTimingとnoteTypeに値が代入されたのちにDebug.Log等で値を出力させると、実際に値が代入されていることが確認できます。 ノーツの生成 CSVで読み取った値をもとに、実際にノーツを生成していきます。 まず、ノーツの原型となるオブジェクトNoteを作成し、Resourcesファイルへドラッグしてください。(GameObjectのPrefab化) 次に、先ほど作成したGameController.csを以下のように書き換えてください。 GameController.cs using System.Collections; using System.Collections.Generic; using UnityEngine; using System.IO; public class GameController : MonoBehaviour { public string filePass; public Vector3 noteOffset; public float laneInterval; public float highSpeed; TextAsset csvFile; private List<float> noteTiming = new List<float>(); private List<int> noteType = new List<int>(); private string[] csvDatas = new string[2]; void Start() { LoadScore(); Initialize(); } void LoadScore() { csvFile = Resources.Load(filePass) as TextAsset; StringReader reader = new StringReader(csvFile.text); while(reader.Peek() != -1) { string line = reader.ReadLine(); csvDatas = line.Split(','); noteTiming.Add(float.Parse(csvDatas[0])); noteType.Add(int.Parse(csvDatas[1])); } } void Initialize() { GameObject obj = (GameObject)Resources.Load("Note"); int noteLane = 0; for(int i = 0; i < noteTiming.Count; i++) { string noteName = "Note" + (i+1).ToString(); noteLane = noteType[i]; GameObject note = Instantiate(obj, new Vector3(noteOffset.x + (noteLane - 1) * laneInterval, (noteTiming[i] + noteOffset.y) * highSpeed, noteOffset.z), Quaternion.identity); note.name = noteName; } } } 書き換えられたら、GameControllerのInspector画面に追加された項目に以下の値を入力していきます。 Note Offset 0秒、1レーンの位置(初期位置) Lane Interval レーン間の距離 High Speed ノーツの移動する速さ これらを設定し、ゲームを実行すると実際にノーツが生成されます。 ノーツの動作 ノーツを動かす際に、RididBody.velocity等を使用すると簡単に記述することができますが、音ゲーというゲームの性質上、必ずしも音楽(=現実の時間)と同期しないこの機能はあまり適していません。そこで、今回はUpdate()内で各ノーツについて現在の時間から座標を計算し、その地点にオブジェクトを移動させる方法を使用します。 まず、GameController.csを以下のように書き換えます。 GameController.cs using System.Collections; using System.Collections.Generic; using UnityEngine; using System.IO; public class GameController : MonoBehaviour { public string filePass; public Vector3 noteOffset; public float laneInterval; public float highSpeed; TextAsset csvFile; public float startTime = 0.0f; private List<float> noteTiming = new List<float>(); private List<int> noteType = new List<int>(); private string[] csvDatas = new string[2]; void Awake() { LoadScore(); Initialize(); startTime = Time.time; } void LoadScore() { csvFile = Resources.Load(filePass) as TextAsset; StringReader reader = new StringReader(csvFile.text); while(reader.Peek() != -1) { string line = reader.ReadLine(); csvDatas = line.Split(','); noteTiming.Add(float.Parse(csvDatas[0])); noteType.Add(int.Parse(csvDatas[1])); } } void Initialize() { GameObject obj = (GameObject)Resources.Load("Note"); int noteLane = 0; for(int i = 0; i < noteTiming.Count; i++) { string noteName = "Note" + (i+1).ToString(); noteLane = noteType[i]; GameObject note = Instantiate(obj, new Vector3(noteOffset.x + (noteLane - 1) * laneInterval, (noteTiming[i] + noteOffset.y) * highSpeed, noteOffset.z), Quaternion.identity); note.name = noteName; } } } 曲の開始時間を計測し、ノーツを移動するスクリプトのためにStart()で行っていた動作をAwake()で行うよう変更しました。 次にNoteMovement.csを以下のように作成し、Resourcesフォルダ内のNoteに適用します。 NoteMovement.cs using System.Collections; using System.Collections.Generic; using UnityEngine; public class NoteMovement : MonoBehaviour { private Vector3 pos; private float offset; private float songTime; private float diffTime; private float highSpeed; GameController gc; void Start() { GameObject gcobj = GameObject.Find ("GameController"); gc = gcobj.GetComponent<GameController>(); pos = this.transform.position; songTime = gc.startTime; highSpeed = gc.highSpeed; } void Update() { diffTime = Time.time - songTime; pos.y -= diffTime * highSpeed; this.transform.position = pos; songTime += diffTime; } } そして、ゲームを実行するとこのようにノーツが生成された後、移動を始めます。 この移動の速さはGameControllerのHigh Speedの値によって変更することができます。 今後実装したいこと ノーツの判定 音楽の再生 様々なエフェクト これらは時間がなく、実装することができませんでした。 ですが、来年度の祇園祭にて完成版を展示することを予定していますので、ご期待ください。 出来なかったらすまん 参考にしたサイト あとがき 今回初めてQiitaの記事を執筆しました。拙い点も多々あったと思いますが、ここまで閲覧していただきありがとうございました。それでは。 Happy Holidays!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Spring Joint 2D で ソフトボディを作る

この記事は、Unityアドベントカレンダー25日目の記事です。 はじめに Unity の Spring Joint 2D を利用することで、やわらかい物体(ソフトボディ)を作ることができます。 GitHubリポジトリ ソフトボディの作り方 パーティクル(Rigidbody)をばね(Spring Joint 2D)で接続すると、 ソフトボディのようにふるまうオブジェクトを作ることができます。 ソフトボディの実装 ソフトボディの実装コード ソフトボディのパーティクルを表現するクラス(SoftbodyParticle)を用意します。 SoftbodyParticle.cs using UnityEngine; public class SoftbodyParticle : MonoBehaviour { [SerializeField] private new Rigidbody2D rigidbody; public Rigidbody2D Rigidbody => rigidbody; } 次に、ソフトボディ(Softbody2D)を実装します。 SoftbodyParticleを円周上に並べ、SpringJoint2Dで接続しています。 Softbody2D.cs using System; using System.Collections; using System.Collections.Generic; using System.Security.Cryptography; using Unity.VisualScripting; using UnityEngine; #if UNITY_EDITOR using UnityEditor; [CustomEditor(typeof(Softbody2D))] public class Softbody2DEditor : Editor { public override void OnInspectorGUI() { if (GUILayout.Button("Create")) { var component = target as Softbody2D; if (component != null) { component.Create(); } } base.OnInspectorGUI(); } } #endif public class Softbody2D : MonoBehaviour { [Header("=== Create Settings ===")] [SerializeField] private int particleCount = 32; [SerializeField] private float softbodyRadius = 4f; [SerializeField] private SoftbodyParticle _particlePrefab; [SerializeField] private bool aroundConfigureDistance = false; [SerializeField] private bool centerConfigureDistance = false; [Header("=== Runtime Settings ===")] [SerializeField] private float aroundFrequency = 25f; [SerializeField] private float centerFrequency = 5f; [Header("=== Cache ===")] [SerializeField] private SoftbodyParticle[] aroundParticles; [SerializeField] private SoftbodyParticle centerParticle; [SerializeField] private List<SpringJoint2D> aroundJoints = new List<SpringJoint2D>(); [SerializeField] private List<SpringJoint2D> centerJoints = new List<SpringJoint2D>(); private void Update() { foreach (var joint in aroundJoints) { joint.frequency = aroundFrequency; } foreach (var joint in centerJoints) { joint.frequency = centerFrequency; } } private void OnDrawGizmos() { Gizmos.matrix = Matrix4x4.Translate(new Vector3(0, 0, -4f)); foreach (var joint in aroundJoints) { Gizmos.color = Color.red; if (joint != null) Gizmos.DrawLine(joint.transform.position, joint.connectedBody.position); } foreach (var joint in centerJoints) { Gizmos.color = Color.yellow; if (joint != null) Gizmos.DrawLine(joint.transform.position, joint.connectedBody.position); } } /// <summary> /// ソフトボディの作成 /// </summary> public void Create() { CreateParticles(); CreateJoint(); } /// <summary> /// パーティクルをJointで接続 /// </summary> private void CreateJoint() { aroundJoints.Clear(); centerJoints.Clear(); // 外周パーティクル同士を接続 for (int i = 0; i < aroundParticles.Length; i++) { var p1 = aroundParticles[i]; var p2 = aroundParticles[(i + 1) % aroundParticles.Length]; var joint1 = p1.gameObject.AddComponent<SpringJoint2D>(); var joint2 = p2.gameObject.AddComponent<SpringJoint2D>(); joint1.connectedBody = p2.Rigidbody; joint2.connectedBody = p1.Rigidbody; aroundJoints.Add(joint1); aroundJoints.Add(joint2); } // 中心パーティクルと外周パーティクルを接続 for (int i = 0; i < aroundParticles.Length; i++) { var p1 = aroundParticles[i]; var p2 = centerParticle; var joint1 = p1.gameObject.AddComponent<SpringJoint2D>(); var joint2 = p2.gameObject.AddComponent<SpringJoint2D>(); joint1.connectedBody = p2.Rigidbody; joint2.connectedBody = p1.Rigidbody; centerJoints.Add(joint1); centerJoints.Add(joint2); } // Jointの設定 foreach (var joint in aroundJoints) { joint.autoConfigureDistance = aroundConfigureDistance; joint.enableCollision = false; } foreach (var joint in centerJoints) { joint.autoConfigureDistance = aroundConfigureDistance; joint.enableCollision = false; } } /// <summary> /// パーティクル生成 /// </summary> private void CreateParticles() { if (centerParticle != null) { DestroyObject(centerParticle.gameObject); } foreach (var p in aroundParticles) { DestroyObject(p.gameObject); } centerParticle = CreateParticle(Vector3.zero); aroundParticles = new SoftbodyParticle[particleCount]; for (int i = 0; i < particleCount; i++) { float radian = i * Mathf.PI * 2f / (particleCount - 1); var position = new Vector3(Mathf.Cos(radian), Mathf.Sin(radian), 0f) * softbodyRadius; aroundParticles[i] = CreateParticle(position); } } /// <summary> /// パーティクル作成 /// </summary> private SoftbodyParticle CreateParticle(Vector3 position) { var p = Instantiate(_particlePrefab, transform); p.transform.localPosition = position; return p; } static void DestroyObject(GameObject target) { if (Application.isPlaying) Destroy(target); else DestroyImmediate(target); } }   ソフトボディの作成 パラメータや、Prefabを以下のように設定した状態で、Createボタンを押します。 以下のようなソフトボディが作成されます。 結果
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

VRChatプレイヤーによるParticle System解説 ~Triggers, Sub Emitters Module編~

この記事はUnity 2019.4.29f1の記事です External Forces, Noise Module編 << ここ >> 次 はじめに この記事はちょっとParticle System触れるようになったけどまだまだ知らないパラメーターだらけで抵抗感がある人向けにじゃあ全項目解説しようという記事です。 パーティクル?シェーダー?憧れるけどよくわかんない…という人は最近はVRCUnity勉強会などで初歩の初歩から解説してくれる講座などが解説されているのでそこに参加してみたりするといいでしょう。 その他にこの記事はアドベントカレンダーにしてParticle Systemの記事を増やしてパーティクルへの抵抗感を減らしてやろうという企みもあります。 Triggers, Sub Emitters Moduleってどこ? こここ Triggers 特定のコライダーにのみ関係してパーティクルを消したりTrigger1を引いたりできるModule Colliders リストの形でどのコライダーに関係させるか指定するパラメーター Inside デフォルト Kill パーティクルがコライダーの内側にあるときにどうするか決めるパラメーター Kill(消滅), Ignore(何もしない), Callback(Triggerを送る)の3つ Outside デフォルト Ignore パーティクルがコライダーの外側にあるときにどうするか決めるパラメーター Enter デフォルト Ignore パーティクルがコライダーに入るときにどうするか決めるパラメーター Exit デフォルト Ignore パーティクルがコライダーから出たときにどうするか決めるパラメーター Radius Scale デフォルト 1 (0.0001~3.402823e+38) パーティクルの当たり判定の大きさ Visualize Bounds デフォルト OFF パーティクルの当たり判定の可視化 Sub Emitters パーティクルの動きをきっかけに他のパーティクルを出すためのModule リストになっていてそれぞれ別のParticle Systemを設定できる モード デフォルト Birth どういう条件で設定したParticle Systemが発動するか決めるパラメーター Birth: パーティクルが存在している間1つ1つから設定したParticle SystemのパーティクルのRate over Timeで設定したパーティクルが出続ける Collision: Collisionが有効のときパーティクルがコライダーに衝突した時に設定したParticle SystemがそのBurstsで一回だけ放出される Death: パーティクルが消滅した時に設定したParticle SystemがそのBurstsで一回だけ放出される Trigger: パーティクルがIs Triggerが有効のコライダーに侵入した時に設定したParticle SystemがそのBurstsで一回だけ放出される Manual: スクリプトで呼んだときだけ設定したParticle SystemがそのBurstsで一回だけ放出される Inherit デフォルト Nothing このParticle Systemからパラメーターをなにか引き継ぐか決めるパラメーター Everything, Color, Size, Rotation, Lifetime, Durationが他にある あんま使わない Emit Probability デフォルト 1 (0~1) 単位 割合 設定したパーティクルが出てくる確率を決めるパラメーター おわり というわけでTriggers, Sub Emitters Module編でした 次はTexture Sheet Animation Module編です External Forces, Noise Module編 << ここ >> 次 スクリプトとかアニメーションのイベントのきっかけにできるやつ、もしかしたらアバターでも使えるようになるかも ↩
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

URP複数のカメラのパフォーマンスの最適化に関して

今回の話題: 1)URP複数のカメラのパフォーマンスの最適化に関して 2)Unity Addressablesがパッケージ化する時に、BuildAssetBundleOptions.DisableWriteTypeTreeを設定する方法 3)Unrealは、商用ゲームのホットアップデートプログラムとして使用できます 4)UGUI SpriteAtlas使用中にコールバックがインスタンス化され、AtlasRequestedとStartの順序が逆になります 5)AssetBundleからレンダリングパイプラインが動的にロードされ、後期のレンダリングが異常になります。 Rendering Q1:URP7.4.3、メインカメラを除いて、撮影したモデルをゲームのメインUIにレンダリングするために使用されるサブカメラもあります。Profilerで以下の状況が見えます。 上に示したように、LODの計算はサブカメラでも実行されますが、サブカメラのCullingMaskにはRTModelというLayerのみが有効され、このレイヤーには一つの3Dオブジェクトしかがありません。通常、サブカメラCullScriptableの部分のコストは存在しないはずですが、今は以下のような原因が考えられ ます。つまり、URPがBase Cameraごとにこの部分の計算を実行したが、Overlayカメラを使用すると、カメラのtargetTextureを元の方法でRawImageにレンダリングできません。 この問題に当たった方はいますか? A:問題主の疑問点は、サブカメラのCullScriptableはそれほどコストがかからないはずです(結局のところ、1つのオブジェクトしか持っていません)。 ここには2つの問題があります。 1.Cullingは一体何をしましたか?オブジェクトは1つしか持たないのに、なぜCullingはこれほど時間がかかるのですか(まさか一つのオブジェクトだとしても、たくさんの準備が必要ですか)? 2.Profilerに表示されるデータは本当に実際のデータですか?言い換えれば、サブカメラのCullingは実際に1.68msを実行しましたか? これらの2つの問題とは別に、より良いアプローチがあります。 メインカメラとUIカメラの合計2台のカメラがありますが、UIに表示される3Dオブジェクトはどうですか? 仮想カメラがあります。いわゆるカメラとは、実際には、VPマトリックスを作成し、RTを作成し、可視オブジェクトを描画するとできたものです。では、UnityのSRPを使用し、任意の場所にVPマトリックスを設定し、RTを設定してから、指定したオブジェクトを描画します(UIのすべての3Dオブジェクトはこのオブジェクトの下にハングします)。その後、このRTを自由に使用できます。 UIに2つの3Dオブジェクトがある場合は、それらを1つのRTに配置してみてください。そうでない場合は、2つ以上のRTに配置してください。さらにいくつかの描画コマンド、いくつかのRT(フルスクリーンである必要はありません)、およびいくつかのSwap RT操作が追加されます。私たちのプロジェクトは複数のRTを必要としないため、複数のRTが必要なこの場合、1つのRTと複数のViewporを使用して解決できると仮定します。このコードは既存したもので、Cascade Shadow Mapのメソッドを参照すると、Swap RTは必要なくなります。 要約すると、何を描きたいかがわかっているので、UnityCullingにチャンスを与えないでください。 Q2:データは、Development Buildの実機で見たパフォーマンスデータです。現在、HLODのような方法でこのLODの大きなコストを減らしたいです。Q1に「VPマトリックスの設定とRTの設定」とおっしゃったが、このVPマトリックスは具体的にはどのように操作しますか?もっと詳しく説明いただけませんか。 A:すべてが可能です!しかし、これは重要ではありません。問題主が言及したHLODとLODは、上記のCullingとは何の関係もありません。VPマトリックスは、viewマトリックスとprojectionマトリックスです。カメラの機能は、これら2つのマトリックスを提供することです。 パイプラインに対応するマトリックスを設定してから、指定したオブジェクトを描画する場合、カメラを追加する必要はまったくありません。結局のところ、カメラが1つ増えると、Cullingが1つ増えることになります。 VPマトリックスに詳しくない場合は、それを実装する方法がわからなくても、簡単です。追加のカメラを使用し、このカメラのCullingをオフにしてから、レンダリングpassでcullingresult.visibleobjectを描画せず、Graphics.DrawMeshまたはCommandBuffer.DrawMeshを直接使用して表示したい3Dオブジェクトを描画します。 Addressable Q:元のAssetBunldeがパッケージ化する時、BuildAssetBundleOptions.DisableWriteTypeTreeを設定して、パッケージ本体をはるかに小さくすることができます。今、はAddressablesを使用して、プロジェクトアップグレードしようとしています。BuildAssetBundleOptions.DisableWriteTypeTreeを設定するにはどうすればよいですか? A1:まず、Addressableがパッケージ化したBundleのメインスクリプトはBuildScriptPackedModeです。DoBuild関数では、AddressableAssetsBundleBuildParametersクラスが使用されていることがわかります。このクラスはBuildParametersから継承され、BuildParametersにはpublic ContentBuildFlagsContentBuildFlags{get; set;}というメンバー変数があります。このContentBuildFlagsはDisableWriteTypeTreeを設定するために使用され、BuildParametersはScriptableBuildPiplineに属します。 SBPを参照したCompatibilityBuildPiplineは次の操作を行います。 if ((options & BuildAssetBundleOptions.DisableWriteTypeTree) != 0) parameters.ContentBuildFlags |= ContentBuildFlags.DisableWriteTypeTree; IBundleBuildResults results; ReturnCode exitCode = ContentPipeline.BuildAssetBundles(parameters, content, out results); BuildScriptPackedMode.csに追加することもできます。 var buildParams = new AddressableAssetsBundleBuildParameters( aaContext.Settings, aaContext.bundleToAssetGroup, buildTarget, buildTargetGroup, aaContext.Settings.buildSettings.bundleBuildPath); buildParams.ContentBuildFlags = UnityEditor.Build.Content.ContentBuildFlags.DisableWriteTypeTree; しかし、ここでテストしましたが、機能しませんでした。最下位レベルでサポートがないのか、テストケースに問題があるのか​​わかりません。同じ方法でテストすることをお勧めします。 さらに、コードを調べたところ、SBPがパッケージ化と圧縮の部分でこのパラメーターを使用していないことがわかりました。シーンの依存関係を処理する場合、このパラメーターはBuildSettings構造に結合され、C ++部分に提供されコールします。したがって、このパラメーターを有効にするには、最終的にC ++レイヤーに渡す必要があります。 A2:Addressableはこの設定項目を直接変更する外部インターフェースを提供していないようです。自分でコードを書いてパッケージ化方法を変更する必要があります。BuildModeを作成する必要があります。この投稿の5番目の質問に対する回答を参照できます:https://answer.uwa4d.com/question/5e649911438f7d0db495c724#5e64a4e8438f7d0db495c725 コアコードは、DoBuildでbuildParamsの設定を変更することです。buildParams.ContentBuildFlags |= UnityEditor.Build.Content.ContentBuildFlags.DisableWriteTypeTree; 以下に示すように、 テストを行ったところ、効果的であることがわかりました。 上記はデフォルトのパッケージです。変更後、再びパッケージすると、次の結果になります。 全体が小さくなります。さらにAssetBundleを解凍すると、内部のコンテンツが非常に簡潔になります。 Unreal Q:Unrealに関して、商用ゲームに使用できるホットアップデートソリューションはありますか? A1:当社は自社開発のフレームワークなので、オープンソースのUnrealホットアップデートソリューションがあるかどうかは注意していないですが、印象的にはないようです。 でも、Unityエンジンに基づくオープンソースソリューションが多くあります。Unityのオープンソースソリューションに基づいて実装できます。基本的なアイデアは、リフレクションを使用してエンジンのエクスポートLuaインターフェイスを事前に生成することです。 どのようにリフレクションを利用しますか。簡単に言えば、リフレクションによってエンジンインターフェースの関数名、戻り値タイプ、パラメーター名、パラメータータイプを取得し、ルールで解析パラメーターのタイプとその個数や順序を生成して、結果が正しいLuaエクスポート関数int xxx(lua_State *L)関数に戻ります。クラスメンバー関数をTableにエクスポートする必要があります。C++クラス階層に従って、Metatableを使用して、親クラスのLuaエクスポートメンバー関数を見つけることができます。 これはUnityオープンソースソリューションですが、Unrealも同様です。違いは、UnrealはUClass UPropertyを使用するのに対し、UnityはC#を使用することです。その方法でやってみてください。 A2:次のリンクを参照してください。 https://github.com/Tencent/puerts A3:Tencentには2つのLuaホットアップデートフレームワークがあります。 1.[sLuaUnreal](https://github.com/Tencent/sluaunreal モバイルゲーム「PeaceElite」で採用されているフレームワークと言われています。 2.[UnLua](https://github.com/Tencent/UnLua sLuaの後に導入されたフレームワーク。 Script Q:UGUI SpriteAtlasを使用すると、次の図に示すように、AtlasRequestedとStartの順序が逆になります。 テストプロジェクトは、 https://answer.uwa4d.com/question/5f743b739424416784ef24d6(中国語注意) を参照ください。テスト環境はUnity2019.4です A:Timelineで特定の実行タイミングを確認できます。Main.Updateでインスタンス化すると(テスト時にMain.Updateのintervalを削除しました)、Atlasのコールバックが2番目のフレームに実行され、TestAtlasSpriteの Awake、OnEnable、およびStartが1番目のフレームに実行されました。Main.Startでインスタンス化する場合、これらのプリントは最初のフレームにあります。これは、AtlasのコールバックがEarlyUpdate.SpriteAtlasManagerUpdateにあり、 インスタンス化された TestSpriteAtlas.StartがFixedUpdate.ScriptRunDelayedFixedFrameRateの下にあるため、Atlasコールバックの背後に戻ったからです。 この画像はUpdateで実行される状況です。 これはStartで実行される状況です。すべて最初のフレームにプリントされていることがわかります。 これはMain.Startでインスタンス化を実行しているTimelineです。TestSpriteAtlas.StartはAtlasのコールバックの後に実行されることがわかります。 これはMain.Startでインスタンス化を実行しているTimelineです。 EarlyUpdate,FixedUpdateのようなコールバックの実行順はを参考できます。https://medium.com/@thebeardphantom/unity-2018-and-playerloop-5c46a12a677 Rendering Q:パイプラインを動的に切り替えてエラーが発生する問題に当たったことがありますか。 既存のUBPプロジェクトは、新しいシーンに入った後、指定されたレンダリングパイプラインに切り替える必要があります。シーンをパッケージ化する時、レンダリングパイプラインと一緒にシーンにパッケージ化され、次のコードによってレンダリングパイプラインを切り替えます。 GraphicsSettings.renderPipelineAsset = targetAsset; QualitySettings.renderPipeline = targetAsset; Copy しかし、AssetBundleを介して読み込まれるレンダリングプロセス:後処理では、UberPostに2つのキーワードが欠けています。 次のような画像になりました。 Project Setting -》 Qualitでプロジェクトに手動で設定されたhero_showパイプラインが正常に表示されます。 ブレークポイントのデバッグにより、Renderプロセスで、Keywordsが実際に割り振られていることがわかります。両方のプロセスは同じです。 PostProcessPass.csファイルには: void Render(CommandBuffer cmd, ref RenderingData renderingData) ただし、Frame ProfilerのフレームにはKeywordsがないことが示されています。簡単なプロジェクトテストを添付します。 デフォルトはWindowsプラットフォームです。 defaultSceneを直接実行します。 そうでない場合は、以下の手順に従ってください。 1.AssetBundle-> build 2.defaultSceneを実行します。 リンク:https://pan.baidu.com/s/1q3s6mAUwE723wTJ3VmS81g パスワード:8kwn A1:その問題に当たったことがないが、その原因は推測できます。 まず問題をまとめてみてください。 Project Setting -》 Qualityでレンダリングパイプラインを手動で設定します。表示は正常です。 AssetBundleの形式でレンダリングパイプラインをロードすると、キーワードが失われたために表示が異常になります。 そうすれば、答えは非常に簡単になります。 これらの2つのモードでは、Unityがレンダリングパイプラインのアセットを異なる方法で処理するからです。 一番目の方法では、Unityはレンダリングパイプラインをデフォルトのアセットと見なし、すべてをパッケージ本体にパックして使用します。 二番目の方法では、Unityはレンダリングパイプライン、特にレンダリングパイプラインに関連したShaderによって、そのKeywordが使用されているかどうかを判断します。使用されていない場合は、最適化します。 プロジェクトはまだ見ていません。問題主がコードでオンにしたこの2つのKeywordからだと思います。このようにコードがKeywordをオンにした方法は、Unityが検出できないため、失われます。 解決策も簡単です。Keywordに対する常用なソリューションは、一般的に使えるソリューションは、役に立たない材質球を作成し、対応するShaderを使用し、材質球でKeywordの使用をオンにしてからAssetBundleにパッケージ化します。これにより、UnityはこのShaderのこれらのKeywordは役に立つものだと知るようになり、Skipしないにします。(実際、この方法は、instance_onというKeywordの損失のを防ぐためによく使用されます)。 A2:A1の方法を試したいのですが、このシェーダーはPackageディレクトリに配置されているため、材質球がUberPostをShaderに直接参照できないことが発見した。そのため、https://answer.uwa4d.com/question/5f3d10b19424416784ef1c82(中国語注意) にある方法でパッケージ化してみます。には、エディターのSVC収集方法で、SVCを収集しました。SVCのUberPostには、その2つのKeywordがあります。UberPostとこのSVCを一緒にパッケージ化します。解凍した後、ubqSceneシーンがこのSVCのShaderを参照していることがわかります。シーンを切り替えた後、AwakeにSVCをロードし、Warmupしますが、問題はまだ解決されていません。最後に、問題主の元のプロジェクトをexeパッケージ化したところ、Keywordの損失の問題はなく、レンダリングはすべて正常になります。さらに、APKテストにパッケージ化されており、Xiaomi9でのテストも正常にレンダリングされます。 おそらくUnityエディターの問題です。以下を参照してください。 https://answer.uwa4d.com/question/5ee0883e50fb7c2938d1f265#5ef5b06d1bd523380210b86d UWA Technologyは、モバイル/VRなど様々なゲーム開発者向け、パフォーマンス分析と最適化ソリューション及びコンサルティングサービスを提供している会社でございます。 今なら、UWA GOTローカルツールが15日間に無償試用できます!! よければ、ぜひ! UWA公式サイト:https://jp.uwa4d.com UWA GOT OnlineレポートDemo:https://jp.uwa4d.com/u/got/demo.html UWA公式ブログ:https://blog.jp.uwa4d.com
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Hololens2のSceneUnderstandingを利用しようとしたときに出たエラーを解決

現象 こちらの記事のようなエラーが出ていて、同じようにエラー回避しようとしてもできなかったでした Library\PackageCache\com.microsoft.mixedreality.toolkit.foundation@2387a6a2d46b-1639703055967\Providers\Experimental\WindowsSceneUnderstanding\WindowsSceneUnderstandingObserver.cs(502,35): error CS7069: Reference to type 'Matrix4x4' claims it is defined in 'System.Numerics', but it could not be found 環境 Unity v2019.4.18 MRTK v2.7.2 SceneUnderstanding v0.6.0 解決した方法と注意点 参考記事に書いてあった方法 build settingsで.NET4に SceneUnderstandingManagerのQuery Scene From Devieのチェック外す 追加で試した方法 TextMeshProのバージョンが3系だと動かず、2.1.6だと動いた プロジェクトパスが変わっていた場合Libraryフォルダを一回消し、Unityを立ち上げなおす(その後もう一回build settingsは確かめる) 追加で試した方法で解決できました! ちなみに 実機だとここにチェックいれるのよく忘れるのでどうにかしたい…
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Resourcesディレクトリのメリットと問題点

Unityのプロジェクトには、先週Assetsについて――Unityアセットマッピングに言及したルート・ディレクトリの以外、UnityのAssetsディレクトリの下に、特別な働きがある固定的なフォルダーがある。でも、これらのフォルダーは、新規作成したプロジェクトのディレクトリに、デフォルトで作成されなかったです。Unity 2018.3.8で空のプロジェクトを作成して、Assetsに入って確認しましょう。 一、特別なプロジェクトディレクトリ まず、Unityのデフォルトの空のプロジェクトのディレクトリを見てください。以下に示すように: 1、新しいプロジェクトのデフォルトディレクトリ 古いバージョンでは、Unityが空のプロジェクトを作成した後、空のAssets 以外何もありません。今は、AssetsにデフォルトでScenesディレクトリがあり、中にはSampleSceneのデフォルトの空白のシーンがあります。Assetsのレベルでは、Packagesディレクトリがあります。これは2018年にPackagesManagerと一緒に現れ、現在のプロジェクトによって導入されたPackagesを表示します。ただし、このディレクトリは読み取り専用であり、操作できないことに注意してください。すべての変更は、PackagesManagerウィンドウを介して行われます。もちろん、ディスクの対応するディレクトリに手動でJsonファイルを変更することもできます。それも効果は得られますが、あまり推奨しません。 2.Unityの特別ディレクトリ 新しいプロジェクトにはデフォルトでScenesディレクトリが与えられていますが、このディレクトリには特別な意味はありません。シーンを任意のカスタムディレクトリに保存できます。 (1)Editor 最初に紹介するのはこのディレクトリです。このディレクトリは開発を支援するために使用され、1つまたは複数にすることができ、任意のサブディレクトリの下に置くことができます。主な機能は、Unityエディターモードで提供されるスクリプトとインターフェイスをコンパイルして、研究開発を支援し、さまざまなアセットチェックを作成し、ツールを生成し、Unityのツールバーやウィンドウバーなどをカスタマイズすることです。 Editorディレクトリ内のすべてのスクリプトが公式リリースパッケージにコンパイルされるわけではありません。多くの優れたプラグインは、Unityが提供するエディターの拡張インターフェイスを介して、機能拡張を実現するのです。 (2)Editor Default Resources これは、Editorと組み合わせて使用​​する必要があります。むき出しの拡張パネルやツールは見栄えがよくありません。美化されたアセットを追加すると、プラグインやツールがさらに高級に見えます。このディレクトリは唯一的であり、アセットのルートディレクトリにのみ配置できることに注意してください。 (3)Plugins このディレクトリは、コード以外のライブラリファイルを保存するためのものです。たとえば、導入されたサードパーティコード、SDKによってアクセスされるさまざまなjarパッケージ、.aファイル、.soファイル、framworkファイルなど、これらのライブラリファイルは、Unityのコンパイル時にDLLにリンクされます。 (4)Resources これはEditorと同じで、Assetsの下の任意のディレクトリに配置でき、任意の数のコピーを配置できます。Resourcesディレクトリ内のすべてのファイルは、特別なBundlesに直接パッケージして、ゲームを起動すると、シリアル化されたマッピングテーブルが生成され、メモリにロードされます。 (5)Gizmos このディレクトリは比較的に簡単です。つまり、UnityのSceneウィンドウにいくつかの補助的なマーキング、アイコン、またはその他の記号を表示し、ポジショニングリアセットの開発を支援するのに用いられます。例えば: ボタンはSceneウィンドウの右上隅にあります。Sceneウィンドウであるため、Gameウィンドウおよびリリース後は表示されないことに注意してください。 (6)StreamingAssets このファイルはUnityの重要なファイルです。Unityがプログラムまたはゲームをリリースし、アセットがパッケージ化される場所は2つだけです。1つはResourcesディレクトリで、もう1つはStreamingAssetsです。このディレクトリ内のアセット、ファイル、またはその他のものは、そのまま最終的なApkまたはiOSパッケージにコピーされます。 上記の特別なディレクトリ以外、通常のプロジェクトには、他に多くの導入されたプラグインまたはカスタムディレクトリがあります。以前に書いた記事を参考してください。それは、複数の人やさまざまな機能のコラボレーションに適応するように、Unityプロジェクトディレクトリを計画するために使用されました。 リンク:https://zhuanlan.zhihu.com/p/77058380(中国語注意) 二、Resourcesの詳説 Resourcesが広く使われる理由は、使い方がとても簡単で、同期して読み込まれるからだと思います。一般的に、正式な商用プロジェクトでは、AssetBundleを使用してアセットを外部にリリースします。 AssetBundlesアプローチには、次のような多くの欠点があります。 (1)パッケージ内のアセットの状況を視覚的に確認することはできません。 (2)非同期ロードには、Hierarchy面倒なコールバック処理が必要です。 (3)デバッグ時には、Hierarchyからアセットを直接特定することはできません。 (4)使用する前に、時間をかけてパッケージ化する必要があります。特に開発中は、パッケージ化することを忘れると、アセットを頻繁に調整するとBugが発生する可能性があります。 前に述べたように、UnityはResourcesとAssetBundlesの2つの方法でアセットを処理します。したがって、AssetBundleの開発期間は使いにくいため、ほとんどの場合、Resourcesを使います。 では、Resourcesを使用したら問題なくなるのでしょうか? 1、Resourcesのディレクトリのベストプラクティス 欠点について話す前に、Unity公式がResources使用へのベストプラクティスを見てみましょう。 使いないでください!! 驚かないでください、これは公式の態度です。いくつかの理由で、Unityはアセットを使いすぎることを望んでいません。理由は次のとおりです。 Resourcesのアセットは、アプリケーションの起動時間とビルド時間を増加させます。 Resourcesのアセットは、量増えて更新することはできません。これは、モバイルゲーム開発の致命的なポイントです。 したがって、公式はAssetBundlesを使用することをお勧めします。 実際、あまり気にする必要はありません。何年にもわたる開発の結果、ソリューションはすでに蓄積されています。少し後で触れますが、最大の解決策は、シリーズのテーマであるAddressable Asset Systemです。まず、このソリューションがない時どのような解決策があるかについて検討します。 2、どのような状況でResourcesを使用できますか Resourcesには致命的な欠点がありますが、存在は合理的です。また、次のようないくつかの使用場面があります。 (1)一部のアセットは、プロジェクトのライフサイクル全体に使用するもの (2)重要ですが、メモリをあまり使用しないもの (3)変更の必要はあまりなく、プラットフォームを差別化する必要も特にないもの。 (4)システム起動時の最小限の起動に使用されたもの もう1つの場面は、上司にいくつかの効果をすばやく表示する必要がある場合、Demoをすばやく完了したい場合、またはチュートリアルや記事を作成し、ソリューションのプレゼンテーションを共有したい場合に、Resourcesを使用すると時間を節約できます。ただし、確立されたプロジェクトを正式な本番環境で使用することにした場合は、必ずAssetBundlesで書き直してください。 3、Resourcesのシリアル化 前述のように、プロジェクトをビルドすると、Resourcesディレクトリ内のすべてのファイルがシリアル化されたファイルにマージされます。ファイルには、独自のmetadata情報とインデックス情報が含まれます。内部的には、赤黒木でアセット検索を実現し、対応するFile GUIDとLocal IDのインデックスに使用され、シリアル化されたファイルにオフセットを記録することにも使用されます。 公式の実際のテストデータによると、10,000個のAssetsを含むResourcesディレクトリは、ローエンドのモバイルデバイスで初期化するのに5〜10秒以上かかる場合があります。しかし実際には、開始時にこれらのAssetsはすべて使用されているわけではありません。 4.開発中の代替案 ResourcesとAssetBundlesの不便さについては前に説明しましたが、アセットの欠点なしに開発中にすばやくロードできるソリューションはありますか?それはAssetDatabaseです。 これはエディターモードのUnityアセットロードクラスであり、従来のCreate、Delete、Save、Loadなどの一般的なインターフェイスを提供し、同期的にロードされます。したがって、アセット管理クラスを自分で作成し、マクロを使用してEditorモードを区別し、EditorでAssetDatabaseを使用してアセットを直接ロードし、非同期コールバックをシミュレートしてAssetBundlesのロードプロセスに似たものにします。非Editorモードで、通常のAssetBundleのロードをコールします。 このアセットマネージャーは、作成するのが非常に面倒ですが、プロセスが正しくデバッグされると、後で処理する必要はありません。 AssetDatabaseについては、説明しません。より詳細なドキュメントを見つけました。https://www.jianshu.com/p/2cae2f082f66を参照してください。 AssetDatabaseソリューション以外、Addressable Asset Systemもあります。これは2018年以降に正式に導入されました。これは、今まで言ったことをカプセル化して組み合わせ、開発中のアセット管理のいくつかの問題点を解決します。しかし、これについて話す前に、次の記事はAssetBundlesのシステム知識を説明する予定です。 UWA Technologyは、モバイル/VRなど様々なゲーム開発者向け、パフォーマンス分析と最適化ソリューション及びコンサルティングサービスを提供している会社でございます。 今なら、UWA GOTローカルツールが15日間に無償試用できます!! よければ、ぜひ! UWA公式サイト:https://jp.uwa4d.com UWA GOT OnlineレポートDemo:https://jp.uwa4d.com/u/got/demo.html UWA公式ブログ:https://blog.jp.uwa4d.com
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

聖夜にUnityでクソアプリを作る

初めに 皆さんこんばんは~! クリスマスをいかがお過ごしでしょうか? クリスマスの定番と言ったら何でしょうか?…そうクソアプリ開発ですよね!! ということで今回は自分が作ったクリスマスにぴったりのクソアプリとその作り方について紹介していこうと思います 今回作るもの 今回作るもの(作ったもの)はこちらになります。 このアプリについて簡単に説明すると、スマホの画面をタッチした場所に某漫画の人気キャラクターが勇ましいBGMと共に3Dで登場するというものです。 聖夜に作るにふさわしいクソアプリですよね! Unityでapkファイルとしてこのアプリを作り、それをAndroid(バージョンは7以上ならOK)のスマホで動かしています。 もしこのアプリを自分のスマホで動かしたい方は自分のGitHubのリポジトリからダウンロードしてください 作り方 このアプリは以下のサイトの情報をもとに作りました。 このアプリの作成手順は上記の記事(特に一番目の記事)で詳しく説明されているので、この記事では作成手順については扱いません。しかし、その代わりにこの記事ではこのアプリの動作(挙動)を担うスクリプトを詳しく見ていこうと思います。(スクリプトについて興味がない方は読み飛ばしてしまって大丈夫です!) アプリの動作(挙動)を担うスクリプト そのスクリプトは以下の通りです。コメントアウト部分は解説用につけたものや元から書いてあるのを消し忘れたものなので、気にしなくてよいです。 using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.XR.ARFoundation; using UnityEngine.XR.ARSubsystems; // .......(1) public class PlaneDetection : MonoBehaviour { ARRaycastManager raycastManager; [SerializeField] GameObject obj; AudioSource audioSource; [SerializeField] AudioClip sound1; // .......(2) // Start is called before the first frame update private void Awake() // .......(3) { raycastManager = GetComponent<ARRaycastManager>(); audioSource = GetComponent<AudioSource>(); audioSource.clip = sound1; } // Update is called once per frame private void Update() // .......(4) { if(Input.touchCount == 0 || Input.GetTouch(0).phase != TouchPhase.Ended || obj == null) { return; } var hits = new List<ARRaycastHit>(); if(raycastManager.Raycast(Input.GetTouch(0).position, hits, TrackableType.Planes)) { var hitPose = hits[0].pose; Instantiate(obj , hitPose.position, hitPose.rotation); audioSource.Play(); } } } ここからはコメントアウトとして付け加えた番号順でこのスクリプトの解説をしていきます。(このアプリの作成を通じて初めてC#を触れた身ですので、解説がガバいところがあります) (1)まずは宣言されている名前空間の確認をします。 System.CollectionsおよびSystem.Collections.GenericはC#においてコレクションの利用のために宣言されています。コレクションとは配列よりも縛りの緩い要素の集合体です。(自分が使用してきたPHPやJSだと要素の集合体にコレクションや配列という区別がなく、基本的には要素の集合体=配列です) UnityEngineにはUnit内の要素の操作に必要なものが含まれていて、この名前空間内のMonoBehaviourクラスやInputクラスの利用のためには宣言必須のものとなっています。 UnityEngine.XR.ARFoundationには3Dオブジェクトを表示する場所の検知するクラスなどが含まれており、ARを利用する上では必須のものとなっています。 UnityEngine.XR.ARSubsystemsには検知する場所の形状を表す定数などが含まれており、こちらもARを利用する上では必須のもの(?)となっています。 (2)次に継承するクラスや初めに宣言する変数について見ていきます。 PlaneDetectionクラスが継承しているのはMonoBehaviourクラスというものであり、このクラスを継承することで継承先のクラスはUnity内のオブジェクトのコンポーネントが参照できるGetComponentメソッドやUnityの世界内に新たなオブジェクトを配置するInstantiateメソッドが使えるようになります。 変数raycastManagerは後程行われるUnityEngine.XR.ARFoundation内のARRaycastManagerクラスのインスタンスの代入のために宣言されます。 変数objにはこのアプリで表示するオブジェクトが入ります。変数の前に[SerializeField]と書くことで、Unityのインスペクターウィンドウから表示したいオブジェクトを指定できます。 変数'audioSource'は後程行われるUnityEngine内のAudioSourceクラスのインスタンスの代入のために宣言されます。 変数sound1には再生したい音声ファイルが入ります。これもUnityのインスペクターウィンドウから表示したいオブジェクトを指定できます。 (3)そして今度はAwakeメソッドを見ていきます。AwakeメソッドはMonoBehaviourクラスが所有するメソッドで、このスクリプトが実行される際に最も早く、そして一度だけ行われるメソッドです。 GetComponentメソッドを使用し、変数raycastManager、audioSourceにそれぞれGameObject内のコンポーネントであるAR Raycast Manager、Audio Sourceが代入されます。ちなみにGetComponentの横にある<>はジェネリックと呼ばれ、これによりこの中に書かれた型に対応したクラスを返してくれるそうです。(PHPにはこんな簡単に返り値の型を指定できる方法が(おそらく)ないので良いな~) audioSourceのclipプロパティに先ほどセットしたsound1を代入します。 (4)最後にUpdateメソッドを見ていきます。UpdateメソッドもAwakeメソッドと同様にMonoBehaviourクラスが所有するメソッドで、このアプリの毎フレームごとに呼び出されます。公式サイトでは、Not every MonoBehaviour script needs Update.と書かれていたので、Unityの動作をつけるうえでは基本となるメソッドのようです。 最初のif文では、Inputクラスを使用してアプリの使用者が画面のタッチを行る状態の場合かつ表示するオブジェクトが指定されている場合のみ次のステップへ進み、それ以外は何もしません。 変数hitsにSystem.Collections.Generic内のListクラスによってコレクション化されたARRaycastHitが代入されます。ARRaycastHitにはアプリ内のオブジェクトを表示する場所の位置情報などが書き込まれます。 二つ目のif文ではARRaycastManagerクラスのRaycastメソッドを使用し、アプリ内でオブジェクトが配置可能な場所に使用者がタッチした場合次のステップへ進み、そうでない場合は何もせずに次のUpdateメソッドへ進みます。Raycastメソッドについてもう少し詳しく言うと、第一引数Input.GetTouch(0).positionが第三引数TrackableType.Planesにおいて検知可能とされた場合に、その位置情報を第二引数のhitsへ渡すという感じです。 Raycastメソッドで渡された位置情報を変数hitPoseへ代入し、第2、3引数にその情報による場所と表示する向き、そして第1引数に表示するオブジェクトがセットされたInstantiateメソッドが実行され、アプリ内にオブジェクトが表示されます。 一番最後にAudioSourceクラスのPlayメソッドが実行され、変数sound1としてセットした音声ファイルが鳴ります。 終わりに 初めてUnityやC#を触り、またWebアプリしか作ってこなかったにも関わらず簡単にAndroidで動くアプリを作れて感動しました。 今度はARマーカーを使ったアプリやWebで動くARアプリなんかも作れたらな~と考えています。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

BlenderのパーティクルをUnityに持ってくる方法

STYLYアドベントカレンダー24日目の記事です。 2021年のSTYLY NEWVIEW AWARDSに参加して、宮沢賢治の「やまなし」という童話を題材にした作品を制作しました。 この作品で優雅に泳いでいるモブの魚たちはあまり目立たない存在ですが、実はBlenderのパーティクルで魚の群れのシミュレーションをして、Unityに持ってきています。この記事では魚の群れ表現を実現するために調べたことをまとめたいと思います。 魚の群れの動きをBlenderでシミュレーション 「やまなし」ではカワセミの登場で魚が逃げ惑う表現を検討していたので、リアルな魚の動きをシミュレーションしたいと考えていました。Unityで魚の群れをつくりたいときは通常C#のプログラムで「Boid」の仕組みを作ったり、群れ制御のアセットを使ったりすると思うのですが、STYLYで実現するためにはPlayMakerというアセットが必要になるので他の方法があるかどうか調べたところ、Blenderのパーティクルでも実現することがわかりました。 Boid Particle https://www.youtube.com/watch?v=J3TUPYVsxow Blenderのパーティクルをアニメーションに変換 BlenderのパーティクルはそのままUnityに持ってくることができません。そこで、パーティクルの動きをアニメーションに変換するベイク処理をします。Blenderは標準ではベイクをサポートしていないのですが、pythonを利用する方法がBlenderのStackExchangeに書いてありました。 まず、Scriptingのタブを開いて上記のコードを貼り付けます。 次に、パーティクルとして動かしたいオブジェクト(この場合は魚一匹)とパーティクルを選択します。 2つのオブジェクトを選択した状態でスクリプトを実行します。 しばらく待つとパーティクルの動きがアニメーションとしてベイクされます。 出力はこのように設定しました。 おわりに 演出の関係で魚が激しく動き回るようなモーションを使うことはありませんでしたが、BlenderのパーティクルをUnityに持ってくることができるとわかり、いろいろと試してみたいと思いました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Unityで構造体の配列メンバーが表示されない謎

はじめに おはようございます。先程ブログに書いたのですが、かなり気になる現象でしたのでこちらでも記事にします。 背景 アニメーション関連の効率化(詳細は本筋とは関係ないので控えます)のために、Inspector上で構造体の配列をやり取りしようと考えました。 環境は以下のとおりです。 Unity: Unity2021.2.7f1 OS: Windows10 x64 (最新パッチ適応済み) CPU: Intel Core i7 4771 GPU: GeForce RTX 3070 Ti 現象 実装自体は問題ないはずなのですが、メンバーが空白で表示されない状態です。 調査 単体で表示させたりするとメンバーが表示されるので、この場合独自の問題のようです。 また、Odinを導入するとメンバーが表示されることも確認しています。 現状では、「Odinを入れる」が最適解の模様です。 その後の対応 最終的に、Unityのバグではと考えてバグレポートを提出いたしました。 一体、何が原因なのだろう…。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

3DモデルをBlenderで.pmxから.fbx形式に変換しUnityで動かすまで

はじめに この記事は 法政大学情報科学部 Advent Calendar 2021 の21日目の記事です。 どうもこんちにちは、HirokiLuckyです! 今回は初投稿ということで、大好きなUnityに関する投稿をしたいと思いまーす さて、Unityで3Dモデルを使いたいと思った時に、拡張子が違くて困った経験はありませんか? Unityでは.fbx形式にモデルを変換しなければいけないため正直面倒くさいです。 私は前に原神の3Dモデルを使わせていただこうと思ったときに、.pmx形式のモデルだったので様々な記事を参考にして何とか使えるようにしたことを覚えています... (MMDからの拡張子変換に関するの文献はあるのにBlenderのはあんまりなくないですか?) 今回はその時の苦労をこの記事にまとめたいと思います。 モデルのダウンロード モデルをダウンロードしてくる。今回私は原神のモデルをダウンロードして進めていきます。 原神のモデルは公式でも配布されていますが、bilibili(まとめサイトに飛びます)で多くのモデルが配布されています! ※bilibiliを利用する場合は上記先よりモデルのバージョンのURLに飛び、「模型下裁」のような場所でダウンロードすることができます。 ↑公式ダウンロードページ ↑bilibiliダウンロードページ Blenderで拡張子を変換しよう zipファイルをダウンロードして解凍(フォルダ先の指定などはありません)出来たらBlenderで変換していきましょう! ここで行うことをあげると、 アドオン「mmd_tools」を追加する インポートし、テクスチャを貼り付け直す 拡張子変換する アドオン「mmd_tools」を追加する Blenderでモデルをインポートしたくても初期設定のBlenderでは.pmx形式をインポートすることができないので.pmx形式をインポートできるようにするアドオンを追加していきましょう。 GitHub > Code > Download ZIP この順番でmmd_toolsのzipファイルをダウンロードし、解凍しましょう。 次に、この解凍したフォルダを、 ~ \blender\2.90\scripts\addons の下に配置しましょう。 これだけではまだ有効化されていない場合があるので、Blender側でも有効化していきましょう。 Blenderを起動 > 編集 > preferences... この順番で「Blenderプリファレンス」を展開しましょう。 Object: mmd_tools にチェックを付けて有効化します。 さて、インポートできるようになっているか確認してみましょう ファイル > インポート > MikuMikuDance Model(.pmd, .pmx) MikuMikuDance Model(.pmd, .pmx) が追加されていたら成功です! インポートし、テクスチャを貼り付け直す それでは!モデルをインポートしてみましょう! ファイル > インポート > MikuMikuDance Model(.pmd, .pmx) から、先ほどダウンロードした.pmx形式のモデルをインポートしてみましょう。 今回私はディルックを使わせていただきました おお!すげえ。でもこれだけじゃ物足りねえよなあ!ということで、テクスチャが貼られているか確認しましょう! 下記の図より、右上にある4つの○の内、右から2番目を選択してみてください。 色がつきましたね! でも、顔にテクスチャが張られていませんね...(ピンク紫のようになっているところ) 配布先などによるのですが、テクスチャの参照が上手くできる場合とできない場合があります。 今回は貼り付けられていない場所があるので貼り付けていきましょう! モデルを選択(クリック)、オレンジ色の枠が出るようにしましょう。 次に右のマテリアルプロパティを選択しましょう。 すると、現在貼られているテクスチャが表示されます(瞼、眼白、眼晴みたいなのがあるとこ)。 ※表示されていない場合は、上の画像の▶プレビューの上のマテリアルテクスチャと同じマークを選択してみてください。 上の画像だと瞼、眼白にテクスチャが張られていないようです(ピンク紫だからです)。 そのテクスチャを選択した状態で下にスライドしていくと MMD Texture という項目があります。その中の Texture に正しいテクスチャを追加します。 また追加してもピンク紫の場合は MMD Texture 項目の一番下にある「Use Shared to...」という項目にチェックが入っている場合があるので、チェックを外してみてください。 すると... でも、まだボーン(四角錐みたいなやつ)が邪魔?安心してください。消せますよ! モデルによって名前は違いますが、体のようなマークがついていたりするものの一番右にある目のマークをクリックしてみましょう! WRYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYYY!!!!!! 拡張子を変換しよう さて、拡張子変換はいたって簡単です、パパっと拡張子変換をしちゃいましょう! ファイル > エクスポート > FBX(.fbx) フォルダ選択まで来たら右にオブジェクトタイプを選ぶところがあるので、いらないところは省いちゃいましょう!カメラ、ランプは必要ではないと思いますが、最低限アーマチュアとメッシュは選択しておきましょう。 ※複数選択する場合はshiftを押しながら選択します (適当なフォルダ)> FBXをエクスポート .fbx形式のモデルが出力されたか確認できたら成功です! Unityでモデルを動かせるようにしよう .fbx形式のモデルを作れたら、Unityにモデルを入れてみましょう! .fbxファイルとテクスチャ情報が入っているフォルダをprojectの中にドラック&ドロップしてモデルをいれてください ※テクスチャ情報が入っているフォルダは後で使いますので必ず入れましょう そしてScene内に、今入れたモデルをドラック&ドロップして入れてみましょう なんか、緑とか水色のものがある... これらは手のパーツなどで判定する際などに必要なものなのですが見えなくすることができます。 左のヒエラルキー内にある、今入れたモデルの▶を展開してみましょう かなりの部品からなっていますね... 今回の場合、000_上半身~069_bz_6_1(armとmesh以外)を選択し、 インスペクター上部のチェックを外しましょう これでちゃんとモデルが見えるようになりました! さて、準備はできたのでやることを挙げていきます ・テクスチャを貼り付けよう ・Rigを設定する テクスチャを貼り付けよう ※Unityでのテクスチャの貼り付け方は私の自己流ですので、他も調べてみると良きかもです。 Unityで使うためために.fbxにしましたが、テクスチャはそのまま持ってこれないようです。 なので、Unity内でもテクスチャを貼り付けましょう。 先ほどProjectに入れたモデルを選択するとモデルのインスペクターが右に出ます。 Materialsからテクスチャをそれぞれ入れていきましょう。 手作業で入れても良いですが、せっかくなので自動で入れてみましょう。 Locationが「Use Embedded Materials」となっていることを確認し、 Materialsの「Extract Materials」をクリックしてみましょう。 その後、モデルのテクスチャをまとめてあるフォルダを選択すると、テクスチャが入っている!? しかし、先ほど選んだテクスチャフォルダを見てみましょう。 先ほど追加されたテクスチャはどうやらこのフォルダに追加され、 .fbxにした時にデフォルトで真っ白になってしまうみたいですね... 真っ白になってしまったなら、また設定すればいいわけです!(簡単なのでご安心ください) 真っ白になってしまったテクスチャを選び、インスペクターを表示しましょう 上の画像で赤で囲まれた部分に注目してみましょう。 実はここに画像を入れられるんです! ということで、テクスチャ画像をそれぞれに入れていきましょう! どの画像?と詰まったらBlenderを参考にするとどれがどれかが分かりやすいです ※キャラクター等によりますが、Detail Albedo x2にベースとなる画像をいれ、Normal Mapには影などのテクスチャを入れるようです。 試しに衣服を入れると、しっかり色がついていますね! 全て適用してみるとちゃんと全体塗れていますねえ! Rigを設定する さて、やっと動かすための設定を行う時が来ました!! では早速、モデルのマテリアルを設定したインスペクターを開き「Rig」というタグに移動します Animation Type を humanoid に変更し、Apply を押し変更を適用 適用後エラーが発生する場合がありますが、ここでは気にしなくて大丈夫です。 「Configure」を選択し、下の画像のような画面に遷移します。 それではまずインスペクター(右側にあるやつ)から修正していきましょう。 ここでは、どの部分がどのパーツと対応しているかを示すのですが抜けていたり、赤くエラーを吐いていることが大半なので、正しいパーツを入れていきましょう。 ※キャラなどによってもうできあがっている場合があります。その場合は飛ばしても大丈夫です。私の環境では原神の万葉のモデルは最初から出来上がっていました。 上の画像のようにエラーは吐いていなくても間違っている場合(人差指と親指が逆)や左右対称のパーツを配置することに気を付けてください。また変更後は Apply することをお忘れなきよう 原神のモデルを使用している場合、下記のように配置してみました(中国語ワカラナイ) それでは次は左側です。異常なほどエラー吐いているのですが何時間かかるんでしょうかねえ。 とりあえず騙されたと思って、先ほど直していたインスペクターの下のほうにある Pose > Enforce T-Pose  に設定してみて下さい。 なんということでしょう!エラーが綺麗になくなりました! では Apply 後に Done で終了していきましょう! エラーも消えていますね! ここまで来たらもうモデルの設定は終了です!お疲れ様でした! モデルを動かしてみよう では、最後にモデルを動かしてみましょう! 今回私が使うのは、unity-chan! を使います。もっとも基本的で無料かつモデルを動かすのに必要なものが全て入っているので、モデルを動かすテストのみなら十分だと思います!オススメです アセットをパッケージマネージャでダウンロード、インポートできたら早速使ってみましょう! モデルを動かす際に最低限必要と言われているのが、Locomotion、モデル、スクリプトの3つと言われています。 モデルは今までのものを使うとして、Locomotionはどのように状態が遷移をするか示したものです。 unity-chan!では、 Asset > unity-chan! > unity-chan!Model > Art > Animations > Animators に入っています いくつかありますが、上の画像のものを使用するとWASD(デフォでは矢印だけだったかも...)で動きます。 これをインスペクター内の Animator > Controller に指定することで Locomotion を設定できます。 スクリプトですが、これは○○キーを押したら○○の値が変わるなどを(もちろん他にもたくさん書いていますが...)書いています。 unity-chan!では、 Asset > unity-chan! > unity-chan!Model > Scripts に入っています。 今回は Unity Chan Control Script With Rigit Body を使っています。 これをコンポーネントとして追加してあげましょう。(ただドラック&7ドロップするだけです) RigitBody を入れている場合、念のため Mass(質量)をある程度人間の体重くらいにしておき、 Freeze Rotation にチェックを入れておきましょう。 ※ここにチェックを入れない場合、ちょっとのことでモデルが回転し宙を舞ったりします。 またカメラはモデルが見やすいように各自で設定してください 以上で実行をしてみると... 動きましたあああああああああああああああああああああ! おつかれさまでしたあああああああああああああああああ! おわりに ここまで読んでくださった方、本当にお疲れ様でした!そして何よりありがとうございました! 割と長い説明にはなってしまいましたがモデルは動かせるようになったでしょうか... それでは楽しいUnity開発ライフをっ!!! 書いてて楽しかったので、また新しいの書くかも... 参考文献: bilibiliモデルダウンロードまとめサイト bilibiliモデルダウンロード 公式モデルダウンロード mmd_tools unity-chan!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む