1P by GN⁺ | ★ favorite | 댓글 1개
  • 하늘 배경용 달과 가스 행성은 실제 구 메시 없이도 원형 디스크와 픽셀 셰이더만으로 표면, 회전, 대기 표현을 처리할 수 있음
  • 기존 UV sphere는 2×1 텍스처 매핑은 쉽지만 각진 외곽선, mipmap 샘플링 손실, 반복 패턴, seam, 극점 왜곡, 대기 halo 한계가 함께 생김
  • 디스크 방식은 중심 UV에서 구 표면 위치를 복원한 뒤 asin 기반 구면 UV, 회전 행렬, u좌표 이동 spin으로 구처럼 보이는 표면을 픽셀 단위로 만듦
  • 셰이딩은 표면 위치를 normal로 쓰는 Lambertian 조명에서 출발하고, 암석 표면에는 TBN 행렬과 normal map을 적용하며, 대기는 halo 밝기와 채널별 흡수를 근사함
  • Substance Designer 정적 텍스처와 Unreal 동적 렌더링 텍스처를 같은 방식으로 다룰 수 있어, 더 작은 동적 텍스처와 tiling 조정으로 성능 부담을 줄일 수 있음

스카이박스 행성의 시각 목표

  • 프로젝트의 스카이박스는 애니메이션 달가스 행성으로 외계 하늘 같은 구성을 만드는 데 초점을 둠
  • 두 행성은 회전하고, 가스 행성에는 움직이는 대기 흐름도 들어감
    • 실제 움직임은 미묘하지만, 시각적 효과를 위해 속도를 높임
  • 미술 방향은 1970~80년대 SF 아트에서 영감을 받은 반사실적(semi-realistic) 스타일임

표면 텍스처 입력과 제약

  • 가스 행성 표면은 픽셀 셰이더와 render-to-texture 방식으로 실시간 생성
  • 달 텍스처는 Substance Designer에서 만들며, 색상 팔레트와 material seed를 바꿔 다양한 look을 실험할 수 있음
  • 동적 가스 행성은 매 프레임 텍스처를 렌더링해야 해 성능 비용이 커짐
    • 텍스처 해상도를 2배로 올리면 렌더링 비용은 4배가 됨
  • 정적 Substance Designer 텍스처와 Unreal에서 동적으로 렌더링한 텍스처 모두에 일관되게 동작하는 해결책이 필요함
  • cubemap은 처음에 고려됐지만 정사각형 텍스처 대비 6배 리소스를 쓸 수 있고, Substance Designer가 cubemap 생성을 지원하지 않아 실용적이지 않음

UV sphere에서 드러난 한계

  • UV sphere는 2×1 직사각형 텍스처와 좌표를 맞추기 쉬워 기본 선택지처럼 보임
  • 한 번에 구의 한쪽 면만 보이므로 전체 고유 직사각형 텍스처 대신 타일링 정사각형 텍스처를 쓸 수도 있음
  • 실제 적용에서는 여러 문제가 겹침
    • 외곽선이 눈에 띄게 각져 보이며, subdivision을 늘리거나 픽셀 셰이더 마스크로 가려야 함
    • 구 표면 대부분이 비스듬히 보여 낮은 mipmap에서 샘플링되고, 동적 텍스처에서는 매 프레임 생성한 픽셀 상당수가 거의 보이지 않는 영역에 쓰임
    • tiling은 정수 배수로 늘려야 전체 패턴이 이어지며, 2배만 늘려도 반복이 눈에 띔
    • fractional tiling은 북극에서 남극까지 이어지는 seam을 만듦
    • 극점에서는 texture pinching과 삼각형 매핑 왜곡이 생기며, PSX의 흔들리는 텍스처 같은 왜곡과 비슷하게 보임
    • 표면만 그릴 수 있어 atmospheric halo에는 별도 모델이 필요함
  • UV sphere는 행성 모델링에는 여전히 쓸 수 있지만, 스카이박스 용도에서는 수정과 hack이 많아짐

