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

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

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

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

Unity

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

Q&A

解決済

2回答

1775閲覧

Unity2D Graphics.DrawMesh

退会済みユーザー

退会済みユーザー

総合スコア0

C#

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

Unity

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

0グッド

0クリップ

投稿2019/04/09 13:05

前提・実現したいこと

Graphics.DrawMeshを使って、正方形のメッシュを大量に描画したい。

該当のソースコード

using System.Collections; using System.Collections.Generic; using UnityEngine; public class ExampleClass : MonoBehaviour { Mesh mesh; public Material material; private void Start() { mesh = new Mesh(); mesh.vertices = new Vector3[] { new Vector3 (-1f, -1f, 0), new Vector3 (-1f, 1f, 0), new Vector3 (1f , -1f, 0), new Vector3 (1f , 1f, 0), }; mesh.uv = new Vector2[] { new Vector2 (0, 0), new Vector2 (0, 1), new Vector2 (1, 0), new Vector2 (1, 1), }; mesh.triangles = new int[] { 0, 1, 2, 1, 3, 2, }; mesh.RecalculateNormals(); mesh.RecalculateBounds(); } void Update() { Graphics.DrawMesh(mesh, Vector3.zero, Quaternion.AngleAxis(0.0f, new Vector3(1.0f, 0.0f, 0.0f)), material, 0); } }

試したこと

正方形のメッシュをGraphics.DrawMeshを使って描画しました。ですが、100×100のように、メッシュを大量に描画するやり方が分かりません。

試行錯誤しましたが、どうやっていいか、どうしても分かりませんでした。エラーは出ていません。

やり方を教えていただけると有り難いです。回答よろしくお願いします。

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

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

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

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

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

guest

回答2

0

ベストアンサー

ループを回して何度もDrawMeshを実行すればいいかと思いますが、それではうまくいかなかったでしょうか?

C#

