중요했던 부분:
- foreach loops: foreach 반복문
foreach는 기본적으로 array를 요구사항으로 함으로써 그 array라는 모든 요소에 대해 동일한 작업을 반복수행하주려는 반복문이다.
foreach (array안에 들어있는 각각의 정보를 대변하는 변수; array) {} 이러한 형식으로 구성된다.
foreach (pt, pts) {
}
해석: 우리가 가진 모든 pts의 array에 대해서 작업을 수행해 주세요. 이 pts가 가지고 있는 array의 값을 pt가 대변해주겠습니다.
// 이 값을 가지고 있는 array variable twa생성
int twa[] = {2, 7, 3, -2, 8};
i[]@twa = twa; // 이 값을 attribute twa로 나타냄
foreach (int x; twa) { // array twa안에 있는 모든값들에 대해
addpoint (0, 0)); // (0, 0, 0)에 점들을 생성해주어라
}
// 이 값을 가지고 있는 array variable twa생성
int twa[] = {2, 7, 3, -2, 8};
i[]@twa = twa; // 이 값을 attribute twa로 나타냄
foreach (int x; twa) { // array twa안에 있는 모든값들에 대해
addpoint (0, set (x, 0, 0)); // array안에 있는 각각의 수치에 따라 생성되는 포인트들의 x값이 정해진다
}
foreach에서는 array가 가지고 있는 모든 요소에 대해 각각 수행을 해주는것. 이때 우리가 가지고 있는 요소를 대변해줄 변수 x가 필요했고 그 x가 식에서 쓰인다.
// array variable twa 안에 각각의 vector값을 저장
vector twa[] = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}};
v[]@twa = twa; // array variable twa를 attribute twa로 표현
vector A; // array twa안의 정보들을 각각 대변시켜줄 vector variable A 선언
foreach (A; twa) { // array안에 모든 값들에 대해
addpoint (0, A); // 이 식을 수행해 주어라. 정확히 점들을 전부 생성해주어라
}
그러므로 지난 강의때 중첩을 했을때 array의 값들을 전부 복붙하느라 너무 코드의 양이 길어졌던것을 기억했을때 foreach를 사용하여 한번에 모두 계산되게 만들어 더욱 경제적으로 코드를 작성할 수 있었다. 효과들을 각각에 포인트들에다가 하나하나씩 적용해서 attribute에 그 모든 포인트들의 대한 효과들을 누적시켰던 것을 foreach를 사용하여 코드를 더욱 간략하게 작성할 수 있었다.
// 지난번 코드
/* * 변수 설정 * */
vector pos = 0;
vector col = 0;
int pts[];
int pt;
float d = 0;
float radius = chf ("RADIUS");
/* 0번 geometry로부터 1번 geometry를 구성하는 점들중 반경 40안에서 가장 가까운 것들의 포인트 넘버들을 찾아
int array variable pts에 저장하여라*/
pts = nearpoints (1, @P, 40);
@Cd = 0; // @Cd 컬러값을 0으로 초기화
/* * 효과 생성 & 원본에 저장 * */
/* 이 효과들을 전부 array안 각각의 포인트에 대하여 나온 값들을 @Cd값안에 누적시켜 중첩이 되게 하는 방식을 하였다*/
///
pt = pts[0]; // pts array에 있는 값들중 첫번째 값만 pt에 저장
// 1번 인풋 geometry에서 pt에 해당하는 포인트 넘버를 가진 포인트 위치값을 가져와 pos에 저장
pos = point (1, "P", pt);
// 1번 인풋 geometry에서 pt에 해당하는 포인트 넘버를 가진 색깔값을 가져와 pos에 저장
col = point (1, "Cd", pt);
// 방금 선언한 각각의 pos값과 grid상의 모든 포인트 위치사이의 거리길이값을 d에 저장
d = distance (@P, pos);
// fit()을 통해 안쪽으로 갈수록 효과값이 커지고 멀어질수록 떨어지게끔 조정
d = fit (d, 0, radius, 1, 0);
@Cd += col*d; // 이 값들을 색깔로써 보여주게 함
/* 이 다른 포인트들을 중심으로 계속 반복하여 @Cd값에 누적시켜 중첩되는 효과를 만든다*/
///
pt = pts[1];
pos = point (1, "P", pt);
col = point (1, "Cd", pt);
d = distance (@P, pos);
d = fit (d, 0, radius, 1, 0);
@Cd += col*d;
///
pt = pts[2];
pos = point (1, "P", pt);
col = point (1, "Cd", pt);
d = distance (@P, pos);
d = fit (d, 0, radius, 1, 0);
@Cd += col*d;
///
pt = pts[3];
pos = point (1, "P", pt);
col = point (1, "Cd", pt);
d = distance (@P, pos);
d = fit (d, 0, radius, 1, 0);
@Cd += col*d;
///
pt = pts[4];
pos = point (1, "P", pt);
col = point (1, "Cd", pt);
d = distance (@P, pos);
d = fit (d, 0, radius, 1, 0);
@Cd += col*d;
///
pt = pts[5];
pos = point (1, "P", pt);
col = point (1, "Cd", pt);
d = distance (@P, pos);
d = fit (d, 0, radius, 1, 0);
@Cd += col*d;
///
pt = pts[6];
pos = point (1, "P", pt);
col = point (1, "Cd", pt);
d = distance (@P, pos);
d = fit (d, 0, radius, 1, 0);
@Cd += col*d;
// 이번 코드
vector pos = 0;
vector col = 0;
int pts[]; // integer array variable pts선언
int pt; // array pts안에 있는 각각의 요소를 어떻게 대변할지에 대해 integer variable pt를 선언
float d = 0;
float radius = chf ("RADIUS");
pts = nearpoints (1, @P, 40);
@Cd = 0;
foreach (pt; pts) { // array안에 모든 값들에 대해
// 아래 효과들을 모두 적용시켜주어라
pos = point (1, "P", pt);
col = point (1, "Cd", pt);
d = distance (@P, pos);
d = fit (d, 0, radius, 1, 0);
@Cd += col*d; // 그리고 이 값들은 모두 @Cd값에 누적시켜주어 서로 색깔들이 중첩이 되게끔 만든다.
}
foreach의 주된 특징은 간략하자면 이로 나타낼 수 있다.
1. array pts가 7개의 정보를 가지고 있다면 foreach는 7번 반복될 예정이다.
2. 이때 첫번째 pt부터 마지막 pt까지 반복되며 작업이 된다.
3. twa가 가진 요소의 갯수만큼 반복을 할 건데 모든 요소에 대해서 값을 활용할 거다.
- for loops: for 반복문
for은 foreach와 거의 동일 하게 작동되지만 array가 가진 요소의 갯수만큼 반복을 안하게끔 유저가 조절 할 수 있게 만드는 반복문이다.
for (시작하려는 값; test; 값의 증가) {} 이러한 형식으로 구성된다.
for (int i = 0; i < 13; i++) { // i가 1일때부터 13이 되기 전까지의 1씩 증가됬을때
addpoint (0, set(i, 0, 0)); // x값이 i일 경우의 포인트들을 모두 생성하여 보여주어라
}
*i++ 는 i += 1 혹은 i = i + 1과 동일한 뜻을 가진다.
이때 위에서 이미지는 (0,0,0)에서 0번과 1번 포인트들이 겹쳐져 있는 것을 볼 수 있는데 이는 기존에 add node로 생성된 점과 wrangle상에서 addpoint()로 생성된 점들이 겹쳐지기 때문이다. for loop의 기준으로 처음 포인트의 점의 위치는 (0, 0, 0)이기 때문이다.
for (int i = 0; i < 13; i+=2) { // i가 1일때부터 13이 되기 전까지의 2씩 증가됬을때
addpoint (0, set(i, 0, 0)); // x값이 i일 경우의 포인트들을 모두 생성하여 보여주어라
}
마찬가지로 for loop도 지난 강의때 생성해 보았던 효과들의 중첩들을 구현하였을때 만들어진 코드의 양을 엄청 줄일 수 있다. 이는 for loop이 알아서 array안에 있는 수치들에 해당하는 포인트들에 하나하나 효과들을 적용시켜주기 때문이다.
// 지난번 코드
/* * 변수 설정 * */
int pt;
vector pos = 0;
float d = 0;
float w = 0;
float radius = chf ("RADIUS");
float r = chf ("R");
int num = chi ("NUM");
/* 0번 geometry로부터 1번 geometry를 구성하는 점들중 유저가 선택한 반경안에서 가장 가까운 것들의 포인트 넘버들을 찾아
int array variable pts에 저장하여라*/
pts = nearpoints (1, @P, radius, num);
pt = pts[0]; // pts array에 있는 값들중 첫번째 값만 pt에 저장
// 1번 인풋 geometry에서 pt에 해당하는 포인트 넘버를 가진 포인트 위치값을 가져와 pos에 저장
pos = point (1, "P", pt);
// 방금 선언한 각각의 pos값과 grid상의 모든 포인트 위치사이의 거리길이값을 d에 저장
d = distance (@P, pos);
w = d*ch("FREQ"); // 효과에 freqency를 조절하여 파형의 촘촘함을 설정
w -= @Time*ch ("SPEED"); // 효과의 스피드를 설정
w = sin (w); // 파형이 sin()으로 sine wave로써 나타나게끔 설정
w *= chf ("AMP"); // 파형의 높이값을 설정
w *= fit (d, 0, r, 1, 0); // 포인트로부터 파형이 멀어질수록 효과가 덜나도록 설정
@P.y += w; // 이 모든 효과들을 높이값으로 설정
/* 이 다른 포인트들을 중심으로 계속 반복하여 @P.y값에 누적시켜 중첩되는 효과를 만든다*/
pt = pts[1];
pos = point (1, "P", pt);
d = distance (@P, pos);
w = d*ch("FREQ");
w -= @Time*ch ("SPEED");
w = sin (w);
w *= chf ("AMP");
w *= fit (d, 0, r, 1, 0);
@P.y += w;
pt = pts[2];
pos = point (1, "P", pt);
d = distance (@P, pos);
w = d*ch("FREQ");
w -= @Time*ch ("SPEED");
w = sin (w);
w *= chf ("AMP");
w *= fit (d, 0, r, 1, 0);
@P.y += w;
// 이번 코드
int pts[]; // integer array variable pts선언
int pt; // array안에 들어있는 각각의 정보를 대변해 주기 위한 integer variable pt선언
vector pos = 0;
float d = 0;
float w = 0;
float radius = chf ("RADIUS");
float r = chf ("R");
int num = chi ("NUM");
pts = nearpoints (1, @P, radius, num);
/* integer variable i의 값이 0에서 부터 array pts안에 들어있는 정보의 수까지 도달하기 전까지 1씩 늘어날때*/
for (int i = 0; i < len (pts); i++) {
/* array pts안에 있는 정보의 순서는 integer variable i로 결정되고 순서에 해당하는 수치는 integer
variable pt에 저장된다*/
pt = pts[i];
// 효과 생성
pos = point (1, "P", pt);
d = distance (@P, pos);
w = d*ch("FREQ");
w -= @Time*ch ("SPEED");
w = sin (w);
w *= chf ("AMP");
w *= fit (d, 0, r, 1, 0);
@P.y += w; // 그리고 이 값들은 모두 @P.y값에 누적시켜주어 서로 높이값들이 중첩이 되게끔 만든다.
}
Exercises:
1. Make ripples that are red at their peaks and green at the lowest points
파형에서 어떻게 하여 가장 높은 값에 빨간색을 적용하고 낮은값에 초록색을 적용하라는지 아무리 생각해도 어떻게 할지 감히 잡히지 않았다...ㅠ 우선 파형에 적용되는 식에 빨간색을 적용해서 만들어주고 나머지 값을 초록색을 하여 조건문을 완성할 수 는 있었지만 그렇게 되면 가장 높은 그리고 낮은 포인트들이 아니라서 정답이 아닌 것 같았다. 대략 난감해서 다음에 다시 풀어보기로 하였다. amp파라미터를 조절한다고 해도 계속해서 높고 낮은 포인트들의 색깔이 유지되어야 할텐데 감이 잡히지 않는다.
2. Make each ripple setup have the wave frequency be determined by data coming from the scatter points. Eg, multiply frequency by the scatter point's @ptnum, or @P.x value.
scatter 노드로 전해져 오는 포인트들의 @P.x값에 따라 파형의 frequency value가 정해지도록 설정해주었다. 이는 기존에 pos로 scatter 포인트들의 위치값을 불러왔는데 이의 x값만 따로 때내어 frequency값에 곱해줌으로써 새로운 파형의 모양이 생성되게끔 세팅해주었다. 이때 @P.x값이 0에서로부터 멀어지는 포인트들로 생성되는 파형의 frequency값들은 더욱 커져 점점 촘촘한 모양을 달성하는데 비해 @P.x값이 0으로 가까워질 수록 frequency값이 더욱 작아져 파형이 더욱 널널하게 만들어진 것을 확인 할 수 있다.
// 아래식들은 위에 색깔의 중첩에 대해 코드를 작성하였을때와 동일하다
int pts[];
int pt;
vector pos = 0;
float d = 0;
float w = 0;
float freq = 0;
float radius = chf ("RADIUS");
float r = chf ("R");
int num = chi ("NUM");
pts = nearpoints (1, @P, radius, num);
/* integer variable i의 값이 0에서 부터 array pts안에 들어있는 정보의 수까지 도달하기 전까지 1씩 늘어날때*/
for (int i = 0; i < len (pts); i++) {
/* array pts안에 있는 정보의 순서는 integer variable i로 결정되고 순서에 해당하는 수치는 integer
variable pt에 저장된다*/
pt = pts[i];
// 효과 생성
pos = point (1, "P", pt);
d = distance (@P, pos);
/* frequency를 지정하는 값에 pos.x를 집어넣어 scatter points들의 위치값으로부터
파형 frequency가 지정되게끔 세팅하였다.*/
freq = d*pos.x*chf ("FREQ");
w = freq;
w -= @Time*ch ("SPEED");
w = sin (w);
w *= chf ("AMP");
w *= fit (d, 0, r, 1, 0);
@P.y += w;
}
3. I initially had an exercise "make the colour example do a colour blend in multiply mode rather than additive", but its not easy to get right! I include the finished result below, your exercise is to pull it apart and understand why it works as it does. :)
우선 TWA님께서 쓰신 코드를 비교를 하기 위해 먼저 붙여놓아보아보았다.
vector pos = 0;
vector col = 0;
int pts[]; // integer array variable pts선언
int pt; // array pts안에 있는 각각의 요소를 어떻게 대변할지에 대해 integer variable pt를 선언
float d = 0;
float radius = chf ("RADIUS");
pts = nearpoints (1, @P, 40);
@Cd = 0;
foreach (pt; pts) { // array안에 모든 값들에 대해
// 아래 효과들을 모두 적용시켜주어라
pos = point (1, "P", pt);
col = point (1, "Cd", pt);
d = distance (@P, pos);
d = fit (d, 0, radius, 1, 0);
@Cd += col*d; // 그리고 이 값들은 모두 @Cd값에 누적시켜주어 서로 색깔들이 중첩이 되게끔 만든다.
}
아래 CGWiki님께서 쓰신 코드를 해석하기 위해 복사 붙여넣기 하고 옆에 설명 코멘트들을 작성해주었다.
int pts[]; // integer array variable pts선언
int pt; // array안에 들어있는 각각의 정보를 대변해 주기 위한 integer variable pt선언
vector col,pos; // 1번 인풋 geometry에서의 color값과 position값을 불러오기 위한 vector variables을 미리 선언
float d; // 0번 인풋 geometry에서 1번 인풋 geometry에서 까지 가장 가까운 거리 길이값을 저장해줄 float variable d 선언
/* 0번 인풋 geometry에서 부터 1번 인풋 geometry를 구성하는 점들까지 가장 가까운 점들을 반경 20안에서 모두
찾아주어라*/
pts = nearpoints(1,@P,20);
// treat this as ink on paper, so start with white paper
@Cd = 1; // 효과를 종이위의 잉크처럼 표현하기 위해 grid를 흰색으로 지정
foreach(pt; pts) { // integer array variable pts의 모든 값들에 대해
/* 1번 인풋 geometry에서 pt값에 해당되는 포인트 넘버를 가진 포인트들의 포지션 값들을 불러와
vector variable pos에 저장하고*/
pos = point(1,'P',pt);
/* 1번 인풋 geometry에서 pt값에 해당되는 포인트 넘버를 가진 포인트들의 컬러 값들을 불러와
vector variable col에 저장한다*/
col = point(1,'Cd',pt);
/* 0번 인풋 geometry를 구성하는 모든 포인트들로부터 각각의 가장 가까운 1번 인풋 geometry의 점들까지의
거리 길이들을 float variable d값에 저장해라*/
d = distance(@P,pos);
/* fit()으로 거리값의 최대값을 파라미터 radius로 조절 가능하게 하고
거리 Range값을 0에서 1까지로 맞추어준다*/
d = fit(d,0,ch('radius'),0,1);
// adjust the ramp so its mostly 0,
// then suddenly 1 at the end
/* range값이 0에서 1까지로 맞추어졌으므로 chramp()을 활용하여 range안에 있는 수치에 따라 효과의 모양과
세기가 조절될 수 있게 한다*/
d = chramp('fade',d);
// lerp is interpolate. we use d to make the colour
// mostly the point colour, the quickly fade to white
// at the radius border
/* 지금까지 fit()을 사용하여 range를 뒤집어
효과의 컬러값이 안쪽으로 갈수록 진해지고 바깥으로 갈수록 옅어지게끔 만들어주었는데
여기서는 lerp을 사용하여 동일한 효과를 내보았다*/
col = lerp(col,1,d);
// multiply the colour
// 모든 효과값을 @Cd에 곱해서 컬러값으로 표현하였다
@Cd *= col;
}
가장 큰 차이점은 CGWiki님과 다르게 twa님의 코드는 chramp를 사용해서 0에서 1까지의 range로 잡아두지 않았고 lerp()를 사용하지도 않았다. 내가 계속 시도하면서 @Cd값에 col값을 더해줬을때와 곱해줬을때 어떤 차이점이 나타나는지 계속 실험을 시도해보았지만 더하기를할때 컬러값이 너무 커져 색깔이 보이지 않았다는것을 제외하고는 큰 차이점을 찾기가 너무 어려웠다. CGWiki님이 굳이 색깔값을 더하기와 곱하기에서 할때 나타나는 차이점에 대해 설명해보라고 요구하지는 않았지만 막상 내가 시도해보려고 할때 너무 어려웠다. 그래도 곱하기를 하면서 나타나는 장점은 chramp()으로써 더욱 radius border의 선명함을 더욱 조절할 수 있었다.
이해가 안되었던 부분:
- 1번 exercise에서 어떻게 가장 파형에서 가장 높은 포인트들과 가장 낮은 포인트들의 색상을 따로 딱 지정해주었을지 이해가 되지 않았다. 그리고 이번 시간에 배운 부분들이 loop 반복문인데 이를 사용하여 식을 써어야 할지 아니면 조건문인지 아니면 아예 다른 방식인지 어떠한 방식으로 풀어야 할지에 대해 감을 잡기가 쉽지 않았다.
- 3번 exercise에서 CGWiki님이 작성한 코드를 대충 해석하는데는 성공하였지만 CGWiki님이 문제에서 언급했던 것처럼 컬러의 중첩이 이루어질때 더하기가 아닌 곱셈으로 적용시키기 위해 새롭게 만든 코드에 대해 덧셈과 비교했을때 어떠한 차이를 가지는지 이해가 쉽지 않았다. 왜 덧셈으로 계산되면 @Cd의 값이 커지는지 그리고 제대로 radius에 따라 컬러의 반경 값이 조절되지 않는지 이해가 되지 않았다.
공부하면서 들었던 생각:
드디어 foreach 와 for loop을 마치며 반복문을 완전히 배웠다. 다행히도 학교에서 배웠던 코딩 문법들이 이번에 내 머릿속에 충분히 이해되는데 많은 기여를 한 것 같다. 반복문을 배우며 안 사실은 코드를 이렇게 간략히 써질 수 있구나 라는 생각이었다. 중첩을 할때 특히 array를 이용하였을때 너무 복사 붙여넣기가 많아 이렇게 vex를 쓰다간 후디니가 터질 수 도 있겠다라는 생각이 들었지만 반복문을 통해 이러한 걱정을 덜게 되어서 기분이 좋다. 드디어 13일차를 돌파하고 나니 이제 20일 마스터하기까지 얼마 남지 않았다는 생각이 든다. 차근 차근 꾸준히 나아가다 보면 드디어 언젠간 조이오브벡스를 끝낼 수 있다는 생각이 설레게 만든다. 또한 이번 exercises가 생각보다 어려워 잘 풀어지지 않아 속상하지만 복습일기를 작성할때 다시한번 시도해보아 꼭 답을 찾아야 겠다는 생각이 든다.
'FX > Houdini_Joy of VEX' 카테고리의 다른 글
Joy of Vex - Day 14: creating geometry, deleting geometry, debugging vex (0) | 2022.07.20 |
---|---|
Joy of Vex - Recap of Week 4 (0) | 2022.07.18 |
Joy of Vex - Day 12-3: nearpoints, arrays (0) | 2022.07.16 |
Joy of Vex - Day 12-2: overlapping effect (0) | 2022.07.13 |
Joy of Vex - Day 12-1: ripple effect (0) | 2022.07.13 |