FX/Houdini_Joy of VEX

Joy of Vex - Day 17-2: copy sop, orient, quaternions

Gamestonk118 2022. 7. 31. 03:07

중요했던 부분:

- 지난 시간에 배웠던 부분 복습

지난 시간에 배웠던 quaternion()과 @orient의 원리를 응용하여 코드를 작성해보아 어떠한 shape을 만들어보았다. 우선 색깔을 지정해준 각각의 box가 grid를 구성하는 모든 포인트들의 위치에 카피될수 있도록 copy to points를 연결해주었고 어떠한 방향으로 rotation할 수 있게끔 vex code를 작성하였다.

 

일반적인 angle 과 axis 값을 variable로 만들어 줌으로써 rotation을 하는 방법

// angle에 @Time에 반인 값을 지정하여 프레임이 흐를수록 angle의 수치가 올라감
float angle = @Time*0.5;
// axis의 값을 chv()으로 유저가 파라미터로 조절가능
vector axis = chv ("AXIS");
// axis값을 normalize()를 이용하여 크기값이 1인 값으로 만들음
axis = normalize (axis);

/* @orient에 quaternion()을 적용한 angle과 axis를 저장하여 얼마나 copy 된 geometry가 얼마나 rotation
할지 그리고 어느 축을 기준으로 rotation될지 지정해줌*/
@orient = quaternion (angle, axis);
원초적인 quaternion()의 방식을 사용하여 해당 angle만큼 axis를 축으로 rotation되게끔 설정하였다.
// 나중에 값을 저장해줄 variable들을 미리 선언해줌
float angle;
vector axis;

// angle 값을 chf()으로 유저가 파라미터로 조절가능
angle = chf ("ANGLE");
// angle값에 @ptnum에서 chf ()을 곱한 값을 빼서 업데이트함
/* 이는 angle값에 포인트 넘버값을 뺀값을 float variable angle에 저장하여 기본적으로 grid상에서 @ptnum
이 높은 숫자일들수록 rotation이 먼저 실행되도록 설정. 이때 덧셈이 아닌 뺄셈으로 진행됨으로 반대방향으로 rotation
이 되게끔 설정. 이때 angle 즉 돌아가는 세기를 chf()으로 유저가 offset을 조절가능케함*/
angle = angle - @ptnum*chf ("OFFSET");
/* angle에 @Time을 더한 값을 업데이트 해줌으로써 프레임이 올라감에 따라 서서히 box들이 rotation되게끔 설정
이때 chf()으로 설정한 상수값을 @Time에 곱해줌으로써 스피드를 조절 가능케함*/
angle = angle + @Time*chf ("SPEED");

// axis 즉 box가 rotation될 때의 축을 chv()으로써 유저가 직접 조절가능케함
axis = chv ("AXIS");
// axis값을 normalize()를 적용하여 vector 크기값을 1로써 설정함
axis = normalize (axis);

// @orient 방향값을 quaternion()이 지정된 angle과 axis값으로써 지정하여 scene view상에서 copy된 box
들이 유저들이 알맞게 세부적으로 파라미터들을 조절한 값들에 맞게끔 모션이 진행되게끔 함*/
@orient = quaternion (angle, axis);

 

파라미터들을 조절하여 angle값과 @ptnum에 따른 offset값을 직접 유저가 조절할 수 있게끔 설정하였다

방금적 만든 방식에서 angle값을 degree값으로 파라미터로 지정해주고 싶을때 쓰는 방법

/* float variable angle을 chf()으로써 유저가 파라미터로 조절 할 수 있게 하는데 이때 radians()을 
적용함으로써 degrees값으로 유저가 조절 할 수 있게만듦*/
float angle = radians (chf ("ANGLE"));

// axis의 값을 chv()으로 유저가 파라미터로 조절가능
vector axis = chv ("AXIS");

/* @orient에 quaternion()을 적용한 angle과 axis를 저장하여 얼마나 copy 된 geometry가 얼마나 rotation
할지 그리고 어느 축을 기준으로 rotation될지 지정해줌*/
@orient = quaternion (angle, axis);
유저가 파라미터로 조절할때 radians값이 아닌 degree값으로 angle을 조절할 수있게 만들어주었다.

$PI 값을 이용하여 얼만큼 rotation할 건지의 대한 angle을 조절하는 방법 & quaternion()에 값 하나만 넣기.

파형에서 $PI의 값은 radians값으로써 degree값에서의 180도와 동일한 수치를 나타낸다. 그러므로 아래 식에서 만들어진 파라미터들 중에서 SUM값이 1로 지정될 경우에는 정확히 box가 180도 rotation이 되어 축을 중심으로 정반대로 뒤집혀지는 것을 알 수 있다.

