🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
C#

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

Unity

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

Q&A

解決済

2回答

1760閲覧

Unity2D テクスチャブレンド

退会済みユーザー

退会済みユーザー

総合スコア0

C#

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

Unity

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

0グッド

0クリップ

投稿2019/04/15 15:45

編集2019/04/15 16:00

前提・実現したいこと

メッシュにシェーダーを適応させて、自然な見た目の地形表現をしたい。

該当のソースコード

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 public string seed; 17 public bool randomSeed; 18 19 public float frequency; 20 public float amplitude; 21 22 public float lacunarity; 23 public float persistance; 24 25 public int octaves; 26 27 Noise noise; 28 29 public float seaLevel; 30 31 public float beachStartHeight; 32 public float beachEndHeight; 33 34 public float grassStartHeight; 35 public float grassEndHeight; 36 37 public float dirtStartHeight; 38 public float dirtEndHeight; 39 40 public float stoneStartHeight; 41 public float stoneEndHeight; 42 43 private void Awake() 44 { 45 if(randomSeed == true) 46 { 47 int value = Random.Range(-1000, 10000); 48 seed = value.ToString(); 49 } 50 51 noise = new Noise(seed.GetHashCode(), frequency, amplitude, lacunarity, persistance, octaves); 52 } 53 54 // Use this for initialization 55 void Start() 56 { 57 CreateTiles(); 58 GenerateMesh(); 59 } 60 61 // Update is called once per frame 62 void Update() 63 { 64 Graphics.DrawMesh(mesh, Vector3.zero, Quaternion.identity, material, 0); 65 } 66 67 void CreateTiles() 68 { 69 this.tiles = new Tile[this.width, this.height]; 70 71 float[,] noiseValues = this.noise.GetNoiseValues(this.width + 1, this.height + 1); 72 73 for (int i = 0; i < this.width; i++) 74 { 75 for (int j = 0; j < this.height; j++) 76 { 77 Vector4 weights = new Vector4(noiseValues[i, j], noiseValues[i + 1, j], noiseValues[i, j + 1], noiseValues[i + 1, j + 1]); 78 79 float currentHeight = noiseValues[i, j]; 80 81 if(currentHeight < seaLevel) 82 { 83 Tile.Type type = Tile.Type.Water; 84 this.tiles[i, j] = new Tile(type, Tile.Type.Sand, Tile.Type.Water, weights); 85 } 86 else if (currentHeight >= beachStartHeight && currentHeight <= beachEndHeight) 87 { 88 Tile.Type type = Tile.Type.Sand; 89 this.tiles[i, j] = new Tile(type, Tile.Type.Grass, Tile.Type.Sand, weights); 90 } 91 else if(currentHeight >= grassStartHeight && currentHeight <= grassEndHeight) 92 { 93 Tile.Type type = Tile.Type.Grass; 94 this.tiles[i, j] = new Tile(type, Tile.Type.Grass, Tile.Type.Sand, weights); 95 } 96 else if(currentHeight >= dirtStartHeight && currentHeight <= dirtEndHeight) 97 { 98 Tile.Type type = Tile.Type.Grass; 99 this.tiles[i, j] = new Tile(type, Tile.Type.Grass, Tile.Type.Sand, weights); 100 } 101 else if(currentHeight >= stoneStartHeight && currentHeight <= stoneEndHeight) 102 { 103 Tile.Type type = Tile.Type.Grass; 104 this.tiles[i, j] = new Tile(type, Tile.Type.Grass, Tile.Type.Grass, weights); 105 } 106 else 107 { 108 Tile.Type type = Tile.Type.Grass; 109 this.tiles[i, j] = new Tile(type, Tile.Type.Grass, Tile.Type.Sand, weights); 110 } 111 } 112 } 113 } 114 115 void GenerateMesh() 116 { 117 MeshData data = new MeshData(this.tiles); 118 this.mesh = new Mesh(); 119 120 this.mesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32; 121 122 this.mesh.vertices = data.vertices.ToArray(); 123 this.mesh.triangles = data.triangles.ToArray(); 124 125 this.mesh.SetUVs(0, data.UVs); 126 127 this.mesh.colors = data.colors.ToArray(); 128 129 this.mesh.RecalculateNormals(); 130 this.mesh.RecalculateBounds(); 131 } 132}

