중요했던 부분:
- Day 6때 배웠던 point/vertex/primitive 복습
point (점) - 3D공간을 구성하기 위한 가장 기본이 되는 요소
vertex (배열) - 프리미티브를 만들때 포인트의 순서/배열을 구성하는 요소
primitive (선/면) - vertex의 배열에 따라 만들어진 선 혹은 면
vertex의 원리
우리가 인식하는 원리 | 후디니에서 Geometry spreadsheet상에서 나타내는 방법 |
0번 primitive - 첫번째 요소 | [0:0] 0 |
0번 primitive - 두번째 요소 | [0:0] 1 |
0번 primitive - 세번째 요소 | [0:0] 2 |
이때 아래의 다이어그램에서 빨간색으로 적힌 부분이 primitive number이고 파란색으로 적힌 부분이 point number이라고 했을때 vertex geometry spreadsheet에서는 이와같이 나타낼 수 있다.
[0:0] 0 | 0번 프리미티브를 구성하는 첫번째 요소는 0번 포인트이다 |
[0:1] 1 | 0번 프리미티브를 구성하는 두번째 요소는 1번 포인트이다 |
[1:0] 1 | 1번 프리미티브를 구성하는 첫번째 요소는 1번 포인트이다 |
[1:1] 2 | 1번 프리미티브를 구성하는 두번째 요소는 2번 포인트이다 |
또한 이와 같이 프리미티브는 만에하나 꺾여있어도 하나의 프리미티브로써 유지될 수 있다.
[0:0] 0 | 0번 프리미티브를 구성하는 첫번째 요소는 0번 포인트이다 |
[0:1] 1 | 0번 프리미티브를 구성하는 두번째 요소는 1번 포인트이다 |
[0:2] 2 | 0번 프리미티브를 구성하는 세번째 요소는 2번 포인트이다 |
- Add (Polygons -> By Patterns)
지금까지 polygons -> by group으로 선을 자동으로 만들어주었던 것과 대조되게 by patterns에서는 유저가 어떤 배열로 선이 이어질지 직접 vertex의 구성을 세팅해 줄 수 있다.
만약 이와 같은 geometry를 구성해주고 싶다면 우선 add노드로 포인트들 세 개 생성시켜 준다음 merge로 이어 한번에 보이게 만든다음 다시 add노드를 연결해 vertex를 구성하여 primitive를 형성하게끔 만들 수 있다.
또한 윗 사진의 Number of Primitives로 생성되는 프리미티브의 갯수를 조절 시킬 수 있다.
아래 있는 closed는 눌러서 작동위 되기 위해 오직 하나의 프리미티브에 대해서만 요구를 한다. 즉 위의 삼각형을 닫히게 하려면 0 1 2 와 같이 세개의 포인트들을 담고 있는 하나의 프리미티브를 형성해 면으로 닫히게끔 할 수 있다.
즉 add노드는 다음에 배울 addpoint(), addprim(), addvertex()와 같은 function들의 기능들을 이미 이 노드가 처리해 줌을 알 수 있다.
- addpoint(): Addpoint Function
addpoint()는 포인트를 생성해주는 function이다. 이때 run over가 point라면 모든 포인트들의 대해서 포인트를 새롭게 형성시켜주므로 기존에 있던 포인트들의 갯수와 동일하게 생성되는 것을 볼 수 있다. 이때 기존에 있던 포인트가 없다면 wrangle을 Detail (Only Once)로 설정해주어야 작동한다. 이때 특이한 사실은 addpoint()는 어떠한 variable이나 attribute에 저장해주지 않아도 작동되는 것을 볼 수 있다. 본래 저장하려면 type casting을 integer로 설정해주어야 햔다.
addpoint()에 들어가는 인풋 정보들은 geohandle인 0과 생성하려는 vector point위치 혹은 그 정보를 담고있는 variable을 집어넣어주면 된다.
eg) int a = addpoint (0, {0, 0, 0}); // 위치가 {0, 0, 0}인 곳에 포인트를 생성하여라. 그리고 그 값은 integer variable a에 저장하여라.
eg) vector pos = {0, 0, 0}; // 값이 0, 0, 0인 수치를 vector variable pos에 저장하여라
int a = addpoint (0, pos); // 방금 전 생성된 vector variable pos의 위치에 포인트를 생성하여라
- removepoint(): Removepoint Function
removepoint()는 반대로 포인트를 지워주는 function이다. removepoint()의 특이한 사실은 어떠한 variable이나 attribute에 값을 저장해 줄 수 없다. 오직 function 그자체로만 작동되기 때문이다.
removepoint()에 들어가는 인풋 정보들은 geohandle인 0과 생성하려는 지우려는 포인트 넘버 혹은 그 정보를 담고있는 variable을 집어넣어주면 된다.
eg) removepoint (0, 2); // geometry에서 2번 포인트를 지워주어라
eg) int pt = 10; // 값이 10인 값을 integer variable pt에 저장하여라
removepoint (0, pt); // 방금 전 생성된 integer variable pt의 포인트 넘버 값을 가진 포인트를 지워주어라
eg) int p0 = addpoint (0, {1, 0, 0}); // 위치가 {1, 0, 0}인 곳에 포인트를 하나 생성하고 그 값을 integer variable p0에 저장하여라
removepoint (0, p0); // 방금전 생성된 variable p0에 해당하는 포인트를 지워주어라
이때 removepoint()에서 또 응용할 점은 grid에서 removepoint()를 사용하여 특정 포인트 넘버를 지워줄시 이렇게 되는 것을 알 수 있다.
removepoint (0, 3); // 3번 포인트를 지워주어라
- addprim(): Addprimitive Function
addprim()은 프리미티브를 생성해주는 function이다. 이 function은 vertex의 식 없이 온전히 작동되지 않으며 만드려는 프리미티브가 면인지 선인지 결정할 수 있다. 본래 저장하려면 type casting을 integer로 설정해주어야 햔다.
addprim()에 들어가는 인풋 정보들은 geohandle인 0과 poly 아니면 polyline을 따옴표 사이 써넣어야 한다. poly는 면을 만들때 사용되는 명령이고 polyline은 선을 만들때 사용되는 명령이다.
eg) int prim0 = addprim (0, "poly"); // 면으로 이루어진 프리미티브를 vertex의 순서로 이루어진 포인트들을 조합하여 만들어라. 그리고 그 값을 integer variable prim0에 저장하여라.
eg) int prim1 = addprim (0, "polyline"); // 선으로 이루어진 프리미티브를 vertex의 순서로 이루어진 포인트들을 조합하여 만들어라. 그리고 그 값을 integer variable prim1에 저장하여라.
- removeprim(): Removeprimitive Function
Removeprim()은 아까 배웠던 removepoint()와 마찬가지로 특정 포인트넘버를 지정하여 그 부분에 해당하는 primitive를 지워줄 수 있다 이때 지울때 프리미티브만 지워줄지 아니면 프리미티브를 구성하는 모든 포인트까지 지워줄지 지정할 수 있다.
removepoint()에 들어가는 인풋 정보들은 geohandle인 0과 생성하려는 지우려는 포인트 넘버 혹은 그 정보를 담고있는 variable을 집어넣어주면 된다. 그리고 0이나 1을 써 넣어 프리미티브만 지워줄지 아니면 프리미티브를 구성하는 모든 포인트까지 지워줄지 지정할 수 있다. 0은 프리미티브만 지워주고 1은 모든 포인트까지 다 지워주는 역할을 한다.
removeprim (0, 0, 0); // 0번 포인트에 있는 프리미티브를 이루는 포인트들은 남겨둔채 지워주어라
removeprim (0, 0, 1); // 0번 포인트에 있는 프리미티브와 이루는 포인트들까지 지워주어라
- addvertex(): Addvertex Function
addvetex()는 프리미티브를 생성할때 포인트들의 배열을 정해주는 function이다. 이 function을 적음으로써 온전하게 면이나 선의 형태가 나타나고 이도 본래 저장하려면 type casting을 integer로 설정해주어야 햔다.
addvertex()에 들어가는 인풋 정보들은 geohandle인 0과 만드려는 primitive variable이름 그리고 구성되는 point variable이름을 쓰면된다. 자세한건 윗 테이블을 참조하면 된다. 이때 몇번째 요소인지 구분하는 방법은 위에서 부터 아래로의 순서로 구성된다.
eg) int v00 = addvertex (0, prim0, p0); // prim0 (0번 프리미티브)를 만들기위해 p0 (0번 포인트)를 첫번째요소로써 구성하여라. 그리고 그 값을 integer variable v00에 저장하여라
int v01 = addvertex (0, prim0, p1); // prim0 (0번 프리미티브)를 만들기위해 p1 (1번 포인트)를 두번째요소로써 구성하여라그리고 그 값을 integer variable v01에 저장하여라
- 윗 function들을 이용한 코드
아래와 같은 식들은 위에서 배운 function들을 활용하여 알맞은 geometry를 코드로써 만들어주는 방식이다.
/* wrangle에 연결된 geometry가 하나도 없어 기존에 있는 포인트가 없다면 run over를 detail (only once)로
설정해주어야 작동된다*/
// 아래에 해당되는 vector값을 가진 포인트들을 알맞은 위치에 생성하고 그 수치들을 variable들에 저장한다
int p0 = addpoint (0, {0, 0, 0});
int p1 = addpoint (0, {2, 0, 0});
int p2 = addpoint (0, {2, 0, -2});
// 포인트들로 이루어진 프리미티브를 생성하기 위해 면으로써 구성하고 그 값을 integer variable prim0에 저장
int prim0 = addprim (0, "poly");
// 윗 prim0이라는 프리미티브를 면으로 생성해주기 위해 구성되는 포인트의 배열순서에 따라 정해진다
int v00 = addvertex (0, prim0, p0);
int v01 = addvertex (0, prim0, p2);
int v02 = addvertex (0, prim0, p1);
/* wrangle에 연결된 geometry가 하나도 없어 기존에 있는 포인트가 없다면 run over를 detail (only once)로
설정해주어야 작동된다*/
// 아래에 해당되는 vector값을 각기 알맞은 variable들에 저장한다
vector a = {1, 0, 0};
vector b = {1, 0, 1};
vector c = {2, 0, 0};
// 위에서 생성된 vector값을 가진 포인트들을 알맞은 위치에 생성하고 그 값들을 또 알맞은 variable에 저장한다
int p0 = addpoint (0, a);
int p1 = addpoint (0, b);
int p2 = addpoint (0, c);
// 포인트들로 이루어진 프리미티브를 생성하기 위해 면과 선으로써 구성하고 그 값을 알맞은 variabled에 저장
int prim0 = addprim (0, "polyline"); // 선
int prim1 = addprim (0, "polyline"); // 선
int prim2 = addprim (0, "poly"); // 면
//각기 만들어진 vertex값들은 각기 또 알맞은 variable에 저장된다.
// prim0이라는 선으로써의 프리미티브를 만들기위해 p0과 p1을 순서대로 잇는다
int v00 = addvertex (0, prim0, p0);
int v01 = addvertex (0, prim0, p1);
// prim1 이라는 선으로써의 프리미티브를 만들기위해 p0과 p2을 순서대로 잇는다
int v10 = addvertex (0, prim1, p0);
int v11 = addvertex (0, prim1, p2);
// prim2 이라는 면으로써의 프리미티브를 만들기위해 p0과 p2와 p1을 순서대로 잇는다
int v20 = addvertex (0, prim2, p0);
int v21 = addvertex (0, prim2, p2);
int v22 = addvertex (0, prim2, p1);
근데 만약 addvertex()를 쓰기 귀찮다? 이럴때는 이와 같은 방법으로 addprim()안에 세번째 인풋 정보부터 이을 포인트들의 포인트 넘버나 아니면 포인트 넘버나 addpoint로 생성된 포인트의 variable값을 집어넣어주면 addvertex()없이 프리미티브를 생성시킬수 있다.
/* wrangle에 연결된 geometry가 하나도 없어 기존에 있는 포인트가 없다면 run over를 detail (only once)로
설정해주어야 작동된다*/
// 아래에 해당되는 vector값을 각기 알맞은 variable들에 저장한다
vector a = {0, 0, 0};
vector b = {1, 0, 0};
vector c = {1, 0, 1};
vector d = {0, 0, 1};
// 위에서 생성된 vector값을 가진 포인트들을 알맞은 위치에 생성하고 그 값들을 또 알맞은 variable에 저장한다
int p0 = addpoint (0, a);
int p1 = addpoint (0, b);
int p2 = addpoint (0, c);
int p3 = addpoint (0, d);
// 포인트들로 이루어진 프리미티브를 생성하기 위해 면과 선으로써 구성하고 그 값을 알맞은 variables에 저장
addprim (0, "poly", p3, p1); // p3과 p1에 해당하는 포인트들을 선으로 이어주어라
- 조건문을 활용한 코드
지금까지 point wrangle노드상에서는 기존에 있던 포인트의 갯수와 동일하게 addpoint()를 사용했을때 새롭게 생성된다는 사실을 알 수 있었다. 하지만 이를 무시하고 기존에 포인트가 여러개더라도 하나의 포인트에 대해서만 새로운 포인트를 생성시킬수 있는데 이는 조건문으로 작동된다.
if (@ptnum == 0) { // 만약 @ptnum 포인트 넘버 값이 0이라면
addpoint (0, {0, 3, 0}); // 그 포인트에 대해서만 해당 vector값에 위치한 포인트를 생성한다.
}
- Advanced Coding
이와 같이 각기 새로운 방법으로 여러개의 point들을 생성시켜줄 수 있다.
// geometry의 모든 포인트의 대해서 y값이 1씩 올라간 vector variable k위치값에
vector k = @P + {0, 1, 0};
addpoint (0, k); // 기존포인트와 동일한 갯수의 새로운 포인트들을 생성시켜주어라
// geometry의 모든 포인트에 대해서 normal값의 방향으로 떨어진 수치를 vector variable k에 저장한다
// 이때 chf()를 @N에 곱하여 얼마나 @N값이 센지 유저가 파라미터로 조절할 수 있게하여라
vector k = @P + @N*chf ("HOWMUCH");
addpoint (0, k); // 떨어진 값에 모든 포인트에 대해서 동일한 갯수의 새로운 포인트를 생성하여 버려라 제발
/* 모든 포인트에 대해서 입력된 Vector값에 해당하는 위치에 포인트를 생성해주어라. 그리고 그 값을 integer variable
pt에 저장하여라*/
int pt = addpoint (0, {0, 3, 0});
// 그리고 각기 해당되는 @ptnum 포인트 넘버값과 아까 생성해준 포인트들을 서로 각각 연결하여 선으로 프리미티브를 형성하여라
addprim (0, "polyline", @ptnum, pt);
// 모든 포지션 값에서 노멀의 방향만큼인데 0.1간격만 떨어진 값을 vector variable pos로 저장하여라
vector pos = @P + @N*0.1;
// 위에서 생성한 vector값의 위치를 가진 위치에 새로운 포인트들을 모든 포인트들에 대해 생성하여라
int pt = addpoint (0, pos);
// 각기 모든 포인트 넘버에 해당하는 포인트들로부터 각기 위에 생성된 모든 포인트들까지 선으로 이어버려 프리미티브를 생성
addprim (0, "polyline", @ptnum, pt);
위에서 생성된 가시들을 막 살랑살랑 흔들리게 만들기 위해선 다음과 같은 코드 작성을 필요로한다.
/* geometry의 모든 포인트의 위치에 noise()가 적용된 값 안에 @Time이 더해져 offset을 더해져 프레임이 흐를수록
모션이 더해지게끔 만든다.*/
vector NN = noise (@P + @Time);
/* 근데 털의 방향이 한곳으로 쏠려있는 것을 알 수 있다. 이를 방지하기 위해 기존에 noise()파형이 0에서 1까지의
range값으로 설정되어있었는데 이를 -0.5와 0.5사이로 조정해주어 world상에서 중심에 위치하게끔 설정하였다*/
NN = fit (NN, 0, 1, -0.5, 0.5);
NN = NN*0.3; // 입력된 파형에 0.3이라는 상수를 곱해주어 amp값을 정해준다. 이는 파형의 높이값을 나타낸다.
/* 그리고 normal값의 방향 크기가 정해진 @N값에 방금 만들어준 noise파형을 더해 geometry의 표면의 방향을 따라
위치값이 정해지게 한다. 그리고 정해진 값을 vector variable pos에 저장하여라. 이 noise파형은 여기서
모션값으로 지정되어 noise()로 생성된 파형에 따라 위치값들이 마구 흔들리게 만들어 준다.*/
vector pos = @N*0.2 + NN;
/* 위에 생성된 위치값에 geometry의 모든 포인트로부터 pos의 방향만큼 떨어진
곳에 포인트들 전부 생성해준다*/
int pt = addpoint (0, @P+pos);
// geometry의 모든 포인트에 대해 위에 만들어진 포인트들끼리 각기 연결되어 선으로써 프리미티브가 형성되게하여라
addprim (0, "polyline", @ptnum, pt);
- 반복문을 활용한 코드
조건문을 이용해서 기존에 여러 포인트가 있었을때 오직 하나에만 새로운 포인트를 생성할 수 있었다. 반대로 반복문을 활용하면 기존에 포인트가 하나만 있었을때 그 포인트에 대해서 여러개의 새로운 포인트를 생성할 수 있다.
// 기존의 normal값이 아닌 x값이 1인 방향이고 나머지는 0인 방향으로 @N normal값을 지정한다
@N = {1, 0, 0};
for (int i = 0; i < 10; i++) { // i가 0에서부터 10가지 1씩 늘어나는 동안
// 위에서 정한 normal값의 방향대로 10에 오기 전까지지만 0.1을 또 곱하여 10분의 1간격으로
vector k = @P + @N*i*0.1;
addpoint (0, k); // 한 포인트에 대해 새로운 점들을 모두 생성해주어라
}
for (int i = 0; i < 10; i++) { // i가 0에서부터 10가지 1씩 늘어나는 동안
// normal값의 방향대로 10에 오기 전까지지만 0.1을 또 곱하여 10분의 1간격으로
vector k = @P + @N*i*0.1;
addpoint (0, k); // 한 포인트에 대해 새로운 점들을 모두 생성해주어라
}
반복문을 이러한 형식으로 활용하면 프리미티브를 생성했을때 프리미티브의 길이값도 결정해 줄 수 있다.
만일 이렇게 생성된 코드가 있다고 가정했을시 이러한 원리로 작동된다: 포인트를 만들고 vertex로 지정해주고 또 포인트를 만들고 vertex로 순서를 지정해주고 이걸 반복하여 맨 위의 선언된 프리미티브의 타입대로 올바른 프리미티브를 형성하게 된다.
// 프리미티브를 선으로써 만들겠다고 우선 먼저 선언해주자
int pr = addprim (0, "polyline");
// 아래에 해당되는 vector값을 각기 알맞은 variable들에 저장한다
vector a0 = {0, 0, 0};
vector a1 = {0, 1, 0};
vector a2 = {0, 2, 0};
/* 방금전 만들어진 식과 비슷하지만 차이점은 addpoint(), addprim(), 그리고 addvertex()가 작성되는
순서가 많이 차이가 나는 것을 볼 수 있다. 이런식으로 보면 반복문을 어떻게 활용할지 직관적으로 보이게 된다*/
// 위에서 생성된 vector값을 가진 포인트들을 알맞은 위치에 생성하고 그 값들을 또 알맞은 variable에 저장한다
int p0 = addpoint (0, a0);
//각기 만들어진 vertex값들은 각기 또 알맞은 variable에 저장된다.
int v0 = addvertex (0, pr, p0);
int p1 = addpoint (0, a1);
int v1 = addvertex (0, pr, p1);
int p2 = addpoint (0, a2);
int v2 = addvertex (0, pr, p2);
int p3 = addpoint (0, p3);
int v3 = addvertex (0, pr, p3);
방금 전 만든식을 반복문 for loop을 활용하여 이렇게 코드의 양을 확 줄여줄 수 있다.
// 프리미티브를 선으로써 만들겠다고 우선 먼저 선언해주자
int pr = addprim (0, "polyline");
for (int i = 0; i < 7; i++) { // i가 0에서부터 7까지 1씩 늘어나는 동안
// y값이 i인 모든 포인트들을 생성해준다. 그리고 그 값들을 int variable pt에 저장한다.
int pt = addpoint (0, set (0, i, 0));
// 그리고 선언된 프리미티브에 대해서 pt값끼리 연결될 수 있도록 addvertex()를 반복문안에 작성한다.
addvertex (0, pr, pt);
}
// 아래에서 활용할 variable 변수값을 모두 선언해준다.
vector offset, pos;
int pr, pt;
float stepsize;
// 프리미티브를 선으로써 만들겠다고 우선 먼저 선언해주자
pr = addprim (0, "polyline");
stepsize = 0.5; // 이 stepsize는 프리미티브 선이 꺾어질때 간격의 사이즈를 나타낸다
for (int i = 0; i < 6; i++) { // i가 0에서부터 6까지 1씩 늘어나는 동안
/* geometry의 모든 포인트의 위치에 noise()가 적용된 값 안에 @Time이 빼져 offset을 빼져
프레임이 흐를수록 모션이 더해지게끔 만든다. 그리고 i를 더해 반복문의 횟수가 반복이 될수록
offset이 업데이트되게 해준다. 그리고 0.2를 전체에 곱해 amp값을 줄여 range 파형의 높이
간격을 줄여준다*/
offset = curlnoise (@P - @Time + i)*0.2;
/* 모든 포인트에 대해 normal의 방향대로 위치값이 지정되고 이는 반복문대로 0에서 6이 될때까지 모든 위치값들이
생성되어지고 offset을 더해주어 noise()파형을 적용시켜 약간의 랜덤한 값을 갖게 하여 vector variable pos에
저장한다*/
pos = @P + @N*i*stepsize+offset;
pt = addpoint (0, pos); // 위에서 선언된 pos값의 위치에 모든 새로운 점들을 생성시켜주어라
addvertex (0, pr, pt); // 위에서 만들어진 모든 새로운 점들을 primitive 선으로 이어주어 만들어주어라
}
이를 다른 geometry인 pighead에 똑같이 적용하면 이러한 쉐입을 띄는 것을 확인 할 수 있다.
// 아래에서 활용할 variable 변수값을 모두 선언해준다.
vector offset, pos;
int pr, pt;
float stepsize;
// 프리미티브를 선으로써 만들겠다고 우선 먼저 선언해주자
pr = addprim (0, "polyline");
stepsize = 0.02; // 이 stepsize는 프리미티브 선이 꺾어질때 간격의 사이즈를 나타낸다
for (int i = 0; i < 12; i++) { // i가 0에서부터 12까지 1씩 늘어나는 동안
/* geometry의 모든 포인트의 위치에 noise()가 적용된 값 안에 @Time이 빼져 offset을 빼져
프레임이 흐를수록 모션이 더해지게끔 만든다. 여기서 @P값에 1.3이라는 상수값을 곱하여 frequenct를
조절하여주기도 하였다. 그리고 i를 더해 반복문의 횟수가 반복이 될수록
offset이 업데이트되게 해준다. 그리고 0.02를 전체에 곱해 amp값을 줄여 range 파형의 높이
간격을 줄여준다*/
offset = curlnoise (@P*1.3 - @Time + i)*0.02;
/* 모든 포인트에 대해 normal의 방향대로 위치값이 지정되고 이는 반복문대로 0에서 6이 될때까지 모든 위치값들이
생성되어지고 offset을 더해주어 noise()파형을 적용시켜 약간의 랜덤한 값을 갖게 하여 vector variable pos에
저장한다*/
pos = @P + @N*i*stepsize+offset;
pt = addpoint (0, pos); // 위에서 선언된 pos값의 위치에 모든 새로운 점들을 생성시켜주어라
addvertex (0, pr, pt); // 위에서 만들어진 모든 새로운 점들을 primitive 선으로 이어주어 만들어주어라
}
- removepoint()를 이용한 애니메이션
이와 같이 @primnum값에 rand()를 활용하여 조건문을 통해 랜덤하게 프리미티브가 일정한 횟수로 지워지는 시간이 따라 지워지는 것을 만들어 줄 수 있다. 이때 rand()에는 두 번째 인풋 정보로써 Seed값을 조절 할 수 있게 해준다.
// 만약 랜덤으로 지정된 @primnum 프리미티브 넘버 값이 chf()으로 만들어진 cutoff parameter 수치보다 작다면
if (rand (@primnum, chf ("SEED")) < chf ("CUTOFF")) {
// 해당된 프리미티브 넘버에 해당되는 프리미티브는 이루는 포인트까지 포함해서 전부 지워주어라
removeprim (0, @primnum, 1);
}
만일 seed값을 조절하여 다른 seed값을 가진 grid와 함께 애니메이션을 만들어준다면 아래와 같이 서로 다른 결과를 볼 수 있다.
Exercises:
1. The seaweed example above doesn't lock the roots in place, fix that. You want to multiply the offset by 0 at the start of the loop, and gradually ramp it up until it has a large effect at the end. If only there were some counter, starting from 0, that you could multiply by a small fraction, that you could use for this...
이는 noise() 파형 전체에 곱해진 amp값을 반복문안에 선언된 i 변수로 대신해줌으로써 점차적으로 점들이 위로 반복되는 횟수가 높아질수록 noise파형의 높이값들이 놓아지게끔 설정하였다. 그리고 chf()를 다시한번 더해줌으로써 얼마나 amp값이 크게 설정될지 유저가 파라미터로 설정할 수 있게끔하였다.
// 아래에서 활용할 variable 변수값을 모두 선언해준다.
vector offset, pos;
int pr, pt;
float stepsize;
// 프리미티브를 선으로써 만들겠다고 우선 먼저 선언해주자
pr = addprim (0, "polyline");
stepsize = 0.5; // 이 stepsize는 프리미티브 선이 꺾어질때 간격의 사이즈를 나타낸다
for (int i = 0; i < 6; i++) { // i가 0에서부터 6까지 1씩 늘어나는 동안
/* geometry의 모든 포인트의 위치에 noise()가 적용된 값 안에 @Time이 빼져 offset을 빼져
프레임이 흐를수록 모션이 더해지게끔 만든다. 그리고 i를 더해 반복문의 횟수가 반복이 될수록
offset이 업데이트되게 해준다. */
// 이때 amp값을 i로 설정하여 반복문이 반복될수록 amp값이 커지게끔 설정하였다. 그리고 chf()로 생성된 파라미터로써
파형의 amp값이 유동적으로 조절되게끔 설정하였다.*/
offset = curlnoise (@P - @Time + i)*i*chf ("AMP");
/* 모든 포인트에 대해 normal의 방향대로 위치값이 지정되고 이는 반복문대로 0에서 6이 될때까지 모든 위치값들이
생성되어지고 offset을 더해주어 noise()파형을 적용시켜 약간의 랜덤한 값을 갖게 하여 vector variable pos에
저장한다*/
pos = @P + @N*i*stepsize+offset;
pt = addpoint (0, pos); // 위에서 선언된 pos값의 위치에 모든 새로운 점들을 생성시켜주어라
addvertex (0, pr, pt); // 위에서 만들어진 모든 새로운 점들을 primitive 선으로 이어주어 만들어주어라
}
2. Make the seaweed move in very computery circles, offset slightly from each other (gif and answer is below, look at the gif first, try and avoid the code. Hint: You'll be moving each point's x and z position based on sin and cos...)
갑자기 cgwiki님께서 너무 어려운 문제를 내주셔서 어쩔수 없이 샘플 코드를 참조하였다... 지금 내 상황은 머리가 터지기 일부직전인데 너무 심화적인것을 주시는 것같다. 복습일기때 제대로 한번 다시한번 참조하기로 하였다.
// 아래에서 활용할 variable 변수값을 모두 선언해준다.
// spirally seaweed using sin and cos
vector offset, pos;
int pr, pt;
float stepsize;
float x, y, inc;
pr = addprim(0,'polyline');
stepsize = 0.5;
for (int i = 0; i < 6;i++) { // i가 0에서부터 6까지 1씩 늘어나는 동안
inc = @ptnum*0.3; // offset 조절 값으로 들어갈 int variable inc를 생성
x = cos(i*0.6+@Time+inc); // cos()에 각기 freq와 offset이 적용된 i값을 집어넣어 x변수에 저장
y = sin(i*0.6+@Time+inc); // sin()에 각기 freq와 offset이 적용된 i값을 집어넣어 y변수에 저장
// 모션이 x와 z방향으로 움직이도록 설정하고 root에서는 움직이지 않게끔 i로 amp를 설정
offset = set(x,0,y)*0.1*i;
/* 모든 포인트에 대해 normal의 방향대로 위치값이 지정되고 이는 반복문대로 0에서 6이 될때까지 모든 위치값들이
생성되어지고 offset을 더해주어 noise()파형을 적용시켜 약간의 랜덤한 값을 갖게 하여 vector variable pos에
저장한다*/
pos = @P + @N * i * stepsize + offset;
pt = addpoint(0,pos); // 위에서 선언된 pos값의 위치에 모든 새로운 점들을 생성시켜주어라
addvertex(0,pr,pt);// 위에서 만들어진 모든 새로운 점들을 primitive 선으로 이어주어 만들어주어라
}
3. colour the lines from root to tip somehow
밑에 wrangle노드를 하나 더 추가하여 grid의 마지막 포인트 넘버인 440보다 더 큰 포인트들은 모두 컬러값이 적용되도록 세팅해주었다.
if (@ptnum > 440) { // 만약 포인트 넘버값이 440보다 더 크면
@Cd = {1, 0, 1}; // 이의 값으로 컬러값을 지정해주어라
}
4. take the stocastic slider based prim delete example from above, change its mode to a point wrangle, and make it remove points instead.
이렇게 코딩을 하였더니 기존에 프리미티브를 지웠을때와는 다르게 마름모 형식으로 지워지는 것을 확인 할 수 있었다 또한 포인트들이 군데군데 남겨져 다없어지기 직전에는 포인트들만 앙상하게 있는 grid를 확인 할 수 있었다.
// 만약 랜덤으로 지정된 @point 포인트 넘버 값이 chf()으로 만들어진 cutoff parameter 수치보다 작다면
if (rand (@ptnum, chf ("SEED")) < chf ("CUTOFF")) {
// 해당된 포인트 넘버에 해당되는 포인트들은 전부 지워주어라
removepoint (0, @ptnum, 1);
}
5. rand is pure white-noise static, sometimes you want more structure for the delete trick. try and make the delete work based on noise. Note that noise() doesn't take a seed variable, but you'll probably want controls to scale the size of the noise, and to offset it, maybe even animate the noise over time.
rand()에서 noise()로 바꿔주기 위해 frequency값과 offset을 유동적으로 조절할 수 있게끔 코딩을 해주었다. 상기되었듯이 noise()에는Seed를 결정하는 정보가 없으므로 offset을 이용하여 Seed와 비슷한 결과를 낼 수 있게끔 설정하였고 frequency값을 사용하여 noise파형의 크기를 촘촘하게끔 조절 가능케하고 @Time을 더하여 애니메이션의 효과를 낼 수 있게 하였다.
// 만약 noise파형으로 지정된 @point 포인트 넘버 값이 chf()으로 만들어진 cutoff parameter 수치보다 작다면
// frequncy값으로 noise 파형의 간격값과, offset으로 Seed비슷하게 설정 그리고 @Time을 더해 애니메이션 형성
if (noise (@primnum*chf ("FREQ") + @Time*chf ("OFFSET")) < chf ("CUTOFF")) {
// 해당된 포인트 넘버에 해당되는 포인트들은 전부 지워주어라
removeprim (0, @primnum, 1);
}
이해가 안되었던 부분:
- 마지막 부분에서 seaweed motion을 만들어 줄때 코딩을 작성하였을때 아래 코드 부분에서 offset variable 변수의 식을 noise()와 함께 써주었을때 noise()안에 @P에 더해진 i가 정확히 어떤 역할을 하는지 약간 햇갈렸다. 이를 없애니 꼳꼳히 있는 선들이 있어서 아마 이 변수로 통해 선들이 꺾인다는 것은 이해 하였는데 정확히 어떠한 원리로 작동되는지 이해하기 어려웠다. 나는 i를 더해 반복문의 횟수가 반복이 될수록 Offset이 업데이트 되게 해주어서 총 다섯번 offset꺾인다 이렇게 해석했지만 맞는지 어려웠다.
// 아래에서 활용할 variable 변수값을 모두 선언해준다.
vector offset, pos;
int pr, pt;
float stepsize;
// 프리미티브를 선으로써 만들겠다고 우선 먼저 선언해주자
pr = addprim (0, "polyline");
stepsize = 0.5; // 이 stepsize는 프리미티브 선이 꺾어질때 간격의 사이즈를 나타낸다
for (int i = 0; i < 6; i++) { // i가 0에서부터 6까지 1씩 늘어나는 동안
/* geometry의 모든 포인트의 위치에 noise()가 적용된 값 안에 @Time이 빼져 offset을 빼져
프레임이 흐를수록 모션이 더해지게끔 만든다. 그리고 i를 더해 반복문의 횟수가 반복이 될수록
offset이 업데이트되게 해준다. 그리고 0.2를 전체에 곱해 amp값을 줄여 range 파형의 높이
간격을 줄여준다*/
offset = curlnoise (@P - @Time + i)*0.2;
/* 모든 포인트에 대해 normal의 방향대로 위치값이 지정되고 이는 반복문대로 0에서 6이 될때까지 모든 위치값들이
생성되어지고 offset을 더해주어 noise()파형을 적용시켜 약간의 랜덤한 값을 갖게 하여 vector variable pos에
저장한다*/
pos = @P + @N*i*stepsize+offset;
pt = addpoint (0, pos); // 위에서 선언된 pos값의 위치에 모든 새로운 점들을 생성시켜주어라
addvertex (0, pr, pt); // 위에서 만들어진 모든 새로운 점들을 primitive 선으로 이어주어 만들어주어라
}
- 2번 exercise에서 어떠한 원리로 원을 돌면서 선들이 구성되는지는 해석을 하였지만 cgwiki님의 정답을 보지않고 직접 하려고 하니 어려움을 느꼈다. 이는 복습일기를 작성할때 다시한번 직접 코딩을 해보아 어떠한 원리로 작동되는지 머릿속에 집어넣어야 겠다는 생각이든다. noise()가 아닌 sin()과 cos()를 사용할때 function들 안에 무엇을 집어 넣어야 할 것인지 더욱 직접 연구를 해봐야 할 것 같다.
- 5번 exercise에서 rand()가 아닌 noise()를 사용할때 약간 grid가 깜빡거리는 구간이 있었다. 자연스래 사라지는 것이 아닌 중간에 갑자기 사라진 프리미티브가 다시 생겼다가 다시 없어지는 그런 현상이 있어서 당황하였다. (freq와 offset이 둘다 1로 설정되었을때). 도대체 어떠한 원리로 그런 것이 생겼는지 나중에 다시한번 고찰 해봐야 할 것 같다. 자세한건 영상으로 첨부하겠다. cutoff는 $T/4로 설정되어있음.
공부하면서 들었던 생각:
이번 강의는 역대급으로 길었다. 중간에 많이 어렵기도 하고 햇갈리는 부분도 많고 배우는 부분과 코드의 양도 지난번과 비교했을때 어마무시하게 많아 머리가 역대급으로 터지는 경험을 할 수 있었다. 그래도 후디니에서 코드만을 사용하여 이제는 점, 선, 면 모두 마음대로 생성할 수 있다는 것이 무척 신기하기도 했다. 예전만해도 3D 물체를 코딩으로 생성하는 것이 도대체 어떻게 가능하지 이런생각을 하였는데 정말 컴퓨터 언어란 대단한것 같다. 그리고 마지막 seaweed effect에서는 마치 블렌더에서의 헤어 파티클 effect를 보는 것 같았다. 마치 후디니 뿐만 아닌 3D 소프트웨어 개발자들이 이런식으로 그래픽 툴들을 개발해내구나 라는 체험을 약간이나마 할 수 있었던 것 같다. 개인적으로 day 7과 day 12때보다 이번이 더욱 어렵고 심화적으로 느껴졌던 것같다. 그래서 그런지 공부일지도 이번 강의만은 대충 넘어갈 수 없다고 생각되어 무척 꼼꼼히 작성하려고 노력하였다. 이제 점점 드디어 fx의 기본기에 발을 들이는 것 같아 그래도 기분은 좋은 것 같다. 14일차 강의부터 이제 joy of vex 후반 코스라고 twa님께서 언급하셨듯이 이제 끝이 얼마 남지 않은 것 같다. Day 20까지 초심 잃지 않고 계속해서 천천히 나아가야 할 것 같다.
'FX > Houdini_Joy of VEX' 카테고리의 다른 글
Joy of Vex - Day 16: copy sop, midweight instance attributes (scale, N) (0) | 2022.07.24 |
---|---|
Joy of Vex - Day 15: copy sop, simple instance attributes (pscale) (0) | 2022.07.22 |
Joy of Vex - Recap of Week 4 (0) | 2022.07.18 |
Joy of Vex - Day 13: for loops (ties nicely into arrays) (0) | 2022.07.18 |
Joy of Vex - Day 12-3: nearpoints, arrays (0) | 2022.07.16 |