前回、キューブでマップを作ってみたものの、やっぱりオブジェクトをたくさん出すと重いですよね。なのであまりマップも大きくできません。
そんなわけで今度はメッシュでやってみました。
GameObject>3DObject>Plane で作ったPlaneに以下のスクリプトをアタッチします。
using UnityEngine;
public class PerlinNoiseMesh : MonoBehaviour
{
[SerializeField, Range(0f, 1f)] float m_threshold = 0.5f;
[SerializeField, Range(0.05f, 0.3f)] float m_scale = 0.1f;
int sz = 100;
float heightScale =5f;
// Start is called before the first frame update
void Start()
{
HeightInfo[,] heightArr = new HeightInfo[sz, sz];
for (int x = 0; x < sz; ++x){
for (int z = 0; z < sz; ++z){
float noise = Mathf.PerlinNoise((float)x * m_scale, (float)z * m_scale);
if (noise < m_threshold){
float thRate = (m_threshold - noise) / (m_threshold);
heightArr[x, z].height = thRate * heightScale;
heightArr[x, z].vertCol = new Color(1f - thRate * 1.1f, 0.8f + thRate * 0.3f, 0.9f - thRate * 1.2f);
}
else{
heightArr[x, z].height = 0f;
heightArr[x, z].vertCol = new Color(0.3f, 0.5f, 0.9f);
}
}
}
GetComponent<MeshFilter>().mesh = CreateHeightMesh(heightArr);
MeshCollider mc = GetComponent<MeshCollider>();
mc.sharedMesh = GetComponent<MeshFilter>().mesh;
}
void Update() {}
[System.Serializable]
public struct HeightInfo
{
public float height;
public Color vertCol;
};
public static Mesh CreateHeightMesh(HeightInfo[,] _heightArr, bool _isUnitPerGrid=true)
{
int _divX = _heightArr.GetLength(0) - 1;
int _divZ = _heightArr.GetLength(1) - 1;
int vertNum = (_divX + 1) * (_divZ + 1);
int quadNum = _divX * _divZ;
int[] triangles = new int[quadNum * 6];
Vector3[] vertices = new Vector3[vertNum];
Vector2[] uv = new Vector2[vertNum];
Color[] colors = new Color[vertNum];
Vector3[] normals = new Vector3[vertNum];
Vector4[] tangents = new Vector4[vertNum];
for (int zz = 0; zz < (_divZ + 1); ![2020-11-06_214107.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/59911/a49cc3e4-9dcc-b835-b348-6bc56e989452.png)
++zz)
{
for (int xx = 0; xx < (_divX + 1); ++xx)
{
float height = _heightArr[xx, zz].height;
Vector2 uvPos = new Vector2((float)xx / (float)_divX, (float)zz / (float)_divZ);
vertices[zz * (_divX + 1) + xx] = new Vector3(uvPos.x - 0.5f, height, uvPos.y - 0.5f);
if (_isUnitPerGrid)
{
vertices[zz * (_divX + 1) + xx] = Vector3.Scale(vertices[zz * (_divX + 1) + xx], new Vector3(_divX, 1f, _divZ));
}
uv[zz * (_divX + 1) + xx] = uvPos;
colors[zz * (_divX + 1) + xx] = _heightArr[xx, zz].vertCol*0.1f;
normals[zz * (_divX + 1) + xx] = new Vector3(0.0f, 1.0f, 0.0f);
tangents[zz * (_divX + 1) + xx] = new Vector4(1.0f, 0.0f, 0.0f);
if ((xx < _divX) && (zz < _divZ))
{
int[] sw = { 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1 };
for (int ii = 0; ii < 6; ++ii)
{
triangles[(zz * _divX + xx) * 6 + ii] = (zz + sw[ii * 2 + 1]) * (_divX + 1) + (xx + sw[ii * 2 + 0]);
}
}
}
}
Mesh mesh = new Mesh();
mesh.vertices = vertices;
mesh.triangles = triangles;
mesh.uv = uv;
mesh.colors = colors;
mesh.normals = normals;
mesh.tangents = tangents;
mesh.RecalculateNormals();
mesh.RecalculateBounds();
mesh.SetIndices(mesh.GetIndices(0), MeshTopology.Triangles, 0);
return mesh;
}
}
実行するとこうなります。
こちらで公開されている頂点カラーシェーダーを使うとこうなります。
1つのメッシュの頂点数が65535を超えると破綻するので、その際はメッシュを分割しましょう。