TWA Houdini1/Rigidbody

TWA 후디니 1 RIGIDBODY_02 : PACK 훈련 & 나무플랭크 시스템 만들기

yiss09 2023. 3. 21. 05:52

https://www.twahoudini.com/course/rigidbody1

 

HOUDINI1_ RIGIDBODY

3️⃣ 출동 SIMULATION 기초 이론부터 심화된 내용을 공부합니다. 또한 자동차를 이용한 리깅 시뮬레이션 BASIC을 훈련합니다.

www.twahoudini.com

 

지난 시간에는 Pack의 원리와 특징들에 대해 배웠다.

특징에는 복잡하고 많은 자료를 하나의 자료로 압축해서 작업이 가능하다는 점, 메모리에 업로드된 자료를 마치 스트리밍하듯 불러서 껍데기(가상의 원본)만 활용이 가능하다는 점이 있었다. 이에 의해 메모리 효율에 큰 이익이 있게 된다.

그런데 이렇게 이론적으로 Pack에 대해 아는 것과 Pack을 능수능란하게 쓰는 건 다른 문제이다.

실전적인 감각을 기르기 위해서 RigidBody02에서는 나무 판자들을 만들어보려 한다.

 

나무 판자를 만들기위해서 먼저 제작 과정의 큰 순서를 짚어보도록 하겠다.

1. Box 하나에서부터 시작한다.

2. Box의 면을 늘려주고, 모양도 삐뚤빼뚤하게 만들어준다.

3. Box를 조각내고 약간의 빈틈이 있는 나무처럼 묘사해준다.

4. 앞에서의 결과를 바탕으로 구체적인 나무의 질감이 느껴지도록 해준다.

우리는 이렇게 만든 결과가 하나의 Box에만 적용되길 원하는 것이 아니다. For-each Primitves를 이용해서 반복을 준다.

이때 중요한건 앞서 만든 시스템에 어떠한 Box가 들어가더라도 올바르게 작동하는가이다. 이에 반복 작업을 대비해서 작업을 해주도록 하겠다.

여러개로 만들어줄 때는 모든 나무 조각들이 완벽하게 같은 모양은 없도록 해줄 예정이다.

이러한 나무 조각을 만드는 이유는 Pack을 쉽게 다루기 위해서인 것을 잊지말고 생각하며 공부하도록 하자.

 

목차

1. Random한 Size, Color의 Box 만들기

2. Polybevel로 면, 형태 다듬기

3. Voronoi Fracture, Assemble, Point Jitter로 조각 내기

4. Remesh to Grid, Displace Along Normal, Veins로 질감 내기

5. Simulation을 위한 준비(Bouding Box 맞추기)

 

 


1. Random한 Size, Color의 Box 만들기

 

Single과 Multy의 용도로서 Geometry를 두 개 생성해준다.

single_plank로 들어가서 먼저 작업해주도록 하겠다.

가장 먼저 해줄 작업은 나무 조각에 쓰일 재료인 Box들을 다양하게 만드는 것이다. 그리고 그 Box들의 크기가 어떠한 기준을 두고 Random했으면 한다.

먼저 Box를 생성해준다. 그 다음 x축 값이 순서대로 0, 2, 4인 points를 생성해준다. 이 세 점을 Merge로 묶어준다.

Copy to Points로 세 점에 Box를 붙여준다.

 

이제 각각의 점들이 서로 다른 사이즈로 Box를 복제하기를 바란다(JOY OF VEX 16일차).

점들의 @pscale이 다르다면 Copy to Points를 할 때 Box들이 서로 다른 사이즈로 만들어지게 될 것이다.

Attribute Wrangle을 Merge 아래에 달아 @pscale에 random 값을 주었다. 결과를 보면 사이즈가 각기 다른 Box가 만들어진 것을 볼 수 있다.

이때 Box의 사이즈가 마음에 들지 않는다면, rand function 안에 float 값을 더하거나 곱해주어 seed를 변경해주면 된다.

 

