전반적인 학습 순서
- 볼륨이 무엇인가?에 대해 학습
- 볼륨 출력하는 방법에 대해 학습
- vector field / smoke solver / pyro solver 학습
볼륨은 FX에서 정말 중요한 부분이다.
- 얼마나 자연스러운 볼륨 결과를 내느냐 이 부분이 FX 퀄리티에 어마어마한 영향을 줄 것이다
앞서 작업한 파티클의 결과에 모두 조금씩 볼륨을 추가해줄 수도 있다.
- 이 때 얻게 될 FX 결과물의 느낌 차이는 꽤 크다.
볼륨, 쉽지 않다.
자기 최면의 시간.
스스로의 마음을 비우고,
나는 초보자다. 이제 처음 배우는 것이다.
지금까지 배워온 학습량 때문에 자만할 경우 볼륨에 관한 내용들이 온전히 받아들여지지 않을지도 모른다.
볼륨이 무엇인가?
- 공간을 voxel이라는 단위로써 표현한 부피를 가진 결과물
- 볼륨의 기본 단위 : voxel (volume + pixel)
볼륨의 두가지 분류
- 결과로써의 볼륨
- 눈으로 보게 되는 볼륨, 직관적으로 이해하기에 용이하다.
- 일반적으로 밀도(density)에 의해 시각적인 표현이 가능하다.
- 연기, 구름, 불, 화염, 에너지 등
- 정보저장으로써의 볼륨
- 시각적으로는 큰 의미를 가지지 않는 것이 대부분
- 작업에 유용한 정보로서는 대단히 중요함
- (공간에 부는) 바람, (표면이 가지는) 곡률, (표면이 가지는) 노멀 등
- 이 정보들은 볼륨을 통한 모델링에서도 활용이 가능하다.
우리가 어려워하는 쪽은 정보저장으로써의 볼륨쪽이 많다.
- 정보로써 활용되는 볼륨을 잘 활용하느냐 마느냐가 최대 관건이 될 것이다.
- 정보가 잘 다뤄진 뒤에, 그에 맞는 좋은 결과가 나온다.(당연한 이야기이다.)
볼륨은 어떤 식으로 정보를 저장하는가.
위의 이미지 속 박스의 갯수를 세어보면, 3x3x3 개인 것을 알 수 있다.
위와 같이 3x3x3인 볼륨에 대해 [3,3,3] 볼륨이다 라고 표기할 예정이다.
위의 이미지의 볼륨은 전체 몇개의 voxel을 이용하게 되는가?
3 X 3 X 3 = 27개의 voxel을 이용하게 된다.
그렇다면, [4, 10, 8] 볼륨은 몇개의 voxel을 이용하는가?
4 X 10 X 8 = 320개의 voxel을 이용하게 된다. (위의 예시의 볼륨보다 더 무거운 볼륨(더 많은 정보를 가진 볼륨)이다.)
이제 시각적으로 비교를 해보자.
가운데의 박스만 속이 차있고, 나머지 박스는 투명한 것을 볼 수 있다.
속이 차있는 박스는 다른 박스에 비해 밀도가 높을 것이라 예측할 수 있다.
투명하게 보이는 박스는 가운데 박스에 비해 밀도가 낮을 것이라 예측할 수 있다.
임의로 값을 지정해준다면, 가운데 박스의 밀도는 1, 주변의 투명한 박스의 밀도가 0.1이라고 했을 때, 밀도가 0이었다면, 눈에 보이지 않았을 것이다.
볼륨은 밀도에 대한 정보를 가질 수 있다.
이 정보를 가지기 위해서는 이름이 필요하고, 후디니에서 가장 기본적인 밀도에 대한 이름은 density를 사용한다.
굳이 density가 아니어도 상관은 없다. 볼륨 정보를 저장하기 위해서는 A, TWA 등 어떠한 이름도 상관이 없다.
만약 위의 3 x 3 x 3의 볼륨의 이름이 density일 경우, 표현법은 다음과 같다.
density [3,3,3] // 볼륨 이름 [ 해상도 ]
또한 이름에는 어떠한 이름이 올 수도 있기 때문에, A[3,3,3], TWA[3,3,3]이 될 수도 있다.
우리가 앞으로 사용하게 될 볼륨에는 vel[..., ..., ...](속도에 대한 볼륨), temperature[..., ..., ...](온도에 대한 볼륨)이 있다.
볼륨의 해상도도 같고, 볼륨의 형태도 같을 수 있으나, 이름이 서로 다르게 지정된다면, 서로 다른 볼륨으로 활용될 수 있다.
후디니는 볼륨 정보를 어떻게 취급하는가?
해상도와 상관없이 하나의 볼륨은 하나의 primitive에 모든 정보가 저장된다.
그리고 primitive에 저장된 볼륨은 포인트 한개로써 위치정보를 가지게 된다.
- 이 위치정보는 볼륨이 어디에 놓이게 될지를 정해주는 포인트 정보일 뿐이다.
위의 예시의 이미지를 density 볼륨이라 가정하고 volume info를 적어본다면 다음과 같다.
point 1 (위치정보 저장)
prim 1 (볼륨이 가지는 정보 저장)
volume || vdb (prim이 가지는 정보가 volume인지, vdb인지 기입되어있음)
density[3, 3, 3] (우리가 가진 볼륨의 이름과 해상도가 기입되어있음)
볼륨을 구성하는 각각의 voxel은 어떠한 형태의 정보를 가지고 있나?
밀도나 온도의 경우, 각각의 voxel은 float 형태의 정보를 가지게 될 것이다.
속도의 경우, 각각의 voxel은 vector 형태의 정보를 가지게 될 것이다.
vector 형태의 정보를 가지게 될 경우, info의 내용이 조금 다를 수 있다.
위와 같이 두가지 형태로 나타날 수 있다.
density(float) / temperature(float) / vel(vector) 로 표기된다면, point와 prim의 갯수는 3개로 나타나지만,
density(float) / temperature(float) / vel.x(float) / vel.y(float) / vel.z(float) 로 표기된다면, 우리에게 유용하다고 생각하는 볼륨의 정보는 3개이지만, point와 prim의 갯수는 5개로 나타난다.
각각의 voxel의 실제 위치나 값은 어디에 저장될까?
- intrinsics에 저장된다.
각각 voxel의 실제 위치값 같은 것은 존재하지 않는다.
우리가 흔히 사용하는 포지션에 대한 실제 위치값은 저장되지 않는다.
그럼에도 시각적으로 표현된 것을 볼 수 있는데, 볼륨이 어떻게 정보를 다루는지 이해를 할 필요가 있다.
큰 행렬이 쓰인다고 생각하면 좋다.
빨간색 박스의 위치를 나타낸다면, x축으로 첫번째, y축으로 첫번째, z축으로 첫번째 위치에 있기 때문에 (0, 0, 0)으로 쓸 수 있을 것이다.(후디니에서는 0부터 시작하므로)
마찬가지로 초록색 박스의 위치를 나타낸다면 x축으로 첫번째, y축으로 세번째, z축으로 첫번째 위치에 있기 때문에 (0, 2, 0)으로 표기가 가능하다.
하늘색 박스의 위치는 x축으로 세번째, y축으로 두번째, z축으로 세번째 위치, 즉 (2, 1, 2)로 나타낼 수 있다.
마지막으로 가운데의 하얀색 박스는 (1, 1, 1)로 나타낼 수 있을 것이다.
위치를 표기하는데 사용된 인자는 모두 integer이다.(몇번째에 위치하고 있는지를 나타내고 있기 때문) 이 integer 정보로 이루어진 정보를 활용해서 행렬을 만들어줄것이다.
volume[a, b, c]가 있을 때,
각각의 voxel의 고유한 번호는 다음과 같은 식으로 정의된다.
x + (y x a) + (z x a x b)
ex) volume[ 5, 6, 8 ] 이 있을 때, 위의 식에 대입해본다면
x + (y x 5) + (z x 5 x 6)
이 값이 만약 223 라고 한다면, 큰 값부터 계산을 해서 223 / (5 x 6) = 7 (나머지 13) -- z는 7
위에서의 나머지 13에 대해 13 / 5 = 2 (나머지 3) -- y는 2
x는 3
223를 고유번호로 가지는 voxel의 위치는 (3, 2, 7)이 된다.
point의 위치정보는 볼륨의 중앙의 위치이다.
volume과 vdb의 차이점
위의 이미지는 7 x 7 x 7의 볼륨이고, 안에 밀도로서 표현된 내용이 있다.
맨 밖의 테두리는 상대적으로 밀도가 낮다. 그래서 지금은 '테두리가 가지는 밀도가 0이거나 정보를 딱히 가지고 있지 않다.' 라고 가정을 하자.
해상도가 낮은 지금은 7 x 7 x 7 볼륨이 요구하는 정보의 양이 많지 않다.
하지만, 만약 400 x 400 x 400 볼륨이었다면? 64,000,000개의 voxel 자료가 필요해진다. 특히나 실질적으로 밀도로 표현되는 구간이 극히 일부분이라면, 굉장히 큰 정보적 낭비가 발생하게 된다.
후디니가 원래 제공했던 볼륨의 체계는 낭비되는 부분에 관계없이 설정된 해상도를 전부 묘사해줬다.
보여줄 것이 없는 부분도 0이라는 정보를 가진 볼륨이 되는 것이었다.
(폭발처럼 작게 시작해서 크게 퍼져나가는 효과등에서 낭비가 더욱 크게 느껴진다)
작업의 효율에도 안좋은 쪽으로 영향을 주게 된다.
이런 부분을 해결하기 위한 방법이 vdb이다.
vdb : 정보로써 의미가 크지 않은 부분에 대해 아예 제거해줌으로써 볼륨의 해상도의 변화를 주게 된다.
[ 7, 7, 7 ]의 볼륨이 [ 5, 5, 5 ]의 볼륨으로 바뀌었다.
하지만 밀도로써 실질적인 의미를 가지는 볼륨을 표현함에 있어서는 두 방식 다 크게 차이가 없다.
볼륨이 가지는 정보의 종류에 대해, wind에 대한 vector field를 만들어준다고 하면,
일반 볼륨은 wind.x[ ..., ..., ... ] wind.y[ ..., ..., ... ] wind.z[ ..., ..., ... ] 이런식으로 총 세개의 볼륨이 만들어지게 되지만,
vdb의 경우 wind[..., ..., ...] vector 볼륨이 생성될 수 있다. (세개의 float 볼륨으로 쪼개지는 것이 아니고, 한개의 vector 볼륨으로 생성된다는 의미)
대부분의 경우에서 vdb가 일반 볼륨보다 효율적이고 편하다.
Signed Distance Field(SDF)
- Signed Distance Field(SDF)에서 가장 관심있는 구간의 밀도값은 0이다. 목표로 하는 관심구역 자체가 0에 있다.
sphere를 기준으로 볼륨을 만들었다 가정하자.
sphere 안쪽의 voxel들은 밀도값이 0보다 큰 값을 가지고 있을 것이고, sphere 바깥의 voxel들은 밀도가 0일 것이다.
0보다 큰 밀도값을 가지는 모든 voxel의 밀도값을 1로 치환해주면, 위처럼 블러가 들어간 느낌이 아닌, 아래처럼 블럭같은 느낌으로 표현이 가능할 것이다.
위 이미지는 SDF를 밀도로 봤을 때의 결과이다.
Signed Distance Field
Distance Field - 거리와 연관이 있다.
무엇에 대한 거리인가? 우리가 구하고자 하는 물체의 표면과 voxel 간의 최단 거리에 대한 이야기이다.
임의의 위치의 voxel에서 물체의 표면간의 최단 거리를 구하려면, voxel이 중심이 되는 원을 그려보다가 원이 물체와 접할 때, 그때의 원의 반지름이 voxel과 물체 사이의 최단거리가 될 것이다. 이것이 우리가 원하는 SDF의 값이다.
물체의 표면에 대해 표면 밖에서 접하게 되는 voxel과 표면 안에서 접하게 되는 voxel이 존재한다. 거리는 항상 양수값을 가지게 되기 때문에 표면 안과 밖을 구분해주기 위해서 표면 안쪽을 -, 바깥쪽을 +로 표기한다. (이와같이 안과 밖을 구분하기 위해 +/-를 붙이는 과정에서 Signed라는 단어가 붙는 것이다.)
그냥 일반적인 distance field 였다면, 물체 안쪽도 거리에 대한 값으로 + 값을 가지게 되었을 것이다. 하지만 Signed Distance Field이기 때문에 물체 안쪽은 -를 붙여주는 것이다.
정리.
Signed Distance Field : 각각의 Voxel에서 주어진 물체까지의 최단거리를 구한 정보
- 이 때 주어진 물체의 안과 밖을 구분해주기 위해 밖은 양수의 값으로, 안은 음수의 값으로 표현한다.
SDF가 0인 곳은?
- 물체의 표면에 해당하는 볼륨(voxel)이다.
물체를 기준으로 Density 볼륨을 만들어주는 원리가 무엇일까?
- SDF에 -1을 곱해서 영역을 반전시켜준다.
- 안쪽이 양수의 값을 가지게 되고, 바깥이 음수의 값을 가지게 된다.
- 이제 우리가 가지는 값에 대해 0보다 작은 음수는 모두 0으로 고정한다. 그렇다면 물체의 바깥부분은 0이 되고, 우리가 가지는 정보는 0과 양수의 값으로 이뤄진 정보가 된다.
- 물론 정확하게 이 방식으로 만들어지는 것은 아니다.
pop solver를 설명할 때, 앞으로의 충돌조건은 모두 volume이다 라고 했었다.(선생님이)
sphere가 벽을 향해 날아가고 있다고 가정하자.
sphere의 SDF는 내부는 -, sphere의 바깥은 +이고, 벽의 SDF 또한 벽의 내부는 -, 벽의 바깥은 +로 표현할 수 있다.
이 때, 두 SDF를 서로 곱해준다면 오른쪽의 결과를 얻을 수 있다.
물체를 기준으로 본다면, 두 물체의 상호작용(SDF를 서로 곱해주는 것)으로 인해서 두 물체의 SDF가 변화가 발생하거나 하지는 않았다.
만약 sphere가 날아가서 두 물체가 충돌을 일으켰다면?
SDF에 변화가 발생하였다. 원래 -였어야 하는 SDF가 +로 변한 구간이 있다. 이와같은 조건을 만족했을 때, 충돌이 발생했다 라고 이야기할 수 있다.
요약
- 볼륨 : 공간상의 정보를 담는 어떠한 새로운 방식
- 점, 선, 면을 다루던 방식과는 다르다.
- 각각의 정보를 담는 그릇을 voxel이라 부른다.
- voxel은 float 값이 될 수도 있고, vector 값이 될 수도 있다.
- 볼륨을 정의해주기 위해서는 몇가지 정보가 필요하다.
- 우리가 만든 볼륨을 어디에 두고 싶은지에 대한 내용을 포인트의 위치정보로써 정해줘야 한다.
- 바운딩 박스가 존재해서 어느정도 규모에서 공간을 나눌지 정해줘야한다.
- 어떻게 쪼개져있을지를 정해줘야한다. x축, y축, z축으로 몇번씩 쪼개져있는 것에 의해 해상도가 결정된다.
- 노드를 다루는 시점에는 voxel의 사이즈를 미리 정해두고 쪼개는 방법도 있고, 축을 기준으로 잡고 횟수로써 쪼개는 방법도 있다.
- 볼륨이 정의가 되었다면, 이 내용들은 모두 primitive에 저장된다. (intrinsics)
- 어떠한 오브젝트를 기준으로 볼륨을 만들려면 안과 밖의 구분이 필요하다. 이 때 각각의 voxel에서 오브젝트까지의 최단거리를 활용하면 SDF(signed distance field)를 구해줄 수 있다.
- SDF를 활용해서 밀도로 볼륨을 표현해줄 수도 있다.
- 정보의 효율을 위해서 일반 볼륨이 아니라 vdb를 이용하기도 한다.
vdb로 sdf와 볼륨에 관련된 이야기를 해보자.
시각적으로는 큰 차이를 보기는 어렵지만, 노드 인포를 보면 다르다.
point와 primitive는 각각 1개씩 있다.
그리고 일반 볼륨은 volumes가 1개, vdb는 VDBs가 1개로 표현되어 있다.
아래쪽 구름모양을 보면
일반볼륨은 A라는 이름의 볼륨이 있고, 이 볼륨의 해상도는 [104, 104, 104]이다. voxel의 숫자는 1,124,864개이다.
vdb의 경우, density라는 이름의 볼륨이 있고, 해상도는 [101, 99, 101]이다. 동일한 물체로 만들어낸 볼륨이지만, 해상도가 다르고, 이용된 voxel의 수는 절반수준에 불과하다. vdb의 해상도대로라면 1,009,899개의 voxel을 활용해야 하는것이 맞지만, 절반정도만 사용된 voxel의 수치는 다음 이미지를 보면 확인이 가능하다.
일반 볼륨은 빈 공간에도 포인트가 가득찬 반면, vdb는 속도 비어있고, sphere 외부도 비어있다.
맨 왼쪽 : sphere를 가지고 SDF를 보여달라고 요청했을 때 보게 되는 형태
다른 결과물에 비해 면으로 표현되는 느낌이다.
일반적으로 SDF의 결과로 우리가 보고자 하는 것은 거리가 0인 것들이다. 그래서 거리가 0인 곳에 면같은 것을 대서 보여준 결과가 맨 왼쪽의 결과이다. 즉 밀도나 볼륨으로 본 결과는 아니라는 것이다.
왼쪽에서 두번째 : 실제 SDF의 결과를 밀도로서 시각화한 것이다. 중간에 비어있는 것처럼 표현된 것은 Scene view가 어떤 값 미만의 밀도에 대해 표현하지 않아서 그런 것이다.
왼쪽에서 세번째 : 느낌을 살리기 위해 선생님이 수치값에 변화를 준 것. 속은 비어있고, 밖의 밀도가 더 높다.
왼쪽에서 네번째 : 우리가 SDF에 대해 가장 많이 오해하는 결과. 표면에 얇은 볼륨이 있는 것 처럼 보인다. 표면에 볼륨정보가 몰려있다고 생각할 수 있지만, 그렇지 않다. 실제 SDF는 왼쪽에서 두번째 처럼 나타나고, 이해하기 편하게 보자면 왼쪽에서 세번째 결과에 가까운 느낌이다.
맨 왼쪽 : 거리가 0인곳이 우리의 관심이고, 그 부분에 대해 후디니가 면으로 치환해서 보여주는 것이다.
중간, 맨 오른쪽: 일반 볼륨의 경우, 바운딩 박스의 모든 부분에 밀도에 대한 정보가 있기 때문에 정육면체의 윤곽이 보이고 있다. 하지만 vdb로 만든 SDF의 경우, 정육면체 윤곽같은 것은 보이지 않는다. SDF가 중요하다고 판단하는 것은 거리가 0인 부분이다. 그래서 어느 기준을 넘어서면 vdb가 판단하기에 불필요하다 생각되는 voxel들은 다 지워버린다. 그래서 마치 밀도가 표면에 있는것처럼 보인다.
SDF가 0인 부분(물체의 표면)에 포커스를 맞추고, 일정 범위까지는 정보를 저장하지만, vdb의 판단 하에 일정 범위 이상이 되는 voxel에 대해서는 제거해버린다. 표면 안쪽도 마찬가지로 일정 범위까지는 SDF의 음수값을 저장하지만, 이 또한 일정 범위 이상의 voxel에 대해서는 제거해버린다.
일반 볼륨이나 vdb나 우리가 가진 sphere는 동일하다. 하지만 vdb에서는 우리가 원하는 한계지점까지만 정보를 구해주게 된다.
아... 이론은 머리가 아프다...
아프고 잘 돌아가지 않는 머리이지만, 열시미 깨고 또 깨서 머리에 집어넣자.
나는 초보자다. 1도 모르는 초보자다. 모르니까 모든 것을 다 머릿속에 저장하고 또 저장해야한다... 근자감은 아랫집 멍멍이나 줬다...
sdf에 대한 개념은 다른 곳에서 본 기억이 있는데, 그 때는 후디니하고는 부호가 달랐던 기억이 있다. 난 후디니스트니까 이것을 기준으로... 얍!
첫 수업부터 이리 어려운데 다음수업은... 버틸 수 있을까... 하하
'Houdini > Houdini1_Volumes' 카테고리의 다른 글
05_볼륨의 확산? 이류? VOLUME ADVECT (0) | 2023.02.22 |
---|---|
04_Vector Volume / VOL TRAIL, GRADIENT, CURVATURE 🔥완전중요🔥 (1) | 2023.02.21 |
03_VOLUME_part2. Volume 계산능력 향상 필수 (0) | 2023.02.17 |
03_VOLUME_part1. Volume 계산 Wrangle, Vop & Volume Sample, 구름 (0) | 2023.02.16 |
02_VOLUME NODE 다루기 & 시각화 (0) | 2023.02.15 |