Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

IndexOutOfRangeException Error

Discussion in 'Scripting' started by grqphical, Dec 26, 2021.

  1. grqphical

    grqphical

    Joined:
    Jul 15, 2021
    Posts:
    10
    So I have a script that generates a procedural world gen and I tried to fix a normals issue on the mesh and now I seem to have a IndexOutOfRangeException on line 103. I can't figure it out

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public static class MeshGenerator
    6. {
    7.     public static MeshData GenerateTerrainMesh(float[,] heightMap, float heightMultiplier, AnimationCurve _heightCurve, int levelOfDetail)
    8.     {
    9.         AnimationCurve heightCurve = new AnimationCurve(_heightCurve.keys);
    10.  
    11.         int meshSimplificationIncrement = (levelOfDetail == 0) ? 1 : levelOfDetail * 2;
    12.  
    13.         int borderedSize = heightMap.GetLength(0);
    14.         int meshSize = borderedSize - 2 * meshSimplificationIncrement;
    15.         int meshSizeUnsimplified = borderedSize - 2;
    16.  
    17.         float topLeftX = (meshSizeUnsimplified - 1) / -2f;
    18.         float topLeftZ = (meshSizeUnsimplified - 1) / 2f;
    19.  
    20.  
    21.         int verticesPerLine = (meshSize - 1) / meshSimplificationIncrement + 1;
    22.  
    23.         MeshData meshData = new MeshData(verticesPerLine);
    24.         int[,] vertexIndicesMap = new int[borderedSize,borderedSize];
    25.         int meshVertexIndex = 0;
    26.         int borderVertexIndex = -1;
    27.  
    28.         for (int y = 0; y < borderedSize; y++)
    29.         {
    30.             for (int x = 0; x < borderedSize; x++)
    31.             {
    32.                 bool isBorderVertex = y == 0 || y == borderedSize - 1 || x == 0 || x == borderedSize - 1;
    33.                 if (isBorderVertex)
    34.                 {
    35.                     vertexIndicesMap[x, y] = borderVertexIndex;
    36.                     borderVertexIndex--;
    37.                 }
    38.                 else
    39.                 {
    40.                     vertexIndicesMap[x, y] = meshVertexIndex;
    41.                     meshVertexIndex++;
    42.                 }
    43.             }
    44.         }
    45.  
    46.         for (int y = 0; y < borderedSize; y += meshSimplificationIncrement)
    47.         {
    48.             for (int x = 0; x < borderedSize; x += meshSimplificationIncrement)
    49.             {
    50.                 int vertexIndex = vertexIndicesMap[x, y];
    51.  
    52.                 Vector2 percent = new Vector2((x - meshSimplificationIncrement) / (float)meshSize, (y - meshSimplificationIncrement) / (float)meshSize);
    53.                 float height = heightCurve.Evaluate(heightMap[x, y]) * heightMultiplier;
    54.                 Vector3 vertexPosition = new Vector3(topLeftX + percent.x * meshSizeUnsimplified, height, topLeftZ - percent.y * meshSize);
    55.  
    56.                 meshData.AddVertex(vertexPosition, percent, vertexIndex);
    57.  
    58.  
    59.                 if (x < borderedSize-1 && y < borderedSize - 1)
    60.                 {
    61.                     int a = vertexIndicesMap[x, y];
    62.                     int b = vertexIndicesMap[x + meshSimplificationIncrement, y];
    63.                     int c = vertexIndicesMap[x, y + meshSimplificationIncrement];
    64.                     int d = vertexIndicesMap[x + meshSimplificationIncrement, y + meshSimplificationIncrement];
    65.                     meshData.AddTriangle(a,d,c);
    66.                     meshData.AddTriangle(d,a,b);
    67.                 }
    68.                 vertexIndex++;
    69.                
    70.             }
    71.         }
    72.         return meshData;
    73.     }
    74. }
    75.  
    76.  
    77. public class MeshData
    78. {
    79.     Vector3[] vertices;
    80.     int[] triangles;
    81.     Vector2[] uvs;
    82.  
    83.     Vector3[] borderVertices;
    84.     int[] borderTriangles;
    85.  
    86.     int triangleIndex;
    87.     int borderTriangleIndex;
    88.  
    89.     public MeshData(int verticesPerLine)
    90.     {
    91.         vertices = new Vector3[verticesPerLine * verticesPerLine];
    92.         uvs = new Vector2[verticesPerLine * verticesPerLine];
    93.         triangles = new int[(verticesPerLine - 1) * (verticesPerLine - 1)*6];
    94.  
    95.         borderVertices = new Vector3[verticesPerLine * 4 + 4];
    96.         borderTriangles = new int[24 * verticesPerLine];
    97.     }
    98.  
    99.     public void AddVertex(Vector3 position, Vector2 uv, int vertexIndex)
    100.     {
    101.         if (vertexIndex < 0)
    102.         {
    103.             borderVertices[-vertexIndex - 1] = position;
    104.         }
    105.         else
    106.         {
    107.             vertices[vertexIndex] = position;
    108.             uvs[vertexIndex] = uv;
    109.         }
    110.     }
    111.  
    112.     public void AddTriangle(int a, int b, int c)
    113.     {
    114.         if (a < 0 || b < 0 || c < 0)
    115.         {
    116.             borderTriangles[borderTriangleIndex] = a;
    117.             borderTriangles[borderTriangleIndex + 1] = b;
    118.             borderTriangles[borderTriangleIndex + 2] = c;
    119.         }
    120.         else
    121.         {
    122.             triangles[triangleIndex] = a;
    123.             triangles[triangleIndex + 1] = b;
    124.             triangles[triangleIndex + 2] = c;
    125.         }
    126.  
    127.         triangleIndex += 3;
    128.     }
    129.     Vector3[] CalculateNormals()
    130.     {
    131.         Vector3[] vertexNormals = new Vector3[vertices.Length];
    132.         int triangleCount = triangles.Length/3;
    133.         for (int i = 0; i < triangleCount; i++)
    134.         {
    135.             int normalTriangleIndex = i * 3;
    136.             int vertexIndexA = triangles[normalTriangleIndex];
    137.             int vertexIndexB = triangles[normalTriangleIndex + 1];
    138.             int vertexIndexC = triangles[normalTriangleIndex + 2];
    139.  
    140.             Vector3 triangleNormal = SurfaceNormalFromIndices(vertexIndexA, vertexIndexB, vertexIndexC);
    141.             vertexNormals[vertexIndexA] += triangleNormal;
    142.             vertexNormals[vertexIndexB] += triangleNormal;
    143.             vertexNormals[vertexIndexC] += triangleNormal;
    144.  
    145.  
    146.         }
    147.         int borderTriangleCount = borderTriangles.Length / 3;
    148.         for (int i = 0; i < triangleCount; i++)
    149.         {
    150.             int normalTriangleIndex = i * 3;
    151.             int vertexIndexA = borderTriangles[normalTriangleIndex];
    152.             int vertexIndexB = borderTriangles[normalTriangleIndex + 1];
    153.             int vertexIndexC = borderTriangles[normalTriangleIndex + 2];
    154.  
    155.             Vector3 triangleNormal = SurfaceNormalFromIndices(vertexIndexA, vertexIndexB, vertexIndexC);
    156.             if (vertexIndexA >= 0)
    157.             {
    158.                 vertexNormals[vertexIndexA] += triangleNormal;
    159.             }
    160.             if (vertexIndexB >= 0)
    161.             {
    162.                 vertexNormals[vertexIndexB] += triangleNormal;
    163.             }
    164.             if (vertexIndexC >= 0)
    165.             {
    166.                 vertexNormals[vertexIndexC] += triangleNormal;
    167.             }
    168.  
    169.  
    170.         }
    171.  
    172.         for ( int i = 0; i < vertexNormals.Length; i++)
    173.         {
    174.             vertexNormals[i].Normalize();
    175.         }
    176.         return vertexNormals;
    177.     }
    178.  
    179.     Vector3 SurfaceNormalFromIndices(int indexA, int indexB, int indexC)
    180.     {
    181.         Vector3 pointA = (indexA < 0) ? borderVertices[-indexA - 1] : vertices[indexA];
    182.         Vector3 pointB = (indexB < 0) ? borderVertices[-indexB - 1] : vertices[indexB];
    183.         Vector3 pointC = (indexC < 0) ? borderVertices[-indexC - 1] : vertices[indexC];
    184.  
    185.         Vector3 sideAB = pointB - pointA;
    186.         Vector3 sideAC = pointC - pointA;
    187.         return Vector3.Cross(sideAB, sideAC).normalized;
    188.     }
    189.  
    190.     public Mesh CreateMesh()
    191.     {
    192.         Mesh mesh = new Mesh();
    193.         mesh.vertices = vertices;
    194.         mesh.triangles = triangles;
    195.         mesh.uv = uvs;
    196.         mesh.normals = CalculateNormals();
    197.         return mesh;
    198.     }
    199. }
     
  2. Serge_Billault

    Serge_Billault

    Joined:
    Aug 26, 2014
    Posts:
    190
    An IndexOutOfRangeException is just that, an index out of range. It means that whatever vertexIndex is passed at line 103, the resulting -vertexIndex - 1 is not in the range [0...borderVertices.Length-1].

    Since your vertexIndex is obtained at line 50
    it means that either whatever you poured into vertexIndicesMap is flawed, or your -vertexIndex - 1 is flawed.

    More over, and because there are no fancy adaptive tesslation in your terrain, you could do what most usually do to simplify the task and avoid what you are facing by generating a simple grid mesh, and then only, sample height for the vertices of the grid mesh. It greatly simplify things up.
     
    Bunny83 likes this.
  3. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,965
    Welcome to debugging!

    Here are some notes on IndexOutOfRangeException and ArgumentOutOfRangeException:

    http://plbm.com/?p=236

    Steps to success:
    - find which collection it is (critical first step!)
    - find out why it has fewer items than you expect
    - fix whatever logic is making the indexing value exceed the collection
    - remember you might have more than one instance of this script in your scene/prefab
     
  4. sambutle

    sambutle

    Joined:
    Sep 6, 2022
    Posts:
    2
    This exception means that you're trying to access a collection item by index, using an invalid index. An index is invalid when it's lower than the collection's lower bound or greater than or equal to the number of elements it contains. Indexing an empty list will always throw an exception. Use a method like Add to append the item to the end of the list, or Insert to place the item in the middle of the list somewhere, etc. You cannot index into a c# list if that offset doesn't exist. IndexOutOfRangeException exception is thrown as a result of developer error. Instead of handling the exception, you should diagnose the cause of the error and correct your code.

    Handling the Exception:

    Use for-each loop: This automatically handles indices while accessing the elements of an array.

    Use Try-Catch: Consider enclosing your code inside a try-catch statement and manipulate the exception accordingly. As mentioned, C# won’t let you access an invalid index and will definitely throw an IndexOutOfRangeException. However, we should be careful inside the block of the catch statement, because if we don’t handle the exception appropriately, we may conceal it and thus, create a bug in your application.