質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.51%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

Q&A

解決済

2回答

1886閲覧

Unity2D Graphics.DrawMesh メッシュの結合

退会済みユーザー

退会済みユーザー

総合スコア0

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

1グッド

0クリップ

投稿2019/04/27 17:02

編集2019/04/27 17:08

前提・実現したいこと

Graphics.DrawMeshを使って生成しているメッシュを結合して、FPSを改善させたい。

該当のソースコード

C#

1using System.Collections; 2using System.Collections.Generic; 3using UnityEngine; 4 5public class ExampleWorld : MonoBehaviour 6{ 7 public int width; 8 public int height; 9 10 public ExampleTile[,] tiles; 11 12 public Material material; 13 14 Mesh mesh; 15 16 // Use this for initialization 17 void Start() 18 { 19 CreateTiles(); 20 GenerateMesh(); 21 } 22 23 // Update is called once per frame 24 void Update() 25 { 26 Graphics.DrawMesh(mesh, Vector3.zero, Quaternion.identity, material, 0); 27 } 28 29 void CreateTiles() 30 { 31 tiles = new ExampleTile[width, height]; 32 33 for (int i = 0; i < width; i++) 34 { 35 for (int j = 0; j < height; j++) 36 { 37 tiles[i, j] = new ExampleTile(ExampleTile.Type.Stone); 38 } 39 } 40 } 41 42 void GenerateMesh() 43 { 44 ExampleMeshData data = new ExampleMeshData(tiles); 45 mesh = new Mesh(); 46 mesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32; 47 mesh.vertices = data.vertices.ToArray(); 48 mesh.triangles = data.triangles.ToArray(); 49 mesh.RecalculateNormals(); 50 mesh.RecalculateBounds(); 51 } 52} 53

C#

1using System.Collections; 2using System.Collections.Generic; 3using UnityEngine; 4 5public class ExampleMeshData 6{ 7 public List<Vector3> vertices; 8 public List<int> triangles; 9 10 public ExampleMeshData(ExampleTile[,] data) 11 { 12 vertices = new List<Vector3>(); 13 triangles = new List<int>(); 14 15 for (int i = 0; i < data.GetLength(0); i++) 16 { 17 for (int j = 0; j < data.GetLength(1); j++) 18 { 19 CreateSquare(data[i, j], i, j); 20 } 21 } 22 } 23 24 void CreateSquare(ExampleTile tile, int x, int y) 25 { 26 vertices.Add(new Vector3(x + 0, y + 0)); 27 vertices.Add(new Vector3(x + 1, y + 0)); 28 vertices.Add(new Vector3(x + 0, y + 1)); 29 vertices.Add(new Vector3(x + 1, y + 1)); 30 31 triangles.Add(vertices.Count - 1); 32 triangles.Add(vertices.Count - 3); 33 triangles.Add(vertices.Count - 4); 34 35 triangles.Add(vertices.Count - 2); 36 triangles.Add(vertices.Count - 1); 37 triangles.Add(vertices.Count - 4); 38 } 39 40} 41

C#

1using System.Collections; 2using System.Collections.Generic; 3using UnityEngine; 4 5public class ExampleTile { 6 public enum Type { Stone } 7 public Type type; 8 9 public ExampleTile(Type type) 10 { 11 this.type = type; 12 } 13} 14

試したこと

Graphics.DrawMeshを使って動的に生成しているメッシュを結合して一つにする方法を調べたのですが、出て来なかったので質問しました。
プロジェクトで使っているコードはもっと大量にメッシュを生成しているため、SetPass Callは2なのですが、saved by batchingが約30000以上あります。そのため、30~40FPS程度しか出ないので、動かすとカクカクしている状態です。
300×300のマップをそのコードで生成しようとすると、出力するのに10分以上かかってしまっています。
どのようにすればFPSを上げることが出来るのでしょうか? メッシュを結合すればいいのではないか、と自分は考えました。載せているコードは、最小限のものです。

回答お願いします。

実際のコードで生成した場合↓

イメージ説明

bochan2👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

このソースだけ見ていると、ExampleWorldのMeshに頂点情報を集めて1MeshDrawを実行しているように見えるのですが、30~40FPSで動作しているものはこのソースを利用せずそれぞれのタイルで描画しているということですか?
他の質問を見るとDrawMeshInstancedなども確認されているようですが、ネックになっているのはCPU/GPUどちらかの切り分けはできているのでしょうか?
300x300は常に描画が必要なのでしょうか。300x300の一部だけだったらその範囲内だけ描画する(カリングする)とか。
ミニマップ状態で300x300が必要なら、一度それを構築した後RenderTextureからTextureに保持して描画するとかもあると思います。

ちなみに例えばですが、mesh.verticesをどこかのUpdateで

void Update() { for (int i = 0; mesh.vertices.Length > i; ++i) { // なにか } }

みたいにしているとしたら、mesh.verticesは中で逐次ToArrayをしているので一時変数で受け取ってからのほうが断然いいのですが、そんなことをしていたりしますか?

300×300のマップをそのコードで生成しようとすると、出力するのに10分以上かかってしまっています。

全く試してないですが、ExampleTileのclassを一つずつnewしているからな気もします。
ExampleTileの情報がもっと他にもあるなら別かもしれませんが、そうでないのならTypeだけの二次元配列にしてしまうとか、もうちょっと拡張データがあるならclassでなくstructにして一気に確保にするのは効果があると思います。
ただ、コンストラクタが引数付きで作られているので、コンストラクタ自体をなくす必要はあるかもしれません。

また、ExampleTileをstructにした場合、ExampleMeshDataのコンストラクタの引数が値渡しになったかは忘れました。
配列だから多分参照渡しなので問題ないですが、そうでなかったらrefキーワードで参照渡しにするとかしないとコピーが作られるため、コピー生成分処理を食います。

List.Addも確か容量不足のときに倍々で拡張してた気がするので、先に容量確保してからだと倍々拡張しないからそこそこ高速化できると思います。
変更はListのnewの部分だけで、Addの部分は変更しなくてもいいはずです。

// 300x300の4頂点分の容量を先に確保 vertices = new List<Vector3>(300 * 300 * 4);

ちなみにグリッドとして考えるとすべてのタイルにつき4頂点分確保はなくてもできるような気もします。(別の理由があるならこれしかないですが)
インデックスは今の状態が必要です。

GetLength()って内部のテンポラリサイズを参照していましたっけ...
毎回計算の可能性もあるので、for文の直前に一度保持してからその値を使うのも場合によっては効果があるかもしれません。(ないかもしれません)

生成部分についてはこんな感じで軽減できそうな気もします。
もちろん、ほかの何かの要因があれば話は別です。

追記
例えば今回の300x300が2D-RPGのワールドマップで、一画面に描画されるものが10x10で済む場合、
300x300-10x10 = 89900タイルの描画処理(DrawMesh)が無駄です。
上記の場合、自分だったら 10x10 の一回り分の 12x12 タイル分だけのMeshを作ります。
そして、描画範囲内の情報だけ(Materialや頂点の座標)を設定して描画自体の処理を限定させます。
キャラクタが移動したのだったら移動したときに範囲の情報を再設定します。
要は先に無駄と分かっている処理を省きます。

昔、MSのDirectX関連の偉い方(だったと思う)が言った言葉です。(若干ニュアンスは違うかもですが)

Q. 一番早いプログラムは? A. 何もしないプログラム

投稿2019/05/12 09:20

編集2019/05/12 11:01
vo3

総合スコア321

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2019/07/07 06:09

回答ありがとうございました。返信遅れて申し訳ないです。
guest

0

質問いただきありがとうございます!
模様だけならテクスチャを使えば良いと思います。
t2t21212さんの生成したいメッシュがある程度複雑な形の場合は、Vertex ShaderでGPU側に処理させればテクスチャを形状に反映させることができます。

投稿2019/05/03 10:11

bochan2

総合スコア2050

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.51%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問