1P by GN⁺ 3시간전 | ★ favorite | 댓글 1개
  • 브라우저 셰이더가 Rayleigh 산란, Mie 산란, 오존 흡수를 조합해 파란 하늘과 일몰·일출을 실시간 렌더링함
  • 카메라 광선의 광학 깊이와 Beer's Law 투과율을 누적하고, 위상 함수로 태양 방향에 따른 산란 분포를 계산함
  • 일몰 효과는 각 샘플에서 태양 방향으로 별도 light-march를 수행해, 태양빛이 대기를 통과하며 잃는 양을 반영함
  • 평면 하늘 셰이더는 depth buffer와 월드 좌표 복원으로 후처리 효과가 되어, 장면 오브젝트 사이 대기 안개까지 처리함
  • 행성 규모에서는 logarithmic depth buffer, ray-sphere intersection, LUT 기반 Transmittance·Sky-view·Aerial Perspective로 확장됨

대기 산란 셰이더의 목표와 참고 자료

하늘 렌더링의 기본 모델

  • 단순 그라디언트가 부족한 이유

    • 하늘색은 단순한 파란 배경이 아니라, 빛이 공기와 그 구성 요소와 상호작용한 결과로 다뤄야 함
    • 관측자의 고도, 먼지의 양, 시간대 같은 변수를 고려해야 하며, 계산은 부피(volume) 안에서 이뤄짐
  • 대기 밀도 샘플링

    • 대기는 volumetric cloudsvolumetric light처럼 raymarching으로 샘플링함
    • 카메라 위치에서 광선을 쏘고 투명한 매질을 따라 전진하면서, 대기를 통과하며 살아남는 빛인 투과율(transmittance) 과 각 샘플에서 카메라 쪽으로 재지향되는 산란(scattering) 을 계산함
    • raymarching 복습 자료로 Painting with Math: A Gentle Study of Raymarching를 참고할 수 있음
  • Rayleigh 밀도와 광학 깊이

    • 투과율을 구하려면 광선이 지나며 만나는 대기 밀도를 누적해 광학 깊이(optical depth) 를 계산해야 함
    • Rayleigh 밀도 함수는 고도 h에서 “공기”가 얼마나 있는지를 나타내며, 고도가 높아질수록 대기가 희박해지는 효과를 반영함
    • 예시 구현은 RAYLEIGH_SCALE_HEIGHT = 8.0km, ATMOSPHERE_HEIGHT = 100.0km, VIEW_DISTANCE = 200.0km, PRIMARY_STEPS = 24를 사용함
    • rayleighDensity(h)exp(-max(h, 0.0) / RAYLEIGH_SCALE_HEIGHT)이고, 루프에서 viewOpticalDepth += dR * stepSize로 누적됨
  • Beer's Law와 낮 하늘의 파란색

    • 광학 깊이에서 특정 지점의 투과율 T를 계산하며, T=1.0은 빛 손실 없음, T=0.0은 빛이 완전히 사라졌다는 뜻임
    • 투과율은 Beer's Law로 계산되며, 예시 코드는 vec3 transmittance = exp(-rayleighBeta * viewOpticalDepth)를 사용함
    • rayleighBeta는 Rayleigh 산란 계수이며, 셰이더에서는 vec3(0.0058, 0.0135, 0.0331)로 저장됨
    • 태양광 방향과 시선 광선 사이의 각도는 3.0 / (16.0 * PI) * (1.0 + mu * mu) 형태의 Rayleigh phase function으로 모델링됨
    • Rayleigh 산란 계수 때문에 빨강은 거의 산란되지 않고, 초록은 조금 더 산란되며, 파랑이 가장 많이 산란되어 낮의 하늘이 파랗게 보임
    • 픽셀마다 하나의 광선으로 확장하면 지평선 쪽은 더 많은 대기를 통과해 밝은 흰 안개처럼 보이고, 고도가 높아질수록 더 깊고 어두운 파란색으로 바뀜

