1 pontos por GN⁺ 2 시간 전 | 1 comentários | Compartilhar no WhatsApp
  • O shader no navegador combina espalhamento de Rayleigh, espalhamento de Mie e absorção de ozônio para renderizar em tempo real o céu azul e o pôr/nascer do sol
  • Ele acumula a profundidade óptica do raio da câmera e a transmitância pela Lei de Beer, e calcula com funções de fase a distribuição do espalhamento conforme a direção do sol
  • O efeito de pôr do sol realiza um light-march separado na direção do sol em cada amostra, refletindo quanto da luz solar é perdido ao atravessar a atmosfera
  • O shader de céu plano se torna um efeito de pós-processamento com buffer de profundidade e reconstrução de coordenadas de mundo, tratando até a névoa atmosférica entre os objetos da cena
  • Em escala planetária, ele se expande com logarithmic depth buffer, interseção raio-esfera e LUTs de Transmittance, Sky-view e Aerial Perspective

Objetivos do shader de espalhamento atmosférico e materiais de referência

  • O objetivo é reproduzir em um shader no navegador, como na foto do pôr do sol em órbita baixa do ônibus espacial Endeavour, as camadas que passam do laranja escuro, azul e preto do fundo do espaço na alta atmosfera da Terra
  • O escopo da implementação começa com um sky dome realista que combina raymarching, espalhamento de Rayleigh, espalhamento de Mie e absorção de ozônio, e depois se expande para a casca atmosférica ao redor de um planeta e otimizações baseadas em LUT
  • As principais referências são Three Geospatial, A Scalable and Production Ready Sky and Atmosphere Rendering Technique de Sébastien Hillaire e Atmospheric Scattering (and also just faking it)

Modelo básico de renderização do céu

  • Por que um gradiente simples não basta

    • A cor do céu não deve ser tratada como um simples fundo azul, mas como o resultado da interação da luz com o ar e seus componentes
    • É preciso considerar variáveis como altitude do observador, quantidade de poeira e horário do dia, e os cálculos acontecem dentro de um volume
  • Amostragem da densidade atmosférica

    • A atmosfera é amostrada com raymarching, como em volumetric clouds ou volumetric light
    • Dispara-se um raio a partir da posição da câmera e ele avança pelo meio transparente, calculando a transmitância, que é a luz que sobrevive ao atravessar a atmosfera, e o espalhamento, que é redirecionado de cada amostra em direção à câmera
    • Como revisão de raymarching, dá para consultar Painting with Math: A Gentle Study of Raymarching
  • Densidade de Rayleigh e profundidade óptica

    • Para obter a transmitância, é preciso acumular a densidade atmosférica encontrada pelo raio ao longo do caminho e calcular a profundidade óptica
    • A função de densidade de Rayleigh representa quanto “ar” existe na altitude h, refletindo o efeito de a atmosfera ficar mais rarefeita quanto maior a altitude
    • A implementação de exemplo usa RAYLEIGH_SCALE_HEIGHT = 8.0km, ATMOSPHERE_HEIGHT = 100.0km, VIEW_DISTANCE = 200.0km e PRIMARY_STEPS = 24
    • rayleighDensity(h) é exp(-max(h, 0.0) / RAYLEIGH_SCALE_HEIGHT), e no loop o acúmulo é feito com viewOpticalDepth += dR * stepSize
  • Lei de Beer e o azul do céu diurno

    • A partir da profundidade óptica, calcula-se a transmitância T em um ponto específico; T=1.0 significa nenhuma perda de luz e T=0.0 significa que a luz desapareceu completamente
    • A transmitância é calculada pela Lei de Beer, e o código de exemplo usa vec3 transmittance = exp(-rayleighBeta * viewOpticalDepth)
    • rayleighBeta é o coeficiente de espalhamento de Rayleigh e, no shader, é armazenado como vec3(0.0058, 0.0135, 0.0331)
    • O ângulo entre a direção da luz solar e o raio de visão é modelado pela função de fase de Rayleigh na forma 3.0 / (16.0 * PI) * (1.0 + mu * mu)
    • Por causa do coeficiente de espalhamento de Rayleigh, o vermelho quase não é espalhado, o verde é espalhado um pouco mais e o azul é o mais espalhado, fazendo o céu diurno parecer azul
    • Ao expandir isso para um raio por pixel, a região do horizonte atravessa mais atmosfera e parece uma névoa branca brilhante, enquanto em maiores altitudes a cor muda para um azul mais profundo e escuro

