[ Fluid Simulation ] 04. 유체의 화면 공간 렌더링 기법 (Screen-Space Fluid Rendering)

2025. 5. 27. 01:34·물리 기반 시뮬레이션/Fluid Simulation

💠 Screen Space Fluid Rendering

기존의 유체 렌더링 방식 중 하나인 Marching Cubes와 같은 볼륨 기반 표면 재구성 기법은, 복잡한 연산량으로 인해 성능적인 한계를 보인다.

이를 해결하기 위해 본 프로젝트에서는 GLSL 쉐이더를 활용한 Screen Space Fluid Rendering 기법을 채택한다. 이 방식은 GPU의 병렬 처리 능력을 활용하여 연산을 하드웨어 가속하고, 화면 공간 상에서 직접 유체의 깊이와 두께(Thickness)를 재구성함으로써 렌더링 성능을 비약적으로 향상시키는 동시에 시각적 품질 또한 유지 또는 개선할 수 있습니다.

 

과정은 다음과 같다:

  • 1. 입자 정보 수집
  • 2. Depth 이미지 버퍼 생성
  • 3. Depth smoothing (optional blur)
  • 4. Normal 계산
  • 5. Lighting 계산
  • 6. Thickness 이미지 버퍼 생성
  • 7. Surface Shader로 시각적 처리

🧲 입자 정보 수집

Shader를 위한 입자 정보는 기존의 GPU에서 렌더링하기 위해 CPU 메모리로 복사하던 것을 OpenGL을 통해 VBO 바인딩을 수행하여 GLSL 쉐이더에서 접근 가능하도록 했다.


📸 Depth 버퍼 생성

Depth 버퍼 생성을 위해 다음 과정을 거친다:

  • 1. Sphere Rendering
  • 2. Depth Rendering

🟢 Sphere Rendering

먼저 VBO에 저장된 각 입자의 위치 정보를 활용해 구(Sphere) 형태로 렌더링하는 과정이 필요하다.

이때 vertex shader에서 카메라로부터 각 입자까지의 거리를 계산하고, 설정한 구의 반지름에 스케일링을 수행한다:

 

다음으로, fragment shader에서 정점의 텍스처 좌표를 $(0,1) \rightarrow (-1,1)$ 범위로 변경하고, 해당 좌표의 magnitude를 계산하여 설정한 point Radius보다 바깥 쪽에 있는 경우 무시한다.

또한, 구 방정식을 활용해 법선 벡터의 Z 성분을 계산하여 lighting을 설정할 수 있다.

 

 

구 렌더링 결과

💾 Depth 이미지 버퍼 생성

먼저, depth 계산을 위해 vertex shader에서 ModelViewProjection 행렬을 활용해 각 정점을 clipping space 좌표로 이동시킨다:

이를 통해 fragment shader에서 depth를 clipping space에서의 z 좌표를 원근 투영에서 발생하는 w 좌표로 나누어 계산할 수 있다:

이렇게 계산한 depth 값을 다음 normal 계산에 사용하기 위해 FBO(Fame Buffer Object)를 활용해 depth 값을 텍스처에 저장 및 로드하는 과정을 거친다.

 

 

depth 이미지 생성 결과

🧹 Depth Smoothing

depth smoothing 과정은 크게 두 가지 방식으로 진행할 수 있다.

  • Gaussian Filtering
  • Bilateral Filtering

이때, gaussian filtering의 경우 입자의 edge 정보가 smoothing되어 사라진다는 문제가 있기에, bilateral filter를 채택했다.

Bilateral Filter의 과정과 특징

 

  • 모든 픽셀을 순회하며 공간 도메인과 값 도메인에 대해 필터링을 진행한다.
  • Spatial Domain (공간 도메인): 
    • 픽셀 간 거리 r에 따라 가까운 이웃에 더 높은 가중치를 준다.
  • Range Domain (값 도메인):
    • 현재 픽셀의 깊이 값과 이웃 픽셀 s의 깊이 값을 활용
    • 깊이 값의 차이가 너무 크면(ex 입자의 경계) 가중치를 줄인다.
    • 물체의 경계가 smoothing 되지 않도록 보호

 

depth smoothing 결과

🧭 Normal 계산

normal을 계산하기 위해 다음과 같은 과정을 거친다:

  • uv 좌표에서 카메라 좌표계로의 변환
  • 주변 픽셀의 값과 비교하여 normal 계산

이를 코드로 표현하면 다음과 같다:

  • 이는 화면의 픽셀 위치와 깊이 값을 입력 받아 해당 픽셀이 3D 공간 어디에 위치하는지 계산한다.
  • 주요 로직은 투영 행렬의 역행렬을 곱해서 clip space -> view space로 복원하는 것이다.
  • 이때, perspective를 고려하여 w 좌표를 나눠준다.

 

  • 좌,우,상,하(=zl, zr, zt, zb) 방향으로 한 픽셀 떨어진 곳의 3D 위치를 각각 계산한다.
  • 이후, x축 y축을 표현하는 벡터를 설정하기 위해 depth 값을 고려하여 더 가까운 방향(depth 값이 작은) 값으로 설정한다.
  • 최종적으로, x축과 y축을 의미하는 벡터를 외적하여 normal을 계산한다.
normal 계산 결과
normal smoothing 결과

💡 Lighting 계산

앞서 계산한 normal를 활용해 lighting을 적용할 수 있다. lighting은 크게 세 가지로 나눌 수 있다:

  • Diffuse Lighting
  • Specular Lighting
  • Fresnel

☀️ Diffuse Lighting