/* float variable angle값을 $PI값으로 설정하고 이에 chf()으로 설정된 SUM값을 곱해주어 $PI가 얼마나
적용될지 angle에서 설정함*/
float angle = $PI*chf ("SUM"); 
// axis의 값을 chv()으로 유저가 파라미터로 조절가능
vector axis = chv ("AXIS");
// axis값을 normalize()를 이용하여 크기값이 1인 값으로 만들음
axis = normalize (axis);

// axis값에 angle을 곱해주어 나중에 quaternion()에 하나의 값만 집어넣기로함
axis *= angle;

/* @orient에 quaternion()을 적용한 angle이 곱하여진 axis를 저장하여 얼마나 copy 된 geometry가 얼마나 rotation
할지 그리고 어느 축을 기준으로 rotation될지 지정해줌*/
@orient = quaternion (axis);

 

$PI를 기준으로 angle값을 조절하게 만들어 sum파라미터가 1이 되면 방향이 180도 뒤집혀지는 것을 알 수 있다

angle값에 특정 파형으로 값을 입력하여 @P grid의 포인트 위치에 따라 카피된 box들이 각기 파형의 위치를 따라 rotation되는 세기가 정해지게 해주는 방법

// axis의 값을 chv()으로 유저가 파라미터로 조절가능
vector axis = chv ("AXIS");
// axis값을 normalize()를 이용하여 크기값이 1인 값으로 만들음
axis = normalize (axis);

// @A값에 rand()나 noise()로 생성된 파형을 집어넣어 @A를 나중에 angle의 역할로서 작동되게끔 설정하였다.
//@A = rand (@P + @Time);
// noise안에 @P에 @Time을 더하여 모션을 취하도록 하였다. 
// 그리고 noise()에 4를 곱하여 amp값을 더욱 크게 만들도록 하였다
@A = noise (@P + @Time)*4;
/* @A값에 trunc()을 적용하여 파형을 block 형태 즉 소수점이 없게끔 설정하였고 $PI/2을 곱하여 
angle이 정확히 90도 방향으로만 돌아가게끔 설정하였다*/
@A =  trunc (@A)*$PI/2;

// axis값에 angle을 곱해주어 나중에 quaternion()에 하나의 값만 집어넣기로함
axis *= @A;
/* @orient에 quaternion()을 적용한 angle이 곱하여진 axis를 저장하여 얼마나 copy 된 geometry가 얼마나 rotation
할지 그리고 어느 축을 기준으로 rotation될지 지정해줌*/
@orient = quaternion (axis);

 

noise()으로 인해 각기 포인트 위치에 따라 무작위로 rotation되는것을 알 수 있고 trunc()때문에 rotation될때 스무스가 아닌 확 딱딱 rotation되는 것을 알수 있다.

아래 식은 거의 위와 동일하지만 fit()을 noise()파형에 사용하여 더욱 rotation이 적용되는 양이 많아지게끔 설정하였다.

// axis의 값을 chv()으로 유저가 파라미터로 조절가능
vector axis = chv ("AXIS");
// axis값을 normalize()를 이용하여 크기값이 1인 값으로 만들음
axis = normalize (axis);

// noise안에 @P에 @Time을 더하여 모션을 취하도록 하였다. 
@A = noise (@P + @Time);

// fit()을 이용하여 noise파형이 있는 @A값을 0.4에서 0.6사이로 clamp해주고 0과 1으로 fit을 맞춰줌
@A = fit (@A, 0.4, 0.6, 0, 1);
// noise파형이 있는 @A값에 4를 곱하여 amp값을 곱해줌
@A *= 4;
/* noise파형이 있는 @A값에 trunc()를 적용하여 소수점을 없에 블럭형태로 만들어준다음 $PI/2값을 곱하여 90만큼
만 rotation되게끔 설정하였다*/
@A =  trunc (@A)*$PI/2;
// axis값에 noise()파형이 있는 @A값을 곱하여 나중에 quaternion에서 값을 한 정보만 받아드릴수 있게끔 설정
axis *= @A;
/* @orient에 quaternion()을 적용한 angle이 곱하여진 axis를 저장하여 얼마나 copy 된 geometry가 얼마나 rotation
할지 그리고 어느 축을 기준으로 rotation될지 지정해줌*/
@orient = quaternion (axis);
위의 모션과는 거의 동일하지만 fit()을 사용하니 noise()의 파형이 더욱 심해지는것을 알 수 있었다.
// axis의 값을 chv()으로 유저가 파라미터로 조절가능
vector axis = chv ("AXIS");
// axis값을 normalize()를 이용하여 크기값이 1인 값으로 만들음
axis = normalize (axis);