Mie 산란과 오존 흡수

  • Rayleigh만으로 부족한 효과

    • Rayleigh 산란만으로도 괜찮은 결과를 얻을 수 있지만, 더 현실적인 하늘에는 추가 대기 효과가 필요함
    • Mie 산란은 먼지나 에어로졸처럼 더 큰 입자와 빛의 상호작용을 나타내며, 밀도 함수와 방향별 재분배를 나타내는 위상 함수를 가짐
    • 오존 흡수는 상층 대기를 통과하는 빛의 일부 파장을 산란시키지 않고 경로에서 제거함
    • 오존 흡수는 특히 지평선, 일몰, 일출 전후 박명에서 하늘색을 더 깊게 만들고 색을 이동시킴
  • Mie와 오존의 누적

    • Rayleigh, Mie, 오존을 함께 쓰는 구현은 viewODR, viewODM, viewODO로 각각의 광학 깊이를 누적함
    • 각 샘플에서는 dR = rayleighDensity(h), dM = mieDensity(h), dO = ozoneDensity(h)를 계산하고, tauBETA_R * viewODR, BETA_M_EXT * viewODM, BETA_OZONE_ABS * viewODO의 합으로 구성함
    • 투과율은 exp(-tau)로 계산되고, sumR, sumM, sumO에 각 밀도와 투과율, stepSize가 누적됨
    • 최종 산란은 SUN_INTENSITY * (phaseR * BETA_R * sumR + phaseM * BETA_M_SCATTER * sumM + BETA_OZONE_SCATTER * sumO) 형태로 계산됨
  • 주요 상수와 효과

    • MIE_SCALE_HEIGHT는 에어로졸용 RAYLEIGH_SCALE_HEIGHT에 해당하며, 입자가 보통 지평선 가까이에 집중되므로 1.2km로 더 작게 설정됨
    • MIE_BETA_SCATTER는 입자가 빛을 카메라 쪽으로 얼마나 산란시키는지 제어하며, 대부분 파장 독립적이어서 vec3(0.003)으로 설정됨
    • MIE_BETA_EXT는 경로에서 얼마나 많은 빛이 제거되는지 나타내는 Mie 소멸 계수이며, 먼 대기를 더 뿌옇게 보이게 만듦
    • MIE_G는 이방성을 제어하며, 0.0은 균일 산란, 1.0은 더 강한 전방 산란 편향을 뜻함
    • OZONE_BETA_ABSvec3(0.00065, 0.00188, 0.00008) 값을 가지며, 초록과 노랑-주황 계열을 더 많이 흡수해 하늘색을 파랑·빨강·보라 쪽으로 이동시킴
    • Mie와 오존을 통합하면 더 자연스러운 “sky blue” 색과 태양 주변의 뿌연 빛무리가 생기며, 태양이 지평선 가까이에 있을 때 Mie 산란 효과가 더 뚜렷해짐

빛 경로와 일몰·일출

  • 기존 구현의 한계

    • sky fragment shader는 다양한 고도에서 자연스러운 색을 렌더링하고 Mie, Rayleigh, 오존 투과율 모델을 반영할 수 있음
    • 그러나 태양을 지평선 가까이 옮겨도 빛 감쇠나 일몰·일출 효과 없이 흰색의 뿌연 빛무리만 나타남
    • 기존 raymarching 루프가 카메라에서 각 샘플까지의 시선 광선에서만 빛 감쇠를 계산했기 때문임
    • 샘플 지점에 도달하기 전, 태양광이 대기를 통과하며 얼마나 손실되는지도 계산해야 함
  • light-march 중첩 루프

    • 각 샘플 지점에서 광원 방향으로 별도 중첩 루프를 돌려 해당 경로의 투과율을 샘플링함
    • 관련 접근은 real-time cloudscapesvolumetric lighting에서도 사용됨
    • lightMarch(float start, float sunY)LIGHTMARCH_STEPS만큼 반복하면서 odR, odM, odO를 누적함
    • 기존 구현의 광학 깊이 viewODR, viewODM, viewODO에 태양 방향 광학 깊이 sunOD를 더함
    • 최종 tauBETA_R * (viewODR + sunOD.x), BETA_M_EXT * (viewODM + sunOD.y), BETA_OZONE_ABS * (viewODO + sunOD.z)를 합쳐 구성됨
    • 이 구현으로 일몰, 일출, 천정의 태양, 그 사이 조명 조건의 하늘을 렌더링할 수 있음
    • sun angle uniform으로 하루 동안의 하늘 파란색 변화를 만들고, Mie 산란은 일몰과 일출에서 빛을 지평선과 자연스럽게 섞어줌
    • 태양이 낮을 때 오존은 하늘에 보랏빛 톤을 더함