우리는 이제 @pscale이 아닌 그냥 @scale이라는 Attributes를 이용해 사이즈를 변경해보려 한다.

Attribute Wrangle을 각각의  점 밑에 달아 준다.

앞서 이용했던 @pscale은 점의 크기라고 생각하면 좋다. Transform node의 Uniform Scale과 그 결이 같다.

이번에 쓸 @scale은 Transform node의 Scale과 비슷하다. 그래서 vector 정보로서 다루게 된다.

일단 하나의 점에 대해서 작업해보겠다.

@scale이 chv에 의해서 조절되도록 해주었다. 이렇게 x,y,z 모든 방향에 대해서 각각 사이즈를 조절할 수 있게 되었다.

 

@scale을 Merge 아래에서 조절해주도록 하겠다. 세 Box가 모두 같은 크기로 조절된다.

이때 만약 점들이 가지고 모든 @scale 값이 점들마다 다르면, 서로 다른 크기의 Box가 생성될 것이다.

먼저 기준이 되는 @scale 값을 지정해준다.

이제 base_size를 기준으로 하되 랜덤한 결과를 얻고 싶다. 랜덤한 값을 생성해 @scale에 더해주도록 하겠다.

set()을 이용해서 바로 rand function을 이용해주겠다. x,y,z에 각각 다른 random한 seed를 넣어준다.

그런데 지금까지 만든 random 값들은 0~1 사이의 값으로 너무 큰 느낌이 있어 추가적으로 조절해주도록 하겠다.

x,y,z 값의 폭이 다 다르게 조절되었으면 한다.

rand 값에 곱해줄 vector 값을 생성해준다. chv로 vector 값을 만들어 쉽게 조절해주도록 하겠다.

방금 만든 vector 값을 각각의 rand function 뒤에 multiply 해준다. 이때 x 값에는 rand_mult.x, y 값에는 rand_mult.y와 같은 방식으로 곱해주도록 한다.

 

이제 Box에 색을 주기 위해서 Attribute Vop으로 작업해주겠다.

이번에도 Random을 이용하기 위해서 @ptnum을 사용할 예정이다. @ptnum은 integer 정보이기에 그대로 사용하면 Random 값 또한 integer 값으로 인식된다. Integer to Float node로 @ptnum을 float 정보로 변경해준다.

f@ptnum을 Random node에 연결해준다.

이제 만들어진 Random 정보를 Vop Output의 Cd에 넣어준다.

Random 값을 그때 그때 바꾸어 색을 변환하기 위해서 Seed 값을 달아준다. f@ptnum에 Parameter node를 더해준다. 해당 Parameter를 Seed라고 명명해준다.

결과를 보면 Random한 색이 들어온 것을 볼 수 있다.

 

이렇게 여러 Box를 만들었다면 이후에 각각의 Box 하나씩 효과가 적용되어야 할 것이다. 그런데 지금 상태에서는 Houdini에서 세 개의 Box를 세 개로 나뉘어 있다고 인식하지 않는다.

우리는 의도를 가지고 있기에 해당 결과가 3개라는 것을 인식하고 있을 뿐이다. Node Info를 보면 후디니는 해당 결과를 Points 24개, Primtives 18개로 인식하고 있다. 그래서 지금 바로 For-each Primitives를 쓴다면, 각각의 Box가 아닌 각각의 점이나 면에 대해서 작업을 해주게 될 것이다.

 

이러한 문제는 Copy to Points에 들어가기전 Box를 Pack해줌으로써 쉽게 해결해줄 수 있다.

Copy to Points의 Node Info를 보면, 3개의 Points와 Packed Geo로 구성되어 있는 것을 볼 수 있다.

만약 작업을 해주고 싶다면 이후에 Unpack으로 풀어줄 수 있을 것이다.

 

이제 위쪽의 Points의 규칙을 바꿔주도록 하겠다.

