[shaderPixel] transluscent

나우히즈·2024년 11월 19일

Graphics

목록 보기
17/17
post-thumbnail

오랜만에 쉐이더픽셀 포스트로 돌아왔다.

이번에 해본것은 volumetric ray march 로, 불투명한 구름, 연기, 불 등 불규칙하게 움직이는 물체에 대한 렌더링을 할 수 있었다.

나는 구름덩어리? 를 렌더링해보았는데 상당히 부족한 부분이 많아 아쉽지만 이러다간 아무것도 나아가지 못할 것 같아서 일단 정리를 좀 하고 보려고 한다.

내가 작성한 fragment shader는 아래와 같다.

https://github.com/sihkang/ShaderPixel/blob/main/shader/transluscent.fs
쉐이더토이 : https://www.shadertoy.com/view/WlfXzX

우선 엄청 긴데, 대부분의 파트가 fastnoise라는 공개된 노이즈 라이브러리이다.

해당 노이즈 라이브러리로부터 노이즈를 받아서 불규칙한 움직임을 재현한다.
노이즈에 대한 자세한 사항은 내용이 워낙 많기때문에 별도의 포스트로 게시할 예정이다.

일단 오늘은 프레그먼트 쉐이더의 구성과 진행흐름에 대해 정리해보는 시간을 갖겠다.


void main()

메인함수는 여타 ray marching fs들과 크게 다르지 않았다.

  • 화면 픽셀상의 값을 uv로 받고, 화면 해상도 비율에 맞게 찌그러지지 않도록 비율을 곱해준다.
  • rayDir 을 통해 현재 위치에서 진행할 광선의 방향 설정.
    • 카메라 위치에서 uv로의 광선을 쏘는 상황.
  • camPos 설정하여 광선 발생 위치 지정.
  • 이후 shading() 함수를 거쳐 색상을 받아와 반환.

vec3 shading(vec3 rayOrigin, vec3 rayDir)

ray marching을 통해 색상을 지정하는 부분이다.
기존에는 SDF를 통해 프랙탈 표면에 점점 가까워지는 상황이었지만 지금은 상황이 다르다.
불투명한 물체이기 때문에 빛이 투과할 수 있는 상황이다.
이에 맞추어, 연기 구체가 존재할 범위를 설정하고 그 범위를 광선이 일정 거리씩 진행하며 해당 위치에서의 밀도값을 합산해 어떤 색상을 갖게 할지를 결정한다.

  • 광원 방향 설정

  • 구체 영역 및 ray march 파라미터 설정

    • nbStep : ray march 반복 횟수
    • diam : 연기 구체 반경
    • raylength : 반복 당 광선이 진행하는 거리
  • end 에서부터 start로 raylength 씩 진행하며 smoke()로부터 구해진 연기의 밀도를 합산해옴.

  • 일정 값 이상의 밀도라면 해당 위치는 진한 색상이 찍혀야하므로 sumDif 에 값을 합산.

  • 반복 후 구해진 sumDen, sumDif를 바탕으로 색상을 결정하여 리턴

  • 구체는 (0,0,0) 중심이다. 따라서, dot(pos, pos) > diam*diam 의 의미는 현재 위치가 연기구체 바깥이라면 더이상 계산을 진행하지 않음을 의미.

여기서 궁금할 수 있는 포인트는 왜 end -> start 진행을 하는지이다.

  • 뒤쪽에서부터 계산하면, 광선이 먼저 "깊은 곳의 연기"를 통과하면서 빛의 세기가 점차 약해지는 효과를 누적하는 방식으로 구현됩니다. 결과적으로, 뒷부분의 연기가 앞부분보다 더 강하게 영향을 미치게 됩니다.
  • 빛의 색상이나 강도는 연기 내부를 통과하면서 누적됩니다. 뒤에서부터 빛을 계산하면, 깊은 곳에서 약해진 빛이 점차적으로 겉으로 드러나는 효과를 표현할 수 있습니다.

float smoke(vec3 pos)

  • q를 반복적으로 키워주는 것은 프랙탈 브라운 운동(fBm)의 주요 요소 중 하나로, 큰 스케일에서 작은 스케일까지 다양한 수준의 세부 사항을 더하기 위함.

  • amp는 반복 횟수가 증가할수록 더 작은 기여도를 가지도록 조정. 이는 큰 스케일의 기여도를 강조하고, 점점 작은 세부 사항은 덜 중요하게 만드는 역할.

  • f에 누적하는 과정은 여러 주파수에서 얻은 노이즈를 조합하여 복잡하고 자연스러운 패턴을 생성. f는 프랙탈 브라운 운동(fBm)의 결과로, 해당 위치의 노이즈 밀도를 나타냄. f가 크면 해당 위치에서 연기의 노이즈 밀도가 높다는 뜻.

  • noiseShape은 pos.y (연기가 위로 퍼지는 방향)에 대해서는 +를, xz방향으로 퍼질수록 -를 하여 연기의 형태로 퍼저나가는 분포를 그려주도록 설정

float noise(vec3 pos)

위치에 대한 노이즈 값을 리턴한다.
앞서 이야기했듯, fastnoise 라이브러리를 활용해 노이즈세팅을 받아왔다.
노이즈가 파라미터에 따라 크게 달라지고, 표현하고자 하는 형상에 따라 다양한 노이즈가 존재해서 그에 대한 옵션을 잘 설정해주는 것이 필요하다.


결과

정리해놓고 보니 막상 뭐가 없게 느껴지지만
제일 중요한 부분은 noise이다. 노이즈의 형태에 따라 구름이 어떤 식으로 분포될지가 결정된다. 실제로 보고 따라한 쉐이더토이 코드에서 노이즈 텍스처가 바뀌면 전혀 구름같지 않은 형태로 바뀌어버린다. 그냥 랜덤한 값을 가진다고 다 같은 노이즈가 아니라는 말이다...

만든 결과는 뭔가 뭉게뭉게 구름보다는 타오르는 불같다... 색만 빨갛게 입히면 불이라고 해야할듯

noise에 대해서 여러가지로 잘 정리해서 포스팅해보겠따.

ps)
파라미터를 살짝 다르게 만지면 이렇게 이쁜 윤슬? 느낌도 얻어진당.ㅋㅅㅋ

0개의 댓글