행성 대기로 확장

  • 평면 배경에서 후처리 효과로

    • 앞서 만든 셰이더는 좋은 하늘 배경을 제공하지만, React Three Fiber 장면의 평면 배경에 가까움
    • 다음 단계는 이를 후처리 효과(post-processing effect) 로 바꿔 장면 깊이를 고려하는 부피와 행성 메시에 둘러싼 대기 껍질로 렌더링하는 것임
    • 이를 위해 screenUV 좌표에서 월드 공간 좌표를 재구성하고, 장면의 depth buffer를 raymarching에 반영함
  • 월드 공간 재구성과 3D 광선

    • 대기 산란을 장면에 적용하려면 하늘만 그리는 것이 아니라 카메라와 화면에 렌더링된 오브젝트 사이의 공간을 채워야 함
    • 필요한 데이터는 장면의 depth buffer, 카메라의 projectionMatrixInverse, matrixWorld, position이며, 이 값들을 후처리 효과의 uniform으로 전달함
    • getWorldPosition(vec2 uv, float depth)depth * 2.0 - 1.0으로 clipZ를 만들고, uv * 2.0 - 1.0로 NDC 좌표를 만든 뒤 projectionMatrixInverseviewMatrixInverse를 적용함
    • 같은 과정은 On Shaping Light의 volumetric lighting 후처리 효과에도 사용됨
    • 현재 픽셀의 worldPosition을 얻은 뒤 rayOrigin은 카메라 위치로, rayDirnormalize(worldPosition - rayOrigin)으로 계산해 화면상의 픽셀별 3D 광선을 따라 전진함
  • 깊이 버퍼로 raymarch 구간 조정

    • 장면 지오메트리를 고려하려면 고정 stepSize 대신 depth buffer로 현재 광선의 raymarch 구간을 정해야 함
    • sceneDepth = depthToRayDistance(uv, depth)로 광선상의 장면 깊이를 구함
    • 배경 픽셀은 depth >= 1.0 - 1e-7로 판별하고, “sky pixels”에는 sceneDepth = atmosphereHeight * SKY_MARCH_DISTANCE_MULTIPLIER를 적용함
    • 광선이 아래쪽을 향하면 tGround = observerAltitude / max(-rayDir.y, 1e-4)로 지면 교차를 계산하고 rayEnd = min(rayEnd, tGround)로 제한함
    • 최종 stepSize(rayEnd - rayStart) / float(PRIMARY_STEPS)로 계산함
    • 가까운 오브젝트나 지면에 닿는 광선은 작은 stepSize로 더 정확히 샘플링되고, 멀리 가는 광선은 같은 수의 샘플을 더 긴 거리 위에 분포시킴
  • 장면 안 대기 안개

    • 후처리 효과로 구현된 셰이더는 장면의 부피 전체에 대기 산란을 적용하고, 장면 지오메트리를 고려하면서 sky shader를 배경으로 사용할 수 있음
    • 카메라에 가까운 오브젝트는 더 선명하게 보이고, 멀리 있는 오브젝트는 더 많이 흐려짐
    • Raycaster로 드래그 가능한 천체를 넣은 상호작용 예시는 MaximeHeckel의 트윗에서 확인 가능함

