Study Lab

은하의 우주1

은하의 우주1

Makonea
··18분
Step 1 Lab experiment
Loading lab experiment...

Galaxy of Universes & Spiral Nebula

Warning

해당 글은 AI로 대부분의 코드가 작성됨을 알림.

사람의 손을 썼으나, 수학적 표현 및 코드 대부분 AI가 작성함

재귀 구면반전 프랙탈과 다중 옥타브 확률장을 결합한 순수 WebGL/GLSL 우주 시각화

샘플 선 적분, 차등 나선 위상, value noise, FBM과 선형광 합성의 수학적 구조

1. 개요 (Overview)

이 프로젝트는 서로 다른 생성 원리를 가진 세 개의 실시간 셰이더를 제공한다.

모드

핵심 모델

시각적 역할

Hybrid Universe

8회 Kali 구면반전 + FBM 나선 가스 + 먼지 감쇠

정동우의 독자 설계로 두 밀도장을 하나의 선형광 장면에 결합한 기본 화면

Galaxy of Universes

pseudo-3D sample-line 적분 + 재귀 구면반전 + 반지름 의존 차등 위상

미세 별빛 궤도와 중심 프랙탈 코어

Spiral Nebula

2D value noise + 5-octave FBM + 극좌표 나선 warp

유기적인 발광 가스와 맥동 코어

모드

Hybrid Universe

핵심 모델

8회 Kali 구면반전 + FBM 나선 가스 + 먼지 감쇠

시각적 역할

정동우의 독자 설계로 두 밀도장을 하나의 선형광 장면에 결합한 기본 화면

모드

Galaxy of Universes

핵심 모델

pseudo-3D sample-line 적분 + 재귀 구면반전 + 반지름 의존 차등 위상

시각적 역할

미세 별빛 궤도와 중심 프랙탈 코어

모드

Spiral Nebula

핵심 모델

2D value noise + 5-octave FBM + 극좌표 나선 warp

시각적 역할

유기적인 발광 가스와 맥동 코어

세 모드는 같은 Speed, Intensity, Field Zoom, Manual Rotation과 drag 좌표계를 공유하지만, 같은 물리 현상을 세 가지 방식으로 근사한 것이 아니다. Galaxy는 반복함수의 궤도 에너지를, Nebula는 확률장의 공간 상관을, Hybrid는 두 결과의 결합을 연구한다.

1.1 저작 관계와 모델 차이

Hybrid Univers는 제작자가 직접 설계하고 구현한 커스텀 셰이더다.

Dave Hoskins의 Galaxy of Universes와 Kali 계열 구면반전은 프랙탈 branch의 알고리즘 계보이고, value noise와 FBM은 성운 branch의 수학적 재료.

두 원본 화면을 응용해서 두 장을 같은 좌표·시간·노출 체계 안에서 결합하는 방법 자체가 Hybrid의 독자 구현이다.

비교 항목

Galaxy of Universes

Spiral Nebula

Hybrid Universe

기본 장

재귀 구면반전의 궤도 에너지

나선 warp된 확률 밀도장

궤도 에너지와 가스 밀도의 결합장

공간 계산

pseudo-3D sample-line 적분

2D FBM field

sample-line branch와 FBM branch가 같은 u,t\mathbf u,t 공유

결합 방식

단일 프랙탈 출력

단일 가스 출력

프랙탈 광도에 반응하는 비선형 선형광 결합

가림/감쇠

radial window

지수 반경 감쇠

FBM 기반 먼지 mask가 합성광을 선택적으로 감쇠

출력 변환

power contrast + clamp

exponential exposure

두 branch 합성 후 exponential exposure 한 번

색의 소유자

(v1,v2,v3)(v1,v2,v_3) 궤도 누적기

(n1,n2,r)(n1,n2,r) 가스 좌표

두 팔레트의 상호 변조와 dust attenuation

비교 항목

기본 장

Galaxy of Universes

재귀 구면반전의 궤도 에너지

Spiral Nebula

나선 warp된 확률 밀도장

Hybrid Universe

궤도 에너지와 가스 밀도의 결합장

비교 항목

공간 계산

Galaxy of Universes

pseudo-3D sample-line 적분

Spiral Nebula

2D FBM field

Hybrid Universe

sample-line branch와 FBM branch가 같은 u,t\mathbf u,t 공유

비교 항목

결합 방식

Galaxy of Universes

단일 프랙탈 출력

Spiral Nebula

단일 가스 출력

Hybrid Universe

프랙탈 광도에 반응하는 비선형 선형광 결합

비교 항목

가림/감쇠

Galaxy of Universes

radial window

Spiral Nebula

지수 반경 감쇠

Hybrid Universe

FBM 기반 먼지 mask가 합성광을 선택적으로 감쇠

비교 항목

출력 변환

Galaxy of Universes

power contrast + clamp

Spiral Nebula

exponential exposure

Hybrid Universe

