안동민 개발노트

본문 시작

유체 효과 구현

Grid 3D·Vector Field·Noise Force로 흐름과 난류를 만들고 밀도·부력·렌더링을 조정해 연기 기둥을 구현합니다.

연기·거품·먼지의 흐름은 힘을 받는 Sprite 파티클로 모방할 수도 있고, Niagara Fluids의 격자 시뮬레이션으로 계산할 수도 있습니다. 필요한 상호작용과 화면 표현에 따라 구분합니다.

Sprite 흐름과 Grid 3D

일반 Collision 모듈에 Fluid 응답을 켜고 Fluid Density Scale/Fluid Resistance를 설정하면 유체 solver가 완성된다는 절차는 사용하지 않습니다. 단순 파티클의 충돌·저항과 격자의 밀도·온도·속도 계산은 다른 구조입니다.

Niagara Fluids 플러그인은 2D/3D Gas·Liquid 등의 템플릿을 제공합니다. Grid 3D Gas에서는 셀에 저장한 상태를 시뮬레이션하고 볼륨으로 렌더링합니다. Bounds, 셀 크기, solver 설정, 렌더 샘플링을 함께 다룹니다. 공간 범위가 같을 때 각 축 해상도를 두 배로 올리면 셀 수는 약 8배가 되므로 메모리와 GPU 비용을 확인해야 합니다. Niagara Fluids 참조

이 절의 실습은 격자 solver 구현이 아닌 Sprite 연기 기둥입니다. 실제 압력·부력·경계 상호작용이 필요하면 Fluids 템플릿에서 별도로 시작합니다.

흐름을 만드는 힘

  • 상승: Spawn의 초기 Z 속도와 Update의 위쪽 가속도로 큰 흐름을 정합니다. 아래 방향 중력만 줄인다고 상승이 계속 유지되는 것은 아닙니다.
  • Drag: 속도를 감쇠해 과도한 확산을 줄입니다. 상승·난류를 조정하기 전에 기본 궤적을 확인합니다.
  • Curl Noise Force / Vector Noise Force: 공간 노이즈로 불규칙한 힘을 더합니다. Strength는 크기, Frequency는 공간 패턴의 스케일과 관련됩니다. 시간 변화 입력과 공간 주파수를 혼동하지 않습니다. 모든 버전의 Noise Force가 같은 Noise Speed 필드를 갖는다고 가정하지 않습니다.
  • Vector Field: 미리 만든 3D 벡터 데이터를 샘플링해 큰 방향과 와류를 구성할 수 있습니다. 실제 프로젝트의 에셋, 모듈·DI 지원과 필드 좌표 공간을 확인합니다. 특정 VF_Turbulence 에셋이 모든 설치에 포함되는 것은 아닙니다.

반투명 연기의 경계

연기용 Translucent 머티리얼에서 Texture Alpha와 Particle Color Alpha를 곱해 Opacity로 전달합니다. 벽·바닥과의 딱딱한 교차는 머티리얼 DepthFade로 완화할 수 있습니다. Renderer의 공통 Soft Particle 체크박스를 켜는 절차와 구분합니다. DepthFade의 Opacity 입력에 기존 알파를 넣고 결과를 머티리얼 Opacity에 연결하며 Fade Distance를 월드 단위로 조절합니다. DepthFade 설명

DepthFade는 표면 관통을 물리적으로 막는 기능이 아닙니다. 실제 충돌이 필요하면 별도 Collision이 필요하며, Volumetric Fog/Cloud와 조합할 때도 Sprite와 볼륨의 비용을 따로 봅니다.

직접 해보기: 연기 기둥

기본 Sprite 시스템을 복제해 NS_SimpleSmoke로 저장합니다. Emitter State가 계속 재생되게 하고 Emitter Update의 Spawn Rate는 20개/초 정도부터 시작합니다.

Particle Spawn의 Initialize Particle에서 Lifetime 35초, Sprite Size 50100 cm, Color (0.1,0.1,0.1,1)을 설정합니다. Shape Location으로 작은 원천 영역을 정합니다.

Particle Spawn의 Add Velocity에서 Z=50100 cm/s, X/Y=-1010 cm/s를 초기 속도로 줍니다. 아래 방향 Gravity Force는 우선 끄고 기본 상승을 확인합니다.

Particle Update에 Particle State, Drag 0.5와 Solve Forces and Velocity를 둡니다. 연속 상승이 필요하면 solver 앞의 Acceleration Force에서 Z=20 cm/s² 정도의 약한 상승 가속도를 시험합니다. 이는 부력의 시각적 근사이며 실제 밀도 차이를 푸는 solver가 아닙니다.

solver 앞에 Curl Noise Force를 추가합니다. Noise Strength 50, Noise Frequency 0.02처럼 작은 시작값에서 한 축씩 조절합니다. 강도를 올릴 때 상승 방향이 난류에 묻히지 않는지 확인합니다. 파티클마다 고정된 난수 입력이 필요하면 Spawn에서 한 번 정해 보관합니다.

Sprite Renderer에 프로젝트의 단일 프레임 연기 텍스처를 쓰는 Translucent 머티리얼을 할당합니다. 텍스처가 시트라면 Sub Image Size·Index·UV를 함께 맞춥니다. 머티리얼의 DepthFade로 불투명 표면과의 교차 경계를 조절합니다.

Particle Update의 Scale Sprite Size에 NormalizedAge 기준 배율 1→2를 연결해 초기 크기에서 점차 팽창하게 합니다. Scale Color의 RGB 배율은 1→3, Alpha 배율은 1→0으로 설정합니다. 초기 RGB 0.1에 배율 3을 곱하면 0.3이 되며, 절대 색상을 커브로 쓰는 것과 구분합니다.

수명 종료 시 입자가 제거되도록 하고 같은 카메라에서 밑동 폭·상승·퍼짐·알파 소멸을 비교합니다. 연기가 떨어지면 아래 가속도를, 산만하면 Noise Strength를, 벽에서 잘리면 DepthFade와 실제 충돌 필요 여부를 나눠 확인합니다.

이 설정의 목표는 위로 이동하며 불규칙하게 퍼지고 사라지는 연기입니다. 동시 입자 수는 정상 상태에서 대략 Spawn Rate × 평균 Lifetime으로 추정할 수 있지만, 투명 면적과 겹침 비용은 따로 측정해야 합니다.