원형 디스크와 픽셀 셰이더 접근

  • 스카이박스 행성은 멀리서 한 위치에서 관찰되므로 복잡한 3D 구 메시가 꼭 필요하지 않음
  • 단순한 채워진 원형 폴리곤 디스크를 쓰고, 픽셀 셰이더에서 텍스처 매핑을 처리함
  • 같은 메시 안에서 atmospheric halo까지 그릴 수 있음
  • 디스크의 UV 원점은 정확히 중심에 있어야 함
    • 행성 반지름을 1로 보면, 대기를 그릴 공간을 위해 UV 좌표는 그보다 바깥까지 확장돼야 함

구 표면 복원

  • 좌표계는 DirectX와 일관된 left-handed, Y-up 시스템을 사용함
    • Unreal Engine도 left-handed지만 up 방향은 Z이므로 방향과 normal map 포맷을 확인해야 함
  • 표면 방정식은 디스크 평면의 2D 위치를 구 표면의 3D 위치로 매핑함
  • 먼저 픽셀이 구 표면 안에 있는지 판단하기 위해 UV 벡터 길이가 반지름보다 작은지 검사함
float CircleMask( float2 uv, float radius)
{
    return length(uv) < radius? 1.0: 0.0;
}
  • 이 방식은 UV 좌표가 메시 중심에 정렬돼 있을 때만 올바르게 동작함
  • 구 표면의 local position은 UV의 x, y를 그대로 쓰고 z만 복원함
float3 ReconstructSurface(float2 uv)
{
    float zSquared = 1.0 - dot(uv, uv);
    float z = sqrt(zSquared);
    return float3(uv, z);
}

구면 UV 생성

  • 정사각형 텍스처를 구 표면에 매핑하는 과정은 세 단계로 나뉨
    • 원통에 감기
    • y축에도 같은 처리 반복
    • 결과를 원 형태로 변형
  • x 텍스처 좌표는 원통을 감는 각도에 비례하며, arcsine(x)를 계산한 뒤 [-π, π][0, 1]로 다시 매핑함
  • 구의 local width인 generatrix를 이용해 극점에서 좌표를 pinching함
float2 GenerateSphericalUV(float3 position)
{
    float width = sqrt(1.0 - position.y * position.y);
    float generatrixX = position.x / width * sign(position.z);
    float2 generatrix = float2(generatrixX, position.y);
    float2 uv = asin(generatrix) / 3.14159 + float2(0.5, 0.5);
    return float2(uv);
}

축 기울기와 회전

  • 더 자연스러운 행성 구도를 위해 pitch와 roll로 행성 축을 기울임
    • SF 아트의 행성은 보통 기울어져 있어 구성이 역동적으로 보이고 극지방 ice cap을 보여줄 수 있음
  • yaw는 회전 운동에 해당하며, seam 문제를 피하기 위해 별도 단계에서 처리함
  • 메시 구에서는 일반적으로 행성을 행렬로 변환하지만, 디스크 방식에서는 각 픽셀이 표면 위치를 정의하므로 회전만 담은 단순한 3×3 행렬을 쓸 수 있음
float3x3 CreateRotationMatrix(float pitch, float roll) {
    float cosPitch = cos(pitch);
    float sinPitch = sin(pitch);
    float cosRoll = cos(roll);
    float sinRoll = sin(roll);

    return (float3x3)(
        cosRoll, -sinRoll * cosPitch, sinRoll * sinPitch,
        sinRoll, cosRoll * cosPitch, -cosRoll * sinPitch,
        0.0, sinPitch, cosPitch
    );
}
  • Unreal의 material editor는 행렬을 데이터 형식으로 지원하지 않지만 우회 방식이 있음

