TECH 으로 돌아가기
TECH HACKER NEWS 7분 읽기 26 READS

화장품 파운데이션을 웹에서: Three.js로 구현한 '퍼지는 액체' 셰이더 분석

화장품 파운데이션을 웹에서: Three.js로 구현한 '퍼지는 액체' 셰이더 분석
SOURCE IMAGE · HACKER NEWS

웹 브라우저에서 액체가 손끝을 따라 번지고, 지나간 자리에 옅은 흔적이 남는 표현은 생각보다 구현이 까다롭다. 일본의 크리에이티브 개발자 mofu-dev가 공개한 이 글은 2021년 일본 화장품 브랜드 primavisa 시리즈의 리퀴드 파운데이션 프로모션 사이트를 위해 만든 '퍼지는 액체' 효과의 내부 구조를 상세히 풀어낸 기록이다. 제작사 homunculus의 의뢰로 구현을 맡았고, 사용자가 다양한 종류와 컬러의 텍스처를 직접 시뮬레이션해볼 수 있는 사이트였다. 필자는 2026년 Vue Fes Japan 발표에서도 이 주제를 다뤘다.

흥미로운 점은 출발부터 '물리적 정확성'이 목표가 아니었다는 것이다. 2021년 1월 의뢰를 받은 필자는 어디서 시작할지 몰라 약 한 달간 실제 파운데이션을 만지며 '액체답게 보이는 움직임'이 무엇인지 고민했다고 한다. 손가락으로 액체를 가르면 반대편이 부풀어 오르고 주변 물질이 끌려오는데, 이 움직임을 재현하기 위해 결국 유체 시뮬레이션을 택했다. 핵심은 이전 글에서 소개한 유체 시뮬레이션이 만들어내는 '속도 맵(velocity map)'이다. 각 화면 위치의 이동 방향과 크기를 담은 이 맵을 재활용해 액체가 번지는 움직임을 만든다.

지오메트리 대신 하이트맵

눈에 띄는 설계 결정은 액체의 솟아오른 형태를 실제 정점(vertex)을 움직여 만들지 않았다는 것이다. 대신 프래그먼트 셰이더 안에서 처리한다. 두께를 표현하기 위해 별도의 FBO를 '하이트맵'으로 준비하고, 각 지점의 액체량을 높이값으로 기록한다. 지형 표현에 흔히 쓰이는 하이트맵을 여기서는 액체 두께 표현에 돌려쓴 셈이다. 초기값은 가운데가 솟은 반구형 blob을 프래그먼트 셰이더로 그려 하이트맵의 R 채널에 저장한다.

두께 갱신은 두 단계로 이뤄진다. 먼저 현재 픽셀의 두께와 속도를 샘플링해, 속도에 따라 빠져나갈 양(removed)을 빼준다. 다음으로 어드벡션(advection)을 적용하는데, 현재 픽셀에서 속도를 거꾸로 거슬러 올라가(backtraceUv 함수) 원래 위치의 두께를 샘플링해 가져온다(added). 최종적으로 removed를 빼고 added를 더해 하이트맵을 갱신하며, 두 개의 FBO를 번갈아 쓰는 핑퐁 방식으로 매 프레임 이전 상태를 참조한다. smoothstep을 써서 속도가 작을 때는 두께가 거의 움직이지 않게 한 점도 실용적이다. 멈춰 있는 영역이 계속 흐르는 현상을 막고, 드래그가 닿은 곳으로 움직임을 집중시키기 위한 조정이다.

흔적을 남기는 알파맵과 노멀 계산

두께만으로는 액체가 얇게 발린 뒤 남는 자국을 표현하기 어렵다. 그래서 별도의 알파맵을 두어, 현재 두께에서 나온 값과 지금까지 기록된 최댓값을 함께 쓴다. R 채널에는 과거 최댓값을, G 채널에는 그 최댓값과 현재값을 반반 섞은 값을 저장하고(B는 미사용), 최종 렌더링은 G 채널을 읽는다. 덕분에 액체가 지나간 자리는 두께가 줄어도 불투명도가 즉시 0으로 떨어지지 않고 색이 표면에 묻어난 듯 남는다. 이는 건조나 흡수의 물리 모델이 아니라 단순히 지나간 흔적을 보존하는 히스토리다.

