Eu folosesc Mathf.PerlinNoise
pentru a genera iarbă/apă într-un pătrat 2d. Funcționează așa cum este prevăzut, însă nu obțin o apă foarte interesantă și, uneori, poate arăta foarte goală sau nerealistă; iată o mostră de generare proastă:
Din păcate, mi-a luat aproximativ 20 de încercări pentru a găsi una interesantă, ceea ce vreau este ceva de genul acesta:
Sau ceva de genul acesta, dar nu vreau zone mici de apă:
Poți să copiezi/lipesti componentele de mai jos și să încerci singur cu cuburi de 1×1 (dacă nu ai Odin, șterge doar partea respectivă):
using UnityEngine;
using Sirenix.OdinInspector;
public class GenerateMap : MonoBehaviour
{
[Range(0, 40)]
public int mapWidth = 20;
[Range(0, 40)]
public int mapHeight = 20;
[Range(0, 20)]
public float noiseScale;
[Space]
public GameObject parent;
public GameObject grassTile, waterTile;
[Button("Generate map")]
public void GenerateMap()
{
for (int i = 0; i < parent.transform.childCount; i++)
{
Destroy(parent.transform.GetChild(i).gameObject);
}
float[,] noiseMap = Noise.GenerateNoiseMap(mapWidth, mapHeight, noiseScale);
for (int x = 0; x < mapWidth; x++)
{
for (int y = 0; y < mapHeight; y++)
{
Debug.Log(noiseMap[x, y]);
if (noiseMap[x, y] >= .3)
Instantiate(grassTile, new Vector3(x, 0, y), Quaternion.identity, parent.transform);
else
Instantiate(waterTile, new Vector3(x, 0, y), Quaternion.identity, parent.transform);
}
}
}
}
Zgomot:
using UnityEngine;
public static class Noise
{
public static float[,] GenerateNoiseMap(int mapWidth, int mapHeight, float scale)
{
float[,] noiseMap = new float[mapWidth, mapHeight];
Vector2 offset = new Vector2(Random.Range(0, 100), Random.Range(0, 100));
if (scale <= 0)
scale = .0001f;
for (int y = 0; y < mapHeight; y++)
{
for (int x = 0; x < mapWidth; x++)
{
float sampleX = x / scale + offset.x;
float sampleY = y / scale + offset.y;
float perlinValue = Mathf.PerlinNoise(sampleX, sampleY);
noiseMap[x, y] = perlinValue;
}
}
return noiseMap;
}
}
- Ne puteți ajuta să înțelegem ce criterii folosiți pentru a evalua cât de „interesant” este un anumit model de apă? Înțelegem că vrei să eviți zonele de apă foarte mici, dar nu este clar ce alte criterii sunt în joc. > Por DMGregory.
- @DMGregory Am încercat să postez 2 imagini cu ceea ce am vrut să spun. Dar, în realitate, tot ce vreau să spun este 1-3 formațiuni de apă de dimensiuni medii-mari. uneori conectate, alteori nu. În momentul de față mă trezesc cu apă doar pe margini, sau cu bălți mici. Are sens? > Por Majs.
- Ai încercat să reduci dimensiunea texturii perlin noise și să folosești o suprafață mai mare din ea?- > Por Jay.
- @Jake Am încercat, dar nu există nicio combinație a acestei soluții actuale care să garanteze tipul de corpuri de apă pe care îl doresc, adică nu bălți la întâmplare, nu doar o linie de-a lungul marginii, etc. – > Por Majs.
- @Jake da, m-am gândit și eu la asta, s-ar putea ca în cele din urmă să fac asta,.-. > Por Majs.
Încearcă să cobori scara și să adaugi mai multe octave.
De asemenea, nu aș sugera Mathf.Perlin, deoarece generează zgomotul său omonim Old Perlin, care are o aliniere pătrată vizibilă. În schimb, aș importa Unity.Mathematics și aș folosi Unity.Mathematics.noise.snoise(float2) pentru o bună implementare a zgomotului 2D Simplex.
Luați orice tutorial sau proiect, care utilizează zgomotul „Perlin”, cu un grăunte de sare. De cele mai multe ori Perlin este folosit, sunt pentru că o bibliotecă a inclus funcția sau pentru că autorul a auzit primul de numele său iconic-sonorizant. Rareori Perlin este ales pentru că a fost gândit cu atenție pentru a fi cel mai bun algoritm pentru acel scop.
Ați putea face următoarele:
- Utilizați un număr mai mare pentru
scale
float2 pos = new float2(sampleX, sampleY);
float noiseValue = noise.snoise(pos) + 0.5f*noise.snoise(pos * 2f + new float2(35f, 66f) + 0.25f*noise.snoise(pos * 4f * 2f + new float2(75f, 104f);
unde frecvența se dublează, dar amplitudinea se înjumătățește de fiecare dată. Decalajul are rolul de a împiedica suprapunerea acelorași caracteristici la originea zgomotului. De asemenea, puteți experimenta cu valori ale frecvenței și amplitudinii care nu sunt exact dublul / jumătatea celei anterioare.
EDIT: Reluând partea din postarea dvs. care discută despre ceea ce căutați, poate că ceea ce doriți să faceți este să alegeți 1-3 puncte aleatorii din harta dvs. care desemnează corpuri de apă, să alegeți o rază, să calculați distanța euclidiană la pătrat de la fiecare (plus raza) și să adăugați un zgomot simplex pe acesta pentru a-i da niște limite interesante. Asigurați-vă că frecvența este suficient de joasă și amplitudinea suficient de mare pentru a-l abate suficient de mult de la circular. În cazul lacurilor care se suprapun, le puteți face să se unească fără probleme dacă folosiți o formulă de genul float lake1 = (1f - (dx*dx + dy*dy) / (radius + smallPadding)); lake1 *= lake1;
unde dx = (input point).x - (lake center).x
și la fel pentru dy
, apoi făcând float totalLake = lake1 + lake2 + lake3 + snoise
și block = totalLake > smallThreshold ? water : grass