점들을 각각 만들지 않고 Copy with Stamp를 통해 점 하나를 복사해 갯수를 쉽게 늘려주도록 하겠다.

Translate의 x 값에 1.1을 넣어 1.1 간격으로 복사되도록 해주겠다.

 

결과를 보면 Size와 Color가 다양한 기본 Box가 준비된 것을 볼 수 있다.

 

 


2. Polybevel로 면, 형태 다듬기

 

다음 내용으로 넘어가보겠다.

앞에서 만든 내용을 복사해 multi_plank에 붙여 넣어준다. 그리고 아래에 For-each Primitives를 달아 준다.

다시 single_plank Geometry로 돌아와, Blast로 0번의 Primitive를 떼어내 가볍게 작업해주도록 하겠다.

점, 선, 면 작업을 해주기 위해서 Unpack으로 압축을 풀어주겠다.

 

이제 Divide로 면을 새롭게 나눠주려한다. 지금까지는 면을 새롭게 나눌 때 Remesh를 사용했었다.

Divide와 Remesh는 느낌의 차이가 있다. Divide에선 Minimum Edge에 의해 면이 나누어지게 된다. 값을 4로 두겠다.

Bricker Polygons의 size를 보면 {1,1,1} 간격으로 면이 나뉜다고 보면 된다. Copy Parameter로 x,y,z 값을 연결해주어 면을 균일하게 나누어주도록 하겠다. 

multi_plank에 붙여넣어 결과를 보면, Random한 Box들에 대해서 동일한 효과가 잘 적용된 것을 볼 수 있다.

 

상자의 각이 너무 명확한게 아쉬운 관계로 Polybevel로 모양을 바꾸어주려한다.

Polybevel의 Distance 값을 조절하면 모양이 바뀌는 것을 볼 수 있다. 이때 Distance 값이 pscale에 따라 바뀌도록 해주려한다.

Attribute Randomize를 divide 아래에 연결해 각각의 point들이 Random한 pscale을 가질 수 있도록 해주겠다. Dimensions는 1로 해준다.

방금 구한 값을 polybevel에 넣어준다면, Distance 값을 올려줄 때 움직이는 모양이 바뀌게 될 것이다. No Scale을 Scale by Attribute로 전환해준다. Point Offset Scale에 Pscale을 입력해준다. 이제 Distance 값을 올리면, vertices마다 Bevel의 효과가 들어가는 속도가 다른 것을 볼 수 있다.

 

앞의 결과에서 vertices마다의 속도차가 너무 크기 때문에 비교를 위해 Attribute Noise를 생성해 대조군을 만들어주겠다.

float 정보의 pscale에 Noise가 들어가도록 해준다.

Polybevel의 Input1에 연결해 Distance 값을 올려주면, 전반적으로 균일하게 효과가 들어가는 것을 볼 수 있다.

 

이제 Randomize 효과와 Noise 효과의 중간쯤의 효과를 원한다.

Blend Shapes를 생성해 Input1에는 Attributes Randomize, Input2에는 Attribute Noise를 연결해주겠다.

이때 Blend Shapes에서의 Attributes란을 수정해 모든 Attributes에 대해 섞어주는 것이 아닌, 오직 pscale 값만을 섞어주도록 해준다.

그리고 Blend Shapes를 Polybevel에 연결해준다. 이때 효과가 들어가지 않았다면, Blend Shapes의 blend1의 값을 높여주도록 하자. Input1에 얼마만큼 Input2에서의 효과가 들어갈지를 정해주는 파라미터이다.

 

multi_plank에 붙여넣어주면, Random하게 Box의 모양들이 변한 것을 볼 수 있다.

 

 


3. Voronoi Fracture, Assemble, Point Jitter로 조각 내기

 

이제 나무같은 모양으로 조각을 내주려한다.

Box를 쪼개기 위해서 Voronoi Fracture를 이용해주겠다.