// noise안에 @P에 @Time을 더하여 모션을 취하도록 하였다. 그리고 4를 곱하여 amp값을 올려주도록 하였다
@A = noise (@P + @Time)*4;
/* chramp()를 사용하여 방금 전 만들었던 noise()가 있던 @A값을 나중에 @P.y로 높이값으로 설정할때
ramp 모양에 따라 모션이 나오게끔 설정 하였다*/
@A = chramp ("TWA", @A);
// @A에 또 4를 곱하여 amp값을 다시 한번 더 올려주었다
@A *= 4;
/* noise파형이 있는 @A값에 trunc()를 적용하여 소수점을 없에 블럭형태로 만들어준다음 $PI/2값을 곱하여 90만큼
만 rotation되게끔 설정하였다*/
@A =  trunc (@A)*$PI/2;

// @P.y로 높이값으로 @A 파형의 결과가 나타나게 하여 위아래로 무작위로 왔다갔다 하는 모션을 완성하였다
// 0.1를 곱하여 높이값을 조금 줄여주었다
@P.y = @A*0.1;
// axis값에 noise()파형이 있는 @A값을 곱하여 나중에 quaternion에서 값을 한 정보만 받아드릴수 있게끔 설정
axis *= @A;
/* @orient에 quaternion()을 적용한 angle이 곱하여진 axis를 저장하여 얼마나 copy 된 geometry가 얼마나 rotation
할지 그리고 어느 축을 기준으로 rotation될지 지정해줌*/
@orient = quaternion (axis);

 

기존에 만들어둔 모션에서 chramp()로 형성된 ramp값이 @P.y 높이값으로 적용되어 위아래로 왔다갔다 하는 모션을 관찰할 수 있었다

@N과 @up만 가지고 quaternion()을 활용하여 @orient를 생성해줌으로써 카피된 Geometry의 rotation을 담당하려 할때

/* when we only have values of @N and @up
instead of values of angle (float) and axis (vector) */

// axis 즉 box가 rotation될 때의 축을 chv()으로써 유저가 직접 조절가능케함
@N = chv ("TWA");
// @N값을 normalize()를 이용하여 크기값이 1인 값으로 만들음
@N = normalize (@N);


// sin()과 cos()를 @Time에다 적용하여 나중에 @up에다 저장하였을때 원운동하게끔 설정하였다
//@Time에 sin()을 적용하여 프레임이 흐를수록 sine파형을 따라 float variable s가 결정되게끔 만듬
float s = sin (@Time);
//@Time에 cos()을 적용하여 프레임이 흐를수록 cosine파형을 따라 float variable c가 결정되게끔 만듬
float c = cos (@Time);
//@up을 사용하여 set()을 이용해 각기 x과,z값에 입력해줌으로써 copy된 Geometry의 머릿부분이 원운동되게 만듦
@up = set (s, 0, c);

/* quaternion()을 이용해서 maketransform()으로 @N과 @up을 matrix의 형태로 만든 수치를 @orient로 생성하여
rotation이 되게끔 만듦*/
@orient = quaternion (maketransform (@N, @up));
카피된 geometry의 @up을 cos()와 sin()이 x와 z 방향으로 모션이 생기게끔 만들어 box들이 y축을 중심으로 원운동하게끔 설정해주었다

matrix의 수치만을 가지고 quaternion()에 적용하여 @orient를 생성하고 싶을때

// matrix3 variable m에 ident()를 적용하여 단위행렬로 만들어줌
// 이때 단위행렬에서의 두번째 행은 @up과 값이 같고 세번째 행은 @N과 값이 같다
matrix3 m = ident (); 
// quaternion에 단위행렬이 된 matrix3 variable m을 적용하여 @orient로 나타나게 함
@orient = quaternion (m);

x/y/z값을 따로따로 축으로 지정하여 degree값과 함께 rotation을 해주는 방법

이때 중요한 점은 지난 복습시간때 궁금했던 eulertoquaternion()의 두번째 정보의 관한 정체를 알 수 있었다. 이는 x/y/z중 무엇을 우선순위로 할것인지 정해주는 방식의 integer value였는데 이는 지금 상황에서는 뭘 선택하든 동일한 결과를 낳는다. 그치만 나중에 매우매우 중요해질 것이라고 twa님께서 언급하셨다.