하이라이트는 하이트맵에서 표면 노멀을 계산해 만든다. 각 픽셀에서 자신과 X·Y 방향 이웃의 높이를 샘플링하면 세 점이 두 벡터를 이루고, 그 외적이 노멀이 된다. 평평한 곳과 가파르게 솟은 곳의 노멀 방향 차이가 음영과 하이라이트를 만들어, 평면 위에 실제로 액체가 솟은 것처럼 보이게 한다. 색과 광택은 Matcap 텍스처를 쓰며, 노멀을 Matcap UV로 변환해 샘플링한 색을 알파맵의 불투명도와 합성한다.

한계를 숨기지 않은 기록

이 글의 미덕은 기법의 한계를 분명히 밝혔다는 점이다. 프래그먼트 셰이더는 픽셀을 병렬 처리하므로, 한 픽셀이 자신의 두께를 속도가 가리키는 목적지 픽셀에 직접 써넣을 수 없다. 그래서 각 목적지가 속도를 역추적해 원본을 샘플링하는 방식인데, 여러 픽셀이 거의 같은 원본 영역을 참조할 수 있어 빼낸 양과 더한 양이 늘 맞지 않는다. 결과적으로 액체 총량은 보존되지 않는다. 직선 이동에서는 비교적 안정적이지만 원을 그리면 샘플링 편향이 누적돼 양이 계속 늘어난다. 보존 정확성보다 시각적 결과를 우선한 선택이다.

개발 중 발견한 또 다른 지점은 텍스처 정밀도 문제다. 32비트 부동소수점 텍스처는 높이값을 더 정밀하게 저장해 매끄러운 음영을 내지만, 8비트 텍스처는 채널당 256단계뿐이라 하이트맵이 양자화되고 음영에 눈에 띄는 계단이 생긴다. 보통 색 그라데이션에서나 겪던 8비트의 한계가 음영 계단으로 드러난 점이 흥미롭다는 설명이다. 나아가 색이 다른 세 반구형 blob을 준비해, 속도 맵은 공유하되 각자 하이트맵과 알파 히스토리를 갖게 하고, 단순화한 Kubelka–Munk 모델로 두께에 따라 색을 섞는 실험도 소개한다. 두께가 거의 0인 곳에서는 각 색의 알파 히스토리로 혼합 비율을 정한다.

실무적으로 이 사례는 '물리 시뮬레이션처럼 보이지만 실은 룩(look)을 위한 조정의 집합'이라는 WebGL 연출의 전형을 잘 보여준다. 정점 변형 대신 프래그먼트 셰이더와 FBO 핑퐁, 하이트맵에서 유도한 노멀, 흔적 보존용 히스토리 버퍼 같은 구성은 액체뿐 아니라 번지는 잉크, 긁힘, 손자국 등 다양한 인터랙션에 응용할 수 있다. 필자가 '이 방법을 다시 쓸 일이 많지 않을 것 같고, AI가 더 유능해지기 전에 스스로 고안한 과정을 남겨두고 싶었다'고 집필 동기를 밝힌 대목도 눈길을 끈다. 지난 1년 사이 AI가 좌표와 공간을 이해하고 원하는 비주얼을 계산·구현으로 연결하는 능력이 크게 좋아졌다는 관찰은, 이런 수작업 노하우의 가치가 어디로 향하는지에 대한 솔직한 질문이기도 하다.

SOURCE · HACKER NEWS
원문 전체 보기 → https://mofu-dev.com/en/blog/fluid-foundation/
SHARE
NEXT · CHOOSE

변화를 읽었다면,
내가 만들 수익 구조를 고릅니다.

정보를 더 모으는 데서 멈추지 않고, 광고·외주·판매·중개·구독 중 내 상황에 맞는 출발점을 정해보세요.

21가지 수익 구조 살펴보기 →
처리 중...