Voronoi Fracture는 점을 기준으로 물체를 쪼개주는 node이다. 그래서 자르는 기준이 될 점들이 필요하다.

first_shape에서 Scatter로 점 2개를 뿌려보겠다. first_shape에서의 결과를 점 2개를 기준으로 나누게 될 것이다.

Voronoi Fracture의 Input1에는 쪼개고 싶은 물체를 넣고, Input2에는 기준이 될 Points를 넣어주면 된다.

중간을 관통하는 대각선의 선이 하나 생긴 것을 볼 수 있다.

Explode View로 확인해보면 해당 선으로 물체가 나뉘어진 것을 볼 수 있다.

 

이때 Scatter의 값이 커진다면, 그 만큼의 Points를 기준으로 더 많이 Object가 쪼개지게 된다.

하지만 지금과 같은 느낌은 나무 표면 같은 느낌의 쪼개짐이 아니다. 위 아래로 길쭉하게 쪼개진 결과를 원한다.

 

방금 만든 Vornoi Fracture를 지워주고 새롭게 node를 쌓아보겠다.

표면 이외에도 점을 만들기 위해서 IsoOffset으로 Volume으로 만들어 Scatter로 점을 뿌려준다. 이 때 범위 밖에 점이 생기는 것을 방지하기 위해 div size는 늘려주어야 한다.

그리고 해당 Points를 Voronoi Fracture에 연결해준다.

여기서 Transform으로 해당 결과를 늘려준다면 어떻게 될까? z축 방향으로 늘려줌에 의해 길쭉하게 쪼개진 것처럼 보이는 느낌이 든다.

하지만 이 상태로는 z축의 길이가 너무 길어져 원하는 느낌이 아니다. 하지만 뉘앙스는 같으니 조금의 수정으로 원하는 결과를 내보겠다.

 

IsoOffset 이전에 Transform node를 달아 먼저 길이를 확 줄여주도록 하겠다.

그 다음 IsoOffset과 Scatter로 점을 나누어준다.

Voronoi Fracture의 Input1에는 Transform에 의해 줄어든 Object를, Input2에는 새롭게 구해준 Points들을 넣어준다.

이렇게 짧게 조각난 Object들을 다시 Transform으로 원래의 길이로 늘려준다.

앞에서 얻었던 길쭉하게 쪼개진 결과를 원래의 사이즈로 얻게 되었다.

쪼개진 효과의 길이를 쉽게 조절해주기 위해서 길이 조절에 쓰인 Transform에서의 z값들을 Copy Parameter로 연결해준다. 이때 아래에 달았던 Transform에서는 역수로 Copy Parameter가 쓰이게 된다. ex) 1/Paste Relative References

굉장히 중요한 효과이니 반드시 기억해두도록 하자.

 

이제 하고 싶은 것은 두 가지이다. 각각의 조각들 중에서 몇몇 녀석들을 Random하게 지우는 것이고, 나머지 하나는 각각의 조각들을 조금씩 비틀어서 나무 느낌을 내주는 것이다.

앞에서의 Voronoi Fracture에 의해 조각에 대한 Attributes가 생성되긴 했지만, 조각별로 나누어 보는게 쉽지는 않다.

만약 각각의 조각을 하나의 Primitive, Point처럼 다룰 수 있다면 더 편할 것이다. 이에 조각별로 Packing 해주려한다.

우리가 Scatter에서 40개의 points를 썼기 때문에, 40개의 조각이 생겼을 것이고 40개의 Packed Geo가 생성될 것이다.

이 작업을 위해 Assemble node를 이용해주겠다.

Assemble node의 Create Packed Primitives를 체크해준다면, 각각의 조각들이 Packing될 것이다.

이렇게 각각의 조각이 Packing될 수 있었던 이유는 Voronoi Fracture에 의해 조각에 대한 이름 Attributes가 생성되었고, 그 내용을 바탕으로 Assemble이 하나의 조각으로 인식하여 Packing하는 과정을 거쳤기 때문이다.

 