Espalhamento de Mie e absorção de ozônio

  • Efeitos que o Rayleigh sozinho não cobre

    • Só com o espalhamento de Rayleigh já dá para obter bons resultados, mas um céu mais realista precisa de efeitos atmosféricos adicionais
    • O espalhamento de Mie representa a interação da luz com partículas maiores, como poeira ou aerossóis, e tem uma função de densidade e uma função de fase que descreve a redistribuição por direção
    • A absorção de ozônio remove do caminho alguns comprimentos de onda da luz que atravessa a alta atmosfera, sem espalhá-los
    • A absorção de ozônio aprofunda a cor do céu e desloca os tons, especialmente no horizonte, no pôr do sol, no nascer do sol e no crepúsculo
  • Acúmulo de Mie e ozônio

    • Em uma implementação que usa Rayleigh, Mie e ozônio juntos, as profundidades ópticas de cada um são acumuladas em viewODR, viewODM e viewODO
    • Em cada amostra, calculam-se dR = rayleighDensity(h), dM = mieDensity(h) e dO = ozoneDensity(h), e tau é formado pela soma de BETA_R * viewODR, BETA_M_EXT * viewODM e BETA_OZONE_ABS * viewODO
    • A transmitância é calculada com exp(-tau), e densidade, transmitância e stepSize são acumulados em sumR, sumM e sumO
    • O espalhamento final é calculado na forma SUN_INTENSITY * (phaseR * BETA_R * sumR + phaseM * BETA_M_SCATTER * sumM + BETA_OZONE_SCATTER * sumO)
  • Principais constantes e efeitos

    • MIE_SCALE_HEIGHT corresponde, para aerossóis, ao RAYLEIGH_SCALE_HEIGHT; como as partículas normalmente se concentram perto do horizonte, ele é definido com um valor menor, 1.2km
    • MIE_BETA_SCATTER controla quanto as partículas espalham a luz em direção à câmera e, por ser em grande parte independente do comprimento de onda, é definido como vec3(0.003)
    • MIE_BETA_EXT é o coeficiente de extinção de Mie, que representa quanta luz é removida do caminho e faz a atmosfera distante parecer mais enevoada
    • MIE_G controla a anisotropia: 0.0 significa espalhamento uniforme e 1.0 indica uma tendência mais forte ao espalhamento para frente
    • OZONE_BETA_ABS tem os valores vec3(0.00065, 0.00188, 0.00008) e absorve mais as faixas de verde e amarelo-alaranjado, deslocando a cor do céu em direção a azul, vermelho e roxo
    • Ao integrar Mie e ozônio, surgem uma cor “sky blue” mais natural e uma auréola difusa ao redor do sol, e o efeito do espalhamento de Mie fica mais evidente quando o sol está perto do horizonte

