Vamos a ver si alguien por ahí tiene más imaginación que yo porque esto me está matando. Estoy intentando hacer un simulador planetario con la orografía, la hidrosfera, etc. Hasta ahora he creado las montañas con ruido Perlin que queda muy bien. El problema lo tengo con el agua.
Supongamos que tengo un array lleno de agua ¿vale? De una dimensión para simplificar. Digamos
int agua[32];
Donde cada valor significa la altura que tiene el agua.
Ahora lo que quiero hacer es "equilibrar" el agua usando únicamente elementos adyacentes.
Por ejemplo:
for(int i=0;i<31;++i)
{
int d=agua[i+1]-agua[i];
agua[i]+=d/2;
agua[i+1]-=d/2;
}
El problema es que al usar aritmética entera (desafortunadamente imprescindible) me quedan escaloncitos de uno. Si el array agua fuera
3,4,5,6,7,8,9,10
El valor d es siempre 1 y d/2=0.
Si intentamos (d+1)/2 entonces, falla cuando es descendente.
Una solución aceptable por ahora sería que la diferencia entre el mayor y menor valor sea de 1. Luego complicaremos un poco la cosa poniendo un array de tierra debajo del agua (y deberían quedarse lagunas en las zonas cóncavas de la tierra).
¿Alguna idea? :blink:
Y si en vez de int usas float?
Saludos
Citar
El problema es que al usar aritmética entera (desafortunadamente imprescindible) me quedan escaloncitos de uno
Si usas aritmética entera como mínimo te quedarán escaloncitos de uno, no entiendo el problema.
Si quieres que no te pase eso haz que la distancia mínima entre uno y otro sean 2, o sea, multiplica por dos el array. Otra solución que se me ocurre es que si el salto es uno pues desplaces el agua un valor de 0 ó 1 (a tu gusto o quizás aleatorio).
Desde luego valores como 0.5 no vas a poder tener, por eso no entiendo lo que te pasa, quizás una imagen... y de paso así nos muestras lo que estás haciendo :)
Si es impresciondible usar aritmetica entera, podrias usar punto fijo.
Saludos.
Voy a ver con punto fijo 8+8. El gran problema es el tamaño del mundo: 4096x4096 son 16Megas por byte de celda. La altura del agua es un byte, con punto fijo serán dos. Tampoco es tanto y otras soluciones que he probado usaban dos bytes también.
He de reconocer que no se me había ocurrido.
¡Te ofuscas cuando no te salen las cosas y muchas veces lo más simple es lo mejor! (nooo)
¡Gracias! :D
Yann L dió una
gran charla hace un tiempo sobre simulación de agua. A lo mejor te sirve de algo.
Saludos.
Para ethernet que pedía una imágen....
El mundo que genero hasta ahora sólo tiene montañas y estoy en poner los ríos.
(http://www.arrakis.es/~gdl/MiniMundo.png)
Esta es una miniversión de 256x256, el mundo total tiene 256 bloques como este.
Cuando le paso el ciclo del agua (evaporar de los océanos y lluvia uniforme) el agua de los océanos sufre del efecto escalón mencionado.
(http://www.arrakis.es/~gdl/MiniMundo2.png)
Eso sí, se empiezan a ver lagos y ríos anchos (supongo que se estrecharán cuando programe la erosión).
Cita de: "BeRSeRKeR"Yann L dió una gran charla hace un tiempo sobre simulación de agua. A lo mejor te sirve de algo.
Saludos.
Esta charla está enfocada en simulación en tiempo real de la ecuación de onda que conforman las ecuaciones de Navier-Stokes. En mi caso no me interesa la ecuación de onda, sólo la asintótica de dispersión (parecida a la de transmisión de calor). Mientras la ecuación de onda es hiperbólica e inestable, la de dispersión no lo es ¡¡si fuera en aritmética real!! Desafortunadamente en aritmética entera no hay unicidad en la solución y se me estabiliza con los escalones arriba mencionados.
En cualquier caso, la charla es
realmente interesante. :D
Gracias por el link.
(ole) muy interesante, unas preguntillas... :)
El proyecto es para el PFC ?
Qué algoritmo usas para generar los mapas?
saludos
CitarEl proyecto es para el PFC ?
La idea es tener un generador automático de mundos para un jueguecillo (como no podía ser de otra manera en estos foros).
CitarQué algoritmo usas para generar los mapas?
Una especie de ruido Perling. El código es muy corto, te lo pongo:
int Noise(int x, int y, int a, int o)
{
int n = x + y * 57 + o*37;
n = (n<<13) ^ n;
return ((n * (n * n * 15731 + 789221) + 1376312589) & 0x7fffffff)%a-a/2;
}
int SNoise(int x, int y, int a, int o, int n)
{
int m=SIDE/n;
int xi=x/n;
int yi=y/n;
int xf=x%n;
int yf=y%n;
int v1=Noise(xi%m,yi%m,a,o);
int v2=Noise((xi+1)%m,yi%m,a,o);
int v3=Noise(xi%m,(yi+1)%m,a,o);
int v4=Noise((xi+1)%m,(yi+1)%m,a,o);
return (v1*(n-xf)*(n-yf)+v2*xf*(n-yf)+v3*(n-xf)*yf+v4*xf*yf)/n/n;
}
void PerlinPass(Map<char> &r, int a, int n)
{
int o=rand();
int x=rand();
int y=rand();
for(int i=0;i<SIDE;++i)
for(int j=0;j<SIDE;++j)
r(i,j)+=SNoise(i+x,j+y,a,o,n);
}
La idea es la siguiente:
Noise() te da un valor aleatorio para cada posición x,y. De amplitud a, con una semilla o y de media cero.
SNoise() te interpola entre cuatro valores (x/n,y/n), (x/n+1,y/n), (x/n,y/n+1) y (x/n+1,y/n+1). Se puede ver n como la resolución.
PerlinPass() te suma a cada punto del mapa un ruido suavizado (SNoise()) con una resolución n y amplitud a. Los rand() son para que no haya coincidencia de vértices a distintas resoluciones (que queda muy feo).
El ruido Perlin se obtendría con algo así como
PerlinPass(R,128,64);
PerlinPass(R,64,16);
PerlinPass(R,32,8);
PerlinPass(R,16,4);
PerlinPass(R,8,2);
Donde tanto n como a son proporcionales (en el caso de usar frecuencias a=k/f).
Luego ponemos el agua. Si la roca está por encima del agua pinto de verde y si el agua está por encima de la roca de azul.
¡Y ya'stá! :D
Aja, interesante, quizás te interese un libro que trata sobre estas cosas: "texturing and modeling: a procedural aproach"
saludos
Y si pones el azul oscuro más claro y sobretodo, muchisima más tierra?
Saludos
Cita de: "StraT"Y si pones el azul oscuro más claro y sobretodo, muchisima más tierra?
Saludos
Pues queda una cosa así (aunque no con mucha más tierra):
(http://www.arrakis.es/~gdl/MiniMundo3.png)
También he puesto el perfil de la mitad del mapa para que se vea lo que hay debajo de la tierra:
Gris -> Roca madre
Celeste -> Tierra con aguas subterráneas
Verde -> Tierra seca
Azul -> Aguas superficiales
Y has pasado el ciclo del agua con los cambios que te dije?
Por cierto, en la foto de perfil veo zonas de agua por encima del mar.
Saludos
CitarY has pasado el ciclo del agua con los cambios que te dije?
Sí, está cambiado. Ahora hay mucha más precisión, pero sigue habiendo desniveles en el agua. Muchos menos, eso sí.
CitarPor cierto, en la foto de perfil veo zonas de agua por encima del mar.
Son aguas subterráneas que se mueven mucho más lentamente y casi siempre se quedan por encima del nivel del mar. Cuando salen al exterior (manantiales) van más rápidas y forman ríos.
El tema generacion de terrenos siempre me ha gustado mucho.
Conoces esta libreria?
libnoise, va muuuy bien.
Y de paso te recomiendo que le eches una ojeada al
World Machine, ideal si te va el tema erosion
tamat: muy buenos los enlaces :)
Están magníficos los screenshots del World Machine. (uoh)
¡¡Gracias por millones, tamat!!
Puedes enseñarnos una imagen del resultado en perspectiva? (genial)
Saludos
CitarPuedes enseñarnos una imagen del resultado en perspectiva?
La verdad es que tendría que hacer un renderizador y eso es difícil. (asco)
¿No hay por ahí ningún programa al que le pases los heightmaps y te haga el rendering?
He encontrado una
animación que muestra algo parecido a lo que quiero hacer.
El código fuente está
aquí.
Cita de: "gdl"CitarPuedes enseñarnos una imagen del resultado en perspectiva?
La verdad es que tendría que hacer un renderizador y eso es difícil. (asco)
¿No hay por ahí ningún programa al que le pases los heightmaps y te haga el rendering?
blender :^P
Cita de: "gdl"CitarPuedes enseñarnos una imagen del resultado en perspectiva?
La verdad es que tendría que hacer un renderizador y eso es difícil. (asco)
¿No hay por ahí ningún programa al que le pases los heightmaps y te haga el rendering?
Y el terragen creo que tambien :D .