/* radians()을 사용하여 chv()으로 생성된 파라미터값을 degree로 조절할 수 있게 만듬 그리고 vector variable
rot값에 저장하여라*/
vector rot = radians (chv ("ROT"));
// eulertoquaternion()으로 @orient를 생성하여 rotation을 x/y/z 방향 따로따로 돌릴 수 있게끔 만듦
@orient = eulertoquaternion (rot, 0);
x/y/z값을 따로따로 rotation을 시켜줄수 있는데 radians()을 이용하여 degree값으로 파라미터를 조절할 수 있게끔 하였다.

- lerp(): Lerp Function

lerp()은 기본적으로 세 float값이나 두 vector값 그리고 하나의 float값이 정보로 들어가며 이는 float이나 vector에 위치한 두 포인트들의 사이의 크기를 1로써 가정했을시 비율상 그 사이의 점이 어디 위치할지 알려준다.

// 1번 인풋으로 연결된 wrangle에서 0번 포인트의 @P 포인트 위치값을 불러와 vector variable a에 저장하여라
vector a = point (1, "P", 0);
// 2번 인풋으로 연결된 wrangle에서 0번 포인트의 @P 포인트 위치값을 불러와 vector variable b에 저장하여라
vector b = point (2, "P", 0);
/* lerp()을 이용하여 각기 vector a와 b사이에 있는 간격을 1로 결정하였을때 chf()으로 결정된 값의 위치에
있는 포인트의 포인트 위치를 vector variable c에 저장하여라*/
vector c = lerp (a, b, chf ("AMOUNT"));

// addpoint()을 사용하여 vector variable c에 위치에 포인트를 생성하여라
addpoint (0, c);

두 점들 사이에 lerp()로 생성된 포인트를 하나 생성하여 보았다.

- slerp(): SLerp Function

slerp()은 lerp()와 원리는 동일한데 @orient값들에 대해 a의 정보와 b의 정보를 사이에  1로써 비율을 맞추어 c의 위치에 있는 @orient값을 내보내 준다.

// {0, 0, 0, 1}값을 vector4 variable a에 저장하여라
vector4 a = {0, 0, 0, 1};
/* quaternion()을 이용하여 {0, 1, 0}즉 y축 방향으로 90도 만큼 돌게끔 설정하여
 vector4 variable b에 저장하여라 (@orient 대채)*/
vector4 b = quaternion ({0, 1, 0}*$PI/2);
/* @Time에 chramp()을 적용하여 만들어진 ramp에 따라 모션이 진행되는 효과를 만들어 준다. 그런데 @Time에
modulo1을 하여 특정 시간대가 반복되게끔 만들게 하였다*/
// 그리고 만든 값을 float variable blend에 저장하여라
float blend = chramp ("TWA", @Time%1);

// slerp()을 사용하여 a즉 @orient가 x/y/z순으로 되었을때 b가 y축을 중심으로 90도 만큼 돌게끔 설정. 
// 돌아가는 방향과 세기는 blend로 정해지게끔 만들어 반복적으로 왔다리 갔다리 하게끔 설정하였다
@orient = slerp (a, b, blend);
slerp()안에 chramp()가 적용되어있는 float variable blend를 이용하여 rotation값을 조절하여 box들이 왔다갔다 하게끔 설정해주었다
// 각기 나중에 값을 지정해줄 variable들을 각기 type에 맞게끔 선언해주었다.
vector4 target, base; 
vector axis;
// 여기서 seed는 angle을 대체한다
float seed, blend;

// axis값을 chv()을 이용하여 유저가 직접 파라미터로 조절 가능케끔 하였다
axis = chv ("AXIS");
// axis값에 normalize()를 조정하여 크기값을 1로써 만들어주었다
axis = normalize (axis);
// seed 값에 @P포인트 위치에 따른 noise()파형을 적용해주고 @Time을 더해 offset이 시간이 흐를수록 업데이트되게함
seed = noise (@P + @Time);
// seed값에 chramp()로 생성된 ramp에 따라 seed가 새롭게 나타나도록 설정함
seed = chramp ("TWA", seed);

// axis값에 trunc()을 seed에 적용하여 소수점이 없어져 껌뻑이게 rotation되게끔 설정하고 그리고 axis값에 $PI/2를 곱하여 90도 까지만 돌아가게끔 설정하였다.
axis *= trunc(seed*4)*$PI/2;