Caminho da luz e pôr do sol·nascer do sol

  • Limites da implementação existente

    • O fragment shader do céu consegue renderizar cores naturais em várias altitudes e refletir os modelos de transmitância de Mie, Rayleigh e ozônio
    • Porém, mesmo ao mover o sol para perto do horizonte, só aparece um halo branco e difuso, sem atenuação da luz nem efeitos de pôr do sol ou nascer do sol
    • Isso acontecia porque o loop de raymarching existente calculava a atenuação da luz apenas no raio de visão da câmera até cada amostra
    • Também é preciso calcular quanto da luz solar se perde ao atravessar a atmosfera antes de chegar ao ponto de amostragem
  • Loop aninhado de light-march

    • Em cada ponto de amostragem, é executado um loop aninhado separado na direção da fonte de luz para amostrar a transmitância desse caminho
    • Essa abordagem relacionada também é usada em real-time cloudscapes e volumetric lighting
    • lightMarch(float start, float sunY) repete LIGHTMARCH_STEPS vezes enquanto acumula odR, odM, odO
    • À profundidade óptica da implementação existente viewODR, viewODM, viewODO é adicionada a profundidade óptica na direção do sol sunOD
    • O tau final é composto pela soma de BETA_R * (viewODR + sunOD.x), BETA_M_EXT * (viewODM + sunOD.y), BETA_OZONE_ABS * (viewODO + sunOD.z)
    • Com essa implementação, é possível renderizar céus com pôr do sol, nascer do sol, sol no zênite e condições de iluminação intermediárias
    • Com o uniform sun angle, dá para criar a variação do azul do céu ao longo do dia, e o espalhamento de Mie mistura naturalmente a luz com o horizonte no pôr do sol e no nascer do sol
    • Quando o sol está baixo, o ozônio adiciona tons arroxeados ao céu

Expansão para atmosfera planetária

  • De fundo plano para efeito de pós-processamento

    • O shader criado antes fornece um bom fundo de céu, mas ainda se parece com um fundo plano em uma cena de React Three Fiber
    • O próximo passo é transformá-lo em um efeito de pós-processamento (post-processing effect) para renderizar um volume que considera a profundidade da cena e uma casca atmosférica ao redor da malha do planeta
    • Para isso, reconstrói-se a coordenada em espaço mundial a partir de screenUV e incorpora-se o depth buffer da cena ao raymarching
  • Reconstrução em espaço mundial e raio 3D

    • Para aplicar o espalhamento atmosférico à cena, não basta desenhar apenas o céu; é preciso preencher o espaço entre a câmera e os objetos renderizados na tela
    • Os dados necessários são o depth buffer da cena, projectionMatrixInverse, matrixWorld e position da câmera, e esses valores são passados como uniforms do efeito de pós-processamento
    • getWorldPosition(vec2 uv, float depth) cria clipZ com depth * 2.0 - 1.0 e coordenadas NDC com uv * 2.0 - 1.0, depois aplica projectionMatrixInverse e viewMatrixInverse
    • O mesmo processo também é usado no efeito de pós-processamento de volumetric lighting de On Shaping Light
    • Depois de obter o worldPosition do pixel atual, rayOrigin é definido como a posição da câmera e rayDir é calculado com normalize(worldPosition - rayOrigin), avançando ao longo de um raio 3D por pixel na tela
  • Ajuste do intervalo de raymarch com o depth buffer

    • Para considerar a geometria da cena, o intervalo de raymarch do raio atual deve ser definido com o depth buffer em vez de um stepSize fixo
    • A profundidade da cena ao longo do raio é obtida com sceneDepth = depthToRayDistance(uv, depth)
    • Pixels de fundo são identificados com depth >= 1.0 - 1e-7, e para “sky pixels” aplica-se sceneDepth = atmosphereHeight * SKY_MARCH_DISTANCE_MULTIPLIER
    • Se o raio aponta para baixo, a interseção com o solo é calculada com tGround = observerAltitude / max(-rayDir.y, 1e-4) e limitada com rayEnd = min(rayEnd, tGround)
    • O stepSize final é calculado como (rayEnd - rayStart) / float(PRIMARY_STEPS)
    • Raios que atingem objetos próximos ou o solo usam stepSize menor para amostragem mais precisa, enquanto raios que vão mais longe distribuem o mesmo número de amostras por uma distância maior
  • Névoa atmosférica dentro da cena

    • O shader implementado como efeito de pós-processamento aplica o espalhamento atmosférico a todo o volume da cena e permite usar o sky shader como fundo, considerando a geometria da cena
    • Objetos próximos da câmera aparecem mais nítidos, enquanto objetos distantes ficam mais desfocados
    • Um exemplo interativo com corpos celestes arrastáveis usando Raycaster pode ser visto no tweet de MaximeHeckel

