This question already has answers here:
What is an IndexOutOfRangeException / ArgumentOutOfRangeException and how do I fix it?
(5 answers)
Closed 4 months ago.
I am trying to make mesh rendering in Unity 3D but the code is supposed to work, Here is what it said: IndexOutOfRangeException: Index was outside the bounds of the array. MeshGen.CreateShape () (at Assets/MeshGen.cs:33)
MeshGen.Start () (at Assets/MeshGen.cs:22)
Here is the code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(MeshFilter))]
public class MeshGen : MonoBehaviour {
Mesh mesh;
Vector3[] vertices;
int[] triangles;
public int xSize = 20;
public int zSize = 20;
// Start is called before the first frame update
void Start()
{
mesh = new Mesh();
GetComponent<MeshFilter>().mesh = mesh;
CreateShape();
UpdateMesh();
}
void CreateShape()
{
vertices = new Vector3[(xSize * 1) * (zSize * 1)];
int i = 0;
for (int z = 0; z <= zSize; z++)
{
for (int x = 0; x <= xSize; x++)
{
vertices[i] = new Vector3(x, 0, z);
i++;
}
}
triangles = new int[xSize * zSize * 6];
int vert = 0;
int tris = 0;
for (int x = 0; x < xSize; x++)
{
triangles[tris + 0] = vert + 0;
triangles[tris + 1] = vert + xSize + 1;
triangles[tris + 2] = vert + 1;
triangles[tris + 3] = vert + 1;
triangles[tris + 4] = vert + xSize + 1;
triangles[tris + 5] = vert + xSize + 2;
vert++;
tris += 6;
}
}
void UpdateMesh()
{
mesh.Clear();
mesh.vertices = vertices;
mesh.triangles = triangles;
mesh.RecalculateNormals();
}
private void OnDrawGizmos()
{
if (vertices == null)
{return;}
for (int i = 0; i < vertices.Length; i++)
{
Gizmos.DrawSphere(vertices[i], .1f);
}
}
}
I tried fixing it, tried searching on google and i made sure that it is right.
This was the only error i got.
Let's check this:
public int xSize = 20;
public int zSize = 20;
// array of size 20*20=400 : indexes in range [0:399]
vertices = new Vector3[(xSize * 1) * (zSize * 1)];
int i = 0;
// loop in range [0:20] (21 iterations)
for (int z = 0; z <= zSize; z++)
{
// loop in range [0:20] (21 iterations)
for (int x = 0; x <= xSize; x++)
{
vertices[i] = new Vector3(x, 0, z);
i++;
// after we reach z=18 and x=20, i=399
// from now on, we are OutOfBounds
}
}
You should probably switch to strict inequality < instead of <=
Related
I am relatively new to Terrain Generation in Unity, and am currently stuck in one place. I have followed Brackey's tutorial on terrain generation, and in that tutorial, he uses something like this:
float y = Mathf.PerlinNoise(x, z) * 2f;
To manipulate the height of the terrain. I also followed Sebastian Lague's tutorial on this. This is where I am stuck.
I want to use Sebastian Lague's Noise.cs file that he created (can be found on his GitHub) to manipulate the terrain height.
The reason is because this noise generator, rather than Mathf.PerlinNoise(), gives you a much better control over the texture it outputs. The problem is, Noise.cs will return a 2D float array, while Mathf.PerlinNoise() returns a 1D float value. Is there a way for Noise.cs to return a float value, just like Mathf's function?
Noise.cs:
using UnityEngine;
using System.Collections;
public static class Noise {
public static float[,] GenerateNoiseMap(int mapWidth, int mapHeight, int seed, float scale, int octaves, float persistance, float lacunarity, Vector2 offset) {
float[,] noiseMap = new float[mapWidth,mapHeight];
System.Random prng = new System.Random (seed);
Vector2[] octaveOffsets = new Vector2[octaves];
for (int i = 0; i < octaves; i++) {
float offsetX = prng.Next (-100000, 100000) + offset.x;
float offsetY = prng.Next (-100000, 100000) + offset.y;
octaveOffsets [i] = new Vector2 (offsetX, offsetY);
}
if (scale <= 0) {
scale = 0.0001f;
}
float maxNoiseHeight = float.MinValue;
float minNoiseHeight = float.MaxValue;
float halfWidth = mapWidth / 2f;
float halfHeight = mapHeight / 2f;
for (int y = 0; y < mapHeight; y++) {
for (int x = 0; x < mapWidth; x++) {
float amplitude = 1;
float frequency = 1;
float noiseHeight = 0;
for (int i = 0; i < octaves; i++) {
float sampleX = (x-halfWidth) / scale * frequency + octaveOffsets[i].x;
float sampleY = (y-halfHeight) / scale * frequency + octaveOffsets[i].y;
float perlinValue = Mathf.PerlinNoise (sampleX, sampleY) * 2 - 1;
noiseHeight += perlinValue * amplitude;
amplitude *= persistance;
frequency *= lacunarity;
}
if (noiseHeight > maxNoiseHeight) {
maxNoiseHeight = noiseHeight;
} else if (noiseHeight < minNoiseHeight) {
minNoiseHeight = noiseHeight;
}
noiseMap [x, y] = noiseHeight;
}
}
for (int y = 0; y < mapHeight; y++) {
for (int x = 0; x < mapWidth; x++) {
noiseMap [x, y] = Mathf.InverseLerp (minNoiseHeight, maxNoiseHeight, noiseMap [x, y]);
}
}
return noiseMap;
}
}
MeshGenerator.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(MeshFilter))]
public class MeshGenerator : MonoBehaviour
{
Mesh mesh;
Vector3[] vertices;
int[] triangles;
public int xSize = 20;
public int zSize = 20;
int mapWidth;
int mapHeight;
int seed;
float scale;
int octaves;
float persistance;
float lacunarity;
Vector2 offset;
// Start is called before the first frame update
void Start()
{
// Initialize everything
mesh = new Mesh();
GetComponent<MeshFilter>().mesh = mesh;
CreateShape();
UpdateMesh();
}
void CreateShape()
{
// Creating the grid of vertices
vertices = new Vector3[(xSize + 1) * (zSize + 1)];
// Setting vertex positions
for (int i = 0, z = 0; z <= zSize; z++)
{
for (int x = 0; x <= xSize; x++)
{
//float y = Mathf.PerlinNoise(x * .3f, z * .3f) * 2f;
float y = Noise.GenerateNoiseMap(mapWidth, mapHeight, seed, scale, octaves, persistance, lacunarity, offset);
vertices[i] = new Vector3(x, y, z);
i++;
}
}
triangles = new int[xSize * zSize * 6];
int vert = 0;
int tris = 0;
for (int z = 0; z < zSize; z++)
{
for (int x = 0; x < xSize; x++)
{
triangles[tris + 0] = vert + 0;
triangles[tris + 1] = vert + xSize + 1;
triangles[tris + 2] = vert + 1;
triangles[tris + 3] = vert + 1;
triangles[tris + 4] = vert + xSize + 1;
triangles[tris + 5] = vert + xSize + 2;
vert++;
tris += 6;
}
vert++;
}
}
void UpdateMesh()
{
// Clear mesh data, reset with above vars and recalculate normals
mesh.Clear();
mesh.vertices = vertices;
mesh.triangles = triangles;
mesh.RecalculateNormals();
}
private void OnDrawGizmos()
{
if (vertices == null) return;
Gizmos.color = Color.red;
// Draw Vertex Gizmos
for (int i = 0; i < vertices.Length; i++)
{
Gizmos.DrawSphere(vertices[i], .1f);
}
}
}
I've figured it out, I would've had to put vertices[i] = new Vector3(x, y[x, z], z); Now I've already tried this, but I suppose visual studio bugged and did not save it properly. Anyways, yes, I just needed to use x/y to pick out my float.
This question already has answers here:
List of object is null even after calling constructor [duplicate]
(4 answers)
Field 'xxx' is never assigned to, and will always have its default value null
(2 answers)
Closed 1 year ago.
(edited for more context)
When I pass my Amplifiers and Frequencies float arrays into my functions corresponding arguments it is passed as null in the function.
Here is a code sample:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(MeshFilter))]
[RequireComponent(typeof(MeshCollider))]
public class MeshGenerator: MonoBehaviour
{
Mesh mesh;
Vector3[] vertices;
int[] triangles;
float[] Amplifiers;
float[] Frequencies;
public int xSize = 20;
public int zSize = 20;
public int Layers = 1;
public float Seed = .3f;
float rNum = 1f;
void Start()
{
mesh = new Mesh();
GetComponent<MeshFilter>().mesh = mesh;
CreateShape();
UpdateMesh();
float[] Frequencies = new float[Layers];
float[] Amplifiers = new float[Layers];
for (int i = 0; i < Layers; i++)
{
Amplifiers[i] = Random.Range(1.5f, 2.5f);
Frequencies[i] = Random.Range(.25f, .4f);
}
}
private void Update()
{
rNum = Random.Range(1f, 2.5f);
}
float TerrainPerlin(int layers, float[] ampArray, float[] freqArray, int x, int y, float seed)
{
if (ampArray == null || freqArray == null)
{
Debug.Log("Amplifier Array or Frequency Array is null");
return Mathf.PerlinNoise(x * .3f, y * .3f) * 2f;
}
if (ampArray.Length != layers || freqArray.Length != layers)
{
Debug.Log("Amplifier Array or Frequency Array and the amount of Layers aren't equal");
return Mathf.PerlinNoise(x * .3f, y * .3f) * 2f;
}
float result = 0;
for (int i = 0; i < layers; i++)
{
result += Mathf.PerlinNoise(x * (freqArray[i] + seed), (y * freqArray[i]) + seed) * ampArray[i];
}
return result;
}
void CreateShape()
{
vertices = new Vector3[(xSize + 1) * (zSize + 1)];
for (int i = 0, z = 0; z <= zSize; z++)
{
for (int x = 0; x <= xSize; x++)
{
//float y = Mathf.PerlinNoise(x * seed, z * (seed * 1.5f)) * (amplifier * rNum);
float y = 0f;
y = TerrainPerlin(Layers, Amplifiers, Frequencies, x, z, Seed);
vertices[i] = new Vector3(x, y, z);
i++;
}
}
triangles = new int[xSize * zSize * 6];
int vert = 0;
int tris = 0;
for (int z = 0; z < zSize; z++)
{
for (int x = 0; x < xSize; x++)
{
triangles[tris + 0] = vert + 0;
triangles[tris + 1] = vert + xSize + 1;
triangles[tris + 2] = vert + 1;
triangles[tris + 3] = vert + 1;
triangles[tris + 4] = vert + xSize + 1;
triangles[tris + 5] = vert + xSize + 2;
vert++;
tris += 6;
}
vert++;
}
}
void UpdateMesh()
{
mesh.Clear();
mesh.vertices = vertices;
mesh.triangles = triangles;
mesh.RecalculateNormals();
mesh.RecalculateBounds();
MeshCollider meshCollider = gameObject.GetComponent<MeshCollider>();
meshCollider.sharedMesh = mesh;
mesh.Optimize();
}
void OnDrawGizmos()
{
if (vertices == null)
return;
for (int i = 0; i < vertices.Length; i++)
{
Gizmos.DrawSphere(vertices[i], .1f);
}
}
}
Before i added the null handling and console messages this was the error i was getting
NullReferenceException: Object reference not set to an instance of an object
MeshGenerator.TerrainPerlin (System.Int32 layers, System.Single[] ampArray, System.Single[] freqArray, System.Int32 x, System.Int32 y, System.Single seed) [at Assets/Scripts/MeshGenerator.cs:51]
Context on what I am trying to do:
I'm trying to make procedural terrain in unity I have been able to use a single layer of Perlin Noise to do that however I want to use multiple octaves of Perlin Noise to generate a terrain mesh so I can have better looking terrain that has mountains and hills, and more detail. However when I try to use my function with randomly generated arrays it just returns null values to the arguments.
This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 1 year ago.
so i have a 3 dimensional int array for my voxel game, and for debugging purposes i set all the blocks in the chunk to id 1(dirt) but on line 18 it gives the error OBJECT REFERENCE NOT SET TO AN INSTANCE OF AN OBJECT. and i know what this means, that the initial value has not been set. i just cant figure out WHY it would return this because i AM setting the initial value.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Chunk : MonoBehaviour
{
Mesh mesh = new Mesh();
int[,,] chunkData = new int[4, 64, 4];
// Start is called before the first frame update
void Start()
{
for (int x = 0; x < 4; x++)
{
for (int y = 0; y < 64; y++)
{
for (int z = 0; z < 4; z++)
{
chunkData[x, y, z] = 1;// returns error here-----------------------------------------------------------------------------------------------------------------------------------
}
}
}
UpdateChunk();
}
// Update is called once per frame
void Update()
{
}
void UpdateChunk()
{
List<Vector3> vertlist = new List<Vector3>();
List<int> tris = new List<int>();
int currentvert = 0;
for (int x = 0; x < 4; x++)
{
for (int y = 0; y < 64; y++)
{
for (int z = 0; z < 4; z++)
{
Vector3[] adjacentBlocks = Block.GetAdjacentChunkBlocks(new Vector3(x, y, z));
for (int i = 0; i < adjacentBlocks.Length; i++)
{
Debug.Log(adjacentBlocks[i]);
}
foreach(Vector3 other in adjacentBlocks)
{
Vector3 result = other - new Vector3(x, y, z);
if (result == Vector3.up && chunkData[(int)other.x, (int)other.y, (int)other.z] == 0 && chunkData[x, y, z] != 0)
{
Debug.Log("upface open");
vertlist.Add(new Vector3(x, y + 1, z));
vertlist.Add(new Vector3(x + 1, y + 1, z));
vertlist.Add(new Vector3(x, y + 1, z + 1));
vertlist.Add(new Vector3(x + 1, y + 1, z + 1));
tris.Add(2 + currentvert);
tris.Add(3 + currentvert);
tris.Add(0 + currentvert);
tris.Add(0 + currentvert);
tris.Add(3 + currentvert);
tris.Add(1 + currentvert);
}
currentvert += 4;
}
Debug.Log("----------------------------------------------------------");
}
}
}
mesh.vertices = vertlist.ToArray();
mesh.triangles = tris.ToArray();
mesh.RecalculateNormals();
GetComponent<MeshFilter>().mesh = mesh;
}
}
If Start is called when chunkData is new int[4, 64, 4]; it will work.
I suspect some other piece of code is setting chunkData to null.
Make chunkData readonly and the culprit will reveal itself.
I'am trying to setup simple Terrain Generator in unity following tutorial, so far it works as intended, but i wanted to do more "natural" look and found out that i need to do Octaves or MultiLevel noise.
Everything i found online regarding Multilevel Perlin noise, was not understandable for me or used completly different methode.
using UnityEngine;
[RequireComponent(typeof(MeshFilter))]
public class Mesh_Generator : MonoBehaviour
{
#region Variables
Mesh mesh;
Vector3[] vertices;
//Vector2[] Uvs;
Color[] colors;
int[] triangles;
[Range(1, 9999)]
public int xSize = 100;
[Range(1, 9999)]
public int zSize = 100;
public Gradient gradient;
public float MinHeight = 0;
public float MaxHeight = 0;
public bool Reset_Min_Max;
#endregion
#region Octaves
[Range(1, 6)]
public int Octaves = 6;
public int Scale = 50;
public float offsetX = 0f;
public float offsetY = 0f;
public float Frequency_01 = 5f;
public float FreqAmp_01 = 3f;
public float Frequency_02 = 6f;
public float FreqAmp_02 = 2.5f;
public float Frequency_03 = 3f;
public float FreqAmp_03 = 1.5f;
public float Frequency_04 = 2.5f;
public float FreqAmp_04 = 1f;
public float Frequency_05 = 2f;
public float FreqAmp_05 = .7f;
public float Frequency_06 = 1f;
public float FreqAmp_06 = .5f;
#endregion
#region Start
void Start()
{
mesh = new Mesh();
GetComponent<MeshFilter>().mesh = mesh;
offsetX = Random.Range(0f, 99999f);
offsetY = Random.Range(0f, 99999f);
}
#endregion
void ResetMinMax()
{
MinHeight = 0f;
MaxHeight = 0f;
Reset_Min_Max = false;
}
#region Update
private void Update()
{
if (Reset_Min_Max)
ResetMinMax();
CreateShape();
UpdateMesh();
}
#endregion
#region CreateShape
void CreateShape()
{
#region Vertices
vertices = new Vector3[(xSize + 1) * (zSize + 1)];
for (int i = 0, z = 0; z <= zSize; z++)
{
for (int x = 0; x <= xSize; x++)
{
float y = Calculate(x, z);
vertices[i] = new Vector3(x, y, z);
if (y > MaxHeight)
MaxHeight = y;
if (y < MinHeight)
MinHeight = y;
i++;
}
}
int vert = 0;
int tris = 0;
#endregion
#region Triangles
triangles = new int[xSize * zSize * 6];
for (int z = 0; z < zSize; z++)
{
for (int x = 0; x < xSize; x++)
{
triangles[tris + 0] = vert + 0;
triangles[tris + 1] = vert + xSize + 1;
triangles[tris + 2] = vert + 1;
triangles[tris + 3] = vert + 1;
triangles[tris + 4] = vert + xSize + 1;
triangles[tris + 5] = vert + xSize + 2;
vert++;
tris += 6;
}
vert++;
}
#endregion
#region Gradient Color
colors = new Color[vertices.Length];
for (int i = 0, z = 0; z <= zSize; z++)
{
for (int x = 0; x <= xSize; x++)
{
float Height = Mathf.InverseLerp(MinHeight, MaxHeight, vertices[i].y);
colors[i] = gradient.Evaluate(Height);
i++;
}
}
#endregion
#region UVs
/*
Uvs = new Vector2[vertices.Length];
for (int i = 0, z = 0; z <= zSize; z++)
{
for (int x = 0; x <= xSize; x++)
{
Uvs[i] = new Vector2((float)x / xSize, (float)z / zSize);
i++;
}
}
*/
#endregion
}
#endregion
#region Octaves Calculation
float Calculate(float x, float z)
{
float[] octaveFrequencies = new float[] { Frequency_01, Frequency_02, Frequency_03, Frequency_04, Frequency_05, Frequency_06 };
float[] octaveAmplitudes = new float[] { FreqAmp_01, FreqAmp_02, FreqAmp_03, FreqAmp_04, FreqAmp_05, FreqAmp_06 };
float y = 0;
for (int i = 0; i < Octaves; i++)
{
y += octaveAmplitudes[i] * Mathf.PerlinNoise(
octaveFrequencies[i] * x + offsetX * Scale,
octaveFrequencies[i] * z + offsetY * Scale) ;
}
return y;
}
#endregion
#region UpdateMesh
void UpdateMesh()
{
mesh.Clear();
mesh.vertices = vertices;
mesh.triangles = triangles;
mesh.colors = colors;
//mesh.uv = Uvs;
mesh.RecalculateNormals();
}
#endregion
#region Gizmos
/*
private void OnDrawGizmos()
{
if (vertices == null)
return;
for (int i = 0; i < vertices.Length; i++){
Gizmos.DrawSphere(vertices[i], .1f);
}
}
*/
#endregion
}
In link below is my current result and result which i'am trying to achieve.
https://imgur.com/a/m9B6ga4
is it possible to achieve such result using this method ?
if so would be possible to show script example ?
Thank you a lot.
*updated code again
multi level, or multi octave perlin is just few iterations of standard perlin added together.
An example code could look like this:
float[] octaveFrequencies=new float() {1,1.5f,2,2.5f} ;
float[] octaveAmplitudes=new float() {1,0.9f,0.7f,0.f} ;
float y=0;
for(int i=0;i<octaveFrequencies.Length;i++)
y += octaveAmplitudes[i]* Mathf.PerlinNoise(
octaveFrequencies[i]*x + .3f,
octaveFrequencies[i]* z + .3f) * 2f ;
The numbers you put into arrays will decide the final shape of the noise. Values from the frequencies array are multiplied by your input, values from the amplitudes array are multiplied by the resulting perlin at that layer.
I'm following this tutorial set: https://www.youtube.com/watch?v=owBt9SNKXCI&index=6&list=PLbghT7MmckI4qGA0Wm_TZS8LVrqS47I9R to dynamically build a tile map layout. It works to a point, but it generates a very strange layout with 128 x 128 sized tiles.
Clearly that strange partitioning shouldn't be happening, but I cannot seem to track down what's going on to cause it. Here is my version of the code, which is mostly identical to quill18creates's version sans a few small differences:
using UnityEngine;
using System.Collections;
[ExecuteInEditMode]
public class TileMap : MonoBehaviour {
public int size_x = 100;
public int size_z = 50;
public float tileSize = 1.0f;
public Texture2D terrainTiles;
int tileResolution = 128;
// Use this for initialization
void Start () {
BuildMesh();
}
Color[][] ChopUpTiles() {
int numTilesPerRow = terrainTiles.width / tileResolution;
int numRows = terrainTiles.height / tileResolution;
Color[][] tiles = new Color[numTilesPerRow*numRows][];
for(int y=0; y < numRows; y++) {
for(int x=0; x < numTilesPerRow; x++) {
tiles[y * numTilesPerRow + x] = terrainTiles.GetPixels( x*tileResolution , y*tileResolution, tileResolution, tileResolution );
}
}
return tiles;
}
void BuildTexture() {
//DTileMap map = new DTileMap(size_x, size_z);
int texWidth = size_x * tileResolution;
int texHeight = size_z * tileResolution;
Texture2D texture = new Texture2D(texWidth, texHeight);
Color[][] tiles = ChopUpTiles();
for(int y=0; y < size_z; y++) {
for(int x=0; x < size_x; x++) {
Color[] p = tiles[Mathf.RoundToInt(Random.Range(0, 5))];
texture.SetPixels(x * tileResolution, y * tileResolution, tileResolution, tileResolution, p);
}
}
//texture.filterMode = FilterMode.Bilinear;
texture.wrapMode = TextureWrapMode.Clamp;
texture.Apply();
MeshRenderer mesh_renderer = GetComponent<MeshRenderer>();
mesh_renderer.sharedMaterials[0].mainTexture = texture;
}
public void BuildMesh() {
int numTiles = size_x * size_z;
int numTris = numTiles * 2;
int vsize_x = size_x + 1;
int vsize_z = size_z + 1;
int numVerts = vsize_x * vsize_z;
// Generate the mesh data
Vector3[] vertices = new Vector3[ numVerts ];
Vector3[] normals = new Vector3[numVerts];
Vector2[] uv = new Vector2[numVerts];
int[] triangles = new int[ numTris * 3 ];
int x, z;
for(z=0; z < vsize_z; z++) {
for(x=0; x < vsize_x; x++) {
vertices[ z * vsize_x + x ] = new Vector3( x*tileSize, 0, -z*tileSize );
normals[ z * vsize_x + x ] = Vector3.up;
uv[ (z * vsize_x) + x ] = new Vector2( (float)x / size_x, (float)z / size_z );
}
}
Debug.Log ("Done Verts!");
for(z=0; z < size_z; z++) {
for(x=0; x < size_x; x++) {
int squareIndex = z * size_x + x;
int triOffset = squareIndex * 6;
triangles[triOffset + 0] = z * vsize_x + x + 0;
triangles[triOffset + 2] = z * vsize_x + x + vsize_x + 0;
triangles[triOffset + 1] = z * vsize_x + x + vsize_x + 1;
triangles[triOffset + 3] = z * vsize_x + x + 0;
triangles[triOffset + 5] = z * vsize_x + x + vsize_x + 1;
triangles[triOffset + 4] = z * vsize_x + x + 1;
}
}
// Create a new Mesh and populate with the data
Mesh mesh = new Mesh();
mesh.vertices = vertices;
mesh.triangles = triangles;
mesh.normals = normals;
mesh.uv = uv;
// Assign our mesh to our filter/renderer/collider
MeshFilter mesh_filter = GetComponent<MeshFilter>();
MeshCollider mesh_collider = GetComponent<MeshCollider>();
mesh_filter.mesh = mesh;
mesh_collider.sharedMesh = mesh;
BuildTexture();
}
}
I don't get exactly what part is wrong in the image but I think it is that the same tiles are lumping together.
I tried your code and it works well for me. But I guess the following part could be causing the lumping together problem for you:
Color[] p = tiles[Mathf.RoundToInt(Random.Range(0, 5))];
Instead you should do:
Color[] p = tiles[Random.Range(0, 5)];
Because, the other way, Random is generating float numbers and maybe they are near the each other that rounding them to the integer gives same tile. Give it a try.
Also just reminding, make sure the width and the height of your texture is divisible by 128.
Well, it was definitely a size issue, but there was also an issue with positioning. Tiles have to start at the bottom-left corner for the coordinate system to find them.