// target에 axis가 quaternion()이 적용된 값을 저장한다. @orient를 변수로 대체하였다.
target = quaternion (axis);
// vector4 variable base의 값을 (0, 0, 0, 1)으로 지정하였다.
base = {0, 0, 0, 1};
/* @Time에 chramp()을 적용하여 만들어진 ramp에 따라 모션이 진행되는 효과를 만들어 준다. 그런데 @Time에
modulo1을 하여 특정 시간대가 반복되게끔 만들게 하였다*/
// 그리고 만든 값을 float variable blend에 저장하여라
blend = chramp ("ANI", @Time%1);

// slerp()을 사용하여 a즉 @orient가 x/y/z순으로 되었을때 어느 축을 중심으로 90도씩 돌아가게끔 설정하였다.
// 돌아가는 방향과 세기는 blend로 정해지게끔 만들어 반복적으로 왔다리 갔다리 하게끔 설정하였다
@orient = slerp (base, target, blend);

그리고 transform node안에 attributes안에 ^orient를 설정하여 카피된 Geometry의 @orient값은 transform의 영향을 받지 않도록 설정해두었다.

attributes안에 ^orient를 써넣어 @orient값은 transform의 영향을 받지 않도록 설정해두었다.

위에 만들어진 모션에 더욱 모션을 꾸며준다음에 transform노드를 붙여주고 @orient값만 때주어 카피된 Geometry의 방향은 grid의 방향과 무관하게 유지되게끔 설정해주었다.

- qmultiply(): QMultiply Function

qmultiply()은 quaternion()을 사용하여 @orient로 받아낸 rotation effect가 두개 있을때 두개 다 동시에 따로따로 작동하게끔 @orient에 저장해주는 function이다.

// @N과 @up을 지정해주기 위해 임시적으로 vector variables들을 선언해준다
vector N, up;
// N값을 모든 sphere의 모든 포인트의 위치들로 결정 그치만 normalize()을 사용하여 vector크기값을 1로설정
N = normalize (@P);
// up값을 y축을 중심으로 향하게끔 설정
up = {0, 1, 0};

// 1st rotation 
/* quaternion()을 이용해서 maketransform()으로 @N과 @up을 matrix의 형태로 만든 수치를 @orient로 생성하여
rotation이 되게끔 만듦*/
@orient = quaternion (maketransform (N, up));

// 2nd rotation
/* quaternion()이 적용된 angle값을 유저가 Chf()으로 파라미터로 조절할 수 있게끔 만들어주고 x방향으로
rotation되게끔 설정해서 vector4 variable extract에 저장*/
vector4 extract = quaternion (radians (chf ("ANGLE")), {1, 0, 0});

/* 방금전 생성한 @orient값에 qmultiply를 사용하여 두 각기 다른 Rotation들이 동시게 따로 작동하게끔 
@orient값으로 나타냄*/
@orient = qmultiply (@orient, extract);
@N과 @up을 사용하여 특정위치를 바라보는 pighead들은 유저는 angle파라미터를 이용하여 0에서 360도 사이로 pighead의 x축 중심 rotation을 조절할 수 있게끔 조절하였다.
// 나중에 수치들을 지정해줄 vector variables들을 선언해준다
vector N, up;
vector4 extraRot, talktalk, wobble;

// N값을 모든 sphere의 모든 포인트의 위치들로 결정 그치만 normalize()을 사용하여 vector크기값을 1로설정
N = normalize (@P);
// up값을 y축을 중심으로 향하게끔 설정
up = {0, 1, 0};
// 1st rotation 
/* quaternion()을 이용해서 maketransform()으로 @N과 @up을 matrix의 형태로 만든 수치를 @orient로 생성하여
rotation이 되게끔 만듦*/
@orient = quaternion (maketransform (N, up));

// 유저가 정한 파라미터의 degree값만큼 x축을 중심으로 하여 rotation이 생기게하는 값을 vector4 variable extraRot에 저장
extraRot = quaternion (radians (chf ("HEADUP")), {1, 0, 0});

/* 시간이 흐를수록 pighead의 고개가 까딱까딱 하게끔 하는 motion을 주기위해 이러한 식을 써주어 vector4 variable
talktalk에 저장*/
// 20도씩 y축의 방향으로 고개가 반복적으로 까딱이는 sine 파형을 형성함
talktalk = quaternion (radians (20)*sin (@Time*3), {0, 1, 0});

/* 시간이 흐를수록 pighead의 고개가 까딱까딱 하게끔 하는 motion을 주기위해 이러한 식을 써주어 vector4 variable
wobble에 저장*/
// 20도씩 z축의 방향으로 고개가 반복적으로 까딱이는 curlnoise 파형을 형성함
// @Time에 @P를 더하여 sphere의 포인트 위치에 따라 각기 다르게 까딱이는 타이밍을 갖게끔 설정하였다.
wobble = quaternion ({0, 0, 1}*curlnoise (@P + @Time*0.2));