Renderização de planetas

  • Duas etapas necessárias

    • Para renderizar uma atmosfera realista ao redor de um planeta, são necessários um logarithmic depth buffer para lidar com escalas grandes e uma casca atmosférica esférica que define onde o raio começa e termina na atmosfera
  • logarithmic depth buffer

    • Em escala planetária, ao observar de longe, o shader pode ter dificuldade para distinguir a diferença de profundidade entre a atmosfera e a casca do planeta, o que pode causar depth fighting
    • Como a altura da atmosfera é de apenas alguns km, é preciso ajustar tanto a definição do depth buffer da cena quanto a forma de leitura nos efeitos de pós-processamento
    • Em React Three Fiber, define-se logarithmicDepthBuffer: true na prop gl que envolve o Canvas
    • Um exemplo de configuração é <Canvas shadows gl={{ alpha: true, logarithmicDepthBuffer: true }}>
    • No shader, a computação de sceneDepth é redefinida para converter o logarithmic depth buffer de volta para a distância ao longo do raio
    • logDepthToViewZ(depth) usa pow(2.0, depth * log2(cameraFar + 1.0)) - 1.0 e retorna -d
  • Encontrando o trecho da atmosfera com ray-sphere intersection

    • Usa-se um teste de ray-sphere intersection para encontrar os pontos em que o raio de visão entra e sai da esfera atmosférica (atmospheric sphere)
    • Ao obter os dois pontos de interseção, evita-se desperdiçar amostras fora da atmosfera e o loop de raymarching pode ser limitado apenas a esse intervalo
    • Como o planeta é uma malha esférica envolvida por uma esfera atmosférica um pouco maior, o mesmo teste de interseção também é aplicado ao próprio planeta
    • Se o raio atingir o solo antes de sair da atmosfera, o ponto de interseção com o solo é usado como fim do intervalo de raymarching
    • A implementação de raySphereIntersect usada toma como referência Ray-Surface intersection functions de Inigo Quilez
  • Objetos da cena e condição de término da atmosfera

    • A atmosfera deve terminar ao tocar a superfície do planeta ou ao encontrar outro objeto da cena antes de atingir o solo
    • Ao tocar o planeta, por padrão ela para no solo com atmosphereFar = min(atmosphereFar, planetHit.x)
    • Se outra malha estiver renderizada antes do solo, isso é detectado pela condição sceneDepth < planetHit.x - 2.0 e aplica-se atmosphereFar = min(atmosphereFar, sceneDepth)
    • Sem essa lógica, surge o problema de a superfície do planeta aparecer à frente do objeto
  • Demo em React Three Fiber e glitches restantes

    • Ao aplicar esses dois ajustes no código, é possível implementar o espalhamento atmosférico como efeito de pós-processamento e renderizar a atmosfera ao redor do planeta
    • A cena de demonstração renderiza um simples “Sun - Earth system” em React Three Fiber e aplica um efeito customizado
    • Ao ajustar a posição do sol e afastar o zoom, é possível ver as cores do céu geradas pelo shader de vários ângulos, do solo até a órbita
    • O mesmo efeito foi usado na imagem de pôster para divulgar o post do início de abril, e a imagem renderizada foi compartilhada em um tweet
    • O torus da cena ainda pode parecer “lit-up” mesmo depois do pôr do sol
    • A causa é que a escala do shadow-map ou da shadow-camera da directional light principal é pequena, então ela não consegue cobrir o torus que está longe demais
    • Como contorno, seria possível reutilizar a abordagem de shadow-mapping do artigo sobre iluminação volumétrica, mas isso não foi realmente testado