두 branch 합성 후 exponential exposure 한 번

비교 항목

색의 소유자

Galaxy of Universes

(v1,v2,v3)(v1,v2,v_3) 궤도 누적기

Spiral Nebula

(n1,n2,r)(n1,n2,r) 가스 좌표

Hybrid Universe

두 팔레트의 상호 변조와 dust attenuation

Hybrid의 핵심 차이는 다음 결합식

Chybrid=Cgalaxy+Cnebula(0.6+0.8Cgalaxy)\mathbf C_{hybrid}= \mathbf C_{galaxy}+ \mathbf C_{nebula} \left(0.6+0.8\mathbf C_{galaxy}\right)

단순 가산 Cg+Cn\mathbf Cg+\mathbf Cn과 달리, 프랙탈 filament가 이미 밝은 곳에서는 성운 방출도 함께 강화되는데,

반대로 FBM에서 얻은 dust field는 일부 영역을 감쇠한다.

ChybridChybrid(10.25D)\mathbf C_{hybrid}\leftarrow \mathbf C_{hybrid}(1-0.25D)

따라서 Hybrid의 형태는 Galaxy와 Nebula 결과를 따로 렌더한 뒤 투명도로 겹쳐서는 재현되지 않는다. 두 branch가 노출 이전의 선형광에서 서로 영향을 주는 결합 규칙을 재현하는 것이 중요했다.


2. 공통 화면 좌표

2.1 종횡비 보정

픽셀 좌표 x=(x,y)\mathbf x=(x,y)와 해상도 R=(Rx,Ry)\mathbf R=(Rx,Ry)에 대해

u=x12RRy\mathbf u= \frac{\mathbf x-\tfrac12\mathbf R}{R_y}

로 정규화한다. 두 축을 각각 Rx,RyRx,Ry로 나누는 방식은 화면 비율에 따라 원형 구조를 타원으로 늘리므로 사용하지 않는다. Nebula는 같은 목적의 min(Rx,Ry)\min(Rx,Ry) 정규화를 사용한다.

2.2 줌, 회전, drag

u=M(θr)(zu)+0.3(m0.5)\mathbf u'= \mathbf M(\theta_r)(z\mathbf u)+0.3(\mathbf m-0.5)
M(θ)=(cosθsinθsinθcosθ)\mathbf M(\theta)= \begin{pmatrix} \cos\theta&-\sin\theta\\ \sin\theta&\cos\theta \end{pmatrix}

zzField Zoom, θr\theta_rManual Rotation, m\mathbf m은 보간된 drag 위치다. Hybrid는 drag 이동량을 0.350.35로 조금 더 크게 사용한다.


3. Galaxy of Universes

“Galaxy of Universes” — ShaderToy, Dave Hoskins 작품을 분석.

galaxy.frag의 구조는 엄밀한 중력 N-body 또는 일반상대론 시뮬레이션이 아니다. 화면의 각 픽셀에서 하나의 pseudo-3D 샘플 선을 전진시키고, 매 위치에 재귀 구면반전을 적용해 얻은 궤도 에너지를 누적하는 절차적 프랙탈이다.

3.1 반지름 의존 차등 나선 위상

중심 거리 r=ur=|\mathbf u|에 따라 회전 위상을 다르게 준다.

θ(r,t)=0.1ts+2.20.25+0.05sin(0.1ts)r+0.07,ts=tspeed\theta(r,t)=0.1t_s+ 2.2\frac{0.25+0.05\sin(0.1t_s)}{r+0.07}, \qquad t_s=t\cdot\mathrm{speed}

중심에 가까울수록 1/(r+0.07)1/(r+0.07) 항이 커지므로 내부 궤도가 더 많이 감기고 바깥은 완만하게 회전한다. 이 식은 시각적 differential swirl이며 Kerr metric이나 실제 frame dragging의 해가 아니다.

3.2 샘플 선과 시작점 jitter

sis_i를 누적 거리라 하면 샘플 위치는

pi=si(ux,uy,0)M(θ)+(0.22,0.30,si1.50.1sin(0.13ts))\mathbf p_i= s_i(u_x,u_y,0)\mathbf M(\theta) +(0.22,0.30,s_i-1.5-0.1\sin(0.13t_s))

로 만든다. 최대 120 step 중 UI의 Fractal Iterations만큼 실행하며 기본값은 90이다. Galaxy의 step 길이는 0.0350.035, Hybrid0.0330.033이다.

고정된 시작점에서 일정 간격으로 적분하면 등고선 형태의 march band가 생긴다. 이를 미세 노이즈로 분산하기 위해 첫 위치를 픽셀 hash로 흔든다.

s0=0.033ξ(x,t),0ξ<1s_0=0.033\,\xi(\mathbf x,t), \qquad 0\le\xi<1

3.3 8회 재귀 구면반전

각 샘플은 다음 변환을 정확히 8회 수행한다.

