복습한 내용과 다시봤더니 이해되는 부분:
Day 14: creating geometry, deleting geometry, debugging vex
Day 14에서는 point, primitive 그리고 vertex를 코드로 생성하는 과정을 전반적으로 배워보았다. 이때 addpoint(), addprimitive() 그리고 addvertex()를 활용하여 각각의 geometry를 이루는 구성들을 알아보았는데 이는 주로 이러한 방식으로 geometry를 생성해준다. 먼저 addpoint()로 생성된 포인트들을 addvertex()으로 배열들을 구성하여 하나하나 포인트들이 어떠한 방식으로 이어질지 순서를 정해준다. 그리고 addprimitive()와 함께 그 순서로 생성된 배열들을 따라 포인트들을 선으로 이어주어 그 안을 면으로 채울 것인지 아님 냅둘것인지 정해줄수 있다.
각각의 function에 들어가는 정보들은 어떤 것으로 이루어져 있을까? | |
addpoint() | Geohandle (0), 생성하려는 포인트 넘버, 포인트 위치 벡터값 |
addprimitive() | Geohandle (0), 생성하려는 타입: "polyline", 혹은 "poly" |
addvertex() | Geohandle (0), 기준이 되는 프리미티브 넘버, 이으려는 포인트 넘버 |
이때 반복문을 활용하여 특정 geometry의 표면위로 포인트들을 일정한 간격으로 계속 생성해주어 무수히 많은 포인트들을 만들어내 이를 이으면 마치 털같은 쉐입을 만들어 줄 수 있다.
- 마지막 부분에서 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로 설정되어있음.
1. 우선은 위에 코드에 코멘트로 적은것 처럼 curlnoise() 안에 있는 정보들에 i값을 더해주어 반복문의 횟수가 반복이 될수록 offset이 업데이트 되게 해준다라고 가정하였다. 이는 아래 영상에도 나와있듯이 자세히 보면 line이 위로 향할수록 꺽어지는 부분들이 계속 생겨나는데 이는 curlnoise()로 생성된 Noise파형으로 이루어진 모션의 offset값에 반복문으로 늘어나는 i값을 더함으로써 더욱 i값이 늘어남에 따라 생긴 위쪽의 포인트들의 모션들이 더욱 다체롭게 보이도록 하였다. 특정 파형에서 offset값은 파형의 모양/생김새들을 담당하는데 curlnoise()안 정보에 i값을 더해줌으로써 각기 점들이 새롭게 기준점으로 변모함으로써 파형의 모양들이 다 달라지게끔 설정한 것이라고 이해할 수 있었다.
2. 이 부분은 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. 이는 frequency값과 밀접한 연관이 있다는 사실을 연구끝에 알아내었다. 만약 frequency값이 1이 아닌 상황에서는 정상적으로 작동이 되지만 frequency값이 1로 설정되었을때 cutoff의 값이 0.5일때 상황에서 모든 프리미티브가 조건문이 부합되지 않는 다는 사실을 알아냈다. 나는 조건문의 있는 식의 값을 알아내려고 다음과 같은 @attribute를 생성하여 geometry spreadsheet에서 알아보자 하였다.
// 만약 noise파형으로 지정된 @point 포인트 넘버 값이 chf()으로 만들어진 cutoff parameter 수치보다 작다면
// frequncy값으로 noise 파형의 간격값과, offset으로 Seed비슷하게 설정 그리고 @Time을 더해 애니메이션 형성
if (noise (@primnum*chf ("FREQ") + @Time*chf ("OFFSET")) < chf ("CUTOFF")) {
// 해당된 포인트 넘버에 해당되는 포인트들은 전부 지워주어라
removeprim (0, @primnum, 1);
}
f@k = noise (@primnum*chf ("FREQ") + @Time*chf ("OFFSET"));
그랬더니 @k의 값이 cutoff가 0.5로 설정되어있는 상황에서 모든 프리미티브가 동일하게 0.5로 나타나있는 것을 알 수 있었다. 그말은 이는 조건문이 성립되지 않아 아래 있는 식을 수행해주지 못하여 그 어떤 프리미티브를 지워주지 못한 것이며 그 다음 상황에서 @k값이 또 업데이트 되어 cutoff의 식보다 작은 값의 결과값을 가진 프리미티브들이 다시 지워지는 것을 알 수 있었다. 정확한 이유는 너무 수학적으로 접근되게 되어 자세히 모르겠지만 결국 결론은 frequency를 1로 설정되었을때 cutoff의 값과 @k의 값이 모든 프리미티브에 대하여 동일한 결과가 나와 조건문을 수행해주지 못해 중간에 튀는 부분이 생긴다는 것을 알 수 있었다.
Day 15: copy sop, simple instance attributes (pscale)
Day 15에서는 Copy to Points노드를 활용하여 여러가지 모션과 쉐입을 만드는 과정을 공부하였다. Copy to Points는 연결된 geometry를 특정 포인트들 위치에 카피켜줄 뿐만 아니라 다음과 같은 정보들을 가져온다.
이때 Apply to Points by " " Attributes. 이때 따옴표 안에 들어갈 메뉴들이 여러개 있는데 이는 이렇다.
Copying - 1번 input geometry의 정보를 0번 input geometry에게 대체해서 붙여넣어준것 |
Nothing - 아무런 작업도 하지 않는다. |
Multiplying - 값을 곱해주는 것으므로써 vector면 vector 끼리 float이면 float끼리 연산이 될것이다. |
Adding - 그야말로 더해주는 것. 0번 input geometry를 기준으로 1번 input geometry의 값들을 더해줄 것 이다. |
Subtracting - 0번 input geometry를 기준으로 1번 input geometry가 가지고 있는 attribute의 값을 빼주게 되는것. |
또한 어떤정보들은 물체의 크기, 회전, 방향 (Point orientation attributes)의 대한 정보를 가지고 있어서 복사하는 물체에 영향을 주는 경우가 있다. 이와 같은 정보에 대해서 copy to points에서 이용을 할지 안할지에 대해서 정해줄 수 있다. Attributes로만 불러오고 물체에 대한 변형을 주지 않게 할 수 있다라는 상식을 배웠다. 이는 @pscale이나 @scale같이 uniform scale을 조정하는 attribute들등이 포함되며 나중에 배울 rigid body에 본격적으로 적용된다는 것을 배워보았다. 또한 코드를 직접 입력해 보는 과정을 통해 copy to points가 연결된 Geometry가 어떠한 모션을 구축할 수 있는지 알아보았다.
- 1번 exercise에서 noise()를 적용시켜 파형을 형성할때 fit()을 사용하여 위치를 고정시키고자 하였는데 그랬을때 다음번에 파형이 음수로 넘어가지 않게끔 할때 아니면 chramp()을 사용하여 색깔을 조절시키려 할때 또 fit()을 사용할때가 있어 어떻게 써야할지 몰라 대략 난감하였다.
- 지난번에 배운 중첩과 이번시간에 배운 것들을 종합하여 코딩을 해보자니 머리가 폭파되기 일부직전이었다. nearpoints()와 array를 이용해서 @scale값을 조절해보고 싶었지만 나중에는 그냥 순간 TWA님이 갑자기 너무 존경스러워지고 내 머리가 원망스러웠다.
- 갈수록 Exercises들이 너무 어려워지는 것 같다. 강의를 들을때는 이해된건줄 알았는데 직접 코딩을 하자니 내맘대로 안되는게 의아하게 된다. 어 이게 왜 안되지? 어 이게 왜 되지? 이런 순간들이 많아지는 것같다. 개발자들의 마음이 공감되는것 같다.
1. 워낙 noise() 자체가 0에서 1까지의 range로 구성되는 것이라 world상에서 땅으로 고정시키려고 할때 난감해지는 것이 머리를 아프게 만드는 것 같다. noise()는 무조건 0에서 1까지의 값을 -0.5에서 0.5로 만들어 줌으로써 world중심에 고정시켜주어야 하는데 이때 fit()을 사용해서 높낮이를 조정할때 문제가 생기는 것 같다. 아마 방법은 있겠지만 이 부분은 복습을 하는데도 깔끔하게 해소되지 않아 다시봐도 이해가 되지 않았던 부분에 언급하고자 한다.
2. nearpoints()와 array를 이용하여 copytopoints와 함께 중첩된 모션을 만드는 내용은 아마 다음시간에 배울 것 같아 기다리기로 하였다. 아마 이부분은 Day 17에 언급되었던 효과의 중첩에서 다뤄질 내용같다.
3. 어렵다...
Day 16: copy sop, midweight instance attributes (scale, N)
Day 16에서는 본격적으로 geometry를 특정 포인트에 위치시키게끔 연결하였을때 어떠한 방향을 따라 geometry가 바라보는지 알 수 있었다. 이는 geometry는 보통 1번 copy to points에 연결된 geometry의 @N방향으로 방향을 향하고 있음을 알 수 있었으며 만일 1번 geometry에 wrangle 노드를 연결해주어 코드상에 @up을 생성하여주면 카피된 geometry의 머리방향을 특정한 쪽으로 향하게 만들 수 있다는 것을 알 았다. 즉 @N방향을 바라보고 있는 카피된 geometry가 @up으로 지정된 vector값을 향해 머리부분이 향하는 것을 알 수 있다. 또한 edit node를 사용하여 특정 geometry의 모양을 원하는 방향으로 꾸며줄 수 있다는 사실을 알아내었다. 그래서 그렇게 꾸며진 geometry에 1번 input geometry의 @up값에 모션을 주어 copy 된 geometry의 머리부분이 프레임이 올라감에 따라 움직여 화려한 애미네이션을 만들어 줄 수있다는 사실을 알아내었다.
- 2번 exercise를 어떻게 해야할 지 감이 잘 잡히지 않았지만 고도의 생각끝에 어떻게 하는지 알아낼 수 있었다. 그래서 그런지 오늘 강의는 많이 어려웠던 부분이 없었던 것 같다. 아마 @up의 방향과 포인트의 normal값이 둘다 적용되어 copy to points로 볼때 특정 방향을 향하는 Geometry에 대한 예측에 대한 연습을 더욱 해야겠다는 생각이 든다.
1. 2번 exercise에서 공이 바운스되는 모션은 생각을 해보니 공은 위에서 아래로 바운스되니까 아래 코드에 fx값에 -를 적용해주어 반대로 작용되게끔 설정해주엇다. 이는 copy to points를 사용하여 새로운 애니메이션을 만들어 주었고 chramp()로 만들어진 ramp의 형태에 따라 공의 모션이 결정되도록 세팅해주었다. 이는 circle의 포인트들이 모션을 진행해주는 방식으로 디자인되었고 포인트들의 위치에 geometry를 카피하여 마치 공이 바운스되는 되는 효과를 만들어 주었다. 그리고 @N과 @up을 예측하는 방식은 3D상에서 geometry가 향하는 원리를 마음속으로 상기하면서 생각해보니 이해하기 쉬웠던 것 같다.
// float variable fx를 선언하면서 효과를 누적시켜줄 변수를 만들어 줌
float fx = 0;
// 모든 포인트의 포인트 넘버값을 float variable pt에 저장하여 포인트의 넘버가 늘어날 수록 바운스 되게끔 설정
float pt = @P.x;
pt *= chf ("FREQ"); // ramp파형을 누적시켜줄 float variable pt값에 chf()을 곱하여 frequency를 조절
// ramp파형을 누적시켜줄 float variable pt값에 @Time을 더하여 모션을 추가
// 그리고 chf()을 곱해주어 스피드를 파라미터로 조절가능케함
pt -= @Time*chf ("SPEED");
fx = chramp ("RAMP", pt); // pt값에 ramp파형을 적용시키게 해 특정한 수치의 변화를 주게끔 만듬
fx *= chf ("AMP"); // 파형값에 chf()값을 곱해주어 amplitude를 조절가능케함
// 만들어진 모든 효과를 @P.y 높이값으로 보여주게 만듬
@P.y = -fx;
@pscale = chf ("PSCALE"); // @pscale값을 파라미터로 조절해 uniform scale을 조절가능케함
Day 17-1: copy sop, orient, quaternions
Day 17-1에서는 quaternion()과 @orient에 대해 자세히 배워보았다. quaternion()에는 기본적으로 @orient값을 만들어 주기 위해 여러가지의 정보들이 들어 갈 수 있으며 이는 기본적으로 카피된 geometry의 회전을 담당하는 사실을 알 수 있었다. @orient값은 기본적으로 유저가 수치상으로 이해하기 어려우며 총 네개의 vector값으로 타입을 가지는 것을 알 수 있었다. 우선 아래와 같은 그림으로 quaternion()에 이러한 정보들을 집어넣을 수 있는데 생각보다 많이 어려웠다.
우선 quaternion()에는 float값인 angle과 Vector값인 axis 즉 두개의 정보를 집어넣어 @orient를 생성해주어 geometry가 얼마나 어느축을 중심으로 돌아갈지 설정해 줄 수 있다.
또한 quaternion()에는 방금전 설명한 float값인 angle과 vector값인 axis 두개의 정보들을 서로 곱해주어 하나의 정보만으로써 위와 동일한 결과를 생성해줄 줄 수 있다. 이는 quaternion()이 원래 직접 해주었던 방식을 유저가 직접 실행해주어 값을 집어넣어주는 것으로써 quaterion()은 생각보다 많은 단계를 거쳐 @orient값을 내놓는 것을 알 수 있었다.
또한 quaternion()에는 유저가 가지고 있는 정보가 @N과 @up밖에 없을때 이를 maketransform()으로 matrix(행렬)의 수치로 변환시켜 이를 집어넣게 하여 @orient를 내보내줄 수 있다. matrix는 type casting을 할때 3matrix, 2matrix, 4matrix 이와 같은 방식으로 진행되며 각기 행렬에 알맞는 수치들의 수에 맞게 여러개의 수치들을 가져다 준다.
또한 matrix값만 있을때는 ident()를 사용하여 단위행렬로 바꾸어주고 이를 quaternion()에 적용하면 @orient를 내보내주는 것을 알 수 있다. 3*3 단위행렬에서 보통 두번째 행은 @up과 동일한 결과를 가지고 세번째 행은 @N과 동일한 결과를 가진다는 것을 알 수 있다.
그리고 qconvert()를 사용하여 @orient값에서 다시 matrix로 바꿔주는 function도 배워보았다.
또한 eulertoquaternion()을 사용하여 방향을 조절할때 x/y/z 방향으로 각기 회전을 시켜주는 방법을 알아내었고 radians()를 통해 degree값을 radians로 변환시킬수 있게 하여 두 function들을 활용하여 copy to points에 연결된 Geometry의 방향을 degree값으로 각기 x/y/z 방향으로 회전시킬수 있다는 사실을 알아내었다.
- eulertoquaternion()안에 두번째 정보로 들어가는 0이 무엇을 의미하는지 정확히 의미를 모르겠다. Houdini 웹사이트에서는 order이라고 표현하는데 정확히 무엇을 의미하는지 햇갈리는 부분이 있어서 여기에 적기로 하였다. integer value로써 작성되는 것은 알것 같다.
- 이번에 기초를 배워서 그나마 이해는 되게 넘어가는 부분이 있는것같는데 다음 예제시간이 두렵기 시작하였다...
1. 아래 보여진 코드처럼 eulertoquaternion()안에 두번째 정보로 0이 들어가는 것을 알 수 있는데 아직도 정확히 모르겠다... 이 부분은 나중에 twa님께 물어봐서 해결해주기도록 결정하였다. 회전순서에 관한 내용같은데 추측하기로는 quaternion()이나 아님 또다른 eulertoquaternion()을 만들어서 @orient를 생성하였을때 무엇이 우선순위가 될것인지 결정해주는 숫자같다. 확실친 않다.
/* chv()으로 만들어진 vector 파라미터에서 degree값을 입력하면 radian()을 통해 radians값으로 후디니가
직접 변환해서 vector variable twaRot에 넣는다*/
vector twaRot = radians (chv ("TWAROT"));
/*방금전 생성한 x/y/z값이 담긴 vector 수치를 eulertoquaternion()을 활용해서 직접 유저가 각도를 조절하여
알맞은 방향으로 geometry를 회전시킬 수 있게 만든다. 이는 @orient에 저장하여 변화를 나타내고 수치를 보여준다*/
@orient = eulertoquaternion (twaRot, 0);
2. 이 강의는 두 번봐서 그런지 막 햇갈리는 부분은 없었다. 근데 다음 예제시간 어떻게 풀어해칠지 두렵긴 하다...
다시봐도 모르겠는부분:
- Day 14에서 seaweed motion에서 모든 라인들이 같은 방향을 따라 모션이 진행되는 과정을 cgwiki님의 코드를 살펴보면서 풀어보았었다. 이는 나중에 내가 직접 만들어봐야겠다는 생각이 들며 까먹지 않게 볼드체로 적어놓기로 하였다.
- Day 15에서 noise()를 사용함으로써 fit()을 이미 사용하였을때 높이값의 range에 제한을 걸어두고 싶어서 fit()을 한번 더 사용해야 할때 어떻게 두 effect들을 전부 적용해줄지 난감하였었다. 이는 도저히 풀리지 않아서 이 부분에 적어두기로 하였다.
- eulertoquaternion()에 들어가는 두번째 정보의 integer value가 도저히 어떠한 것을 의미하는지는 확실치 않았다. 회전 순서가 다른 quaternion()관련 function들과 비교해서 순서를 만들어주는 건지 확실치는 않다.
'FX > Houdini_Joy of VEX' 카테고리의 다른 글
Joy of Vex - Day 18: intrinsics (0) | 2022.08.03 |
---|---|
Joy of Vex - Day 17-2: copy sop, orient, quaternions (0) | 2022.07.31 |
Joy of Vex - Day 17-1: copy sop, orient, quaternions (0) | 2022.07.27 |
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 |