행성 렌더링

  • 필요한 두 단계

    • 행성 주변에 사실적인 대기를 렌더링하려면 큰 스케일을 처리하기 위한 logarithmic depth buffer와, 광선이 대기에서 어디서 시작하고 끝나는지 정의하는 구 형태의 대기 껍질이 필요함
  • logarithmic depth buffer

    • 행성 규모에서는 멀리서 볼 때 대기와 행성 껍질의 깊이 차이를 셰이더가 구분하기 어려워 depth fighting이 발생할 수 있음
    • 대기 높이는 몇 km에 불과하므로, 장면의 depth buffer 정의와 후처리 효과에서의 읽기 방식을 모두 조정해야 함
    • React Three Fiber의 Canvas를 감싸는 gl prop에서 logarithmicDepthBuffer: true를 설정함
    • 예시 설정은 <Canvas shadows gl={{ alpha: true, logarithmicDepthBuffer: true }}> 형태임
    • 셰이더에서는 logarithmic depth buffer를 광선상의 거리로 되돌리기 위해 sceneDepth 계산을 다시 정의함
    • logDepthToViewZ(depth)pow(2.0, depth * log2(cameraFar + 1.0)) - 1.0를 사용하고 -d를 반환함
  • ray-sphere intersection으로 대기 구간 찾기

    • 시선 광선이 대기 구(atmospheric sphere) 에 들어가고 나오는 지점을 찾기 위해 ray-sphere intersection test를 사용함
    • 두 교차점을 얻으면 대기 밖에서 샘플을 낭비하지 않고, 해당 구간으로만 raymarching 루프를 제한할 수 있음
    • 행성은 구형 메시이고 그보다 약간 큰 대기 구가 둘러싼 형태이므로, 같은 교차 테스트를 행성 자체에도 수행함
    • 광선이 대기를 빠져나가기 전에 지면에 닿으면, 지면 교차점을 raymarching 구간의 끝으로 사용함
    • 사용된 raySphereIntersect 구현은 Inigo Quilez의 Ray-Surface intersection functions를 참고함
  • 장면 오브젝트와 대기 종료 조건

    • 대기는 행성 표면에 닿거나, 지면에 닿기 전에 다른 장면 오브젝트를 만나면 종료되어야 함
    • 행성에 닿는 경우 기본적으로 atmosphereFar = min(atmosphereFar, planetHit.x)로 지면에서 멈춤
    • 다른 메시가 지면 앞에 렌더링되어 있으면 sceneDepth < planetHit.x - 2.0 조건으로 판별하고 atmosphereFar = min(atmosphereFar, sceneDepth)를 적용함
    • 이 로직이 없으면 행성 표면이 오브젝트보다 앞에 나타나는 문제가 생김
  • React Three Fiber 데모와 남은 글리치

    • 두 조정을 코드에 반영하면 대기 산란을 후처리 효과로 구현하고, 행성 주변의 대기를 렌더링할 수 있음
    • 데모 장면은 React Three Fiber에서 간단한 “Sun - Earth system”을 렌더링하고 커스텀 효과를 적용함
    • 태양 위치를 조정하고 줌아웃하면 지상에서 궤도까지 다양한 각도에서 셰이더가 만드는 하늘색을 볼 수 있음
    • 같은 효과가 4월 초 글 예고용 포스터 이미지에 사용되었으며, 렌더 이미지는 트윗으로 공유됨
    • 장면의 torus는 해가 진 뒤에도 여전히 “lit-up” 상태로 보일 수 있음
    • 원인은 주 directional light의 shadow-map 또는 shadow-camera 스케일이 작아, 너무 멀리 있는 torus를 덮지 못하는 데 있음
    • 우회책으로 volumetric lighting article의 shadow-mapping 접근을 재사용할 수 있지만, 실제로 시도되지는 않음