/* 방금전 생성한 @orient값에 qmultiply를 사용하여 각기 다른 Rotation들이 동시게 따로 작동하게끔 
@orient값으로 나타냄*/
@orient = qmultiply (@orient, extraRot);
@orient = qmultiply (@orient, talktalk);
@orient = qmultiply (@orient, wobble);
qmultiply()를 사용하여 pighead가 여러가지 방향들로 @orient로 지정된 rotation이 진행되게끔 설정해주었다.

이때 @N값과 @up값을 단위행렬로써 불러오기 위해 아래와 같은 식을 작성해보았다.

// 기존에 만들어진 @orient값에서 qconvert()로 matrix수치를 불러와 matrix3 variable m에 저장
matrix3 m = qconvert (@orient);

// 단위행렬에서의 세번째 행을 matrix3 variable m에 곱해줌으로써 단위행렬이 적용된 @N값을 불러옴
@N = {0, 0, 1}*m;
// 단위행렬에서의 두번째 행을 matrix3 variable m에 곱해줌으로써 단위행렬이 적용된 @up값을 불러옴
@up = {0, 1, 0}*m;

단위행렬이 적용된 위의 @N의 각기 값들
단위행렬이 적용된 위의 @N의 각기 값들

- matrix값을 array수치로 변환해보기

matrix값은 간혹 array수치로 변환하여 특정 행만 가지고 오고싶을 때가 있다. 이때 vector array로 바꾸어 array의 하나의 vector값으로 행렬 중 특정 행만 불러올 수 있다.

// 기존에 만들어진 @orient값에서 qconvert()로 matrix수치를 불러와 matrix3 variable m에 저장
matrix3 m = qconvert (@orient);

// matrix3 variable m값에 set()을 적용하여 vector array variable A로 저장해줌/ array로 변환
vector A[] = set (m);
// 이때 vector array varaible A를 attribute으로 저장하여 geometry spreadsheet으로 보여줌
v[]@A = A;

// @N값으로 matrix값의 3번째 행 (vector array값의 3번째값) 을 불러와 @N에 저장하여라
@N = A[2];
// @up값으로 matrix값의 2번째 행 (vector array값의 2번째값) 을 불러와 @up에 저장하여라
@up = A[1];

matrix로써 m variable에 가져있어졌던 수치들이 vector array로써 vector array variable A로 저장된것을 알 수 있다.

Exercises:

1. Copy a bunch of eyeballs to a grid, make they them all look at a single point

아래와 같이 노드를 구성하여 eyeball들이 grid상에 여러개 있게끔 설정해둔 다음 첫 rotation으로 quaternion()을 이용해 @orient로 값을 지정해두어 전부다 위로향하게끔 설정해주었다. 그리고 또 다른 quaternion()을 만들어주어 각기 x축 방향으로 rotation되게끔 만들어 주었다. 그리고 qmultiply()를 이용하여 각기 @orient가 동시에 나타내게 설정하였다. 이는 위에 pighead를 활용한 예제중 첫번째로 작성한 코드와 똑같이 작성되었다.

eyeball들을 만들어준다음 grid를 구성하는 포인트들에 위치에 전부 카피되도록 기초 설정하였다

// @N과 @up을 지정해주기 위해 임시적으로 vector variables들을 선언해준다
vector N, up;
// N값을 모든 sphere의 모든 포인트의 위치들로 결정 그치만 normalize()을 사용하여 vector크기값을 1로설정
N = normalize (@P);
// up값을 y축을 중심으로 향하게끔 설정
up = {0, 1, 0};

// 1st rotation 
/* quaternion()을 이용해서 maketransform()으로 @N과 @up을 matrix의 형태로 만든 수치를 @orient로 생성하여
rotation이 되게끔 만듦*/
@orient = quaternion (maketransform (N, up));

// 2nd rotation
/* quaternion()이 적용된 angle값을 유저가 Chf()으로 파라미터로 조절할 수 있게끔 만들어주고 x방향으로
rotation되게끔 설정해서 vector4 variable extract에 저장*/
vector4 extract = quaternion (radians (chf ("ANGLE")), {1, 0, 0});

/* 방금전 생성한 @orient값에 qmultiply를 사용하여 두 각기 다른 Rotation들이 동시게 따로 작동하게끔 
@orient값으로 나타냄*/
@orient = qmultiply (@orient, extract);

eyeball들이 전부 한곳을 집중하여 바라보고 있는 것이 보인다