Tratamento de eclipse

  • Quando um grande corpo celeste bloqueia o sol, isso pode ser adicionado chamando a função sunVisibility depois de lightMarch e multiplicando a transmitância pelo valor de retorno [0, 1]
  • A ideia básica é comparar, no ponto de amostragem atual, o produto escalar entre a direção da lua e a direção do sol
  • Se as duas direções forem quase iguais e o produto escalar estiver próximo de 1.0, a lua está bloqueando o sol; se forem ortogonais e estiver próximo de 0.0, não há bloqueio
  • Como um simples produto escalar não reflete o tamanho e a escala dos objetos na cena, a implementação compara a distância angular entre sol e lua e o raio angular de cada um
  • sunVisibility trata os casos em que a lua não bloqueia o sol, em que bloqueia enquanto parece maior ou de tamanho semelhante ao sol do ponto de vista da câmera, e em que bloqueia ao entrar dentro do raio do sol do ponto de vista da câmera
  • A demo adiciona sunVisibility e uma malha da lua ao exemplo existente de espalhamento atmosférico, para que o shader de Atmospheric Scattering lide com a situação de pouca luz quando a lua é alinhada com o sol
  • Simulações mais sofisticadas de eclipse e corona são tratadas no artigo Physically Based Real-Time Rendering of Eclipses, cuja implementação não foi portada para WebGL

Atmosfera de outros planetas

  • O modelo de densidade atmosférica e espalhamento usado é determinado em grande parte pelo raio do planeta e da atmosfera, além de algumas constantes como RayleighScaleHeight, RayleighBeta, MieScaleHeight, MieBeta, mieBetaExt, mieG, OzoneHeight e OzoneWidth
  • Ajustando esses valores, é possível obter resultados próximos da atmosfera de Marte ou da atmosfera de outros planetas
  • Os valores usados para Marte são aproximados
    • planetRadius: 3390
    • atmosphereRadius: 3500, espessura de cerca de 110 km
    • rayleighScaleHeight: 11.1
    • rayleighBeta: new THREE.Vector3(0.019, 0.013, 0.0057)
    • mieScaleHeight: 1.5
    • mieBeta: 0.04
    • mieBetaExt: 0.044
    • mieG: 0.65
    • ozoneCenterHeight: 0.0
    • ozoneWidth: 1.0
    • ozoneBetaAbs: new THREE.Vector3(0.0, 0.0, 0.0)
    • sunIntensity: 15.0
    • planetSurfaceColor: '#8B4513'
  • Ao substituir as constantes existentes por esses valores, obtém-se uma atmosfera mais empoeirada e alaranjada, além do característico tom azulado no pôr do sol de Marte
  • Há também o artigo relacionado Physically Based Rendering of the Martian Atmosphere