C#

1using System.Collections; 2using System.Collections.Generic; 3using UnityEngine; 4using System.Linq; 5 6public class MeshData{ 7 8 public List<Vector3> vertices; 9 public List<int> triangles; 10 public List<Vector4> UVs; 11 public List<Color> colors; 12 13 public MeshData(Tile[,] data) 14 { 15 vertices = new List<Vector3>(); 16 triangles = new List<int>(); 17 UVs = new List<Vector4>(); 18 colors = new List<Color>(); 19 20 for (int i = 0; i < data.GetLength(0); i++) 21 { 22 for (int j = 0; j < data.GetLength(1); j++) 23 { 24 CreateSquare(data[i, j], i, j); 25 } 26 } 27 } 28 29 void CreateSquare(Tile tile, int x, int y) 30 { 31 vertices.Add(new Vector3(x + 0, y + 0)); 32 vertices.Add(new Vector3(x + 1, y + 0)); 33 vertices.Add(new Vector3(x + 0, y + 1)); 34 vertices.Add(new Vector3(x + 1, y + 1)); 35 36 triangles.Add(vertices.Count - 1); 37 triangles.Add(vertices.Count - 3); 38 triangles.Add(vertices.Count - 4); 39 40 triangles.Add(vertices.Count - 2); 41 triangles.Add(vertices.Count - 1); 42 triangles.Add(vertices.Count - 4); 43 44 Vector2[] foregroundUVs = SpriteLoader.instance.GetTileUVs(tile.foregroundType); 45 Vector2[] backgroundUVs = SpriteLoader.instance.GetTileUVs(tile.backgroundType); 46 UVs.AddRange(foregroundUVs.Zip(backgroundUVs, (f, b) => new Vector4(f.x, f.y, b.x, b.y))); 47 48 for (int i = 0; i < 4; i++) 49 { 50 colors.Add(new Color(0.0f, 0.0f, 0.0f, tile.blendWeights[i])); 51 } 52 } 53} 54

C#

1using System.Collections; 2using System.Collections.Generic; 3using UnityEngine; 4 5public class Tile 6{ 7 8 public enum Type { Dirt, Grass,Water,Sand,Void } 9 public Type type; 10 public Type foregroundType; 11 public Type backgroundType; 12 public Vector4 blendWeights; 13 14 public Tile(Type type, Type foreground, Type background, Vector4 weights) 15 { 16 this.type = type; 17 this.foregroundType = foreground; 18 this.backgroundType = background; 19 this.blendWeights = weights; 20 } 21} 22

C#

1using System.Collections; 2using System.Collections.Generic; 3using UnityEngine; 4 5public class Noise { 6 7 int seed; 8 9 float frequency; 10 float amplitude; 11 12 float lacunarity; 13 float persistance; 14 15 int octaves; 16 17 public Noise(int seed,float frequency,float amplitude,float lacunarity,float persistance,int octaves) 18 { 19 this.seed = seed; 20 this.frequency = frequency; 21 this.amplitude = amplitude; 22 this.lacunarity = lacunarity; 23 this.persistance = persistance; 24 this.octaves = octaves; 25 } 26 27 public float [,] GetNoiseValues(int width,int height) 28 { 29 float[,] noiseValues = new float[width, height]; 30 31 float max = 0f; 32 float min = float.MaxValue; 33 34 seed %= 1024; 35 36 for (int i = 0; i < width; i++) 37 { 38 for(int j =0; j < height; j++) 39 { 40 noiseValues[i, j] = 0f; 41 42 float tempA = amplitude; 43 float tempF = frequency; 44 45 for(int k = 0;k < octaves; k++) 46 { 47 noiseValues[i, j] += Mathf.PerlinNoise((i + seed) / (float)width * frequency, j / (float)height * frequency) * amplitude; 48 frequency *= lacunarity; 49 amplitude *= persistance; 50 } 51 52 amplitude = tempA; 53 frequency = tempF; 54 55 if(noiseValues[i,j] > max) 56 { 57 max = noiseValues[i, j]; 58 } 59 60 if(noiseValues[i,j] < min) 61 { 62 min = noiseValues[i, j]; 63 } 64 } 65 } 66 67 for (int i = 0; i < width; i++) 68 { 69 for (int j = 0; j < height; j++) 70 { 71 72 noiseValues[i, j] = Mathf.InverseLerp(max, min, noiseValues[i, j]); 73 } 74 } 75 76 return noiseValues; 77 } 78}

