IndexOutOfRangeException
IndexOutOfRangeException: Index was outside the bounds of the array. MeshData.AddTriangle(System.int32 a, System.int32 b, System.int32 c)
public static class MeshGenerator
{
public static MeshData GenerateTerrainMesh (float[,] heightMap)
{
int width = heightMap.GetLength(0);
int height = heightMap.GetLength(1);
float topLeftX = (width - 1) / -2f;
float topLeftZ = (height - 1) / 2f;
MeshData meshData = new MeshData(width, height);
int vertexIndex = 0;
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
meshData.vertices[vertexIndex] = new Vector3(topLeftX + x, heightMap[x, y], topLeftZ - y);
meshData.uvs[vertexIndex] = new Vector2(x / (float)width, y / (float)height);
if (x < width - 1 && y < height - 1)
{
meshData.AddTriangle(vertexIndex, vertexIndex + width + 1, vertexIndex + width);
meshData.AddTriangle(vertexIndex + width + 1, vertexIndex, vertexIndex + 1);
}
vertexIndex++;
}
}
return meshData;
}
}
public class MeshData
{
public Vector3[] vertices;
public int[] triangles;
public Vector2[] uvs;
int triangleIndex;
public MeshData (int meshWidth, int meshHeight)
{
vertices = new Vector3[meshWidth * meshHeight];
uvs = new Vector2[meshWidth * meshHeight];
triangles = new int[(meshWidth - 1) * (meshHeight - 1)];
}
public void AddTriangle (int a, int b, int c)
{
triangles[triangleIndex] = a;
triangles[triangleIndex + 1] = b;
triangles[triangleIndex + 2] = c;
triangleIndex += 3;
}
public Mesh CreateMesh ()
{
Mesh mesh = new Mesh();
mesh.vertices = vertices;
mesh.triangles = triangles;
mesh.uv = uvs;
mesh.RecalculateNormals();
return mesh;
}
}
Ответы (1 шт):
Автор решения: Yaroslav
→ Ссылка
Ошибка в длине массива triangles. В каждом квадрате 2 полигона с 3 вершинами. (meshWidth-1)*(meshHeight-1)*6.
Если ты хочешь менять карту высот в реальном времени, то зачем каждый раз выстраивать меш с нуля, притом что uv и triangles не меняются. Да и зачем тут статика тоже не ясно, как компонент он может сразу работать с объектом.
using System;
using UnityEngine;
[DisallowMultipleComponent]
[RequireComponent(typeof(MeshFilter), typeof(Renderer))]
public class TerrainGenerator : MonoBehaviour
{
private const string TexturePropertyName = "_MainTex";
private float _space;
private MeshFilter _filter;
private Renderer _renderer;
private Mesh _mesh;
private Vector3[] _vertices;
public Vector2Int Size { get; private set; }
private void Awake ()
{
_filter = GetComponent<MeshFilter>();
_renderer = GetComponent<Renderer>();
}
public void Setup (Vector2Int size, float space)
{
Size = size;
_space = space;
BuildMesh();
}
public void SetHeightMap (float[,] heightMap)
{
if (_mesh == null)
throw new NullReferenceException("Setup terrain before setting height map");
if (heightMap.GetLength(0) != Size.x || heightMap.GetLength(1) != Size.y)
throw new ArgumentException("Wrong size of height map");
for (int y = 0; y < Size.y; y++)
for (int x = 0; x < Size.x; x++)
{
int index = GetIndex(x, y);
Vector3 position = _vertices[index];
position.y = heightMap[x, y];
_vertices[index] = position;
}
_mesh.vertices = _vertices;
_mesh.RecalculateNormals();
_filter.sharedMesh = _mesh;
}
public void SetTexture (Texture texture)
{
_renderer.material.SetTexture(TexturePropertyName, texture);
}
private void BuildMesh ()
{
int pointCount = Size.x*Size.y;
int rectCount = (Size.x-1)*(Size.y-1);
_vertices = new Vector3[pointCount];
Vector2[] uv = new Vector2[pointCount];
int[] triangles = new int[rectCount*6];
for (int y = 0; y < Size.y; y++)
for (int x = 0; x < Size.x; x++)
{
int pointIndex = GetIndex(x, y);
_vertices[pointIndex] = new Vector3(x*_space, 0, y*_space);
uv[pointIndex] = new Vector2(x/(float)Size.x, y/(float)Size.y);
}
int index = 0;
for (int y = 0; y < Size.y-1; y++)
for (int x = 0; x < Size.x-1; x++)
{
int current = GetIndex(x, y);
int currentUp = GetIndex(x, y+1);
triangles[index++] = current+1;
triangles[index++] = current;
triangles[index++] = currentUp+1;
triangles[index++] = currentUp;
triangles[index++] = currentUp+1;
triangles[index++] = current;
}
_mesh = new Mesh();
_mesh.name = "TerrainMesh"+Size.x+"x"+Size.y;
_mesh.vertices = _vertices;
_mesh.triangles = triangles;
_mesh.uv = uv;
_mesh.RecalculateNormals();
_filter.sharedMesh = _mesh;
}
private int GetIndex (int x, int y)
{
return Size.x*y+x;
}
}
using UnityEngine;
public class Foo : MonoBehaviour
{
[SerializeField] private Vector2Int _size = new Vector2Int(11, 11);
[SerializeField] private float _space = 1;
[Space]
[SerializeField] private float _noiseScale = 0.2f;
[SerializeField] private float _noiseHeight = 2;
[Space]
[SerializeField] private TerrainGenerator _terrain;
public void Start ()
{
_terrain.Setup(_size, _space);
float[,] heightMap = new float[_size.x, _size.y];
for (int y = 0; y < _size.y; y++)
for (int x = 0; x < _size.x; x++)
heightMap[x, y] = Mathf.PerlinNoise(x*_noiseScale, y*_noiseScale)*_noiseHeight;
_terrain.SetHeightMap(heightMap);
}
}