1using System.Collections; 2using System.Collections.Generic; 3using UnityEngine; 4 5public class ExampleClass : MonoBehaviour 6{ 7 Mesh mesh; 8 Vector3[] positions; 9 Quaternion[] rotations; 10 int count; 11 public Material material; 12 public int rows = 100; // 行数 13 public int columns = 100; // 列数 14 15 private void Start() 16 { 17 mesh = new Mesh(); 18 mesh.vertices = new Vector3[] { 19 new Vector3 (-1f, -1f, 0), 20 new Vector3 (-1f, 1f, 0), 21 new Vector3 (1f , -1f, 0), 22 new Vector3 (1f , 1f, 0), 23 }; 24 25 mesh.uv = new Vector2[] { 26 new Vector2 (0, 0), 27 new Vector2 (0, 1), 28 new Vector2 (1, 0), 29 new Vector2 (1, 1), 30 }; 31 32 mesh.triangles = new int[] { 33 0, 1, 2, 34 1, 3, 2, 35 }; 36 37 mesh.RecalculateNormals(); 38 mesh.RecalculateBounds(); 39 40 count = rows * columns; 41 positions = new Vector3[count]; 42 rotations = new Quaternion[count]; 43 for (var i = 0; i < rows; i++) 44 { 45 for (var j = 0; j < columns; j++) 46 { 47 var index = (i * columns) + j; 48 49 // XY平面上に縦にrows個、横にcolumn個並ぶように配置する 50 var position = new Vector3((j - ((columns - 1) * 0.5f)) * 2.0f, (i - ((rows - 1) * 0.5f)) * 2.0f, 0.0f); 51 52 // それぞれの正方形の回転を決める 53 // さしあたりランダムに少しだけ傾けてみました 54 var randomAngle = Random.Range(-10.0f, 10.0f); 55 var randomDirection = Random.insideUnitCircle.normalized; 56 var rotation = Quaternion.AngleAxis(randomAngle, randomDirection); 57 58 positions[index] = position; 59 rotations[index] = rotation; 60 } 61 } 62 } 63 64 void Update() 65 { 66 for (var index = 0; index < count; index++) 67 { 68 Graphics.DrawMesh(mesh, positions[index], rotations[index], material, 0); 69 } 70 } 71}

毎フレーム1万回のDrawMeshはけっこうな負荷になると思われます。もしマテリアルがGPUインスタンシングに対応していれば、代わりにDrawMeshInstancedを使うとレンダリングコストを大幅に削減できるかもしれません。

C#

1using System.Collections; 2using System.Collections.Generic; 3using System.Linq; 4using UnityEngine; 5 6public class ExampleClass : MonoBehaviour 7{ 8 Mesh mesh; 9 Matrix4x4[][] matrices; 10 int count; 11 public Material material; 12 public int rows = 100; 13 public int columns = 100; 14 15 private void Start() 16 { 17 mesh = new Mesh(); 18 mesh.vertices = new Vector3[] { 19 new Vector3 (-1f, -1f, 0), 20 new Vector3 (-1f, 1f, 0), 21 new Vector3 (1f , -1f, 0), 22 new Vector3 (1f , 1f, 0), 23 }; 24 25 mesh.uv = new Vector2[] { 26 new Vector2 (0, 0), 27 new Vector2 (0, 1), 28 new Vector2 (1, 0), 29 new Vector2 (1, 1), 30 }; 31 32 mesh.triangles = new int[] { 33 0, 1, 2, 34 1, 3, 2, 35 }; 36 37 mesh.RecalculateNormals(); 38 mesh.RecalculateBounds(); 39 40 // 各インスタンスの姿勢はMatrix4x4として与える 41 count = rows * columns; 42 var flatMatrices = new Matrix4x4[count]; 43 for (var i = 0; i < rows; i++) 44 { 45 for (var j = 0; j < columns; j++) 46 { 47 var index = (i * columns) + j; 48 49 var position = new Vector3((j - ((columns - 1) * 0.5f)) * 2.0f, (i - ((rows - 1) * 0.5f)) * 2.0f, 0.0f); 50 51 var randomAngle = Random.Range(-10.0f, 10.0f); 52 var randomDirection = Random.insideUnitCircle.normalized; 53 var rotation = Quaternion.AngleAxis(randomAngle, randomDirection); 54 55 var scale = Vector3.one; 56 57 flatMatrices[index] = Matrix4x4.TRS(position, rotation, scale); 58 } 59 } 60 61 // 一度に描画できるインスタンスは1023個までなので、あらかじめそれを超えないよう切り分けておく 62 matrices = flatMatrices.Select((m, i) => (m, i / 1023)) 63 .GroupBy(t => t.Item2) 64 .Select(g => g.Select(t => t.Item1).ToArray()).ToArray(); 65 } 66 67 void Update() 68 { 69 foreach (var m in matrices) 70 { 71 Graphics.DrawMeshInstanced(mesh, 0, material, m); 72 } 73 } 74}

結果比較

#追記
タイル1個ごとに頂点が4個生成されますので、頂点総数は130×130×4=67600個となります。頂点インデックスの形式がデフォルトの16ビット整数ですと65535個までしか扱えず、途切れてしまったものと思われます。
さしあたり、indexFormatRendering.IndexFormat.UInt32に切り替えてみてはいかがでしょうか?

C#

1 void GenerateMesh() 2 { 3 MeshData data = new MeshData(tiles); 4 mesh = new Mesh(); 5 6 // 頂点インデックスのフォーマットを32ビット整数に変更する 7 mesh.indexFormat = IndexFormat.UInt32; 8 9 mesh.vertices = data.vertices.ToArray(); 10 mesh.triangles = data.triangles.ToArray(); 11 mesh.RecalculateNormals(); 12 mesh.RecalculateBounds(); 13 Graphics.DrawMesh(mesh, Vector3.zero, Quaternion.identity, material, 0); 14 }

リファレンスによると一部の環境では32ビットインデックスをサポートしないそうですので、それらにも対応させたい場合はメッシュを複数個に分割する必要がありそうですね。

投稿2019/04/09 20:36

編集2019/04/09 21:16
Bongo

総合スコア10807

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

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

Bongo

2019/04/09 20:41

すいません、ご質問者さんの情報追記とかぶってしまいました。ご質問者さんの方法に沿った案が思いつきましたら、追って追記いたします。
Bongo

2019/04/09 21:18

Worldの修正案を追記しました。この方法は使えそうでしょうか?
退会済みユーザー

退会済みユーザー

2019/04/09 21:43

mesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32; と書いたら、300×300でも描画することが出来ました。回答ありがとうございました。
guest

0

とりあえず、自分で書いたコードを載せます。ただ、widthとheightが130以上(?)だと中途半端にしか描画されません。

C#

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

C#

1using System.Collections; 2using System.Collections.Generic; 3using UnityEngine; 4 5public class MeshData{ 6 7 public List<Vector3> vertices; 8 public List<int> triangles; 9 10 public MeshData(Tile[,] 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(Tile 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 Tile{ 6 7 public enum Type { Stone } 8 public Type type; 9 10 public Tile(Type type) 11 { 12 this.type = type; 13 } 14}

200×200で描画すると、中途半端にしか描画されません。なぜなのでしょうか? 100×100は普通に描画されます。

イメージ説明
イメージ説明

投稿2019/04/09 20:28

編集2019/04/09 20:53
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.51%

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

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

質問する

関連した質問