Água fluida de computação da GPU

15

Tenho formação em engenharia civil e realizo análises hidráulicas e hidrológicas regularmente. Eles vendem graus para esse tipo de coisa, mas na verdade não é ciência de foguetes. Recentemente, pensei em implementar todo o processo hidrológico e hidráulico de um terreno na GPU. Eu aprendi os shaders de computação apenas recentemente, então, atualmente, estou preso a ser melhor em engenharia do que projetando fluxos de trabalho de GPU paralelos.

Você pode calcular a quantidade de água gerada durante um evento de chuva usando a fórmula:
Q (CF/S) = c * I (in/hr) * A (acres)

Estou tendo dificuldades para ir além do cálculo da "área cultivada" mesmo da primeira área.

Visão geral da implementação atual:

  1. O terreno é uma grade regular de vértices em intervalos de 1 unidade
  2. Um mapa de altura contém um valor de altura R32 para cada vértice
  3. Atualmente, só estou permitindo o fluxo nas 4 direções cardeais (sem diagonais)
  4. Estou usando um Texture2D [int] como um estêncil para vértices que já analisei

Algoritmo atual:

  1. Quando a ferramenta de terreno estiver ativa e não estiver agora ...
  2. Limpe o "estêncil".
  3. Escaneie todo o terreno para a menor elevação.
  4. Esse ponto único é a entrada inicial para CS_Flood.
  5. CS_Flood faz um passe no eixo X.
  6. Cada vértice de entrada é projetado nas direções X e X + até 2048 vezes.
  7. Encontrar um vértice adjacente com uma coordenada OOB indica a aresta do terreno nessa direção. O CurrentPoint é anexado ao buffer BoundaryPoints e o loop de projeção para essa direção é finalizado. Isso foi fácil e funciona muito bem sempre.
  8. Vértices adjacentes com alturas> = a altura do vértice atual são marcados no estêncil e adicionados ao buffer NextPass.
  9. Vértices adjacentes com alturas <a altura atual do vértice indica o pico de uma crista e termina o loop de projeção. Uma iteração futura do preenchimento de inundação pode fluir em torno da base da cordilheira, subindo pela parte traseira e detectando a mesma cordilheira pela segunda vez.
  10. Quaisquer pontos de pico / cume detectados mais de uma vez não serão um BoundaryPoint, para essa finalidade.
  11. Quaisquer pontos de pico / cume detectados exatamente uma vez são anexados a BoundaryPoints e o loop de projeção nessa direção é encerrado.
  12. CS_Flood faz um eixo Z passar com o mesmo código, usando os pontos gerados pelo eixo X como entrada.
  13. No momento, o CS_Flood continua alternando entre as duas direções indefinidamente. Eventualmente, terminarei o loop geral sempre que o CS_Flood for concluído e o buffer NextPass estiver vazio.

Idealmente, nesse ponto, os BoundaryPoints conteriam cada vértice que ocorre na divisão de drenagem natural. As gotas de água que caem dentro dos limites acabam fluindo para o mesmo ponto baixo. As gotas de água que caem do lado de fora da fronteira vão para "outro lugar".

Então:

  1. Sem limpar o estêncil, digitalize novamente o terreno em busca do vértice mais baixo e sem estêncil.
  2. Iterar CS_Flood.
  3. Repita até que o estêncil esteja cheio (ou algo semelhante).

É difícil perceber o 3D com essas cores; isso mostra linhas de contorno em elevações integrais:
(um buraco cercado por uma berma perto da borda) orifício da borda

Existem cerca de 10 maneiras exclusivas de drenar um vértice; dando a cada uma uma cor única:
(marcas de ferramentas circulares visíveis, "sulcos" aparecem muito bem) insira a descrição da imagem aqui

Isso mostra todos os pontos gerados pelo CS_Flood, limite ou não, como uma POINTLIST: insira a descrição da imagem aqui

O algoritmo sempre quase funciona . Às vezes, até funciona corretamente. Outras vezes, o algoritmo está claramente contido na forma correta, mas continuará a produzir pontos indefinidamente. Como visto na terceira captura de tela, às vezes fica confuso. Deve haver outra situação / fator que eu negligenciei. Agradeço qualquer ajuda para encontrar minha supervisão ou sugestões de maneiras mais simples e / ou mais elegantes de atacar o problema.

ponto ausente

MissingPoint! pode ser incluído auxiliando o algoritmo para adicionar todos os novos BoundaryPoint detectados ao buffer NextPass. Durante a próxima passagem, 99% dos pontos gerados por esse curativo desperdiçarão uma pequena quantidade de tempo na GPU, determinando que eles não podem ir a lugar algum e não fazer nada. Durante a primeira passagem, o envio do LowestPoint junto com os outros pontos NextPass também lidaria com esse cenário específico.

Sei que é plausível e, com tempo suficiente, poderei ajudá-lo o suficiente para fazer o que quero. Gostaria de fazê-lo de uma maneira melhor, mais inteligente e mais rápida, se possível, e ainda não tenho experiência suficiente para conhecê-lo melhor.

Jon
fonte
Então quer dizer que você só quer calcular para onde toda a água é drenada no terreno?
23416 EvilTak
@ EvilTak, acho que decidi por um bom algoritmo, mas ainda estou recebendo "coisas estranhas" que não tenho experiência para explicar. Se você é bom em GPU'ing paralela, confira: gamedev.stackexchange.com/questions/118556/...
Jon

Respostas:

1

Quando uma gota "tentava" visitar um vértice, o estêncil era marcado com o InterlockedExchangeuso do "valor original" para determinar se ele estava estampado (mesmo que eu o tenha substituído).

O melhor algoritmo que eu criei deu ao dilúvio um "bloco de rascunho" e uma única regra: "não desça ladeira abaixo" (alturas iguais ou superiores). Isso eliminou quase todos os testes complicados. Embora seja geralmente bom em não fluir sobre picos / cordilheiras, flui ao longo deles porque os vértices adjacentes são "planos". Ocasionalmente, isso permite que gotas passem furtivamente pelas cordilheiras.

insira a descrição da imagem aqui

Cada um dos pontos "longe demais" é "fluído" e "flui" para a área de drenagem (para em 1) ou não (para em 0). Os "nots" são descartados e o bloco de rascunho corrigido é copiado para o "final". Se a final já estiver estampada, o bloco de rascunho será descartado. (Futuro: essas colisões devem representar coletivamente o limite externo da atual área de drenagem.)

A 10FPS:

insira a descrição da imagem aqui

Os "nots" são mostrados em vermelho, uma vez que a área grande é copiada para a final e fica verde, o algoritmo se repete para as demais áreas não estilizadas.

Jon
fonte