scale, seam, spin 처리

  • 텍스처 scale을 바꾸면 원래 텍스처 가장자리에 맞춰 숨겨져 있던 UV seam이 드러남
  • seam은 완전히 쉽게 제거할 수 없지만, 뒤쪽으로 옮기면 덜 보임
  • 구를 position sign 기준으로 사분면으로 나누고, back-left와 back-right 사분면에 u방향 offset을 적용함
float2 GenerateSphericalUV(float3 position, float spin, float scale)
{
    float leftRightSign = sign(position.x);
    float frontBackSign = sign(position.z);
    float width = sqrt(1.0 - position.y * position.y);
    float generatrixX = position.x / width * frontBackSign;
    float2 generatrix = float2 (generatrixX, position.y);
    float2 uv = asin(generatrix) / 3.14159 + float2 (spin, 0.5);
    if(frontBackSign < 0.0)
    {
        uv = float2 (uv.x + 1.0 * leftRightSign, uv.y);
    }
    return float2 (uv / scale);
}
  • seam은 여전히 북극과 남극을 잇지만, 뒤쪽으로 이동해 훨씬 덜 보임
  • 회전은 구 자체를 돌리지 않고 u좌표 방향으로 표면 텍스처를 이동시켜 처리함
float2 GenerateSphericalUV(float3 position, float scale, float spin)
{
    float width = sqrt(1.0 - position.y * position.y);
    float generatrixX = position.x / width * sign(position.z);
    float2 generatrix = float2(generatrixX, position.y);
    float2 uv = asin(generatrix) / 3.14159 * scale + float2(0.5 + spin, 0.5);
    return float2(uv);
}
float2 sphericalVU = GenerateSphericalUV(position, scale, time*speed)

표면 셰이딩과 normal map

  • 행성이 둥글게 보이려면 셰이딩이 중요함
  • 일반 엔진 셰이딩과 달리 행성은 표면과 대기라는 두 레이어를 가지므로, 두 레이어의 조명과 blending을 수동으로 정의해야 함
  • 반지름이 1인 경우, 회전 전 표면 위치는 곧 surface normal로 쓸 수 있음
  • 조명은 단순한 Lambertian 모델을 사용함
    • 목표는 완전한 사실성이 아니라 NASA 사진에서 영감을 받은 양식화된 SF 표지 미학임
float LambertianLight(float3 normal, float3 lightDirection) {
    float NdotL = max(dot(normal, lightDirection), 0.0);
    return NdotL;
}
  • gas giant처럼 매끈한 표면은 단순 normal로 충분할 수 있음
  • 암석형 행성은 산맥, 능선, 크레이터 같은 지형을 normal map으로 시뮬레이션하는 편이 적합함
  • normal map을 쓰려면 Tangent, Bitangent, Normal로 구성된 TBN 행렬이 필요함
    • 구에서는 이 계산을 픽셀 단위로 수행해야 함
    • TBN 행렬은 normal map의 normal을 World Space Coordinates로 변환하는 데 쓰임

UV 불연속과 mipmap 아티팩트

  • 픽셀 셰이더에서 생성한 UV에는 불연속(discontinuity) 문제가 생길 수 있음
  • back seam은 수평 UV 성분이 경계에서 0.0과 1.0으로 완전히 이어져야 하지만, 실제로는 seam을 따라 blocky artifact가 생김
  • 이 선은 UV의 DDX와 대응함
    • DDX와 DDY는 화면 공간 축에서 UV 변화율을 측정함
    • 텍스처 샘플러는 이 값을 이용해 사용할 mipmap을 결정함
    • 낮은 UV derivative는 고해상도 mipmap에, 높은 derivative는 저해상도 mipmap에 대응함
  • seam 좌우의 값이 급격히 뛰면 DDX가 커지고, 가장 낮은 mipmap에서 샘플링돼 회색 선처럼 보일 수 있음
  • 행성에서는 polar patch로 가려질 예정이라 큰 문제가 아니지만, 눈에 띄는 경우에는 seam의 DDX와 DDY를 수동 보정해 sampler에 전달해야 함
  • 예시 fix는 설명용이며, 실제 값은 mapping에 맞도록 수식을 직접 유도해야 함

