Eu tenho um terreno gerado, com geometria hexagonal, conforme a captura de tela abaixo:
Eu então gero biomas, mas como você pode ver, as fronteiras entre eles são realmente feias e retas. Para esconder essa origem hexagonal, eu precisaria suavizar as fronteiras entre os biomas. É assim que fica agora em estrutura de arame com faces tringulares reais:
O que estou buscando é algo mais ou menos assim:
Cada vértice possui um atributo que contém o tipo de bioma. Também posso adicionar atributos especiais aos vértices na borda entre dois biomas, mas simplesmente não consigo descobrir como fazer isso no código de sombreamento, obviamente ruído. está envolvido aqui, mas como faço para torná-lo contínuo através de múltiplas faces e toda a borda de múltiplos biomas?
Estou renderizando com WebGL usando THREE.js
Respostas:
Outras respostas aqui sugerem o uso de uma textura. Aqui está uma técnica que não usa texturas.
Você deseja que os limites entre hexágonos sejam interessantes. É mais fácil estabelecer limites interessantes quando você os move para o centro do que está desenhando. Em vez de desenhar os ladrilhos diretamente, você desenha o "duplo" do ladrilho. Essa técnica é chamada de "esquadrias" ( aqui e aqui e aqui ). O dual de um hexágono é um triângulo, então desenhávamos esses triângulos em vez dos hexágonos:
Os limites entre hexágonos agora estão no meio dos triângulos renderizados, de modo que vamos fazer coisas mais interessantes com eles. Bônus: você só precisa desenhar dois triângulos por hexágono, em vez de seis (ou vinte e quatro como você está fazendo agora).
Dentro de cada um desses triângulos, queremos que o shader de fragmento desenhe os hexágonos. Podemos fazer isso com coordenadas baricêntricas . Coloque (1,0,0), (0,1,0) e (0,0,1) em cada vértice do triângulo. Dentro do triângulo, essas coordenadas serão interpoladas. O shader de fragmento receberá (a, b, c) e pode ver qual valor é maior - isso nos dirá qual dos três hexágonos deve ser desenhado neste momento.
float max_n = max(barycentric.r, max(barycentric.g, barycentric.b)); if (max_n == barycentric.r) { color = v_color0; } else if (max_n == barycentric.g) { color = v_color1; } else if (max_n == barycentric.b) { color = v_color2; }
Isso é para linhas retas.
Se você deseja bordas ruidosas, pode adicionar ruído às coordenadas baricêntricas:
Ao brincar com o comprimento de onda da amplitude / frequência do ruído, você pode obter alguns efeitos interessantes:
Você precisa ter cuidado com o ruído, certificando-se de que seja consistente através dos limites do triângulo. Uma maneira de fazer isso é passar um id hexadecimal e usá-lo como valor inicial para cada um dos três valores de ruído adicionados às coordenadas baricêntricas.
Eu fiz uma demonstração interativa aqui . (Para a demonstração, não implementei o ID hexadecimal ou outras coisas que você pode precisar se estiver fazendo esse trabalho em um projeto real - é apenas uma demonstração rápida e suja)
fonte
Tenho certeza de que "poderia" ser resolvido com algum algoritmo de imagem, mas se fosse eu, provavelmente o resolveria com texturas. Eu fazia texturas hexagonais, as colocava em um atlas de textura, depois, para cada hexágono, olhava para os vizinhos e decidia qual textura aplicar.
As texturas precisariam ter versões para cada tipo de terreno e versões para cada tipo de transição.
Isso é semelhante a quantos sistemas baseados em ladrilhos fazem terreno. Aqui está um exemplo de jogos 2D .
Outra possibilidade seria apenas ter suas texturas para seus vários tipos de terreno (água, neve, sujeira, grama) e adicionar quantidades de mistura a cada vértice do hexágono para decidir como misturá-las.
Este artigo mostra a ideia de misturar texturas de terreno. Não estou sugerindo seguir a implementação deles, mas isso mostra a ideia.
fonte
Primeiro, renderize seus biomas em uma textura. Mapeie os triângulos para cabos de texto. Você pode fazer isso usando uma projeção mercator, ou, melhor, um mapa de cubo . Agora, no shader de fragmento, faça algo assim:
onde
noise
há alguma função pseudo-aleatória (usando, por exemplo, sinusóides) na posição 3D do vértice no espaço do modelo, que retorna um deslocamento ruidoso para a coordenada da textura. Prove a textura usandoGL_NEAREST
para manter bordas nítidas.fonte