Dispersão atmosférica baseada em LUT

  • Abordagem e simplificações

    • O shader anterior consegue renderizar a atmosfera em pequena e grande escala de forma intuitiva, mas tem custo alto de execução por causa do loop de raymarching com muitos PRIMARY_STEPS, do loop aninhado de lightmarching e do cálculo em resolução de tela inteira
    • A Scalable and Production Ready Sky and Atmosphere Rendering Technique, de Sebastian Hillaire, propõe uma abordagem baseada em Look Up Tables (LUTs) que armazena em texturas os cálculos de dispersão mais custosos e, no render final, faz amostragem e composição dessas texturas pré-calculadas
    • As LUTs tratadas aqui são a Transmittance LUT, que armazena a quantidade de luz que sobrevive ao atravessar a atmosfera; a Sky-view LUT, que armazena a cor do céu em uma posição específica da câmera; e a Aerial Perspective LUT, que armazena o haze atmosférico e a luz dispersa entre a câmera e a geometria visível da cena
    • A implementação não reproduz o artigo inteiro exatamente; embora LUTs combinem bem com compute shaders no WebGPU, por falta de tempo e para manter a continuidade do texto, foi mantido o WebGL
    • No artigo, a Aerial Perspective LUT é uma 3D texture, mas nesta implementação foi usado um render target 2D
    • Essa abordagem exige recriar as texturas sempre que a câmera se move para garantir valores corretos por pixel, o que dificulta pré-cálculo
    • Multi-Scattering foi omitido por falta de tempo
  • Transmittance LUT

    • No shader anterior, todos os pontos de amostragem chamavam lightmarch para calcular quanta luz solar chegava até eles, e esse processo era caro
    • A Transmittance LUT armazena esses dados previamente em baixa resolução, para que as LUTs seguintes possam ler essas informações de luz quando precisarem
    • A implementação define um Frame Buffer Object dedicado com resolução 250 x 64, aplica um material de shader customizado a um full-screen quad da cena dedicada transmittanceLUTScene e depois passa a textura renderizada como uniform para as LUTs downstream
    • Em cada pixel, o raymarching parte de vec3(0.0, radius, 0.0), em que radius aumenta de planetRadius até atmosphereRadius ao longo da coordenada vUv.y
    • O eixo x da LUT representa o ângulo da luz, e o eixo y representa a altitude; branco puro significa transmitância de 100%, enquanto áreas pretas ou coloridas indicam o solo ou as partes mais densas da atmosfera
    • Depois disso, as LUTs seguintes podem obter “a quantidade de luz que sobrevive ao atravessar a atmosfera em um dado ângulo e altitude” com apenas uma consulta de textura
  • Sky-view LUT

    • A Sky-view LUT calcula qual cor o céu tem ao olhar do solo em uma direção específica
    • getSkyViewRayDir mapeia vUv.x para o azimute [-PI, PI] e vUv.y para a elevação [-PI/2, PI/2], definindo assim a direção do raymarching
    • Para a elevação, é usado um mapeamento quadrático (vUv.y * vUv.y - 0.5) * PI, como solução alternativa para evitar cintilação excessiva na Sky View a longas distâncias
    • Se o raio não entrar na atmosfera, retorna preto; para raios que atingem o planeta, o raymarching percorre apenas o trecho visível da atmosfera e para mais cedo ao tocar o planeta
    • O loop de dispersão é igual ao anterior, mas avança na direção da Sky View e usa a Transmittance LUT para a luz solar
  • Aerial Perspective LUT

    • Diferentemente do artigo de Hillaire, o resultado desta implementação é uma textura 2D, e cada pixel corresponde a um pixel visível na tela
    • O depth buffer da cena é usado para determinar até que distância marchar ao longo do raio e acumular dispersão
    • Quase todo o código de dispersão anterior é reaproveitado, mas cada amostra obtém da Transmittance LUT a visibilidade da luz solar
    • A saída armazena a dispersão atmosférica acumulada em RGB e, no alfa, um valor packed de view transmittance usado na composição
    • O fluxo da implementação consiste em ler a profundidade de depthBuffer, reconstruir a posição em espaço de mundo do pixel da tela com getWorldPosition(vUv, depth) e então calcular rayDir da posição da câmera até a posição em mundo
    • Em seguida, logDepthToRayDistance(vUv, depth) converte a profundidade da cena em distância ao longo do raio; depois são calculadas as interseções com a atmosfera e o planeta, e só o trecho visível da atmosfera é percorrido
  • Composição

    • Depois de gerar a Sky-view LUT e a Aerial Perspective LUT, ambas são combinadas no pass final de pós-processamento
    • O trabalho principal é converter o rayDir atual em coordenadas UV da Sky View
    • Na geometria da cena é aplicada a Aerial Perspective LUT; o canal alfa é usado como view transmittance, e o canal RGB como luz dispersa, calculando color = color * aerialPerspective.a + aerialPerspective.rgb
    • Para pixels de fundo, é feita a amostragem da Sky View LUT; se depth >= 1.0 - 1e-7, ele é tratado como fundo e aplica-se color = inputColor.rgb + sampleSkyViewLUT(rayDir, planetCenter)
    • Por fim, são aplicados ACESFilm(color) e pow(color, vec3(1.0 / 2.2))
    • O código completo da implementação atmosférica baseada em LUT pode ser visto em Github link

