I have a Unity project in which I have the necessary code to create a texture anywhere from 2x2 to 512x512 and fill it with perlin noise. I am using this texture to populate a map of blocks (think minecraft) .
The map generates correctly, but Unity starts lagging with that many cubes?
This is an image of the generated map, 256x256.
Any leads in the right direction would be appreciated, I'm just stumped on how to get passed this.
This is the method to populate the map
private void GenerateMap ()
{
for (int x = 0; x < creator.resolution; x++) {
for (int z = 0; z < creator.resolution; z++) {
Object newCube = Instantiate (cube, new Vector3(x, Mathf.Round (texture.GetPixel (x, z).b * 10), z), Quaternion.identity);
newCube.name = "Cube: " + x + ", " + z;
}
}
Debug.Log ("Finished generating world");
}
Probably you should try to load them dynamically as minecraft does to not having to process all the cubes on each tick.
You cannot have that many gameobjects in scene.
Should create mesh chunks (so one mesh piece basically replaces hundreds of cubes)
Browse through the huge minecraft-thread in unity forums: (plenty of explanations and samples too)
http://forum.unity3d.com/threads/after-playing-minecraft.63149/
Or just search for unity minecraft terrain, there are many tutorials for it.
Related
I've managed to put together a procedural terrain with defined regions and I am looking to procedurally place objects within the world within these regions. The regions are defined by their height and I am trying to utilise this to correctly place certain objects in certain regions however my result seems to come out slightly odd where objects are able to spawn outside the defined region height. I am using an AnimationCurve as a mesh height curve to prevent water areas from becoming terrain like. I am unsure if this is causing the issue behind in the correct placement. Would appreciate any insight into where I might be going wrong
Defined regions:
The Rock region is defined with a height of 0.7 and I try to spawn trees on the map only at a Rock location
Spawning object (Spawn 10) at rock location
int amount = 0;
for (int y = 0; y < mapHeight; y++)
{
if(amount < 10)
{
for (int x = 0; x < mapWidth; x++)
{
float currentHeight = noiseMap[x, y];
if(currentHeight.ToString("f1") == (0.7f).ToString())
{
Debug.Log(currentHeight.ToString("f1"));
Vector3 spawnPosition = new Vector3(Random.Range((x), (mapWidth / 2)), currentHeight, Random.Range(y, (mapHeight / 2)));
var block = Instantiate(AssetsToSpawn[0].AssetPrefab, spawnPosition, Quaternion.identity);
block.transform.SetParent(this.transform);
amount++;
break;
}
}
} else
{
return;
}
Result
Some seem to spawn in the right location albeit looking slightly weird but the one on the far left is finding itself on flat land, with water and sand; an area not defined as 0.7 or Rock type.
I think the issue lies in the line
Vector3 spawnPosition = new Vector3(Random.Range((x), (mapWidth / 2)), currentHeight, Random.Range(y, (mapHeight / 2)));
you seem to already iterate your map grid using x and y so why pick random positions on your map that might be anywhere between this current position and the center of the map?
I think you would rather want a random position within the current field and do e.g.
Vector3 spawnPosition = new Vector3(x + Random.Range(-0.5f, 0.5f), currentHeight, y + Random.Range(-0.5f, 0.5f));
Besides that why go through strings in
if(currentHeight.ToString("f1") == (0.7f).ToString())
I see that it's probably for the rounding but I would still prefer to rather do e.g.
if(Mathf.Abs(currentHeight - 0.7f) <= 0.05f)
which would have about the same effect but the threshold is better to control.
However, sounds to me like rock rather would be anything between 0.49 and 0.7 actually so actually it should be
if(currentHeight > 0.49f && currentHeight <= 0.7f)
Finally, unless you store somewhere which map position you already populated with a tree your outer for loop will always over and over enter at the exact same grid position, the first one that is encountered to fulfill your inner loop's condition!
So far you where always using the exact se position for all 10 trees, only the random position caused that it didn't seem so.
I am working on a voxel system for my game that uses dynamic loading of chunks. To optimize it, I have a pool of chunks and a render distance, and what I want to do is fill the pool with a proper amount of chunks. So, I need a way to find that amount. I have tried the following but it seems very inefficient.
private void CreatePool()
{
int poolSize = 0;
for (int x = -m_RenderDistance; x <= m_RenderDistance; x++) {
for (int y = -m_RenderDistance; y <= m_RenderDistance; y++) {
for (int z = -m_RenderDistance; z <= m_RenderDistance; z++) {
if (Position3Int.DistanceFromOrigin(new Position3Int(x, y, z)) <= m_RenderDistance)
poolSize++;
}
}
}
}
More formally, the question involes finding the amount of unique cubes with integer coorindates with a certain distance from the origin.
If you think there is a better way to approach this or I am doing something fundamentally wrong, let me know.
Thanks,
Quintin
I assume its the distance check that you think is inefficient? What you've got shouldn't be too bad if you're just getting the count on Start() or Awake().
Draco18s solution is fine if you are okay with a cubed result. If you want a spherical result without a distance check, you can try some formulation of the volume of a sphere: 4/3*PI*r^3
checkout Bresenham's circle.
Here's a approximation algorithm for a filled 3d Bresenham Circle that I have. It is very similar to what you have already, just with a more effecient squared dist check and a minor adjustment to get a more attractive bresenham-looking circle):
public static List<Vector3> Get3DCircleKeys(int radius){
List<Vector3> keys = new List<Vector3>();
for(int y=-radius; y<=radius; y++){
for(int x=-radius; x<=radius; x++){
for(int z =-radius; z<=radius; z++){
// (+ radius*.08f) = minor modification to match Bresenham result
if(x*x+y*y+z*z <= radius*radius + radius*.08f){
keys.Add(new Vector3(x,y,z));
}
}
}
}
return keys;
}
This, however, will deliver a different count than the volume of sphere would give you, but with some tweaking to it or to the sphere volume calculation, it could be good enough, or at least, more efficient than instantiating a full volume of a cube, where many of the voxels will be outside of the bounds of the render distance.
I'm building a very simple 2d tile map. It just spawns a few different grass tiles in random locations here's what it looks like:
public int tileHeight; //y
public int tileWidth; //x
int tileHeightCounter;
int tileWidthCounter;
public GameObject[] floorTiles;
void Start(){
tileHeightCounter = 0;
tileWidthCounter = 0;
while(tileHeightCounter < tileHeight){
Vector3 tileSpawnPoint = new Vector3 (tileWidthCounter, tileHeightCounter, 0);
GameObject groundTiles = (GameObject)Instantiate (floorTiles[Random.Range(0, floorTiles.Length)], tileSpawnPoint, Quaternion.identity);
groundTiles.transform.parent = transform;
if (tileWidthCounter == tileWidth) {
tileWidthCounter = 0;
tileHeightCounter++;
}
tileWidthCounter++;
}
}
I've run into two problems- say your tileHeight is 10 and your tileWidth is also 10 then the map it generates should be a 10x10 with 100 total tiles randomly distributed.
Instead two weird things are occurring the first is that if your map is 10x10 it actually generates a 10x9 meaning it stops one layer short on the y axis. The second is a grid(grass tile) is being created at 0,0 but the rest of the map is being created with at least x being 1 meaning that the map has a single tile attached to the bottom left sticking out.
I'm a bit confused as to whats going on here or how to fix it. Any help is much appreciated.
The issue is that you're using a < less than, so once it actually hits the tileHeight it exits the loop one iteration too early. Make it <=.
I'm trying to draw lines with offset to main line like on attachment.
I have problems with my code. It generating intersections and cusps on the lines. (attachment)
Maybe someone can help me with this code provide any working example that I can follow.
// LEFT SIDE OF MAIN LINE
int numberOfLines = 10;
float offset = 10f;
lastLinePoints = outerPoints; // outerPoint = Points from Main Line
for(int i = 0; i < numberOfLines; i++)
{
List<Vector3> tempPoints = new List<Vector3> ();
for (int k = 0; k < lastLinePoints.Count; k++) {
if (k + 1 < lastLinePoints.Count) {
Vector3 direction = lastLinePoints [k + 1] - lastLinePoints [k];
// up direction:
Vector3 up = new Vector3(0.0f, 1.0f, 0.0f);
// find right vector:
Vector3 right = Vector3.Cross(direction.normalized, up.normalized);
Vector3 newPoint = lastLinePoints [k] + (right * offset);
tempPoints.Add (newPoint);
}
}
VectorLine lineTemp = new VectorLine ("lineCurved", tempPoints, 120f / _camera2DObject.GetComponent<Camera> ().orthographicSize, LineType.Continuous);
lineTemp.Draw3D ();
lastLinePoints = tempPoints;
}
After some research I know that solution for drawing curved parallel lines can be difficult. I found also some algorithms (https://hal.inria.fr/inria-00518005/document) but this mathematics is to hard for me to make code from it.
After suggestion from #jstreet I tried CLIPPER library. Results are very good but is it possible to draw only parallel line instead closed polygon around line (like on attachment)
UPDATE
I wrote another question becouse I think that using CLIPPER for parallel lines is worth it. LINK TO question
From My Previous Experience, lot of time will be spent to solve your problem without applying a polyline curves offset algorithm,so my advice is to start implementing any of the algorithms regardless the mathematical difficulties. choose one of the published algorithm that suits exactly your case, it could be easier than implementing an algorithm for any shape.
But you can get the below link a shot
https://github.com/skyrpex/clipper
calculate parallel line parameters: you will need to calculate offset as coefficient (angle) remains the same.
calculate line intersections between neighbouring lines based on calculated values from step 1.
use splines over sequential sets of three intersection points. For splines you can use any cubic spline library, there are plenty in guthub (https://gist.github.com/dreikanter/3526685) or codeproject (http://www.codeproject.com/Articles/560163/Csharp-Cubic-Spline-Interpolation).
I've succesfully made a marching cubes class in C# XNA and am using Lib noise to generate 3d perlin noise, but when I tried to generate terrain using the values of the perlin noise as the densities for my marching cubes it generates a large chunk of marching cubes with seemingly random triangles inside of them. I separated the marching cube and gave it arbitrary 3d arrays of densities to run through so I could make sure everything was working and it looked fine, and I had the terrain generation code generate normal cubes and I got a normal looking terrain, but the problem is the corners of each cube gets values from the noise are always switching from negative to positive so fast that the marching cubes just look like a jumbled mess.
This is the code I'm using to generate the terrain:
public MarchingCube[, ,] getTerrainChunk(int size, int stepsize)
{
MarchingCube[, ,] temp = new MarchingCube[size / stepsize, size / stepsize, size / stepsize];
for (int x = 0; x < size; x += stepsize)
{
for (int y = 0; y <size; y += stepsize)
{
for (int z = 0; z < size; z += stepsize)
{
Vector3[] corners = { new Vector3(x,y,z), new Vector3(x,y+stepsize,z),new Vector3(x+stepsize,y+stepsize,z),new Vector3(x+stepsize,y,z), new Vector3(x,y,z+stepsize), new Vector3(x,y+stepsize,z+stepsize),
new Vector3(x+stepsize,y+stepsize,z+stepsize), new Vector3(x+stepsize,y,z+stepsize)};
float[] densities = { GetDensity(corners[0]),GetDensity(corners[1]),GetDensity(corners[2]),GetDensity(corners[3]),GetDensity(corners[4]),
GetDensity(corners[5]),GetDensity(corners[6]),GetDensity(corners[7])};
if (x == 0 && y == 0 && z == 0)
{
temp[x / stepsize, y / stepsize, z / stepsize] = new MarchingCube(densities, corners, device);
}
else
temp[x / stepsize, y / stepsize, z / stepsize] = new MarchingCube(densities, corners);
}
}
}
return temp;
}
and the GetDensity method is as follows:
private float GetDensity(Vector3 point)
{
return (float)terrain.GetValue(point));
}
I think the problem is that I'm not using the noise correctly to get the densities of the marching cubes corners, but so far my google search results haven't been much help at all. So does anyone know how to use the noise properly to generate smooth looking terrain? Or what else may be causing this problem?
I posted screen shots at http://imgur.com/a/D1uMC , the first two are shown using marching cubes and the last one is normal cubes.
Edit:
So from the pictures I figured out that the marching cubes are actually working how they are supposed to with the values they are being given, the problem is defiantly with my noise and how I"m using it. Does anyone know any good resources for 3d terrain generation based on noise?
The problem was how I was reading in the noise, by default I was incredibly "zoomed out" so by changing stepsize to a float and then using smaller increments I was able to get the desired results. Basically "zoomed in" on the area of noise.