pj+1=pjpjpj0.659,j=0,,7\mathbf p_{j+1}= \frac{|\mathbf p_j|}{\mathbf p_j\cdot\mathbf p_j}-0.659, \qquad j=0,\ldots,7

이 변환은 세 연산을 결합한다.

  1. p|\mathbf p|: 모든 옥탄트를 양의 영역으로 fold한다.

  2. p/(pp)\mathbf p/(\mathbf p\cdot\mathbf p): 단위구 기준의 spherical inversion을 수행한다.

  3. 0.659-0.659: 궤도를 다시 반전 중심에서 이동시킨다.

반복 중 p|\mathbf p|가 작은 영역은 크게 확대되고 큰 영역은 압축된다. 그 결과 초기 조건의 작은 차이가 서로 다른 궤도 길이와 미세 필라멘트로 증폭된다.

3.4 세 에너지 누적기

한 샘플의 궤도 에너지를 세 채널에 서로 다른 방식으로 누적한다.

v1+=0.0015p2P1(r,t)v_1\mathrel{+}=0.0015\,\|\mathbf p\|^2 P_1(r,t)
v2+=0.0013p2P2(r,t)v_2\mathrel{+}=0.0013\,\|\mathbf p\|^2 P_2(r,t)
v3+=0.000310pxyv_3\mathrel{+}=0.0003\,\|10\mathbf p_{xy}\|

Wave Modulation이 켜지면 첫 파동은

P1(r,t)=1.8+sin(13r+0.50.2ts)P_1(r,t)=1.8+\sin(13r+0.5-0.2t_s)

이고 두 번째 파동은 더 높은 공간 주파수와 시간 속도를 사용한다.

P2(r,t)=1.5+sin(14.5r+1.20.3ts)P_2(r,t)=1.5+\sin(14.5r+1.2-0.3t_s)

이는 펄사 광도곡선이 아니라 중심에서 바깥으로 이동하는 절차적 밀도 파동이다.

3.5 유한 지지 반경

프랙탈 에너지가 화면 전체를 균일하게 채우지 않도록 서로 다른 radial window를 곱한다.

v1v1smoothstep(0.7,0,r)v_1\leftarrow v_1\,\operatorname{smoothstep}(0.7,0,r)
v2v2smoothstep(0.5,0,r),v3v3smoothstep(0.9,0,r)v_2\leftarrow v_2\,\operatorname{smoothstep}(0.5,0,r), \qquad v_3\leftarrow v_3\,\operatorname{smoothstep}(0.9,0,r)

세 반경의 차이가 중심 코어, 내부 발광, 바깥 filament를 분리한다.

3.6 색과 출력 변환

Galaxy(v1,v2,v3)(v1,v2,v_3)를 비대칭 RGB 조합으로 배치한다. 마지막 출력은

Cout=min(Cγu,1)\mathbf C_{out}= \min\left(|\mathbf C|^{\gamma_u},1\right)

이며 γu\gamma_u가 UI의 Intensity다. 물리적 radiance 보존형 톤매핑이 아니라 프랙탈 에너지의 대비를 조절하는 예술적 출력 변환이다.

3.7 galaxy.frag 수식–코드 대응

아래 식은 설명용 일반식이 아니라 현재 GLSL의 상수와 연산 순서를 그대로 옮긴 정준식이다.

GLSL 기호

수학 기호

정의

uv

u\mathbf u

종횡비 보정·zoom·rotation·drag가 적용된 화면 좌표

t

θ\theta

반지름 의존 차등 회전 위상

s

sis_i

pseudo-3D sample-line 거리

p

pi,j\mathbf p_{i,j}

ii번째 sample의 jj번째 구면반전 상태

v1,v2,v3

v1,v2,v3v1,v2,v_3

궤도 에너지 누적기

GLSL 기호

uv

수학 기호

u\mathbf u

정의

종횡비 보정·zoom·rotation·drag가 적용된 화면 좌표

GLSL 기호

t

수학 기호

θ\theta

정의

반지름 의존 차등 회전 위상

GLSL 기호

s

수학 기호

sis_i

정의

pseudo-3D sample-line 거리

GLSL 기호

p

수학 기호

pi,j\mathbf p_{i,j}

정의

ii번째 sample의 jj번째 구면반전 상태

GLSL 기호

v1,v2,v3

수학 기호

v1,v2,v3v1,v2,v_3

정의

궤도 에너지 누적기

θ=0.1tS+2.20.25+0.05sin(0.1tS)u+0.07\theta=0.1t\,S+ 2.2\frac{0.25+0.05\sin(0.1tS)}{\|\mathbf u\|+0.07}

구현 — shaders/galaxy.frag, main()

GLSL
float t = iTime * 0.1 * uSpeed
        + ((0.25 + 0.05 * sin(iTime * 0.1 * uSpeed))
        / (length(uv) + 0.07)) * 2.2;