극지 패치와 pinching 보정

  • 극점 왜곡은 검증된 방식대로 polar patch로 덮음
  • 행성이나 달에서는 극지방이 얼음으로 덮여 있고 다른 지역과 시각적으로 구분되는 경우가 많아, 별도 텍스처 패치가 문제를 숨기면서 시각적 흥미도 더함
  • polar patch는 회전축에 수직인 평면에 매핑하고 결과 좌표를 회전시키는 방식으로 추가할 수 있음
float2 PolarPatchMapping(float3 position, float scale, float spin)
{
    float cosSpin = cos(spin);
    float sinSpin = sin(spin);
    float scale = 0.4;

    float2 uv = float2(position.x, position.z) * scale;
    float2 spinningUV = float2(uv.x * cosSpin - uv.y * sinSpin,
                               uv.x * sinSpin + uv.y * cosSpin);

    return spinningUV;
}
  • UV map을 정점에 저장하지 않고 픽셀마다 생성하기 때문에, 극점 pinching 보정의 유연성이 커짐
  • 간단한 나눗셈으로 극점 텍스처의 aspect ratio를 보정할 수 있음
uv = float2(uv.x, uv.y/pow(width, 1/3));
  • 보정 결과는 다른 artifact처럼 보일 수 있지만, 현실적인 장면에서는 polar patch와 더 매끄럽게 이어지고 시각적 불일치가 줄어듦

대기 halo 근사

  • 디스크에서 행성 표면이 전체 영역을 차지하지 않기 때문에, 남는 공간에 atmospheric halo를 그릴 수 있음
  • 같은 셰이더 안에서 halo를 그리면 행성 위 대기와 자연스럽게 합칠 수 있음
  • 물리 기반 대기 렌더링은 보통 Rayleigh scattering과 raymarching을 사용하지만, 여기서는 쓰지 않음
  • Quake 1·2의 동적 오브젝트 조명 trick과 비슷한 근사를 사용함
    • Quake의 static lighting은 lightmap으로 미리 계산됐음
    • 동적 몬스터는 아래쪽 lightmap을 샘플링해 색을 조절했고, 물리적으로 정확하지는 않아도 주변과 어울리게 만들었음
  • 같은 방식으로 행성 표면을 이용해 대기 halo의 조명을 근사함
    • bump mapping 전 표면 normal을 확장해 halo 밝기를 계산함
    • 채널별 밝기를 다르게 remap하면 서로 다른 빛 파장 흡수를 단순하게 시뮬레이션할 수 있음
    • 대기는 비스듬한 각도에서 더 잘 보이므로 surface normal의 Z 성분을 remap함
    • halo fade 효과를 위해 구 표면으로부터의 거리도 계산함
  • 마지막에는 표면과 대기를 alpha blending으로 합침

최종 결과와 활용

  • 예상보다 많은 단계가 필요했지만, 최종 결과는 완전한 구처럼 보이며 원하는 텍스처·셰이더 조작을 지원함
  • Substance Designer graph 하나로 표면 텍스처를 만들 수 있고, 결과물에 추가 후처리가 필요하지 않음
  • 애니메이션 텍스처도 같은 방식으로 다룰 수 있음
    • 더 작은 텍스처 크기를 사용해 성능을 아낄 수 있음
    • 필요한 만큼 tiling을 조정할 수 있음
  • 결과 영상은 Video 3에서 확인할 수 있음

댓글과 토론