일식 처리

  • 큰 천체가 태양을 가리는 경우lightMarch 이후 sunVisibility 함수를 호출하고, 반환값 [0, 1]을 투과율에 곱하는 방식으로 추가할 수 있음
  • 기본 아이디어는 현재 샘플 지점에서 달 방향태양 방향의 내적을 비교하는 것임
  • 두 방향이 거의 같아 내적이 1.0에 가까우면 달이 태양을 가리는 상태이고, 직교해 0.0에 가까우면 가림이 없음
  • 단순 내적만으로는 장면 안 객체의 크기와 스케일을 반영하지 못하므로, 구현은 태양과 달의 각거리와 각각의 각반지름을 비교함
  • sunVisibility는 달이 태양을 가리지 않는 경우, 달이 카메라 시점에서 태양보다 크거나 비슷한 크기로 보이는 상태에서 가리는 경우, 달이 카메라 시점에서 태양 반지름 안에 들어가는 상태로 가리는 경우를 다룸
  • 데모는 기존 대기 산란 예제 위에 sunVisibility달 메시를 추가해, 달을 태양과 정렬했을 때 빛이 부족한 상황을 Atmospheric Scattering 셰이더가 처리하도록 함
  • 더 정교한 일식과 코로나 시뮬레이션은 Physically Based Real-Time Rendering of Eclipses 논문에서 다루며, 해당 논문 구현은 WebGL로 포팅하지 않음

다른 행성의 대기

  • 사용한 대기 밀도와 산란 모델은 행성과 대기의 반지름, RayleighScaleHeight, RayleighBeta, MieScaleHeight, MieBeta, mieBetaExt, mieG, OzoneHeight, OzoneWidth 같은 몇 가지 상수로 대부분 결정됨
  • 이 값들을 조정하면 화성 대기나 다른 행성의 대기에 가까운 결과를 만들 수 있음
  • 화성용으로 사용한 값은 근사치임
    • planetRadius: 3390
    • atmosphereRadius: 3500, 약 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'
  • 기존 상수를 이 값들로 바꾸면 더 먼지 많고 주황빛인 대기가 나오며, 화성의 특징적인 일몰 시 푸른 색조도 얻을 수 있음
  • 관련 논문으로 Physically Based Rendering of the Martian Atmosphere가 있음