pi,0=(M(θ)siu+(.22,.30),si1.50.1sin(.13tS))\mathbf p_{i,0}= \left( \mathbf M(\theta)s_i\mathbf u+(.22,.30), s_i-1.5-0.1\sin(.13tS) \right)
GLSL
p = s * vec3(uv, 0.0);
p.xy *= ma;
p += vec3(0.22, 0.3, s - 1.5 - sin(iTime * 0.13 * uSpeed) * 0.1);
pi,j+1=pi,jpi,j20.659,j=0,,7\mathbf p_{i,j+1}= \frac{|\mathbf p_{i,j}|}{\|\mathbf p_{i,j}\|^2}-0.659, \qquad j=0,\ldots,7
GLSL
for (int j = 0; j < 8; j++) {
    p = abs(p) / dot(p, p) - 0.659;
}

최종 RGB 조합도 코드와 동일하다.

Cg=(v3[1.5+0.4sin(0.2tS)]0.3(v1+v3)v2)+0.85smoothstep(0.2,0,r)+0.3smoothstep(0,0.6,v3)\mathbf C_g= \begin{pmatrix} v_3[1.5+0.4\sin(0.2tS)]\\ 0.3(v_1+v_3)\\ v_2 \end{pmatrix} +0.85\,\operatorname{smoothstep}(0.2,0,r) +0.3\,\operatorname{smoothstep}(0,0.6,v_3)
GLSL
vec3 col = vec3(
    v3 * (1.5 + sin(iTime * 0.2 * uSpeed) * 0.4),
    (v1 + v3) * 0.3,
    v2
) + smoothstep(0.2, 0.0, len) * 0.85
  + smoothstep(0.0, 0.6, v3) * 0.3;
Cout=min(CgI,1)\mathbf C_{out}=\min(|\mathbf C_g|^I,1)
GLSL
col = min(pow(abs(col), vec3(uIntensity)), vec3(1.0));

여기서 SSuSpeed, IIuIntensity다.

실제 구현과 GLSL을 1:1 대응 시켜두었다.



4. Spiral Nebula

nebula.frag는 재귀 프랙탈이 아니라 공간적으로 연속인 확률장을 여러 크기로 합성한다.

4.1 2D value noise

좌표 p\mathbf p를 정수 cell i=p\mathbf i=\lfloor \mathbf p\rfloor과 cell 내부 좌표 f=fract(p)\mathbf f=\operatorname{fract}(\mathbf p)로 나눈다. 네 꼭짓점의 hash 값을

h(i)=fract[sin(127.1ix+311.7iy)43758.5453]h(\mathbf i)= \operatorname{fract}\left[ \sin(127.1i_x+311.7i_y)\,43758.5453 \right]

로 만들고 cubic Hermite 곡선

q=f2(32f)\mathbf q=\mathbf f^2(3-2\mathbf f)

을 사용해 bilinear interpolation한다. 선형 보간만 사용할 때 생기는 cell 경계의 기울기 불연속을 줄이는 목적이다.

4.2 5-octave FBM

fbm(p)=k=042(k+1)n(2kp)\operatorname{fbm}(\mathbf p)= \sum_{k=0}^{4}2^{-(k+1)}n(2^k\mathbf p)

각 octave는 주파수를 두 배, 진폭을 절반으로 만든다. 저주파 octave는 큰 가스 덩어리를, 고주파 octave는 가장자리의 작은 요동을 담당한다.

4.3 극좌표 나선 warp

r=u,a=atan2(uy,ux)r=\|\mathbf u\|, \qquad a=\operatorname{atan2}(u_y,u_x)
ψ=a+4r0.5ts\psi=a+4r-0.5t_s
s(r,a,t)=r(cosψ,sinψ)\mathbf s(r,a,t)=r(\cos\psi,\sin\psi)

직교 좌표의 noise를 이 나선 좌표에서 샘플링함으로써 원형 cloud가 감긴 팔 구조를 갖는다.

4.4 세 공간 주파수의 가스장

n1=fbm(3s+0.1ts)n_1=\operatorname{fbm}(3\mathbf s+0.1t_s)
n2=fbm(5s0.15ts)n_2=\operatorname{fbm}(5\mathbf s-0.15t_s)
n3=fbm(8u+(0.05ts,0))n_3=\operatorname{fbm}(8\mathbf u+(0.05t_s,0))

서로 반대 방향으로 이동하는 n1,n2n1,n2가 팔의 전단을 만들고, 화면 좌표에서 직접 샘플한n3n_3 가 나선에 종속되지 않는 미세 난류를 더한다.

N=0.5n1+0.3n2+0.2n3N=0.5n_1+0.3n_2+0.2n_3

최종 밀도는

ρ(u)=smoothstep(0.2,0.8,N)e0.8r\rho(\mathbf u)= \operatorname{smoothstep}(0.2,0.8,N)e^{-0.8r}

이다. smoothstep은 희박한 noise floor를 제거하고, 지수 감쇠는 가스가 화면 끝까지 같은 밀도로 이어지는 것을 막는다.