Encerramento

  • O resultado da dispersão atmosférica baseada em LUT pode parecer quase igual à versão anterior com raymarching completo, mas o processo interno é diferente
  • O trabalho é dividido em LUTs menores e depois composto no efeito final, sem repetir raymarching em direção ao sol para calcular a luz incidente em cada amostra
  • Como a informação de iluminação vem diretamente da Transmittance LUT, os loops aninhados caros são substituídos por consultas simples de textura, trazendo um ganho de desempenho relevante na cena final
  • A implementação fica aquém da de Sébastian Hillaire e de outras implementações da área; em especial, há banding e flickering na Sky View, e as simplificações adotadas prejudicam a otimização
  • É possível que o ideal tivesse sido usar WebGPU desde o começo
  • Como implementação realmente production-grade, a recomendação é three-geospatial, de Shoda Matsuda(@shotamatsuda)
  • Também foi feito um trabalho adicional para adicionar volumetric clouds, mas o resultado ainda é irregular e não está satisfatório o bastante para mostrar em um texto, então precisa de mais trabalho

1 comentários

 
GN⁺ 2 시간 전
Comentários do Hacker News
  • Já vi isso antes, então talvez não seja totalmente relacionado, mas o vídeo do Sebastian Lague sobre renderização atmosférica em um experimento de geração de planetas também foi muito interessante https://www.youtube.com/watch?v=DxfEbulyFcY
    Há algo especialmente divertido em desenvolver efeitos visuais e vê-los se tornar cada vez mais realistas, e um dia eu gostaria de experimentar essa área por conta própria
    • O mais impressionante no Sebastian Lague é o quanto o algoritmo do YouTube pode ferrar uma pessoa
      Antes os vídeos dele tinham milhões de visualizações, agora mal passam de 500 mil. Pode ser efeito da pandemia, quando todo mundo estava em casa e se interessava por coisas aleatórias
    • Minha única reclamação sobre o Sebastian Lague é que não há vídeos suficientes
      Normalmente deixo passando para dormir, e já pensei em tentar fazer eu mesmo mais conteúdo assim, calmo mas aprofundado em temas técnicos
  • Não sei se foi omitido de propósito, mas vale apontar que, em um modelo de pôr do sol, o céu não deveria ficar preto assim que o sol passa abaixo do horizonte
    Por algum tempo depois do pôr do sol, a atmosfera acima de você e a região sobre o horizonte ainda continuam recebendo luz solar, e na atmosfera da Terra ainda há crepúsculo perceptível até o Sol chegar a 18 graus abaixo do horizonte. Talvez não seja prático implementar isso com ray tracing, mas existem algoritmos comuns para modelar isso
  • Bons textos sobre gráficos são sempre bem-vindos. Eu também tenho trabalhado em algo parecido num gerador procedural de universo/planetas, e o legal do espalhamento atmosférico é que, combinado com renderização de nuvens volumétricas, ele pode criar cenas incríveis de pôr do sol e céu
    https://www.threads.com/@mrsharpoblunto/post/DVS4wfYiG8f?xmt...
    https://www.threads.com/@mrsharpoblunto/post/C6Vc-S1O9mX?xmt...
    https://www.threads.com/@mrsharpoblunto/post/C6apksDRa8q?xmt...
  • É realmente impressionante o que celulares e navegadores conseguem fazer hoje em dia
    Lembro de ter implementado “Display of The Earth Taking into Account Atmospheric Scattering”, de Nishita et al., um artigo de 1993 e praticamente um dos trabalhos fundadores do tema, além de ser bem fácil de ler: https://www.researchgate.net/publication/2933032_Display_of_...
    • Em outro comentário eu tentei lembrar o artigo que li quando implementei espalhamento de Rayleigh e espalhamento de Mie, e é esse mesmo
      Quando consegui fazer funcionar, tive aquele momento de “dá para modelar esse fenômeno complexo do mundo real muito bem com só alguns cálculos relativamente simples”. Saí de um céu azul estático para um ciclo completo de dia e noite num instante
  • Muito bom mesmo
    Já pensei em tentar renderizar um céu na web sobrepondo vários gradientes. Talvez eu até tivesse conseguido um resultado razoável, mas não chega nem perto do que foi feito aqui. O resultado é impressionante e inspirador
    • Há muito tempo implementei espalhamento de Rayleigh e espalhamento de Mie em um motor de jogo que eu fazia por hobby
      Só isso já produzia um ciclo de pôr do sol/nascer do sol bem convincente, e, se não me engano, o próprio sol meio que surgia naturalmente dali também. Eu usava o XNA, a plataforma da Microsoft para desenvolvimento de jogos em C#, seguindo a excelente série de tutoriais do Riemer, cuja cópia preservada está aqui https://github.com/SimonDarksideJ/XNAGameStudio/wiki/Riemers...
      Mas não estou vendo a parte sobre espalhamento, então talvez eu tenha tirado isso de outro lugar. Ainda lembro de ter lido artigos com fórmulas
  • SpaceEngine também é famoso por ter investido bastante nessa área, então recomendo muito: https://www.youtube.com/watch?v=_4TjdVAbXks
    https://spaceengine.org/
    • O FAQ dessas coisas é ótimo para mostrar a escala e a variedade das perguntas
      A resposta para “Quantos objetos existem no SpaceEngine?” é algo como: todo o catálogo estelar Hipparcos, todos os exoplanetas conhecidos, mais de dez mil galáxias e a maior parte dos objetos do Sistema Solar, somando 130 mil, além de mais galáxias e sistemas estelares do que realmente existem em todo o universo observável. Para “Como um planeta oceânico pode ser quente?”, a resposta é que a água na alta atmosfera é vapor quente, mas ao descer faz uma transição suave para líquido sob alta pressão, e mais fundo se torna um estado sólido chamado ice VII. E a resposta para “Como se move?” é as teclas WASD
    • Deixar a Wikipedia em uma aba e o SpaceEngine na outra é uma das minhas experiências semieducativas favoritas em jogos
      É um jogo excelente e, mesmo sendo bem antigo, ainda não vi nada tão bom quanto ele
    • É um software excelente que existe há muitos anos, e não só nesse tema como em muitos outros o nível de obsessão por detalhes é impressionante
      Ao ler este texto, eu também pensei em SpaceEngine
  • Espalhamento já era, há muito tempo, um elemento central para criar imagens renderizadas realistas
    Um dos meus artigos favoritos: http://www.graphics.stanford.edu/papers/bssrdf/bssrdf.pdf
    Acho que foi aí que aprendi pela primeira vez que renderizar leite é um problema complicado
  • Uau, foi uma jornada e tanto
    Acho que entendi só uns 5%, mas fiquei realmente muito impressionado
    • Comigo foi a mesma coisa. Só o material visual já fez a leitura valer a pena
  • Ah, isso está realmente lindo e é um texto muito agradável de ler
    E sendo licença MIT, então meu problema de skybox no jogo está resolvido. Como a perspectiva vai ficar fixa, eu só preciso de uma renderização do sol atravessando o céu, e dá para expandir isso com uma periodicidade senoidal para a variação anual do ângulo solar