FFT 바다는 게임이 아닙니다. 실시간으로 바다를 계산해서 그리는 실험이고, 화면의 모든 숫자가 실제로 돌아가는 값입니다. 그래서 "예쁘다"보다 "만져 보면 물리대로 움직인다" 쪽이 이 페이지의 재미입니다.

처음 30초

열면 궤도 카메라로 바다를 내려다보고 있습니다. 키 세 개만 알면 됩니다.

시점
1궤도 — 배를 중심으로 돌려 보기
2자유비행 — 어디든 날아가기
3승선 — 배 위에서 보기, WASD로 조타

배가 뒤집히거나 파도에 묻혀서 안 돌아오면 R로 되돌립니다.

우측 패널이 본체입니다. 프리셋을 잔잔에서 폭풍까지 눌러 보는 것만으로도 이 시뮬레이션이 뭘 하는지 대충 보입니다.

풍속 슬라이더가 진짜 하는 일

여기가 이 실험의 핵심입니다. 풍속만 올리면 파고가 따라 올라갑니다. 그런데 그게 "슬라이더를 1.5배 하면 파도도 1.5배" 같은 눈속임이 아닙니다.

스펙트럼을 완전발달 파고 공식으로 정규화해 놨습니다. 그래서 풍속을 넣으면 그 바람이 만들 수 있는 파고가 물리적으로 결정됩니다. 화면 왼쪽 위 유의파고(Hs) 숫자가 그 결과입니다.

프리셋풍속유의파고
미풍7.5 m/s1.2 m
너울9.0 m/s1.7 m
강풍17.0 m/s6.2 m
폭풍22.0 m/s10.4 m

풍속이 3배가 될 때 파고가 9배 가까이 뛰는 게 보이실 겁니다. 파고가 풍속의 제곱에 비례하기 때문입니다. 슬라이더를 천천히 밀어 보면 그 곡선이 손에 잡힙니다.

피크 파장은 파고를 바꾸지 않습니다. 파도의 모양만 바꿉니다. 처음에는 이것도 독립 슬라이더로 뒀는데, 그러면 에너지가 폭주해서 9m/s 바람에 9m 파도가 나왔습니다. 지금은 파고를 정하는 건 오직 바람입니다.

파도가 부서지는 자리

포말은 손으로 뿌린 게 아니라 수면이 스스로 접히는 지점을 계산해서 나옵니다. 파면이 너무 가팔라져 뒤집히기 직전이 되면 그 자리에 흰 것이 생깁니다.

재미있는 건 캐스케이드마다 다르게 나온다는 점입니다.

파도 종류패치부서지는 비율
스웰(긴 너울)512 m0%
풍파96 m0%
잔물결18 m7.5%

긴 너울은 심해에서 안 부서집니다. 실제 바다가 그렇고, 계산 결과도 그렇게 나옵니다. 포말이 잔물결 스케일에서만 생기는 게 그 이유입니다.

배는 왜 그렇게 기우는가

배는 물 위에 얹힌 그림이 아닙니다. 선체 아래에 14개의 프로브가 있고, 각 프로브가 자기 위치의 수면 높이를 읽어 그만큼 밀어 올립니다. 그래서 파면의 앞뒤 높이 차가 그대로 피치가 되고, 좌우 차가 롤이 됩니다.

프로브 위치는 눈대중이 아니라 선체 메시를 실제로 재서 뽑았습니다. 전장 8.577m, 중앙부 폭 2.35m가 뱃머리에서 1.21m로 좁아지는 실측값에서 유도됩니다. 추측으로 배치하면 프로브가 선체 안쪽이나 바깥에 박혀서, 부력이 눈에 보이는 흘수선과 따로 놉니다.

폭풍 프리셋에서는 배가 자주 파도에 묻힙니다. 10.4m 파도에 8.5m 배니까요. 그건 버그가 아니라 크기 차이입니다. 정상 해상으로 돌아오면 회복합니다.

뒤집혀도 일어납니다 (이건 고쳐서 그렇게 된 겁니다)

선체 모델을 올리고 처음 폭풍을 지나자, 배가 뒤집힌 채 완전히 잠겨서 영영 안 돌아왔습니다. 원인은 프로브가 전부 선저 근처 같은 높이에 있어서 선체가 사실상 평판으로 모델링된 것이었습니다. 평판에는 복원력이 없고, 90도를 넘으면 프로브가 무게중심 위로 올라가 오히려 역진자가 됩니다.

복원 모멘트를 붙이는 데 세 번 걸렸습니다.

시도150도에서
sin(경사), 계수 0.6176도 — 더 뒤집힘
(1−up.y)/2, 계수 1.2139도 — 90도 부근에 갇힘
(1−up.y)/2, 계수 3.08.6도 — 2초 만에 일어섬

sin 형태가 실패한 이유가 명확합니다. 90도에서 최대가 되고 180도에서 0으로 사라집니다. 정확히 완전히 뒤집힌 자세에 복원력이 없는 것입니다.

다만 지금 설정은 실제 선박보다 관대합니다. 이 선체는 어떤 자세에서도 스스로 일어납니다. 자기복원 구명정에는 맞지만 이런 카빈 크루저에는 후한 값입니다. "뒤집힌 채 침몰해 영영 안 돌아오는" 실패를 더 나쁘게 봤기 때문입니다.

느리면 이렇게

FFT를 부동소수점 렌더타깃에서 돌리기 때문에 WebGL2와 EXT_color_buffer_float 가 필요합니다. 데스크톱 브라우저를 권합니다.

첫 로딩이 큽니다. 선체 모델이 11MB거든요. 한 번 받으면 브라우저가 캐시합니다.

프레임이 떨어지면 우측 패널에서 품질을 낮추세요. FFT 해상도가 512에서 128까지 내려갑니다. 바다의 큰 형태는 그대로고 잔물결 디테일만 줄어듭니다. 단, 품질을 바꾸면 시뮬레이션을 다시 만들기 때문에 쌓여 있던 포말이 초기화됩니다.

아직 없는 것

항적이 없습니다. 배가 지나간 자리에 아무것도 안 남습니다. 월드 공간을 따라다니는 별도 포말 렌더타깃이 필요한 작업이라 이번 범위에서 뺐습니다.

수중 시점이 없습니다. 카메라가 수면 아래로 못 내려가게 막아 뒀습니다.

해질녘에 하늘이 평평해집니다. 태양이 낮게 깔리면 대기 모델이 포화해서 하늘이 단색에 가까워집니다. 실제로 재보니 태양 고도 7도에서 60픽셀 떨어진 두 하늘 줄이 완전히 같은 값이었습니다. 단일 산란 가정에서는 물리적으로 맞는 거동이고, 제대로 풀려면 다중 산란 테이블이 필요합니다.

부력이 잔물결을 무시합니다. 배를 띄우는 계산은 18m 이상 파장만 봅니다. 배를 실제로 움직이지 못하는 잔물결을 빼서 프레임을 아낀 선택이지만, 배는 눈에 보이는 표면보다 조금 매끄러운 표면 위에 떠 있습니다.

크레딧

선체 모델은 gogiartSS Minnow III이고 CC BY 4.0입니다. 표기 의무가 있는 라이선스라 앱 우측 패널에도 같은 크레딧이 들어가 있습니다. 바다와 하늘, 셰이더는 전부 직접 쓴 것입니다.