4.5 색 공간

보라색 c1\mathbf c1, 자주색c2\mathbf c2, 청색c3\mathbf c_3 을 두 단계로 보간한다.

c12=mix(c1,c2,n1)\mathbf c_{12}=\operatorname{mix}(\mathbf c_1,\mathbf c_2,n_1)
Cneb=mix(c12,c3,smoothstep(0.3,0.7,r))2ρ\mathbf C_{neb}= \operatorname{mix} (\mathbf c_{12},\mathbf c_3, \operatorname{smoothstep}(0.3,0.7,r)) \,2\rho

내부와 외부의 색 변화는 별도의 후처리 gradient가 아니라 가스 밀도 계산과 같은 좌표에서 결정된다.

4.6 중심 코어와 노출

K(r,t)=e3r[1+0.3sin(3ts)]K(r,t)=e^{-3r}\left[1+0.3\sin(3t_s)\right]

코어를 더한 뒤 전체 색에 지수 노출을 적용한다.

C=1eIC\mathbf C'=1-e^{-I\mathbf C}
Cout=(C)0.85\mathbf C_{out}=(\mathbf C')^{0.85}

IIIntensity / Glow다. 이 변환은 음수가 없고 큰 발광값을 점근적으로 1에 압축하므로 단순 clamp보다 중심부의 색을 오래 유지한다.

4.7 nebula.frag 수식–코드 대응

GLSL 기호

수학 기호

정의

r

rr

u\mathbf u

a

aa

atan2(uy,ux)\operatorname{atan2}(u_y,u_x)

spiralCoord

s\mathbf s

극좌표 나선 warp 위치

n1,n2,n3

n1,n2,n3n_1,n_2,n_3

서로 다른 좌표와 속도의 FBM field

nebula

ρ\rho

threshold와 반경 감쇠가 적용된 가스 밀도

GLSL 기호

r

수학 기호

rr

정의

u\mathbf u

GLSL 기호

a

수학 기호

aa

정의

atan2(uy,ux)\operatorname{atan2}(u_y,u_x)

GLSL 기호

spiralCoord

수학 기호

s\mathbf s

정의

극좌표 나선 warp 위치

GLSL 기호

n1,n2,n3

수학 기호

n1,n2,n3n_1,n_2,n_3

정의

서로 다른 좌표와 속도의 FBM field

GLSL 기호

nebula

수학 기호

ρ\rho

정의

threshold와 반경 감쇠가 적용된 가스 밀도

ψ=a+4r0.5tS,s=r(cosψ,sinψ)\psi=a+4r-0.5tS, \qquad \mathbf s=r(\cos\psi,\sin\psi)

구현 — shaders/nebula.frag, main()

GLSL
float spiral = a + r * 4.0 - time * 0.5;
vec2 spiralCoord = vec2(cos(spiral), sin(spiral)) * r;
n1=F(3s+0.1tS),n2=F(5s0.15tS),n3=F(8u+(0.05tS,0))\begin{aligned} n_1&=F(3\mathbf s+0.1tS),\\ n_2&=F(5\mathbf s-0.15tS),\\ n_3&=F(8\mathbf u+(0.05tS,0)) \end{aligned}
GLSL
float n1 = fbm(spiralCoord * 3.0 + time * 0.1);
float n2 = fbm(spiralCoord * 5.0 - time * 0.15);
float n3 = fbm(uv * 8.0 + vec2(time * 0.05, 0.0));
ρ=smoothstep(0.2,0.8,0.5n1+0.3n2+0.2n3)e0.8r\rho= \operatorname{smoothstep} \left(0.2,0.8,0.5n_1+0.3n_2+0.2n_3\right)e^{-0.8r}
GLSL
float nebula = n1 * 0.5 + n2 * 0.3 + n3 * 0.2;
nebula = smoothstep(0.2, 0.8, nebula) * exp(-r * 0.8);

최종 색은 코드 순서대로

C0=2ρmix[mix(c1,c2,n1),c3,smoothstep(0.3,0.7,r)]\mathbf C_0= 2\rho\,\operatorname{mix} \left[ \operatorname{mix}(\mathbf c_1,\mathbf c_2,n_1), \mathbf c_3, \operatorname{smoothstep}(0.3,0.7,r) \right]
C1=(10.3r)[C0+2(1,.95,.9)e3r(1+0.3sin3tS)]\mathbf C_1=(1-0.3r) \left[ \mathbf C_0+2(1,.95,.9)e^{-3r}(1+0.3\sin 3tS) \right]
Cout=(1eIC1)0.85\mathbf C_{out}=\left(1-e^{-I\mathbf C_1}\right)^{0.85}
GLSL
vec3 finalColor = mix(color1, color2, n1);
finalColor = mix(finalColor, color3, smoothstep(0.3, 0.7, r))
           * nebula * 2.0;
float core = exp(-r * 3.0) * (1.0 + 0.3 * sin(time * 3.0));
finalColor += vec3(1.0, 0.95, 0.9) * core * 2.0;
finalColor *= 1.0 - r * 0.3;
finalColor = 1.0 - exp(-finalColor * uIntensity);
finalColor = pow(finalColor, vec3(0.85));

로 대응한다.


5. Hybrid Universe

hybrid.frag내가 설계한 독자적인 결합 모델이다. Galaxy와 Nebula를 화면 완성본끼리 alpha blend하지 않고, 같은 u\mathbf utst_s 에서 두 밀도장을 계산한 뒤 노출 이전의 선형광에서 상호 변조한다.

5.1 Galaxy branch

  • 최대 120 sample, 기본 90 sample

  • sample당 8회 spherical inversion

  • (v1,v2,v3)(v1,v2,v_3)의 비대칭 RGB 조합

  • 중심 core와 바깥 filament radial window

5.2 Nebula branch

Hybrid는 더 조밀한 세 FBM field를 사용한다.

n1=fbm(3.5s+0.08ts)n_1=\operatorname{fbm}(3.5\mathbf s+0.08t_s)
n2=fbm(6s0.12ts)n_2=\operatorname{fbm}(6\mathbf s-0.12t_s)
n3=fbm(9u+(0.05ts,0.05ts))n_3=\operatorname{fbm}(9\mathbf u+(0.05t_s,-0.05t_s))
ρh=smoothstep(0.2,0.78,0.5n1+0.35n2+0.15n3)e0.9r\rho_h= \operatorname{smoothstep} \left(0.2,0.78, 0.5n_1+0.35n_2+0.15n_3\right)e^{-0.9r}

5.3 선형광 결합

C=Cgalaxy+Cnebula(0.6+0.8Cgalaxy)\mathbf C= \mathbf C_{galaxy}+ \mathbf C_{nebula} \left(0.6+0.8\mathbf C_{galaxy}\right)

이미 밝은 프랙탈 filament 주변에서 성운 방출이 더 강하게 반응한다. 두 branch를 각각 tone map한 뒤 더하지 않으므로 중심 광도와 색 혼합 순서가 보존된다.

5.4 먼지 감쇠

D=smoothstep(0.4,0.7,n2)[1smoothstep(0.05,0.6,r)]D=\operatorname{smoothstep}(0.4,0.7,n_2) \left[1-\operatorname{smoothstep}(0.05,0.6,r)\right]
CC(10.25D)\mathbf C\leftarrow\mathbf C(1-0.25D)

고주파 가스가 일정 임계값을 넘은 내부 영역을 부분적으로 어둡게 해 모든 구조가 가산 발광만 하는 플라스틱 표면처럼 보이는 것을 막는다.

5.5 최종 노출

Cout=(1exp[1.15IC])0.85\mathbf C_{out}= \left(1-\exp[-1.15I\mathbf C]\right)^{0.85}

Hybrid에서 Intensity는 선형광 합성 이후 단 한 번만 적용된다.

5.6 hybrid.frag 정준 수식–코드 대응

Hybrid의 독자성은 두 branch의 존재 자체보다 어떤 순서와 함수로 결합하는가에 있다. 아래는 현재 구현의 전체 합성 순서다.

Galaxy branch

Cg=(v3[1.6+0.4sin(0.2tS)]+0.2v10.38(v1+v3)+0.15v21.1v2+0.25v1)+0.95smoothstep(0.2,0,r)+0.35smoothstep(0,0.6,v3)\mathbf C_g= \begin{pmatrix} v_3[1.6+0.4\sin(0.2tS)]+0.2v_1\\ 0.38(v_1+v_3)+0.15v_2\\ 1.1v_2+0.25v_1 \end{pmatrix} +0.95\,\operatorname{smoothstep}(0.2,0,r) +0.35\,\operatorname{smoothstep}(0,0.6,v_3)

구현 — shaders/hybrid.frag, main()

GLSL
vec3 galaxyCol = vec3(
    v3 * (1.6 + sin(time * 0.2) * 0.4) + v1 * 0.2,
    (v1 + v3) * 0.38 + v2 * 0.15,
    v2 * 1.1 + v1 * 0.25
);
galaxyCol += smoothstep(0.2, 0.0, len) * 0.95;
galaxyCol += smoothstep(0.0, 0.6, v3) * 0.35;

Nebula branch

ρh=smoothstep(0.2,0.78,0.5n1+0.35n2+0.15n3)e0.9r\rho_h= \operatorname{smoothstep} \left(0.2,0.78,0.5n_1+0.35n_2+0.15n_3\right)e^{-0.9r}
Cn=1.6ρhmix[mix(c1,c2,n1),c3,smoothstep(0.3,0.8,r)]\mathbf C_n= 1.6\rho_h\, \operatorname{mix}\left[ \operatorname{mix}(\mathbf c_1,\mathbf c_2,n_1), \mathbf c_3, \operatorname{smoothstep}(0.3,0.8,r) \right]
GLSL
float nebulaGas = n1 * 0.5 + n2 * 0.35 + n3 * 0.15;
nebulaGas = smoothstep(0.2, 0.78, nebulaGas) * exp(-len * 0.9);
vec3 nebulaCol = mix(nebColor1, nebColor2, n1);
nebulaCol = mix(nebulaCol, nebColor3, smoothstep(0.3, 0.8, len))
          * nebulaGas * 1.6;

상호 변조

C=Cg+Cn(0.6+0.8Cg)\mathbf C=\mathbf C_g+\mathbf C_n(0.6+0.8\mathbf C_g)
GLSL
vec3 col = galaxyCol + nebulaCol * (0.6 + galaxyCol * 0.8);

곱셈과 덧셈은 RGB component별 연산이다. 즉 밝은 청색 프랙탈 영역은 성운의 청색 성분을, 밝은 적색 영역은 성운의 적색 성분을 서로 다르게 증폭한다.

코어와 먼지

CC+1.8(1,.96,.92)e3.5r[1+0.25sin(3tS)]\mathbf C\leftarrow\mathbf C+ 1.8(1,.96,.92)e^{-3.5r}[1+0.25\sin(3tS)]
GLSL
float core = exp(-len * 3.5) * (1.0 + 0.25 * sin(time * 3.0));
col += vec3(1.0, 0.96, 0.92) * core * 1.8;
D=smoothstep(0.4,0.7,n2)[1smoothstep(0.05,0.6,r)]D=\operatorname{smoothstep}(0.4,0.7,n_2) [1-\operatorname{smoothstep}(0.05,0.6,r)]
CC(10.25D)\mathbf C\leftarrow\mathbf C(1-0.25D)
GLSL
float dust = smoothstep(0.4, 0.7, n2)
           * (1.0 - smoothstep(0.05, 0.6, len));
col *= 1.0 - dust * 0.25;

단일 출력 변환

Cout=[1exp(1.15IC)]0.85\boxed{ \mathbf C_{out}= \left[1-\exp(-1.15I\mathbf C)\right]^{0.85} }
GLSL
col = 1.0 - exp(-col * uIntensity * 1.15);
col = pow(col, vec3(0.85));

이 boxed 식이 모든 결합·코어·먼지 계산 이후 정확히 한 번만 실행된다.


6. 구현하면서 AI에 도움 받은 수정된 수학적 오류

6.1 종횡비 왜곡

기존 [0.5,0.5]2[-0.5,0.5]^2 좌표는 와이드 화면에서 방사 대칭 구조를 가로로 늘렸다. 현재는 RyRy또는min(Rx,Ry)\min(Rx,R_y)로 두 축을 함께 나눠 원형 거리rr 의 의미를 보존한다.

6.2 색 보간 no-op

과거 Hybrid에는 다음 형태가 있었다.

GLSL
mix(nebColor3, nebColor3, weight)

양쪽 인자가 같아 보간이 아무 효과가 없었고, 앞줄에서 계산한 두 색의 혼합까지 덮어썼다. 현재는

GLSL
mix(mix(nebColor1, nebColor2, n1), nebColor3, radialWeight)

처럼 세 색이 실제 출력에 도달한다.

6.3 고정 step 밴딩

모든 픽셀이 s=0s=0 에서 시작하던 sample-line 적분은 일정한 원형 band를 만들었다. 현재는 픽셀별 hash jitter를 첫 step에 적용한다.

6.4 누락 hash 소유자

galaxy.frag가 시작점 jitter를 호출하면서 hash()를 정의하지 않던 컴파일 오류를 제거했다. 각 fragment shader는 자신이 사용하는 hash/noise 함수를 직접 소유한다.


7. 파라미터와 수학적 영향

UI

uniform

영향

Speed

uSpeed

위상 시간 tst_s, 나선 이동, density wave 속도

Intensity / Glow

uIntensity

Galaxy power contrast 또는 Nebula/Hybrid 지수 노출

Field Zoom

uZoom

정규화 좌표 u\mathbf u의 배율

Fractal Iterations

uIterations

Galaxy/Hybrid sample-line step 수, 최대 120

Manual Rotation

uRotation

입력 좌표의 2D 회전행렬

Auto Rotation

JavaScript state

uRotation을 프레임마다 천천히 증가

Wave Modulation

uPulseEffect

Galaxy/Hybrid의 방사형 밀도 파동 적용 여부

UI

Speed

uniform

uSpeed

영향

위상 시간 tst_s, 나선 이동, density wave 속도

UI

Intensity / Glow

uniform

uIntensity

영향

Galaxy power contrast 또는 Nebula/Hybrid 지수 노출

UI

Field Zoom

uniform

uZoom

영향

정규화 좌표 u\mathbf u의 배율

UI

Fractal Iterations

uniform

uIterations

영향

Galaxy/Hybrid sample-line step 수, 최대 120

UI

Manual Rotation

uniform

uRotation

영향

입력 좌표의 2D 회전행렬

UI

Auto Rotation

uniform

JavaScript state

영향

uRotation을 프레임마다 천천히 증가

UI

Wave Modulation

uniform

uPulseEffect

영향

Galaxy/Hybrid의 방사형 밀도 파동 적용 여부

Fractal Iterations는 구면반전 내부 반복 8회를 바꾸지 않는다. 광선을 따라 평가하는 바깥 sample 수만 바꾼다. 프랙탈 정의 자체와 적분 품질의 경계가 사라진다.


8. 런타임과 구현 구조

Text
galaxy-of-universes/
├── index.html                   # 세 모드와 파라미터 UI
├── style.css                    # fullscreen canvas와 off-canvas studio
├── README.md                    # 수학·렌더링 문서
├── js/
│   ├── shaders.js               # 명시적 GLSL URL과 preset registry
│   ├── renderer.js              # WebGL compile/link, uniforms, animation loop
│   ├── controls.js              # drag/zoom/mode 전환과 접근성 상태
│   └── main.js                  # 초기화와 오류 경계
└── shaders/
    ├── vertex.vert              # fullscreen triangle pair
    ├── hybrid.frag              # Galaxy + Nebula 선형광 결합
    ├── galaxy.frag              # 재귀 구면반전 sample-line field
    └── nebula.frag              # spiral-warped FBM field

GLSL 의존 파일은 정적 프로젝트 수집기와 브라우저가 모두 해석할 수 있도록 명시한다.

JavaScript
const SHADER_URLS = {
  vertex: new URL('../shaders/vertex.vert', import.meta.url),
  hybrid: new URL('../shaders/hybrid.frag', import.meta.url),
  galaxy: new URL('../shaders/galaxy.frag', import.meta.url),
  nebula: new URL('../shaders/nebula.frag', import.meta.url)
};

모든 GLSL은 병렬 fetch한 뒤 시작 시 엄격하게 컴파일한다. 파일 누락, shader compile 실패, program link 실패를 다른 모드로 조용히 대체하지 않는다.


9. 검증 기준

다음을 검증 기준 삼아 작업하였다.

  1. 화면 비율을 바꿔도 중심 코어와 radial window가 원형을 유지한다.

  2. Fractal Iterations를 낮추면 sample 밀도만 줄고 구면반전의 8회 구조는 유지된다.

  3. Wave Modulation을 끄면 방사형 파동만 멈추고 프랙탈 궤도와 FBM 가스는 남는다.

  4. Galaxy의 시작점 band가 고정 원형 띠가 아니라 미세한 dithering으로 보인다.

  5. Nebula의 세 noise field가 서로 다른 속도와 좌표에서 이동한다.

  6. Hybrid의 청색·보라색·자홍색 세 팔레트가 모두 화면에 도달한다.

  7. 모드 전환 시 각 GLSL source viewer가 실제 활성 fragment source를 표시한다.

  8. 누락 파일이나 GLSL 오류는 초기화 오류로 명확히 드러난다.


10. 조작

입력

동작

마우스 드래그

좌표장 이동

마우스 휠

zoom (0.3×0.3\times3.0×3.0\times)

Space

자동 회전 정지/재개

H

타이틀과 FPS HUD 표시/숨김

Tab

컨트롤·GLSL 패널 열기/닫기

Esc

열린 패널 닫기

입력

마우스 드래그

동작

좌표장 이동

입력

마우스 휠

동작

zoom (0.3×0.3\times3.0×3.0\times)

입력

Space

동작

자동 회전 정지/재개

입력

H

동작

타이틀과 FPS HUD 표시/숨김

입력

Tab

동작

컨트롤·GLSL 패널 열기/닫기

입력

Esc

동작

열린 패널 닫기


11. 해석상의 한계

  • 구면반전 장은 실제 은하의 질량 분포나 별 궤도를 적분한 결과가 아니다.

  • 1/(r+0.07)1/(r+0.07) 차등 위상은 나선 구조를 만드는 절차적 warp이며 일반상대론의 frame-dragging 해가 아니다.

  • Spiral Nebula는 2D 확률장을 극좌표로 감은 모델이며 복사유체역학 시뮬레이션이 아니다.

  • RGB 팔레트는 분광 관측값에서 직접 유도하지 않았다.

  • Intensity는 노출/대비 제어이며 에너지 단위가 아니다.

  • hash와 value noise는 결정론적 의사난수이며 물리적 난류의 통계 전체를 재현하지 않는다.


12. 출처와 알고리즘 계보

AI 함께 구현

  • Hybrid Universe : 프랙탈·성운 branch의 공통 좌표 설계,광도 반응형 선형광 결합, FBM dust 감쇠, 단일 노출 파이프라인과 최종 색 설계

알고리즘 계보와 참고 자료

Galaxy of Universes 프랙탈 branch의 기반