Statements and Comments
오늘은 지난주에 이어 processing의 구조에 대한 튜토리얼들을 살펴보자. 다시말하면 Processing은 프로그래밍 환경이다. 때문에 일반적으로 프로그래밍을 할 때 필요한 기능들을 갖추고 있어야하는 것이 당연하다. 다음의 튜토리얼은 아주 간단한 Processing의 코멘트와 스테이트먼트에 대한 이해를 돕기위한 예제이다.
코멘트의 박식은 여러가지가 있는데 c언어와 c++언어에서처럼 "/","/*","*","//"이 있고, python에서의 "#"가 있다. 프로세싱에서는 더블슬래쉬, "//"를 쓴다. 실행에 옮기기 위해서는 마침표를 찍어주어야하는데 이러한 마침표에 해당하는 것이 ";"이다. 예제를 살펴보자.
// The size function is a statement that tells the computer
// how large to make the window.
// Each function statement has zero or more parameters.
// Parameters are data passed into the function
// and used as values for specifying what the computer will do.
size(200, 200);
// The background function is a statement that tells the computer
// which color to make the background of the window
background(102);
Coordinates
모든 형태의 이미지를 포함한 shape은 프로세싱에서 표현될 때 위치를 갖는다. 물론 처음에 디스플레이될 캔버스의 크기를 지정해주고 그 안에서 그릴 모양들의 위치와 크기를 지정해 주면 되는 것이다. 이러한 일련의 과정을 이해하기 위해서는 먼저 "픽셀"이라는 것을 이해해야하는데 이는 디스플레이의 단위가 "픽셀"이가 때문이다. 아래의 예제에서 보이듯이 "size(200,200);"은 "x"축으로 200픽셀, "y"축으로 200픽셀인 캔버스를 나타낸다. 물론 사이즈를 선언하면 이에 해당하는 속성이 있는데 "width"와 "height"이다. 때문에 아래의 코드를 살펴보면 "point(width/2, height/2);"을 볼 수 있는데 이는 너비와 높이를 2로 나눈 위치에 점을 그리라는 코드이다. 이처럼 모든 형태의 모양과 이미지는 각기 고유의 위치를 지정해 주어야 캔버스에 표현된다. 이를 "Coordinate"라 한다.
// Sets the screen to be 200, 200, so the width of the window is 200 pixels
// and the height of the window is 200 pixels
size(200, 200);
background(0);
noFill();
stroke(255);
// The two parameters of the point() method each specify coordinates.
// This call to point() draws at the position [100, 100]
point(width/2, height/2);
// Draws to the position [100, 50]
point(width/2, height/4);
// It is also possible to specify a point with any parameter,
// but only coordinates on the screen are visible
point(60, 30);
point(60, 134);
point(160, 50);
point(280, -800);
point(201, 100);
// Coordinates are used for drawing all shapes, not just points.
// Parameters for different methods are used for different purposes.
// For example, the first two parameters to line() specify the coordinates of the
// first point and the second two parameters specify the second point
stroke(204);
line(0, 73, width, 73);
// The first two parameters to rect() are coordinates
// and the second two are the width and height
rect(110, 55, 40, 36);
Width and Height
아래의 예제는 "width"와 "height"의 변수를 이용한 예제이다. 간단한 코드로 fancy한 60년대 스타일의 디자인을 해보았다. 내용을 보면 순차적으로 20픽셀씩 증가하는 변수 "i"에 따라 수직, 수평선을 그리는 코드이다. 먼저 왼쪽 코너의 위치가 (0,0), 가로 200, 세로 10인 검은색 사각형을 그리면 다음에는 왼쪽코너가 (0,0)인 가로 10, 세로 200의 사각형을 그린다. 이렇게 차례로 위치(0,20),(20,0)...인 사각형을 그리면 아래와 같은 선의 반복이 있는 그래픽이 생성되게 되는 것이다.
size(200, 200);
background(127);
noStroke();
for(int i=0; i < height; i+=20) {
fill(0);
rect(0, i, width, 10);
fill(255);
rect(i, 0, 10, height);
}
Setup and Draw
아래의 예제는 프로세싱의 프로그래밍 구조가 어떤 것인지를 보이는 코드라 할 수 있다. 이제껏 단순한 스테이트먼트를 구사했는데 이번 예제에서는 자주 보게될 "void setup(){}"와 "void draw(){}"기능을 살펴보게 될 것이다.
// The statements in the setup() function
// execute once when the program begins
void setup() {
size(200, 200); // Size must be the first statement
stroke(255); // Set line drawing color to white
frameRate(30);
}
float y = 100;
// The statements in draw() are executed until the
// program is stopped. Each statement is executed in
// sequence and after the last line is read, the first
// line is executed again.
void draw() {
background(0); // Set the background to black
y = y - 1;
if (y < 0) {
y = height;
}
line(0, y, width, y);
}
No loop and loop
"noLoop()"기능은 단지 한번만 "draw()"기능을 실행한다. 반면에 "loop()"기능은 연속적으로 "draw()"기능을 수행한다. 아래의 예제들은 이러한 "noLoop()"과 "loop()"의 기능을 설명한다.
// The statements in the setup() function
// execute once when the program begins
void setup(){
size(200, 200); // Size should be the first statement
stroke(255); // Set line drawing color to white
frameRate(30);
noLoop();
}
float y = 100;
// The statements in draw() are executed until the
// program is stopped. Each statement is executed in
// sequence and after the last line is read, the first
// line is executed again.
void draw(){
background(0); // Set the background to black
y = y - 1;
if (y < 0) { y = height; }
line(0, y, width, y);
}
// The statements in the setup() function
// execute once when the program begins
void setup(){
size(200, 200); // Size should be the first statement
stroke(255); // Set stroke color to white
noLoop();
}
float y = 100;
// The statements in draw() are run until the
// program is stopped. Each statement is run in
// sequence and after the last line is read, the first
// line is run again.
void draw(){
background(0); // Set the background to black
line(0, y, width, y);
y = y - 1;
if (y < 0) {
y = height;
}
}
void mousePressed(){
loop();
}
Redraw
아래는 마우스를 클릭할 때마다 "redraw()"기능을 활성화시키는 코드예제이다.
// The statements in draw() are executed until the
// program is stopped. Each statement is executed in
// sequence and after the last line is read, the first
// line is executed again.
void draw()
{
background(0); // Set the background to black
y = y - 1;
if (y < 0) { y = height; }
line(0, y, width, y);
}
void mousePressed()
{
redraw();
}
How to write your own function
다음 예제는 어떻게 당신이 원하는 기능을 작성하는가에 대한 기본적인 예를 제시하고있다. "void drawTarget(int xloc, int yloc, int size, int num)"이하를 보면 반복적인 "ellipse"를 생성하는 기능을 갖는 "function"을 작성하였다. 따라서 "draw()"기능에 보면 아래에 작성한 기능을 불러오는 것을 볼 수 있다. "drawTarget(68, 34, 200, 10);"이것은 네개의 변수로 작동하는 기능이다. 반복적인 수행을 하기에 편하다. 예를 들자면 데이터변형이나 기본 도형의 반복 등 다양한 기능을 스스로 작성할 수 있다.
void setup(){
size(200, 200);
background(51);
noStroke();
smooth();
noLoop();
}
void draw(){
drawTarget(68, 34, 200, 10);
drawTarget(152, 16, 100, 3);
drawTarget(100, 144, 80, 5);
}
void drawTarget(int xloc, int yloc, int size, int num)
{
float grayvalues = 255/num;
float steps = size/num;
for(int i=0; i<num; i++) {
fill(i*grayvalues);
ellipse(xloc, yloc, size-i*steps, size-i*steps);
}
}
Recursion:재귀
프로그래밍을 하다보면Recursion이나 Recursive하다는 말을 자주 접할 수 있는데 아래의 예는 이러한 프로그래밍에 대한 예제라고 할 수 있다. Recursion이란 말그대로 재귀라는 것인데 자신스스로의 기능을 작업을 수행하는데 있어서 다시 불러내는 것이다. 이것 또한 반복적인 작업을 할 때 많이 쓰이는데 주로 복잡한 이미지를 수학적으로 재생할 때 많이 쓰인다. 아래의 코드를 보면 기능 "drawCircle()"기능 안에 "level"이 1이 될때까지 재귀적인 작업을 수행하도록 코드가 짜여져있다.
void setup(){
size(200, 200);
noStroke();
smooth();
noLoop();
}
void draw(){
drawCircle(126, 170, 6);
}
void drawCircle(int x, int radius, int level){
float tt = 126 * level/4.0;
fill(tt);
ellipse(x, 100, radius*2, radius*2);
if(level > 1) {
level = level - 1;
drawCircle(x - radius/2, radius/2, level);
drawCircle(x + radius/2, radius/2, level);
}
}
Recursion2:재귀2
아래의 예제 또한 재귀적인 기능의 수행의 예를 보인다. 위의 예제와 다른 점이라고 할 것은 "draw()"기능에서 쓰인 것이 아니라 "setup()"의 기능에서 쓰였다는 점이다. 이는 반복적으로 하드디스크에서 메모리로의 작업을 수행하는데 있어서 소위 "out of memory"의 에러를 피할 수 있는 좋은 방법일 수 있다. 다시 말하면 많은 이미지들을 메모리에 위치시키는 작업을 하는데 용이하다.
void setup(){
size(200, 200);
noStroke();
smooth();
drawCircle(100, 100, 80, 8);
}
void drawCircle(float x, float y, int radius, int level){
float tt = 126 * level/6.0;
fill(tt, 153);
ellipse(x, y, radius*2, radius*2);
if(level > 1) {
level = level - 1;
int num = int(random(2, 6));
for(int i=0; i<num; i++) {
float a = random(0, TWO_PI);
float nx = x + cos(a) * 6.0 * level;
float ny = y + sin(a) * 6.0 * level;
drawCircle(nx, ny, radius/2, level);
}
}
}
CreateGraphics
다음 예제는 "createGraphics()"를 통해 프로세싱의 그래픽 클래스인 PGraphics 클래스를 불러낸다. 이는 프로세싱의 메인 그래픽스이다. 이 기능을 사용하기 위해서는 그래픽스를 시작하기위한 "beginDraw()" method가 필요하고 끝내기위해서는 "endDraw()" method가 필요하다.
PGraphics pg;
void setup() {
size(200, 200);
pg = createGraphics(80, 80, P2D);
}
void draw() {
fill(0, 12);
rect(0, 0, width, height);
fill(255);
noStroke();
ellipse(mouseX, mouseY, 60, 60);
pg.beginDraw();
pg.background(102);
pg.noFill();
pg.stroke(255);
pg.ellipse(mouseX-60, mouseY-60, 60, 60);
pg.endDraw();
image(pg, 60, 60);
}