LUT 기반 대기 산란

  • 접근 방식과 단축한 부분

    • 기존 셰이더는 작은 스케일과 큰 스케일의 대기를 직관적으로 렌더링할 수 있지만, PRIMARY_STEPS가 많은 레이마칭 루프, lightmarching 중첩 루프, 전체 화면 해상도 계산 때문에 실행 비용이 큼
    • Sebastian Hillaire의 A Scalable and Production Ready Sky and Atmosphere Rendering Technique는 비용이 큰 산란 계산을 텍스처에 저장하고, 최종 렌더에서 미리 계산된 텍스처를 샘플링·합성하는 Look Up Tables(LUTs) 기반 방식을 제안함
    • 다루는 LUT는 빛이 대기를 통과하면서 살아남는 양을 저장하는 Transmittance LUT, 특정 카메라 위치에서의 하늘 색을 저장하는 Sky-view LUT, 카메라와 보이는 장면 지오메트리 사이의 대기 헤이즈와 산란광을 저장하는 Aerial Perspective LUT
    • 전체 논문 구현을 그대로 옮기지는 않았고, LUT는 WebGPU의 compute shader에 적합하지만 시간 부족과 글의 연속성 때문에 WebGL을 유지함
    • 논문에서 Aerial Perspective LUT는 3D texture지만, 구현에서는 2D render target을 사용함
    • 이 방식은 카메라가 움직일 때마다 올바른 픽셀 값을 위해 텍스처를 다시 생성해야 하며, 미리 계산해두기 어려움
    • Multi-Scattering은 시간 부족으로 생략됨
  • Transmittance LUT

    • 기존 셰이더에서는 모든 샘플 지점이 lightmarch를 호출해 태양빛이 얼마나 도달하는지 계산했으며, 이 과정이 비쌈
    • Transmittance LUT는 이 데이터를 낮은 해상도로 미리 저장해, 이후 LUT들이 빛 데이터를 필요로 할 때 읽어 쓰도록 함
    • 구현은 250 x 64 해상도의 전용 Frame Buffer Object를 정의하고, 커스텀 셰이더 material을 전용 장면 transmittanceLUTScene의 full-screen quad에 적용한 뒤 렌더 결과 텍스처를 downstream LUT의 uniform으로 전달함
    • 각 픽셀에서 vec3(0.0, radius, 0.0)부터 레이마칭하며, radiusvUv.y 좌표를 따라 planetRadius에서 atmosphereRadius까지 증가함
    • LUT의 x축은 빛의 각도, y축은 고도를 나타내며, 순수한 흰색은 100% 투과율이고 검은색 또는 색이 있는 영역은 지면이나 공기가 가장 두꺼운 부분을 나타냄
    • 이후 LUT들은 “주어진 각도와 고도에서 대기를 통과해 살아남는 빛의 양”을 텍스처 조회만으로 얻을 수 있음
  • Sky-view LUT

    • Sky-view LUT는 특정 방향을 지상에서 올려다볼 때 하늘이 어떤 색인지 계산함
    • getSkyViewRayDirvUv.xazimuth [-PI, PI]에, vUv.yelevation [-PI/2, PI/2]에 매핑해 레이마칭 방향을 정의함
    • elevation에는 (vUv.y * vUv.y - 0.5) * PI라는 quadratic mapping을 사용하며, 먼 거리에서 Sky View가 너무 많이 깜빡이는 것을 피하기 위한 우회책임
    • 레이가 대기에 들어가지 않으면 검은색을 반환하고, 행성에 닿는 레이는 보이는 대기 구간까지만 레이마칭하며 행성에 닿으면 더 일찍 멈춤
    • 산란 루프는 이전과 같지만, Sky View 방향을 따라 진행하며 태양빛에는 Transmittance LUT를 사용함
  • Aerial Perspective LUT

    • Hillaire 논문과 달리 구현 결과는 2D 텍스처이고, 각 픽셀은 보이는 화면 픽셀 하나에 대응함
    • 장면 depth buffer를 사용해 해당 레이를 따라 얼마나 멀리 행진하고 산란을 누적할지 결정함
    • 기존 산란 코드를 거의 재사용하되, 각 샘플이 Transmittance LUT에서 태양빛 가시성을 가져옴
    • 출력은 RGB에 누적된 대기 산란을 저장하고, 알파에는 합성 때 사용할 packed view transmittance 값을 저장함
    • 구현 흐름은 depthBuffer에서 깊이를 읽고, getWorldPosition(vUv, depth)로 화면 픽셀의 월드 공간 위치를 복원한 뒤, 카메라 위치에서 월드 위치까지의 rayDir을 계산하는 방식임
    • 이어서 logDepthToRayDistance(vUv, depth)로 장면 깊이를 레이 거리로 변환하고, 대기와 행성 교차를 계산한 뒤 보이는 대기 구간만 march함
  • 합성

    • Sky-view LUT와 Aerial Perspective LUT를 생성한 뒤 마지막 post-processing pass에서 둘을 결합함
    • 핵심 작업은 현재 rayDirSky View UV 좌표로 변환하는 것임
    • 장면 지오메트리에는 Aerial Perspective LUT를 적용하며, 알파 채널은 view transmittance로, RGB 채널은 산란광으로 사용해 color = color * aerialPerspective.a + aerialPerspective.rgb를 계산함
    • 배경 픽셀에는 Sky View LUT를 샘플링하며, depth >= 1.0 - 1e-7이면 배경으로 보고 color = inputColor.rgb + sampleSkyViewLUT(rayDir, planetCenter)를 적용함
    • 마지막으로 ACESFilm(color)pow(color, vec3(1.0 / 2.2))를 적용함
    • 전체 LUT 기반 대기 구현 코드는 Github link에서 확인할 수 있음