쪼개주는 효과를 간단하게 Point Jitter node로 해결해주겠다.

Scale 값을 높여주면 뒤틀리면서 뿌러지는 듯한 효과를 볼 수 있다.

Axis Scale 값을 조절해 x,y,z 축 각각 어느정도의 세기가 적용될지를 정해줄 수 있다.

 

이제 removepoint function으로 Packed된 조각들을 랜덤하게 지워주도록 하겠다.

If문으로 Random한 값이 limit이라는 float 값을 초과할 경우 초과하는 값을 가진 모든 points가 지워지도록 해주었다.

 

해당 결과를 multi_plank에 붙여넣어주면, 모든 Box에 쪼개진 효과가 잘 들어간 것을 볼 수 있다.

그런데 여기서 아쉬운 점이 있다면, 전부 비슷한 부분의 조각이 사라진 것처럼 묘사되었다.

그 이유는 Voronoi Fracture로 면을 쪼개기 전 Scatter의 내용이 전부 똑같게 적용되었기 때문이다.

 

이를 위해서 Metadata를 이용해 Scatter의 Seed 값이 매번 다른 값이 되도록 해주겠다. Metadata가 Detail에 몇번째 싸이클인지에 대한 Iteration 정보를 저장하고 있기 때문이다.

Scatter의 Global Seed에 detail function으로 Metadata에서의 Iteration 정보를 가져오도록 하겠다.

이렇게 Voronoi Fracture에 필요한 점의 위치가 Metadata에 의해 계속 바뀌게 되었다.

 

 


4. Remesh to Grid, Displace Along Normal, Veins로 질감 내기

 

본격적으로 해당 결과에 나무 질감을 표현해주려 한다.

지금 당장은 Packing에 의해 표면에 대한 작업이 가능한 상황이 아니기에 먼저 Unpack 해주도록 한다.

이제 조각조각나 있는 면을 전반적으로 통합시켜주려 한다. 지금 상태는 면이 씹혀있고, 분할되어 있다. 겹친부분은 사라졌으면 하고, 내부는 텅 비어 표면 정보만 얻기를 원하다.

지금까지 배웠던 내용에서는 VDB from Polygons로 변환한 뒤, Convert VDB로 다시 Polygons로 변환하는 과정을 주로 이용했었다. 하지만 이러한 과정은 계산 과정이 오래 걸리기에 굳이 Volume에 대한 정보를 이용할 때가 아니면 이용할 필요가 없다.

새롭게 Remesh to Grid node를 이용해주겠다. 해당 node의 파라미터는 앞선 VDB from Polygons, Convert VDB에서와 유사한 내용으로 구성되어있다.

Division Size로 해상도를 조절해주고, Offset값으로 Isovalue 값을 조절해준다.

결과를 보면 안이 텅 비어있고 면들이 잘 연결된 것을 볼 수 있다.

 

표면에 세로의  나무 껍질 느낌을 줄 차례이다.

Attribute Vop을 생성해 내부에서 작업해주도록 하겠다.

새롭게 Displace Along Normal을 생성해준다. Input을 보면 Position과 Normal 정보가 있는 것을 볼 수 있다.

파라미터의 Displace Amount 값을 키워준다면 @P + @N*mult에서와 같은 효과를 보게 된다.

 

이제 해당 Object의 Points가 일부 부분에서만 Normal 방향으로 커지기를 원한다.

이를 위해서 Noise 정보를 Amount에 달아주겠다. Turbulent Noise를 이용할 수도 있지만, 나무와 같이 길쭉한 느낌의 질감을 만들기 위해서 새롭게 Veins node를 이용해주겠다.

1. Vein Direction에서는 Noise가 들어갈 각도를 조절해줄 수 있다.

2. Vein Spacing에서는 0과 1로 묘사된 Noise 값들의 간격을 조절해줄 수 있다.

