I use 9 similar for loops to create such hexagon which is made up of smaller hexagons.
My question is
How do I replace 9 for loops with just 1 for loop? Any ideas, much appreciated.
Middle column
(x=0,y=(-4;4)
for (int x = 0; x < 1; x++)
{
for (int y = 4; y > -5; y--)
{
Instantiate(cell, new Vector2(x, y), Quaternion.Euler(0.0f, 0.0f, 90.0f));
}
}
First column right
(x=1,y=(-3.5;3.5))
for (float x = 0.75f; x < 1.75; x++)
{
for (float y = 3.5f; y > -4.5; y--)
{
Instantiate(cell, new Vector2(x,y), Quaternion.Euler(0.0f,0.0f,90.0f));
}
}
Second column right
(x=2,y=(-3;3))
for (float x = 1.5f; x < 2.5f; x++)
{
for (int y = 3; y > -4; y--)
{
Instantiate(cell, new Vector2(x, y), Quaternion.Euler(0.0f, 0.0f, 90.0f));
}
}
Third column right
(x=3,y=(-2.5;2.5))
for (float x = 2.25f; x < 3.25; x++)
{
for (float y = 2.5f; y > -3.5; y--)
{
Instantiate(cell, new Vector2(x, y), Quaternion.Euler(0.0f, 0.0f, 90.0f));
}
}
Fourth column right
(x=4,y=(-2;2))
for (int x = 3; x < 4; x++)
{
for (int y = 2; y > -3; y--)
{
Instantiate(cell, new Vector2(x, y), Quaternion.Euler(0.0f, 0.0f, 90.0f));
}
}
First column left
(x=-1,y=(-3.5;3.5))
for (float x = -0.75f; x < 0.25; x++)
{
for (float y = 3.5f; y > -4.5; y--)
{
Instantiate(cell, new Vector2(x, y), Quaternion.Euler(0.0f, 0.0f, 90.0f));
}
}
Second column left
(x=-2,y=(-3;3))
for (float x = -1.5f; x < -0.5f; x++)
{
for (int y = 3; y > -4; y--)
{
Instantiate(cell, new Vector2(x, y), Quaternion.Euler(0.0f, 0.0f, 90.0f));
}
}
Third column left
(x=-3,y=(-2.5;2.5))
for (float x = -2.25f; x < -1.25; x++)
{
for (float y = 2.5f; y > -3.5; y--)
{
Instantiate(cell, new Vector2(x, y), Quaternion.Euler(0.0f, 0.0f, 90.0f));
}
}
Fourth column left
(x=-4,y=(-2;2))
for (int x = -3; x < -2; x++)
{
for (int y = 2; y > -3; y--)
{
Instantiate(cell, new Vector2(x, y), Quaternion.Euler(0.0f, 0.0f, 90.0f));
}
}
And I need this:
One formula creates the whole hexagon
Quaternion rot = Quaternion.Euler(0.0f, 0.0f, 90.0f);
for (int x = -4; x <= 4; x++)
{
float xPos = x * 0.75F;
int nrOfYTiles = 9 - Math.Abs(x);
int halfNrOfYTiles = nrOfYTiles / 2;
float yOffset = 0.5F * Math.Abs(x % 2);
for (int y = 0; y < nrOfYTiles; y++)
{
float yPos = y - halfNrOfYTiles + yOffset;
Instantiate(cell, new Vector2(xPos, yPos), rot);
}
}
A more generic solution is:
Quaternion rot = Quaternion.Euler(0.0f, 0.0f, 90.0f);
const int maxTilesX = 9;
const int halfMaxTilesX = 9 / 2;
const int maxTilesY = 9;
int xMin = -halfMaxTilesX;
int xMax = halfMaxTilesX + (maxTilesX % 2); // add one if nr of tiles is odd
const float tileSizeX = 0.75F;
const float tileSizeY = 1F;
const float halTileSizeY = tileSizeY * 0.5F;
for (int x = xMin; x < xMax; x++)
{
float xPos = x * tileSizeX;
int tilesY = maxTilesY - Math.Abs(x);
int halfTilesY = tilesY / 2;
int yMin = -halfTilesY;
int yMax = halfTilesY + (tilesY % 2);
float yOffset = halTileSizeY * Math.Abs(x % 2);
for (int y = yMin; y < yMax; y++)
{
float yPos = (y * tileSizeY) + yOffset;
Instantiate(cell, new Vector2(xPos, yPos), rot);
}
}
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.
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 experimenting with Perlin Noise in C#. I managed to create a working 2D map generator.
But now I want to make my noise tileable. I want that the right edge of the map fits in the left edge of the map.
I'vw been searching for this on the internet and I have tried different things but I could not get it to work. Is there someone who knows a formula for this?
Here is my code:
public float[,] GenerateNoise(float[,] map, int xsize ,int ysize ,float scale, int seed,
int octaves, float persistance,float lacunarity)
{
Random rnd = new Random(seed);
float offsetX = rnd.Next(0, 100000);
float offsetY = rnd.Next(0, 100000);
if (scale <= 0)
{
scale = 0.0001f;
}
float minNoiseHeight = float.MinValue;
float maxNoiseHeight = float.MaxValue;
float[,] fallmap;
//fallmap = FalloffGenerator.GenerateFalloffMap(xsize);
Perlin Noise = new Perlin();
//perlin noise
for (int y = 0; y <= ysize - 1; y++)
{
for (int x = 0; x <= xsize - 1; x++)
{
float amplitude = 1f;
float frequency = 1f;
float noiseHeight = 0;
for (int i = 0; i < octaves; i++)
{
float sampleX = (xsize - x) / scale * frequency + offsetX;
float sampleY = (ysize - y) / scale * frequency + offsetY;
float PerlinValue = (float)Noise.perlin(sampleX, sampleY, 0) * 2 - 1;
map[x, y] = PerlinValue;
noiseHeight += PerlinValue * amplitude;
amplitude *= persistance;
frequency *= lacunarity;
// map[x, y] = map[x, y] - fallmap[x, y];
}
if(noiseHeight > maxNoiseHeight)
{
maxNoiseHeight = noiseHeight;
}else if (noiseHeight < minNoiseHeight)
{
minNoiseHeight = noiseHeight;
}
map[x, y] = noiseHeight;
//map[x, y] = map[x, y] - fallmap[x, y] ;
}
}
return map;
}
I have a simple question. How can I shift a linear array in 3 dimensions?
It seems too work but in the X & Y axis i got an index problem.
The reson why I wanna do this is simple. I want to create a volumetric terrain with a chunk buffer, so i only have to recalulate values on the edges when the viewport is moving.
I have read an article about this system :
Essentially they provide a way to scroll a potentially infinite data
field through a fixed size multi-resolution cache.
So my pipline for the generation part would be:
When viewport moves get axis
Shift the axis
Generate some noise only for the new cells
Triangulate the new cells
Update all cell positions
Here are my other images:
http://forum.unity3d.com/threads/array-shifting-wrong-index-i-x-y-size-z-size-size.425448/#post-2751774
Nobody in the unity forums could answer my question...
public int size;
public float speed;
private byte[] volume;
private byte[] shifted;
public bool widthShift, heightShift, depthShift;
private int widthOffset = 0;
private int heightOffset = 0;
private int depthOffset = 0;
private float time = 0;
private int cube;
void Start()
{
volume = new byte[size * size * size];
shifted = new byte[size * size * size];
cube = size * size * size;
for (int x = 0; x < size; x++)
for (int y = 0; y < size; y++)
for(int z = 0; z < size; z++)
volume[x + y * size + z * size * size] = (x == 0 || y == 0 || z == 0) ? (byte)1 : (byte)0;
}
void Update()
{
time += Time.fixedDeltaTime * speed;
if (time > 1)
{
time = 0;
widthOffset = (widthOffset >= size) ? 0 : widthOffset;
heightOffset = (heightOffset >= size) ? 0 : heightOffset;
depthOffset = (depthOffset >= size) ? 0 : depthOffset;
if (widthShift)
widthOffset++;
else
widthOffset = 0;
if (heightShift)
heightOffset++;
else
heightOffset = 0;
if (depthShift)
depthOffset++;
else
depthOffset = 0;
Shift(widthOffset, heightOffset, depthOffset);
}
}
void Shift(int xOff, int yOff, int zOff)
{
for (int x = 0; x < size; x++)
for (int y = 0; y < size; y++)
for(int z = 0; z < size; z++)
{
int i = ((x + xOff) + (y + yOff) * size + (z + zOff) * size * size);
i = (i >= cube) ? (i - cube) : i;
shifted[x + y * size + z * size * size] = volume[i];
}
}
void OnDrawGizmos()
{
if(Application.isPlaying)
for(int x = 0; x < size; x++)
for(int y = 0; y < size; y++)
for(int z = 0; z < size; z++)
{
Gizmos.color = (shifted[x + y * size + z * size * size] == 1) ? new Color32(0, 255, 0, 255) : new Color32(255, 0, 0, 4);
Gizmos.DrawWireCube(new Vector3(x + 0.5f, y + 0.5f, z + 0.5f), new Vector3(0.95f, 0.95f, 0.95f));
}
}
Give it a try:
void Shift(int xOff, int yOff, int zOff)
{
for (int x = 0; x < size; x++)
for (int y = 0; y < size; y++)
for(int z = 0; z < size; z++)
{
int nx = (x + xOff) % size;
int ny = (y + yOff) % size;
int nz = (z + zOff) % size;
int i = (nx + ny * size + nz * size * size);
shifted[x + y * size + z * size * size] = volume[i];
}
}
I am trying to achieve drawing triangles from a list of Vector3 Elements.
Previously I have used a heightmap to create vertices and indices however this worked out well because it was a rectangle in a 2d array but not a list.
How would I go about (or modify) my existing code to deal with a list instead of a 2d array.
My existing code for Vertices:
public VertexPositionNormalTexture[] getVerticies(float[,] heightData)
{
VertexPositionNormalTexture[] vertices = new VertexPositionNormalTexture[terrainLength * terrainWidth];
for (int y = 0; y < terrainLength; y++)
{
for (int x = 0; x < terrainWidth; x++)
{
// position the vertices so that the heightfield is centered
// around x=0,z=0
vertices[x + y * terrainWidth].Position.X = terrainScale * (x - ((terrainWidth - 1) / 2.0f));
vertices[x + y * terrainWidth].Position.Z = terrainScale * (y - ((terrainLength - 1) / 2.0f));
vertices[x + y * terrainWidth].Position.Y = (heightData[x, y] - 1);
vertices[x + y * terrainWidth].TextureCoordinate.X = (float)x / terrainScale;
vertices[x + y * terrainWidth].TextureCoordinate.Y = (float)y / terrainScale;
}
}
return vertices;
}
Here is the code for indices:
public int[] getIndicies()
{
int counter = 0;
int [] indices = new int[(terrainWidth - 1) * (terrainLength - 1) * 6];
for (int y = 0; y < terrainLength - 1; y++)
{
for (int x = 0; x < terrainWidth - 1; x++)
{
int lowerLeft = x + y * terrainWidth;
int lowerRight = (x + 1) + y * terrainWidth;
int topLeft = x + (y + 1) * terrainWidth;
int topRight = (x + 1) + (y + 1) * terrainWidth;
indices[counter++] = topLeft;
indices[counter++] = lowerRight;
indices[counter++] = lowerLeft;
indices[counter++] = topLeft;
indices[counter++] = topRight;
indices[counter++] = lowerRight;
}
}
return indices;
}
You'd be looking at List<List<float> or whichever type you're working with here.
Syntax might change slightly.