Criar globos planetários procedimentais

Distorção, ruído contínuo e como trabalhar com eles.

imagem

Nós geramos um planeta


Uma das maneiras mais simples de gerar um planeta é usar ruído. Se decidirmos escolher, então temos algumas opções possíveis. Vamos olhar para cada um e determinar o melhor:

  • O Perlin Noise é a opção mais fácil. O ruído Perlin foi desenvolvido por Ken Perlin em 1983, possui algumas desvantagens - artefatos visuais e velocidade na geração de imagens grandes bastante baixas em comparação com outras opções.
  • Simplex Noise (Simplex Noise) - foi desenvolvido por Ken Perlin em 2001 como uma tentativa de eliminar os defeitos do ruído Perlin; esta é uma solução muito digna e rápida, mas tem uma séria desvantagem: o uso de ruído simplex tridimensional é protegido por uma patente, o que o torna bastante caro.
  • Ruído Simplex Aberto - O KDotJPG foi desenvolvido com um objetivo simples: criar uma versão moderna e gratuita de ruído simplex, relativamente rápida e sem distorção.

Desses três, eu pessoalmente prefiro o Open Simplex Noise, que uso em meus projetos pessoais. Vale ressaltar que, na atual implementação do OpenSimplexNoise , serão necessários trabalhos adicionais para obter fácil acesso a balanças, oitavas e geradores . Há muita informação na Internet sobre o que cada um desses elementos faz, e eu recomendo que você o estude. No entanto, no meu artigo, não vou falar sobre isso.


Aqui está a aparência do Open Simplex Noise com 16 oitavas.

Ruído contínuo


O ruído é interminável, o que significa que, se apenas criarmos uma tela com uma proporção de 2: 1 para obter uma projeção igualmente espaçada , ela não será repetida quando sobreposta na esfera (exprimo gratidão a este site incrível), mas na costura horizontal e nos pólos enormes diferenças.

imagem

Ruído criado sem costuras.

imagem

Observe as enormes costuras que apareceram quando o ruído foi aplicado à esfera.

Existem muitas maneiras de corrigir isso; Por exemplo, neste excelente post da Red Blob Games [ tradução em Habré] , bastava gerar uma ilha usando uma função que recebe a distância do centro como uma variável e define a altura 0 nas bordas para minimizar as costuras.

No entanto, não é disso que precisamos. Queremos gerar um planeta com a possibilidade da existência dos pólos norte e sul, e para isso precisaremos de cálculos matemáticos mais complexos.

Sobreposição esférica


Um método que pode gerar planetas esféricos é converter as coordenadas cartesianas de nossa tela em coordenadas esféricas, gerar ruído com base nessas coordenadas e depois converter o ruído de volta em coordenadas cartesianas e aplicá-lo à tela.

No entanto, essa implementação tem suas limitações, cujas causas são mostradas em um post incrível de Ron Valstar . Mais importante ainda, as formas dos continentes nesse caso parecem extremamente estranhas e distorcidas e, portanto, não usaremos essa opção.

imagem

Sobreposição de ruído esférico. Formas e distorções estranhas tornam os continentes muito feios.

imagem

Mas pelo menos não há mais costuras.

Sobreposição cúbica


Como resultado, usei o segundo método, retirado de um post de Ron Valstar e de uma série de artigos da acko Making Worlds . Eles descrevem a geração de um globo através da geração de um cubo e sua "inflação", como se fosse um balão, até ser um exemplo da forma de uma esfera.


Imagem tirada de acko.net. Explica o conceito de um mapa cúbico de uma maneira simples e visualizada.

Agora só precisamos gerar seis faces, o que é bastante simples, existem muitas maneiras de fazer isso.

No final, decidi criar uma matriz e preenchê-la com dados. Eu converti as coordenadas 2D da tela nas coordenadas 3D do cubo e, em seguida, geramos ruído para cada uma dessas coordenadas 3D, para que eu as salvasse no valor correspondente das coordenadas 2D.

//Z STATIC for(int y = 0; y < cubeFaceSize; y++) { for(int x = 0; x < cubeFaceSize * 2; x++) { //Generates FRONT if(x < cubeFaceSize) { cubeMap[cubeFaceSize+x][cubeFaceSize+y] = noise.noise3D(x, y, 0); } //Generates BACK else { cubeMap[cubeFaceSize*3+(x-cubeFaceSize)][cubeFaceSize+y] = noise.noise3D(cubeFaceSize-(x-cubeFaceSize), y, cubeFaceSize); } } } //X STATIC for(int y = 0; y < cubeFaceSize; y++) { for(int x = 0; x < cubeFaceSize * 2; x++) { //Generates LEFT if(x < cubeFaceSize) { cubeMap[x][cubeFaceSize+y] = noise.noise3D(0, y, cubeFaceSize-x); } //Generates RIGHT else { cubeMap[cubeFaceSize*2+(x-cubeFaceSize)][cubeFaceSize+y] = noise.noise3D(cubeFaceSize, y, x-cubeFaceSize); } } } //Y STATIC for(int y = 0; y < cubeFaceSize * 2; y++) { for(int x = 0; x < cubeFaceSize; x++) { //Generates TOP if(y < cubeFaceSize) { cubeMap[cubeFaceSize+x][y] = noise.noise3D(x, 0, cubeFaceSize-y); } //Generates BOTTOM else { cubeMap[cubeFaceSize+x][cubeFaceSize*2+(y-cubeFaceSize)] = noise.noise3D(x, cubeFaceSize, y-cubeFaceSize); } } } 

Dessa forma, podemos criar um mapa cúbico que pode ser facilmente convertido em uma projeção igualmente espaçada, usando o maravilhoso código escrito por Bartosz .

imagem

Algoritmo gerado mapa cúbico.

imagem

Transformação equidistante de um mapa cúbico.

imagem

Um globo cúbico do mapa rendido em maptoglobe.com .

Como você pode ver, um mapa equidistante tem formas muito mais bonitas e, quando sobreposto a uma esfera, cria resultados semelhantes à superposição esférica, sem todas as suas desvantagens. A propósito, a projeção equidistante pode ser facilmente convertida por diferentes programas, por exemplo, o NASA G.Projector , em quase qualquer tipo de cartão.

Em conclusão


Gerar um planeta inteiro pode parecer uma tarefa assustadora, e embora o ruído, quando usado corretamente, seja uma ferramenta bastante poderosa, ele tem seus próprios problemas que as pessoas enfrentam há muitos séculos, como sobrepor um globo em uma tela 2D com distorção mínima.

A solução que propus cria planetas muito gerados que não levam em consideração placas tectônicas, rios, cadeias de ilhas e até montanhas e, portanto, podem ser usados ​​apenas como demonstração ou como base para simulações mais complexas.

De fato, ele apenas cria uma matriz de valores em um determinado intervalo de valores. Para imagens em escala de cinza, é de 0 a 255. Os valores são então convertidos em um pixel que cria uma imagem semelhante à primeira imagem em escala de cinza ou em uma imagem no intervalo de -11000 a 8000 para simular uma diferença de altura no mundo real, após o qual os pixels são coloridos de acordo com os intervalos de altura (por exemplo, valores de 0 5 são coloridas na cor da areia para simular a costa) .

Na construção do universo, Deus usou a matemática de nível superior.

- Paul Dirac

Source: https://habr.com/ru/post/pt448324/


All Articles