2. Extend the above one to give the eyballs 'saccades'; little random rotations to make them more lifelike

이도 또한 각기 rotation에 각기 다른 sine과 noise파형을 섞어주어 여러 파형방향으로 eyeballs들이 Rotation되게끔 하였다. 마치 랜덤하게 eyeball들이 살아서 두리번 거리는 것처럼 보이게 하였다. 이는 pighead에서 활용한 두번째 예제와 코드가 동일하게 작성되었다.

// 나중에 수치들을 지정해줄 vector variables들을 선언해준다
vector N, up;
vector4 extraRot, talktalk, wobble;

// N값을 모든 sphere의 모든 포인트의 위치들로 결정 그치만 normalize()을 사용하여 vector크기값을 1로설정
N = normalize (@P);
// up값을 y축을 중심으로 향하게끔 설정
up = {0, 1, 0};
// 1st rotation 
/* quaternion()을 이용해서 maketransform()으로 @N과 @up을 matrix의 형태로 만든 수치를 @orient로 생성하여
rotation이 되게끔 만듦*/
@orient = quaternion (maketransform (N, up));

// 유저가 정한 파라미터의 degree값만큼 x축을 중심으로 하여 rotation이 생기게하는 값을 vector4 variable extraRot에 저장
extraRot = quaternion (radians (chf ("HEADUP")), {1, 0, 0});

/* 시간이 흐를수록 pighead의 고개가 까딱까딱 하게끔 하는 motion을 주기위해 이러한 식을 써주어 vector4 variable
talktalk에 저장*/
// 20도씩 y축의 방향으로 고개가 반복적으로 까딱이는 sine 파형을 형성함
talktalk = quaternion (radians (20)*sin (@Time*3), {0, 1, 0});

/* 시간이 흐를수록 pighead의 고개가 까딱까딱 하게끔 하는 motion을 주기위해 이러한 식을 써주어 vector4 variable
wobble에 저장*/
// 20도씩 z축의 방향으로 고개가 반복적으로 까딱이는 curlnoise 파형을 형성함
// @Time에 @P를 더하여 sphere의 포인트 위치에 따라 각기 다르게 까딱이는 타이밍을 갖게끔 설정하였다.
wobble = quaternion ({0, 0, 1}*curlnoise (@P + @Time*0.2));

/* 방금전 생성한 @orient값에 qmultiply를 사용하여 각기 다른 Rotation들이 동시게 따로 작동하게끔 
@orient값으로 나타냄*/
@orient = qmultiply (@orient, extraRot);
@orient = qmultiply (@orient, talktalk);
@orient = qmultiply (@orient, wobble);
@orient로 지정된 eyeballs들의 파형이 여러가지 중첩되어 막 살아있듯이 눈깔들이 여러방향으로 움직이는 것을 관찰 할 수 있었다.

3. Extend again so that you have a slider so that they can all look in random directions when the ch slider is at 0, but focus on a point when the slider is at 1

우선적으로 기존에 있던 코드에 HEADUP에 있던 radians()를 빼주어 parameter로써 더욱 원활하게끔 작동될수 있게 해주고 -를 더해주어 오히려 숫자가 늘어날수록 한곳을 향해 볼수 있게끔 설정해주었다. 그리고 각기 talktalk과 wobble 파형에 동일한 chf()을 나누어주어 amp값의 숫자가 늘어날수록 더욱 파형이 작아지게끔 설정해주었다. 이는 그래서 0에 가까울수록 정신없이 돌고 1로 갈수록 가만히 한곳을 집중하게끔 설정해주었다.

// 나중에 수치들을 지정해줄 vector variables들을 선언해준다
vector N, up;
vector4 extraRot, talktalk, wobble;

// N값을 모든 sphere의 모든 포인트의 위치들로 결정 그치만 normalize()을 사용하여 vector크기값을 1로설정
N = normalize (@P);
// up값을 y축을 중심으로 향하게끔 설정
up = {0, 1, 0};
// 1st rotation 
/* quaternion()을 이용해서 maketransform()으로 @N과 @up을 matrix의 형태로 만든 수치를 @orient로 생성하여
rotation이 되게끔 만듦*/
@orient = quaternion (maketransform (N, up));

// 유저가 정한 파라미터의 x축을 중심으로 하여 rotation이 생기게하는 값을 vector4 variable extraRot에 저장
extraRot = quaternion (-chf ("FOCUS")), {1, 0, 0});