3. Vein Attenuation에서는 값을 줄인다면 Noise 값들이 점점 전부 1로 묘사되게 될 것이다. 하지만 값을 올린다면 Noise 값들이 0으로 묘사되는 부분이 늘어나게 된다.

4. Vein Frequency의 경우는 Noise Amplitude가 들어오지 않았을 때는 Vein Spacing과 그 결과가 유사하다. 하지만 Noise Amplitude 값이 커짐에 따라 Noise가 들어가는 세기에서 차이가 나게 된다. 그 뉘앙스를 잘 파악해 둘 중 적절한 것을 사용하도록 하자.

5. Noise Amplitude 값을 조절해 Noise의 세기를 조절할 수 있다. 0에 가까워질수록 우리가 원했던 세로로 길쭉한 Noise를 얻어 나무 질감을 표현해낼 수 있다.

결과를 보면 값이 1인 부분은 튀어나오고 0인 부분은 들어간 것을 볼 수 있다.

 

Attribute Blur로 부드럽게 해주고 Normal node를 달아 좀 더 울퉁불퉁하게 해준 뒤, Packing으로 마무리해준다.

 

 


5. Simulation을 위한 준비(Bouding Box 맞추기)

 

마지막으로 이후 Simulation에서도 Plank system을 다룰 것이기에, 좀 더 손봐 줄 부분이 남아있다.

Simulation에서 혹시라도 문제가 생길 부분을 예방하기 위해서, Copy to Points로 처음에 제공했던 Box와 마지막 결과의 Bouding Box의 크기를 맞춰주려한다.

두 Object의 Bounding Box의 크기 차이를 보면 마지막 결과의 Bounding Box가 약간 큰 것을 볼 수 있다. 둘의 사이즈가 완벽하게 동일했으면 한다.

 

우리가 마지막으로 만든 결과에서의 크기를 바꾸기 위해 비율에 손을 대보려 한다. 그런데 Geometry Spreadsheet을 확인해보면 해당 결과는 정확히 중간에 있는 것이 아닌 것을 알 수 있다.

중간에 있는 것이 아니기에 비율에 손을 대기가 애매하다. 일단은 둘의 중심점을 {0,0,0}으로 같게 만들어준다.

 

이제 비율을 구해주려한다. 비율을 구하기 위해서 두 결과를 하나의 Attributes Wrangle에 연결해준다.

이 둘은 {0,0,0}에 중심이 똑같이 위치하기에 단 하나의 점만으로도 비율을 구해줄 수 있다.

레퍼런스의 위치에서 Input1의 위치를 나누어주면, vector 값에 대한 비율이 나오게 된다.

point function으로 Input2에서의 모든 점에 대한 P정보를 불러온다.

그 다음 @scale의 값이 레퍼런스의 점에서 Input1에서의 점의 값으로 나눈 값이 되게 한다. @scale의 값이 비율이 된다.

 

Add로 처음의 Box 결과를 점으로 만든 뒤, Copy to Points를 생성해 마지막 결과를 붙여줄 점으로써 활용해주겠다.

Attribute Copy를 생성해 Add에서의 점의 정보를 Input1에 연결해준다. 그리고 Input2에 방금 구한 비율의 값(@scale)을 넣어준다. Attribute Name에 scale을 적어줌으로써 Input2에서의 @scale 정보를 불러올 수 있다.

 

이제 Copy to Points의 결과를 보면 Bounding Box에서의 결과와 사이즈 차이가 없는 것을 볼 수있다.

 

끝으로 {0,0,0}으로 만들어두었던 위치를 원래의 위치로 되돌려주려한다.

@P의 정보를 {0,0,0}으로 변환시키기 전, v@restpos에 저장해주도록 하겠다.

그리고 마지막에 {0,0,0}인 @P의 정보를 v@restpos로 변환해 원래의 위치 정보를 되돌려준다.

 

지금까지의 내용을 multi_plank에 붙여넣어주면 Plank 시스템이 완성된다.