난반사라고도 불리며, 빛이 표면에 부딪힌 뒤 여러 방향으로 퍼지는 빛을 표현한다. 특히, 거친 표면에서 주로 발생한다.

 

diffuse lighting 결과

✨ Specular Lighting

정반사라고도 불리며, 빛이 표면에 부딪힌 뒤 거울처럼 특정 방향으로 튕겨 나가는 빛을 의미한다. 주로 매끄러운 표면에서 발생한다.

 

specular lighting 결과

🌈 Fresnel

Fresnel (프레넬) 효과는 빛이 표면에 닿을 때 반사와 투과(굴절)의 비율이 시선 각도에 따라 달라지는 현상이다.
이는 특히 유체, 유리, 물, 플라스틱처럼 투명하거나 반투명한 물체를 렌더링할 때 굉장히 중요한 시각 효과이다.

$$
\Huge
R(\theta) = R_0 + (1 - R_0)(1 - \cos\theta)^5
$$

fresnel 결과

🧪 Thickness 이미지 버퍼 생성

thickness 값을 계산하기 위해 다음과 같이 fragment shader를 작성한다:

  • gl_PointCoord: 각 입자가 그려질 때, 그 입자를 덮는 각 픽셀에 대해 해당 픽셀이 점 내부 어디에 위치하는지 $(0, 1)$ 범위로 반환
  • $(0,1) \rightarrow (-1,1)$ 범위로 변경
  • $x^2 + y^2 = r^2$ 을 계산 -> 중심에 가까울수록 0, 멀수록 1 값을 가짐
  • $\sqrt{1-r^2}$ 을 통해 얇은 곳은 0, 두꺼운 곳은 1 값을 가짐

이를 활용해 두께에 따른 빛 투과량을 계산하여 다음과 같이 렌더링 한다:


🖼️ 결과

최종 screen space rendering 결과

참고 자료:

https://developer.download.nvidia.com/presentations/2010/gdc/Direct3D_Effects.pdf

 

깃허브:

https://github.com/qkrdmstn/flip3d-turbulence-cuda.git

 

GitHub - qkrdmstn/flip3d-turbulence-cuda

Contribute to qkrdmstn/flip3d-turbulence-cuda development by creating an account on GitHub.

github.com

 

'물리 기반 시뮬레이션 > Fluid Simulation' 카테고리의 다른 글

[ Fluid Simulation ] 05. 화면 공간 유체 렌더링을 위한 좁은 범위 필터 (Narrow-Range Filter for Screen-Space Fluid Rendering)  (0) 2025.05.29
[ Fluid Simulation ] 03. 액체 시뮬레이션에서 파동 난류를 표현하기 위한 GPU 병렬화 (GPU Framework for Simulating Wave Turbulence in Fluid Simulation)  (0) 2025.05.24
[ Fluid Simulation ] 02. 파동 난류 표현 (Wave Turbulence)  (0) 2025.05.23
[ Fluid Simulation ] 01. 유체 시뮬레이션 (Fluid Simulation)  (0) 2025.05.17
'물리 기반 시뮬레이션/Fluid Simulation' 카테고리의 다른 글
  • [ Fluid Simulation ] 05. 화면 공간 유체 렌더링을 위한 좁은 범위 필터 (Narrow-Range Filter for Screen-Space Fluid Rendering)
  • [ Fluid Simulation ] 03. 액체 시뮬레이션에서 파동 난류를 표현하기 위한 GPU 병렬화 (GPU Framework for Simulating Wave Turbulence in Fluid Simulation)
  • [ Fluid Simulation ] 02. 파동 난류 표현 (Wave Turbulence)
  • [ Fluid Simulation ] 01. 유체 시뮬레이션 (Fluid Simulation)
coding-l7
coding-l7
  • coding-l7
    coding-l7rl0
    coding-l7
  • 글쓰기 관리
  • 전체
    오늘
    어제
    • 분류 전체보기 N
      • 기타
      • 유니티
        • OfficeWorkerRunning
      • 프로그래밍 언어 N
        • C N
        • C#
        • C++
      • CS
        • 컴퓨터 구조
        • 운영체제
      • 물리 기반 시뮬레이션
        • 기초
        • Cloth Simulation
        • Fluid Simulation
      • 코딩 테스트
        • 프로그래머스
        • 백준
      • 독서
        • [ 뇌를 자극하는 윈도우즈 시스템 프로그래밍 ]
        • [ 혼자 공부하는 컴퓨터 구조 + 운영체제 ]
        • [ CUDA 기반 GPU 병렬 처리 프로그래밍 ]
      • 영어
        • Basic Grammar In Use
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

    • 깃허브
    • 포트폴리오
  • 공지사항

  • 인기 글

  • 태그

    narrow range filter screen-space fluid rendering
    명령어
    screen-space rendering
    정수 승격
    물리 기반 시뮬레이션
    wave simulation
    실수
    입자 기반 방법
    상수
    jump table
    C언어
    파동 난류
    그리드 기반 방법
    시스템 프로그래밍
    액체 시뮬레이션
    bilateral blur
    유체 시뮬레이션
    컴퓨터 구조
    fluid simulation
    GLSL
    position based dynamics
    surface turbulence
    cloth simulation
    RAM
    OpenGL
    pbd
    screen space fluid rendering
    fluid implicit particle
    Flip
    collision
  • 최근 댓글

  • hELLO· Designed By정상우.v4.10.3
coding-l7
[ Fluid Simulation ] 04. 유체의 화면 공간 렌더링 기법 (Screen-Space Fluid Rendering)
글쓰기
상단으로

티스토리툴바