試したこと

前回アドバイスしていただいたコードを改造して、描画するタイルを増やしたのですが、綺麗な地形表現にはなりませんでした。前回の質問のコードを使い、二枚のタイルだけなら、上手くいきます。

イメージ説明
イメージ説明
前景と背景のグラフィックを混ぜ合わせて描画しているのですが、四角形のメッシュで生成しているので、隣合うグラフィックの問題で、地形のように見えなくなっているのだと自分は考えました。
具体的にはBeach Start HeightとBeach End Heidhtという変数を使い、浜辺のように見せようとしているのですが、四角形に描画されるため、浜辺には見えなくなっています。

増やした変数の値は以下です。

イメージ説明

使用したタイル↓
イメージ説明
文字数制限に引っ掛かるため、「SpriteLoader」というスクリプトは記載しませんでした。前回の質問に記載してあります。
どのようにすればいいでしょうか? 回答お願いします。

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

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

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

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

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

guest

回答2

0

マテリアルは下記のように変更しました。計算の都合上、_EdgeSoftnessは廃止して_EdgeSharpnessに変わっています。1以上上限なし(とはいえ、せいぜい数十までで十分でしょう)の値で、_EdgeSoftnessとは逆に大くするほどエッジがシャープになります。
多分こんな感じのブレンドでそれっぽく見えるかと思いますが、いかがでしょうか?あくまでも一例ですので、お好みなように改造してしまってください。

ShaderLab