/* 시간이 흐를수록 pighead의 고개가 까딱까딱 하게끔 하는 motion을 주기위해 이러한 식을 써주어 vector4 variable
talktalk에 저장*/
// 20도씩 y축의 방향으로 고개가 반복적으로 까딱이는 sine 파형을 형성함
// amplitude값을 직접 유저가 조정할 수 있게끔 설정. 1에 가까워 질수록 파형이 작아짐
talktalk = quaternion (radians (20)*sin (@Time*3)/(chf ("FOCUS")*10), {0, 1, 0});

/* 시간이 흐를수록 pighead의 고개가 까딱까딱 하게끔 하는 motion을 주기위해 이러한 식을 써주어 vector4 variable
wobble에 저장*/
// 20도씩 z축의 방향으로 고개가 반복적으로 까딱이는 curlnoise 파형을 형성함
// @Time에 @P를 더하여 sphere의 포인트 위치에 따라 각기 다르게 까딱이는 타이밍을 갖게끔 설정하였다.
// amplitude값을 직접 유저가 조정할 수 있게끔 설정. 1에 가까워 질수록 파형이 작아짐
wobble = quaternion ({0, 0, 1}*curlnoise (@P + @Time*0.2)/(chf ("FOCUS")*10));

/* 방금전 생성한 @orient값에 qmultiply를 사용하여 각기 다른 Rotation들이 동시게 따로 작동하게끔 
@orient값으로 나타냄*/
@orient = qmultiply (@orient, extraRot);
@orient = qmultiply (@orient, talktalk);
@orient = qmultiply (@orient, wobble);
focus라고 적혀있는 파라미터를 0으로 내릴수록 눈깔들이 살아움직이는 모션을 볼수 있고 1로 올릴수록 한곳을 바라보아 가만히 있는 눈들을 관찰할 수 가 있었다.

이해가 안되었던 부분:

- 전강의를 들었을때만 해도 이것을 어떻게 감당하지라는 생각과는 다르게 전강의의 대한 반복적인 학습이 많아서 생각보다 어느정도 견딜만 했던 것 같다. 문제는 @N과 @up으로 quaternion()을 이용하여 @orient값으로 copy된 geometry에 rotation을 줄 때 어느정도 maketransform()을 사용해야 한다는 것처럼 function적인 원리는 이해했지만 @N과 @up이 어느 방향으로 rotation되어 copytopoints상에서 scene view에서 그러한 결과를 예측하는것이 조금 어려웠던 것 같다. 그래서 1번째 exercise를 할때 생각보다 내 스스로 코드를 작성하여 eyeballs들이 한 곳을 노려보는 형태를 만드는 것이 어려운 부분이 많았다. 그래서 @N과 @up을 활용한 quaternion()과 @orient의 대한 과정은 더욱 복습과 상기가 필요하다고 느낀다.

- 2번 exercise를 공부하면서 quaternion()안에 angle로써 파형을 만드는 과정이 생각보다 햇갈리는 부분이 많았다. 그리고 2번 exercise는 아니지만 특히 chramp()을 활용할때는 정말 예측하기 어려웠던 것 같다. 코드를 더욱 내 스스로 써보기 위해 이 부분에 대해 더욱이 연습을 해야겠다고 느낀다.

- slerp()에 대한 정확한 이해를 해야겠다고 느꼈다. 이는 계속 나아갈 joy of vex코스에서 접하게 된다면 익숙해질것으로 보인다.

 

공부하면서 들었던 생각:

다행이도 겁먹던거와는 다르게 지난강의의 대한 복습이 전부인 강의라서 생각보다 할만했던 것 같다. 오늘 새롭게 배운 것으로는 lerp(), slerp()와 그리고 qmultiply()가 있었다. 나는 quaternion()과 @orient의 관계가 어마어마하게 밀접하고 이러한 관계를 통해 생각보다 다채로운 모션을 만들 수 있다는 생각에 정말 신기하게 느껴졌다. 드디어 마의 Day 17이 끝났다. 이제 진짜 3일차 강의 밖에 안남았다는 생각에 설래기도 한다. 기말고사가 있어 최대한 진도를 빨리 치고 나가야 겠다는 생각도 든다. 공부하면서 Day 17에서 많이 해맸던 것 같아서 계획된 커리큘럼에 페이스대로 쫓아가지 못해 아쉬움이 돋지만 그래도 빨랑 완강을 하여 joy of vex를 정복해야 겠다는 생각이 든다. 이번 예제 시간은 정말 도움이 많이 되었으며 이제 어느정도 quaternion()과 @orient에 대해 조금이나마 자신감을 가진 것 같다. 이 것들을 이용하여 응용을 하는 실력 향상은 이제 나에게 달린 것 같다.