마무리

  • LUT 기반 대기 산란 결과는 이전 완전 레이마칭 버전과 거의 같아 보일 수 있지만, 내부 과정은 다름
  • 작업을 더 작은 LUT들로 나누고 마지막 효과에서 합성하며, 각 샘플마다 태양 쪽으로 반복 레이마칭해 도달 빛을 계산하지 않음
  • Transmittance LUT에서 조명 정보를 직접 가져오므로, 비용 큰 중첩 루프를 단순 텍스처 조회로 대체하고 최종 장면에서 무시할 수 없는 성능 향상을 얻음
  • 구현은 Sébastian Hillaire와 다른 분야 구현에 비하면 부족하며, 특히 Sky View에서 banding과 flickering이 있고 단축한 부분 때문에 최적성이 떨어짐
  • 처음부터 WebGPU를 썼어야 했을 가능성이 있음
  • 실제 production-grade 구현으로 Shoda Matsuda(@shotamatsuda)의 three-geospatial을 추천함
  • 추가로 volumetric clouds를 얹는 작업도 했지만, 결과가 아직 mixed bag이며 글로 보여줄 만큼 만족스럽지는 않아 더 작업이 필요함
Hacker News 의견들
  • 예전에 본 거라 완전히 관련 있진 않을 수 있지만, Sebastian Lague가 행성 생성 실험에서 대기 렌더링을 다룬 영상도 정말 재미있었음 https://www.youtube.com/watch?v=DxfEbulyFcY
    시각 효과를 개발하고 점점 현실처럼 구현되는 걸 보는 데는 특별히 재미있는 면이 있고, 언젠가 이 분야를 직접 실험해보고 싶음
    • Sebastian Lague에서 가장 놀라운 건 YouTube 알고리즘이 사람을 얼마나 망칠 수 있느냐임
      예전엔 영상 조회수가 수백만이었는데 지금은 50만도 겨우 넘김. 코로나 때 모두 집에 있으면서 랜덤한 것들에 관심을 가졌던 영향일 수도 있음
    • Sebastian Lague에 대한 유일한 불만은 영상이 충분히 많지 않다는 것뿐임
      보통 잠들 때 틀어두는데, 차분하지만 깊이 있게 기술 주제를 파고드는 이런 콘텐츠가 더 있었으면 해서 직접 만들어볼까 생각한 적도 있음
  • 의도적으로 뺀 건지 모르겠지만, 일몰 모델에서 해가 지평선 아래로 내려가자마자 하늘이 검게 변하면 안 된다는 점은 짚을 만함
    해가 진 뒤에도 한동안 머리 위 대기와 지평선 위 영역은 여전히 햇빛을 받고, 지구 대기에서는 태양이 지평선 아래 18도까지 내려갈 때까지 눈에 띄는 황혼이 남음. 광선 추적으로 구현하긴 실용적이지 않을 수 있지만, 이를 모델링하는 일반적인 알고리즘은 있음
  • 좋은 그래픽 글은 언제나 반가움. 나도 절차적 우주/행성 생성기에서 비슷한 걸 작업해왔고, 대기 산란은 체적 구름 렌더링과 결합하면 멋진 일몰과 하늘 장면을 만들 수 있다는 점이 좋음
    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...
  • 요즘 휴대폰과 브라우저가 할 수 있는 일이 정말 놀라움
    1993년 논문이자 이 주제의 원조에 가까우며 아주 읽기 쉬운 Nishita 등의 “Display of The Earth Taking into Account Atmospheric Scattering”를 구현했던 기억이 남: https://www.researchgate.net/publication/2933032_Display_of_...
    • 예전에 Rayleigh 산란Mie 산란을 구현하면서 읽었던 논문을 다른 댓글에서 떠올렸는데, 이게 확실함
      작동하게 만들었을 때 “이 복잡한 현실 세계 현상을 비교적 단순한 계산 몇 개로 꽤 잘 모델링할 수 있네”라는 순간이 왔음. 정적인 파란 하늘상자에서 순식간에 완전한 주야 순환으로 넘어갔음
  • 정말 훌륭함
    예전에 웹에서 하늘을 여러 그라데이션을 겹쳐 렌더링해보면 어떨까 생각한 적이 있음. 어느 정도는 성공해서 그럭저럭한 결과를 얻었을 수는 있겠지만, 여기서 만든 것과는 비교가 안 됨. 결과물이 인상적이고 영감을 줌
    • 예전에 취미로 만든 게임 엔진에서 Rayleigh 산란Mie 산란을 구현한 적이 있음
      그것만으로도 꽤 그럴듯한 일몰/일출 순환이 나오는 걸 보고 놀랐고, 기억이 맞다면 태양 자체도 어쩐지 거기서 자연스럽게 튀어나왔음. Microsoft의 C# 게임 개발 플랫폼인 XNA를 쓰면서 Riemer의 훌륭한 튜토리얼 시리즈를 따라갔고, 보존본은 여기 있음 https://github.com/SimonDarksideJ/XNAGameStudio/wiki/Riemers...
      다만 산란 관련 내용은 보이지 않아서 그 부분은 다른 데서 가져왔을 수도 있음. 수식이 들어간 논문들을 읽었던 기억은 남
  • SpaceEngine도 이 분야에 꽤 공을 들인 것으로 유명해서 강력 추천함: https://www.youtube.com/watch?v=_4TjdVAbXks
    https://spaceengine.org/
    • 이런 것들의 FAQ는 스케일과 질문의 다양성을 보여줘서 좋음
      “SpaceEngine에는 객체가 몇 개 있나요?”에 대한 답이 Hipparcos 별 목록 전체, 알려진 외계 행성 전부, 만 개가 넘는 은하, 태양계 대부분의 객체를 합쳐 13만 개이며, 여기에 관측 가능한 우주 전체에 실제로 존재하는 것보다 더 많은 은하와 항성계가 추가된다는 식임. “물 행성이 어떻게 뜨거울 수 있나요?”에는 상층 대기의 물은 뜨거운 수증기지만 아래로 내려가면 고압에서 액체로 부드럽게 전이되고, 더 깊게는 ice VII라는 고체 상태가 된다고 답함. “어떻게 이동하나요?”의 답은 WASD 키임
    • 한쪽 탭에는 Wikipedia, 다른 탭에는 SpaceEngine을 띄워두는 게 내가 좋아하는 준교육적 게임 경험 중 하나임
      훌륭한 게임이고, 꽤 오래됐는데도 이만큼 괜찮은 걸 아직 못 봄
    • 여러 해 전부터 있었던 훌륭한 소프트웨어이고, 이 주제뿐 아니라 많은 부분에서 디테일에 대한 집착이 대단함
      이 글을 보니 나도 SpaceEngine이 떠올랐음
  • 산란은 오래전부터 사실적인 렌더링 이미지를 만드는 핵심이었음
    내가 좋아하는 논문 중 하나: http://www.graphics.stanford.edu/papers/bssrdf/bssrdf.pdf
    우유를 렌더링하는 게 까다로운 문제라는 걸 아마 이때 처음 배웠던 것 같음
  • 와, 꽤 엄청난 여정이었음
    아마 5% 정도밖에 이해 못 했지만, 정말 크게 감탄함
    • 나도 마찬가지임. 시각 자료만으로도 읽을 가치가 있었음
  • 오, 이건 정말 아름답고 읽기 좋은 글임
    게다가 MIT 라이선스라면 내 게임의 하늘상자 문제는 해결된 셈임. 원근이 고정될 테니 태양이 하늘을 가로지르는 렌더만 있으면 되고, 여기에 사인파 주기로 연중 태양 각도 변화를 확장할 수 있음