Hacker News 의견들
  • 글쓴이가 큐브맵을 너무 빨리 배제한 듯한데, 개인 프로젝트에서 동적 가스 행성을 렌더링할 때 써보니 가장 단순한 해법이었음
    큐브맵을 쓴다고 메모리가 6배로 늘지는 않고, 큰 직사각형 텍스처 하나를 작은 직사각형 면 6개로 나누는 것이라 전체 텍스처 디테일은 같음
    장점은 극점 눌림을 신경 쓰지 않아도 되고, 3차원 또는 4차원 노이즈 함수로 텍스처 애니메이션/왜곡용 이음새 없는 흐름장을 쉽게 만들 수 있다는 점임
    https://www.junkship.net/News/2016/06/09/jupiter-jazz

    • 이상한 이음새 아티팩트를 피하려면 입체사영 반구 2개를 쓰는 편이 더 나을 수 있음
      각 반구는 원반으로 투영되지만 텍스처를 정사각형 경계까지 채우고, 각 반구 일부를 다른 쪽 텍스처의 모서리에 중복시킬 수 있음
      원반 중심과 가장자리 사이에 1:2 스케일 차이가 있어 최소 디테일 기준으로 픽셀 낭비가 있다고 볼 수도 있지만, 등각 투영이라 급한 원근에서 대상 픽셀 색을 샘플링하는 방법을 훨씬 덜 까다롭게 만들고, 정방향/역방향 계산도 투영점마다 나눗셈 1번과 덧셈·곱셈 몇 번이면 돼 큐브맵의 중심투영보다도 저렴함
      스케일 변화와 모서리 픽셀 낭비를 더 줄이면서도 개념적으로 너무 어렵지 않은 등각 방식이 필요하면, 서로 직각으로 약간 겹치는 Mercator 투영 2개를 써서 야구공 가죽 두 조각처럼 구를 덮을 수 있음
      각 조각은 직사각형 텍스처가 될 수 있고, NOAA 논문 중에는 지구 날씨 시뮬레이션의 미분방정식 격자에 이 접근을 제안하는 것도 있음
      내가 아는 가장 픽셀 효율적인 투영은 구를 팔면체로 나눈 뒤, 각 팔분면을 “구면 면적 좌표” 기반의 육각 픽셀 격자로 덮는 방식임
      각 팔분면은 일반 정사각 픽셀 이미지에서 반쪽 정사각형, 즉 45-45-90 직각삼각형으로 표현할 수 있어 https://observablehq.com/@jrus/sac-quincuncial 같은 결과가 나오고, https://observablehq.com/@jrus/sphere-resample 같은 육각 격자도 쓸 수 있음
      다만 경계선을 넘어 샘플링해야 할 때의 세부 처리가 입체사영 2개 방식보다 훨씬 번거롭고, 이음새 아티팩트도 생길 수 있음
    • https://en.wikipedia.org/wiki/Peirce_quincuncial_projection
    • 왜곡을 더 줄이고 싶다면 정이십면체의 삼각형 면들을 10개의 마름모로 묶고, 각 마름모를 정사각형 텍스처 하나로 덮을 수도 있음
      수학은 더 필요하지만, 다른 이유로 표면을 더 세분할 계획이 아니라면 보통 그만한 가치까지는 없음
    • 지금 만들고 있는 행성 규모 게임에서 구름 생성에 저 컬 노이즈를 써볼 수 있겠음
  • 극점의 텍스처 눌림은 사실 전체 표면에 존재하는 왜곡이 극단적으로 드러난 형태임
    보통 극점에서만 뚜렷하지만, 구를 삼각형으로 적응형 세분하면 세분 수준이 바뀔 때 왜곡도 함께 변해서 다른 곳에서도 보일 수 있음
    문제는 구가 사각형으로 나뉘고, 각 사각형이 UV 공간에서는 같은 면적을 가진 삼각형 2개로 표현되지만 3D 공간에서는 한 삼각형, 특히 수평 모서리가 극점에 가까운 쪽이 더 작다는 데 있음
    그런데도 UV는 삼각형 내부에서 선형 보간되므로 텍스처의 절반은 줄어들고 절반은 늘어남
    극점에서는 한 삼각형의 3D 면적이 실제로 0이 되어 텍스처 절반만 렌더링되고, 삼각형 사이의 이음새가 뚜렷해짐
    올바른 해법은 정점 단위 선형 보간 대신 픽셀 셰이더에서 픽셀마다 UV 좌표를 계산하는 것이고, 제대로 하면 극점도 이음새 없이 처리됨

    • 렌더링, 셰이더, 게임 개발을 조금씩 만져보기 시작했는데 더 찾아볼 수 있는 힌트나 키워드, 링크가 있으면 알고 싶음
    • XYZ 항목에서 W를 1로 두지 않고 W를 스케일링하면 이 문제가 고쳐지지 않나?
    • 이런 눌림을 줄이려고 구를 여러 렌더링 극점으로 렌더링하는 경우가 있나?
      예를 들어 “진북” 극점이 있는 구를 렌더링할 때, 옆에서 보면 진북 쪽 렌더링 극점을 쓰고, 진북에 가까운 쪽에서 보면 0',0’의 적도 렌더링을 쓰는 식임
  • 변위 매핑을 다시 살펴보고 싶어짐
    글쓴이가 풀려는 문제의 대체재는 아니겠지만 더 단순하고 꽤 재미있음
    약 25년 전 SoundJam용으로 “Eclipse”라는 음악 시각화기를 만들었는데, 입력은 가청 주파수 범위의 레벨 배열과 좌우 채널이었음
    목표는 코로나 방출이 있는 일식된 태양 같은 모습이었고, 음악 데이터가 그 “방출물”이 됨
    데이터의 주파수는 태양 원반 둘레 어디에 나타날지를 결정했음
    시간이 지나면 방출물은 태양에서 멀어지며 “식어서” 검은색으로 사라졌고, 강한 신호는 흰색에서 시작해 약해질수록 노랑, 주황, 빨강, 갈색이 되었음
    방출물이 검은색으로 사라지기 전까지의 시간을 담을 만큼 큰 원형 버퍼에 소리 데이터 값 배열을 유지해야 했음
    전체 “Eclipse”와 방출물 표시는 결국 변위 맵이었고, 각 픽셀 값이 소리 레벨 버퍼의 오프셋이 되는 비트맵을 미리 계산해 두었음
    태양 표면에 가까운 픽셀은 새로 들어오는 데이터 오프셋을, 바깥쪽 픽셀은 곧 만료될 버퍼 꼬리 쪽 오프셋을 가졌음
    원형·방사형 방출을 데카르트 좌표로 매핑하려다 보니 변위값 생성에 약간의 수학이 필요했음
    메인 루프는 새 소리 값을 받아 가장 오래된 값을 덮어쓴 뒤, 변위 맵을 행·열로 순회하며 해당 소리 데이터를 가져오고, 고정 팔레트 색으로 매핑해 표시 버퍼에 넣는 식이었음
    다른 시각화기만큼 화려하지는 않았지만 차분한 아름다움이 있었고, 음악 데이터를 꽤 잘 반영했음
    나중의 시각화기들처럼 침묵을 넣어도 가만히 있지 못하는 느낌과는 달랐음

  • 글은 멋지지만 아래로 스크롤할수록 셰이더를 많이 로드해서, 아주 강력한 컴퓨터가 아니면 브라우저가 거의 멈출 수 있음

    • “아주 강력한 컴퓨터”가 어느 정도를 말하는 건가? 10년 이내 노트북의 내장 그래픽으로도 이런 걸 렌더링하기 힘든가?
  • “사실감”을 사람들이 얼마나 다르게 해석하는지 흥미로움
    자원이 훨씬 제한적이던 시절의 게임에서는 이 차이가 특히 뚜렷했고, 어떤 게임은 네모지고 픽셀ated된 낮은 팔레트 그래픽만으로도 오늘날의 대형 예산 게임보다 더 몰입감을 줬음

    the gas giant’s surface texture will be generated in realtime using a pixel
    shader and a render-to-texture approach
    처음부터 비실용적이고 경계 없는 접근으로 들어가 성능 병목을 부르는 방법을 찾고, 계속 이어가며 토끼굴로 내려가는 과정을 보는 게 흥미로움
    결국 원글 작성자가 이걸 작동시키긴 했는지 궁금함
    현실 제약이 있는 프로젝트와 취미 프로젝트의 차이일 수도 있음
    가스 행성에는 미리 렌더링한 애니메이션 텍스처를 쓰고 나머지 프로젝트로 넘어간 뒤, 전체가 돌아가면 그때 Slartibartfast 코스프레로 돌아와도 됨

    • 낮은 충실도의 게임이 더 몰입감 있었던 건 상상력이 개입할 여지를 남겼기 때문일 수도 있음
      그래서 더 적극적으로 몰입하게 됐던 것 같음
  • 비슷한 접근을 다룬 이 글이 떠오름: https://bgolus.medium.com/rendering-a-sphere-on-a-quad-13c92...

  • GPU나 3D 라이브러리에는 원의 각 가로줄을 수평으로 훑으며 텍스처의 X,Y를 구 위의 “3D” 위치에 매핑하는 함수가 없나?
    구는 원이고 원을 그리는 알고리즘은 단순한데, 삼각형용으로 정점 백만 개를 회전·투영하는 건 엄청난 자원 낭비처럼 보임
    수평으로 훑고 한 줄 내려가 계속 그리면 모든 줄을 그릴 수 있음
    80년대 후반에 Second Reality의 확대 렌즈 같은 걸 미리 계산하려고 이런 일을 했던 기억이 남

    • 아마 구면 선형 보간이 선형 보간보다 느리고 더 특화된 처리라서 그럴 것임
      전체 렌더링 파이프라인은 이미 선형 보간을 처리하도록 만들어져 있음
      셰이더 프로그램 하나와 삼각형 1개만으로도 완벽한 안티앨리어싱 구를 그릴 수 있음
    • GPU는 예전 소프트웨어 렌더러처럼 줄 단위로 래스터화하지 않고, 기본적으로 삼각형 래스터화만 알고 있음
      GPU에서 렌더링한다면 겉보기 복잡도와 달리 글의 접근이 꽤 괜찮아 보임
      GPU 기반 렌더링 구조를 다룬 훌륭한 글 묶음이 있음: https://fgiesen.wordpress.com/2011/07/09/a-trip-through-the-...
      6편은 래스터화를 다룸
    • GPT가 준 코드로는 원 안의 각 픽셀에서 z를 계산하고, 회전한 뒤 atan2와 asin으로 텍스처 좌표를 얻어 색을 찍는 방식이었고, 실행해보니 작동하는 듯했음
  • 배경 위의 2D 픽셀 셰이더 임포스터 행성은 절차적 우주처럼 행성이 많은 작업에 정말 큰 도움이 됨
    메모리와 GPU 대역폭 때문에 구면 큐브 기반 행성은 1개 인스턴스로 제한하고, 가까운 천체들은 배경 기법으로 그림
    우주 공간에서는 두 천체 중간쯤에 둘 다 임포스터로 렌더링되는 거리가 있고, 이후 가장 가까운 천체를 구면 사분 트리 방식으로 처리함
    완벽하진 않지만 착시는 거의 흠잡기 어려움
    또 평면 위에 있으니 멀리 있는 은하나 천체에 대해 카메라 렌즈의 가벼운 물리 효과를 넣기도 쉬워짐
    예를 들어 달이 떠오를 때 실제보다 커 보이거나, 먼 은하가 중력으로 휘어 보이는 효과 같은 것임

  • 가스 행성과 관련 페이지가 마음에 듦: https://emildziewanowski.com/flowfields/

  • 아이코스피어는 훨씬 더 매끄럽게 펼칠 수 있고, 정점 위치와 요소 크기도 규칙적임
    펼치기가 사소하진 않지만 할 수는 있음