1Shader "Unlit/World" 2{ 3 Properties 4 { 5 [NoScaleOffset] _MainTex ("Texture", 2D) = "white" {} 6 7 // 見た目調整用プロパティを変更、前回と異なり大きくするほど鋭くなる 8 [PowerSlider(10)] _EdgeSharpness ("Edge Sharpness", Range(1.0, 100.0)) = 10.0 9 10 _EdgeDist ("Edge Disturbance", Range(0.0, 1.0)) = 0.05 11 _EdgeDistFreq ("Edge Disturbance Frequency", Range(0.0, 16.0)) = 4.0 12 } 13 14 SubShader 15 { 16 Tags { "RenderType"="Opaque" } 17 18 Pass 19 { 20 CGPROGRAM 21 #pragma vertex vert 22 #pragma fragment frag 23 #include "UnityCG.cginc" 24 25 // 頂点アトリビュートからはUV関連を削除 26 struct appdata 27 { 28 float4 vertex : POSITION; 29 float4 color : COLOR; 30 }; 31 32 // tileUvには(0, 0)、(1, 0)、(0, 1)、(1, 1)のいずれかが入る 33 struct v2f 34 { 35 float4 vertex : SV_POSITION; 36 float2 tileUv : TEXCOORD0; 37 float weight : TEXCOORD1; 38 float2 modelPos : TEXCOORD2; 39 }; 40 41 inline float random(float2 st) { 42 return frac(sin(dot(st, float2(12.9898, 78.233))) * 43758.5453123); 43 } 44 45 float noise(float2 st) 46 { 47 float2 i = floor(st); 48 float2 f = frac(st); 49 float a = random(i); 50 float b = random(i + float2(1.0, 0.0)); 51 float c = random(i + float2(0.0, 1.0)); 52 float d = random(i + float2(1.0, 1.0)); 53 float2 u = f * f * (3.0 - 2.0 * f); 54 55 return dot(float2(lerp(a, b, u.x), lerp(c - a, d - b, u.x)), float2(1.0, u.y)); 56 } 57 58 float fractal(float2 st) 59 { 60 float4 amp = float4(1.0, 0.5, 0.25, 0.125); 61 float4 v; 62 63 v.x = noise(st); 64 st = st * 2.0 + float2(14.1421356237, 17.3205080757); 65 v.y = noise(st); 66 st = st * 2.0 + float2(22.360679775, 26.4575131106); 67 v.z = noise(st); 68 st = st * 2.0 + float2(31.4159265359, 27.1828182846); 69 v.w = noise(st); 70 71 return dot(v, amp) / dot(1.0, amp); 72 } 73 74 sampler2D _MainTex; 75 float4 _MainTex_ST; 76 float4 _MainTex_TexelSize; 77 float _EdgeSharpness; 78 float _EdgeDist; 79 float _EdgeDistFreq; 80 81 // ユニフォーム変数を追加 82 #define TYPE_COUNT_MAX 8 83 int _TypeCount; 84 float4 _TypeUvs[TYPE_COUNT_MAX / 2]; 85 float2 _TileSize; 86 float _TypeLevels[TYPE_COUNT_MAX]; 87 88 v2f vert(appdata v) 89 { 90 v2f o; 91 o.tileUv = v.color.xy; 92 o.weight = v.color.a; 93 o.modelPos = v.vertex.xy; 94 o.vertex = UnityObjectToClipPos(v.vertex); 95 return o; 96 } 97 98 fixed4 frag(v2f i) : SV_Target 99 { 100 // まずは前回同様weightを計算する 101 float f = dot(float2(_EdgeDist, 1.0 - _EdgeDist), float2(fractal(i.modelPos * _EdgeDistFreq), 0.5)); 102 float upper = 1.0 - 2.0 * (1.0 - i.weight) * (1.0 - f); 103 float lower = 2.0 * i.weight * f; 104 float weight = lerp(lower, upper, step(0.5, i.weight)); 105 106 // weightを比較してどの範囲にいるか判定し、それを越えない最大のインデックスを調べる 107 uint index = 0; 108 [unroll(TYPE_COUNT_MAX)] 109 for (int k = 0; k < _TypeCount; k++) 110 { 111 if (_TypeLevels[k] < weight) 112 { 113 index = k + 1; 114 continue; 115 } 116 break; 117 } 118 index = min(index, _TypeCount - 1); 119 120 // さらに、その一つ下・一つ上のインデックスを求めておく 121 uint prevIndex = index > 0 ? index - 1 : 0; 122 uint nextIndex = min(index + 1, _TypeCount - 1); 123 124 // 範囲の下限・上限の高さを取得し、lowerLevelを0、upperLevelを1としたときのweightの位置を調べる 125 float lowerLevel = (index == prevIndex) ? 0.0 : _TypeLevels[prevIndex]; 126 float upperLevel = (index == nextIndex) ? 1.0 : _TypeLevels[index]; 127 float weightInRange = (lowerLevel == upperLevel) ? 0.0 : (weight - lowerLevel) / (upperLevel - lowerLevel); 128 129 // weightInRangeが0.5以上かどうかでnextIndex、prevIndexのいずれかを選択する 130 uint edgeIndex = weightInRange >= 0.5 ? nextIndex : prevIndex; 131 132 // weightInRangeが0.5の時0、そこより範囲境界に近いほど1になるような値を作る 133 // このとき_EdgeSharpness乗して、カーブを適宜鋭くする 134 float edgeFactor = saturate(pow(abs(weightInRange * 2.0 - 1.0), _EdgeSharpness)); 135 136 // 範囲中心および範囲境界に対応するUVを取得し、そこからそれぞれ色を取得する 137 float4 edgeVector = _TypeUvs[edgeIndex / 2]; 138 float4 centerVector = _TypeUvs[index / 2]; 139 float2 edgeUv = lerp(edgeVector.xy, edgeVector.zw, edgeIndex % 2); 140 float2 centerUv = lerp(centerVector.xy, centerVector.zw, index % 2); 141 float2 uvOffset = i.tileUv * _TileSize; 142 fixed4 edgeColor = tex2D(_MainTex, edgeUv + uvOffset); 143 fixed4 centerColor = tex2D(_MainTex, centerUv + uvOffset); 144 145 // 範囲中心でcenterColorが100%、境界部分でcenterColorとedgeColorが 146 // 50%混合になるように2つの色を混ぜ合わせる 147 return lerp(centerColor, edgeColor, edgeFactor * 0.5); 148 } 149 ENDCG 150 } 151 } 152}

結果

投稿2019/04/16 11:16

Bongo

総合スコア10811

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

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

退会済みユーザー

退会済みユーザー

2019/04/16 13:22

追記の回答、ありがとうございました。
guest

0

ベストアンサー

方針を一部変更し、地形の種類はさほど多くないだろうと仮定して、各頂点に地形のUVを持たせるのではなく全ての地形のUVをシェーダーのユニフォーム変数に投入することにしました。さしあたり最大8種類までとしています(ユニフォーム変数の領域は貴重ですので節約しました...)。

まず、TileおよびMeshDataは下記のように変更しました。個々のTileに前景・背景タイプを持たせる必要はなくなったので、foregroundTypebackgroundTypeは廃止しました。
MeshDataUVsが不要になったので削除しました。代わりに、colorsのRとGに頂点が左下・右下・左上・右上のいずれであるかを示す値を格納しています。

C#

1using System.Collections; 2using System.Collections.Generic; 3using UnityEngine; 4 5public class Tile 6{ 7 8 public enum Type { Dirt, Grass, Water, Sand, Void } 9 public Type type; 10 public Vector4 blendWeights; 11 12 public Tile(Type type, Vector4 weights) 13 { 14 this.type = type; 15 this.blendWeights = weights; 16 } 17}

C#

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

Worldのフィールドはちょっと変更させていただき~StartHeightは削除して、各地形の終了高さだけを指定する方式にしました。開始高さと終了高さの2点を指定する方式だと、範囲が交差したり隙間が空いた場合の処置がややこしくなる気がしたためです。

C#

1using System.Collections; 2using System.Collections.Generic; 3using System.Linq; 4using UnityEngine; 5 6public class World : MonoBehaviour 7{ 8 // 地形の種類は8種類までとする 9 private const int TypeCountMax = 8; 10 11 // プロパティアクセス用の番号を取得しておく 12 private static readonly int TypeCountProperty = Shader.PropertyToID("_TypeCount"); 13 private static readonly int TypeUvsProperty = Shader.PropertyToID("_TypeUvs"); 14 private static readonly int TileSizeProperty = Shader.PropertyToID("_TileSize"); 15 private static readonly int TypeLevelsProperty = Shader.PropertyToID("_TypeLevels"); 16 17 public int width; 18 public int height; 19 20 public Tile[,] tiles; 21 22 public Material material; 23 24 Mesh mesh; 25 26 public string seed; 27 public bool randomSeed; 28 29 public float frequency; 30 public float amplitude; 31 32 public float lacunarity; 33 public float persistance; 34 35 public int octaves; 36 37 Noise noise; 38 39 // 「~~~StartHeight」は廃止しました 40 public float seaLevel; 41 public float beachEndHeight; 42 public float grassEndHeight; 43 public float dirtEndHeight; 44 public float stoneEndHeight; 45 46 // マテリアルに投入するデータはこれらフィールドに保持しておく 47 int typeCount; 48 List<Vector4> typeUvs; 49 Vector4 tileSize; 50 float[] typeLevels; 51 52 private void Awake() 53 { 54 if(randomSeed == true) 55 { 56 int value = Random.Range(-1000, 10000); 57 seed = value.ToString(); 58 } 59 60 noise = new Noise(seed.GetHashCode(), frequency, amplitude, lacunarity, persistance, octaves); 61 } 62 63 // Use this for initialization 64 void Start() 65 { 66 CreateTiles(); 67 GenerateMesh(); 68 } 69 70 // Update is called once per frame 71 void Update() 72 { 73 // マテリアルにデータを投入する 74 // 毎フレーム変化するデータではないため、データをわざわざフィールドに保持せず 75 // CreateTilesの末尾で投入してもいいと思いますが、これらデータ(特に配列)は 76 // シリアライズされずマテリアルに保存してくれないため、プレイモード中に 77 // シェーダーを編集したりするとリロードされてデータが失われ、正しく描画されなくなるようです 78 // 色々いじって実験するには不便でしたので、Update内で毎回投入することにしました 79 this.material.SetInt(TypeCountProperty, this.typeCount); 80 this.material.SetVectorArray(TypeUvsProperty, this.typeUvs); 81 this.material.SetVector(TileSizeProperty, this.tileSize); 82 this.material.SetFloatArray(TypeLevelsProperty, this.typeLevels); 83 84 Graphics.DrawMesh(mesh, Vector3.zero, Quaternion.identity, material, 0); 85 } 86 87 void CreateTiles() 88 { 89 // まず、各地形タイプと終了高さをペアにした配列を作り、終了高さ順に並べ替え、最大TypeCountMax個まで取り出す 90 (Tile.Type, float)[] types = new[] 91 { 92 (Tile.Type.Water, this.seaLevel), 93 (Tile.Type.Sand, this.beachEndHeight), 94 (Tile.Type.Grass, this.grassEndHeight), 95 (Tile.Type.Grass, this.dirtEndHeight), 96 (Tile.Type.Grass, this.stoneEndHeight) 97 }.OrderBy(pair => pair.Item2).Take(TypeCountMax).ToArray(); 98 99 this.tiles = new Tile[this.width, this.height]; 100 101 float[,] noiseValues = this.noise.GetNoiseValues(this.width + 1, this.height + 1); 102 103 for (int i = 0; i < this.width; i++) 104 { 105 for (int j = 0; j < this.height; j++) 106 { 107 Vector4 weights = new Vector4(noiseValues[i, j], noiseValues[i + 1, j], noiseValues[i, j + 1], noiseValues[i + 1, j + 1]); 108 109 // 四隅の平均ではなく左下隅のノイズ値を使った場合、もしかするとタイルの見た目と 110 // ゲーム上の応答に乖離が生じやすくなるかもしれません 111 // たとえば左下隅が砂地、残り3つの隅が海だった場合、タイルの見た目は高確率で海に 112 // なるでしょうが、ゲーム内のキャラクターにとっては砂地に見えるでしょう 113 float currentHeight = noiseValues[i, j]; 114 115 // currentHeightと終了高さを比較し、適切な地形タイプを見つける 116 var type = types.Where(t => currentHeight < t.Item2).DefaultIfEmpty(types.Last()).Last().Item1; 117 this.tiles[i, j] = new Tile(type, weights); 118 } 119 } 120 121 // UVデータを配列にする 122 // なお、変数節約のためタイルの大きさは全て同じと仮定して(ということでいいですよね?) 123 // 左下隅のUVだけをリストアップすることにした 124 int typesLength = types.Length; 125 int uvVectorCount = (typesLength / 2) + (typesLength % 2); 126 List<Vector4> uvVectors = new List<Vector4>(uvVectorCount); 127 for (int i = 0; i < uvVectorCount; i++) 128 { 129 int j = i * 2; 130 Tile.Type type1 = types[j].Item1; 131 Tile.Type type2 = (j < typesLength - 1) ? types[j + 1].Item1 : Tile.Type.Void; 132 Vector2 uv1 = SpriteLoader.instance.GetTileUVs(type1)[0]; 133 Vector2 uv2 = SpriteLoader.instance.GetTileUVs(type2)[0]; 134 uvVectors.Add(new Vector4(uv1.x, uv1.y, uv2.x, uv2.y)); 135 } 136 137 // 全地形を代表しVoidの大きさを調べる(Voidは一番最後の透明地形でしょうかね?) 138 // 念のため申し上げますと、Void地形も他の地形と同じサイズであることを前提にしていますので 139 // もしそうでないなら代わりのタイプを与えるか、他の手段で設定してみてください 140 Vector2[] voidUvs = SpriteLoader.instance.GetTileUVs(Tile.Type.Void); 141 Vector2 size = voidUvs[3] - voidUvs[0]; 142 143 // できあがったデータをフィールドに保持 144 this.typeCount = types.Length; 145 this.typeUvs = uvVectors; 146 this.tileSize = size; 147 this.typeLevels = types.Select(t => t.Item2).ToArray(); 148 } 149 150 void GenerateMesh() 151 { 152 MeshData data = new MeshData(this.tiles); 153 this.mesh = new Mesh(); 154 155 this.mesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32; 156 157 // UVは不要なので削除 158 this.mesh.vertices = data.vertices.ToArray(); 159 this.mesh.triangles = data.triangles.ToArray(); 160 this.mesh.colors = data.colors.ToArray(); 161 162 this.mesh.RecalculateNormals(); 163 this.mesh.RecalculateBounds(); 164 } 165}

すみませんが字数制限に達してしまったため、マテリアルは別回答に記載いたします。

投稿2019/04/16 11:15

Bongo

総合スコア10811

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

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

退会済みユーザー

退会済みユーザー

2019/04/16 13:22

お忙しい中、再び回答していただき、本当にありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問