본문 바로가기

프로그래밍/clojure

Quil - 클로저로 그림 그리기 (Clojure Processing)

Processing

Processing은 인터랙티브 한 이미지와 애니메이션을 프로그래밍으로 제작할 수 있는 환경을 제공해 주는 오픈 소스 프로그래밍 언어입니다. Processing은 자바로 구현되었습니다. Processing은 캔버스에 스케칭하는 느낌과 흡사하다고 할 수 있습니다. 단지 캔버스에 그리는 도구가 붓이 아니라 프로그래밍일 뿐입니다. Processing을 이용하면 매우 쉽게 캔버스에 그림을 그릴 수 있고, 다양한 시각 효과들을 사용할 수 있어서 범용적으로 사용됩니다. 단지 예술을 목적으로 하는 아티스트가 사용할 수 도 있고, 이미지 프로세싱을 위해 사용될 수도 있고, 연구자가 데이터 시각화를 위해 사용할 수도 있습니다. Processing은 굉장히 간단할 뿐만 아니라 고급 기능들을 사용할 수 있고, OpenGL을 사용하기 때문에 속도도 빠릅니다. 또한 크로스 플랫폼이기 때문에 어떠한 플랫폼에서도 사용할 수 있고, 관련 라이브러리로 굉장히 많은 숫자가 있습니다. 또한 문서화도 잘되어 있어서 배우기도 어렵지 않습니다. 더 자세한 내용은 공식홈페이지를 참조하세요.


Quil

Quil은 Clojure를 사용하여 Processing을 사용할 수 있습니다. Quil의 공식홈페이지라고 할 수 있는 Github 페이지로 들어가 보면 어떤 여자가 붓을 들고 있고 붓에서 붉은 물감이 뚝뚝 떨어지는 그림이 있는데, 개발자의 취향이 좀 그로테스크한것 같습니다.(-.-) Quil에서는 Processing의 기능을 그대로 사용할 수 있습니다. 단지 기존의 Processing에서 언어가 Clojure로 바뀌었다고만 생각하면 될 것 같습니다. 하지만 기존의 Processing의 언어는 절차적 프로밍언어이기 때문에 다채로운 로직을 이용하여 구현해야 하는 반면, Clojure는 상태로 구현하기 때문에 Clojure 쪽의 코드가 더 깔끔해서 좋은것 같습니다.(개인적인 견해입니다.)

Processing 홈페이지에 있는 가장 첫번째 튜토리얼 코드를 Quil과 비교해 보도록 하겠습니다.

//Processing
void setup() {
  size(480, 120);
}

void draw() {
  if (mousePressed) {
    fill(0);
  } else {
    fill(255);
  }
  ellipse(mouseX, mouseY, 80, 80);
}

//Clojure
(defn draw []
  (if (boolean (mouse-state))
    (fill 0)
    (fill 255))
  (ellipse (mouse-x) (mouse-y) 80 80))

(defsketch example                
  :draw draw              
  :size [480 120])    

circles예제 코드로 그려지는 그림

개인적인 차이가 있겠지만 저는 순수하게 상태로만 표현할 수 있는 Clojure가 더 마음에 듭니다.

본격적으로 Quil을 시작해 보도록 하겠습니다. 일단 Clojure로 뭔가를 하려면 Lein이 필요합니다. Lein을 설치하는 방법은 다음 포스팅을 참고해 주세요.

http://edoli.tistory.com/entry/Lein과-함께-클로저-시작하기

Lein을 설치하였으면 lein new 이용하여 새로운 프로젝트를 생성해 줍니다. 새로운 프로젝트를 생성한 이후에 프로젝트의 project.clj 파일을 여러주시고 다음 의존 라이브러리에 [quil "1.6.0"] 를 추가해 주시면 됩니다. 

project.clj 파일에 quil 라이브러리를 추가한 모습

이제 quil를 사용할 준비가 완료되었습니다. 이제 첫번째 quil 코드를 작성해 봅시다. src/core.clj 파일을 열고 다음 코드를 넣어줍시다. (네임스페이스는 만드신 프로젝트의 네임스페이스를 사용하세요.)

(ns quil-test.core
  (:use quil.core))

(defn setup []
  (smooth)                          ;;Turn on anti-aliasing
  (frame-rate 1)                    ;;Set framerate to 1 FPS
  (background 200))                 ;;Set the background colour to
                                    ;;  a nice shade of grey.
(defn draw []
  (stroke (random 255))             ;;Set the stroke colour to a random grey
  (stroke-weight (random 10))       ;;Set the stroke thickness randomly
  (fill (random 255))               ;;Set the fill colour to a random grey

  (let [diam (random 100)           ;;Set the diameter to a value between 0 and 100
        x    (random (width))       ;;Set the x coord randomly within the sketch
        y    (random (height))]     ;;Set the y coord randomly within the sketch
    (ellipse x y diam diam)))       ;;Draw a circle at x y with the correct diameter

(defsketch example                  ;;Define a new sketch named example
  :title "Oh so many grey circles"  ;;Set the title of the sketch
  :setup setup                      ;;Specify the setup fn
  :draw draw                        ;;Specify the draw fn
  :size [323 200])                  ;;You struggle to beat the golden ratio

위의 예제 코드는 quil 메인 페이지에 있는 예제코드 입니다. 위의 예제 코드를 입력 하셨으면 이제 실행해 봅시다. 콘솔창을 키고 프로젝트 루트 디렉토리로 갑시다. 그리고 나서 lein repl를 입력하여 repl을 열어줍니다. repl를 열어주셨으면 (use 'quil-test.core) 를 입력해 줍니다. (quil-test.core 는 자기의 프로젝트의 네임스페이스에 맞게 바꿔서 입력해주세요.)


이제 아래와 같은 그림을 보실 수 있을 것입니다. 상큼한 원들이 하나씩 생겨나면서 20세기 추상주의 화가의 그림을 보는듯한 그림이 생겨나는 것을 확인할 수 있습니다.


circles20세기 추상주의 화가의 그림


Live Coding

여기서 조금만 더 나아가 보도록 하겠습니다. Clojure는 동적 언어이기 때문에 라이브 코딩이 가능합니다. 프로그램 실행중에 로직을 바꿀 수 있다는 것이지요. 어떻게 하면 라이브 코딩이 가능한지 해보도록 하겠습니다. 먼저 src/core.clj 파일을 다음과 같이 바꿔줍니다.

(ns quil-test.core
  (:use quil.core)
  (:require [quil-test.dynamic :as dynamic]))

(defsketch example                
  :title "Oh so many grey circles"
  :setup dynamic/setup           
  :draw dynamic/draw              
  :size [323 200])

그리고나서 src/dynamic.clj 파일을 생성해 주시고 dynamic.clj 파일안에 다음과 같은 코드를 입력해 줍니다.

(ns quil-test.dynamic
  (:use quil.core))

(defn setup []
  (smooth)
  (frame-rate 1)
  (background 200))

(defn draw []
  (stroke (random 255))
  (stroke-weight (random 10))
  (fill (random 255))

  (let [diam (random 100)
        x    (random (width))
        y    (random (height))]
    (ellipse x y diam diam)))

(use :reload 'quil-test.dynamic)

이제 준비가 완료되었습니다. 아까 처럼 lein repl 를 이용하여 repl를 열어주시고 (use 'quil-test.core) 를 입력해서 프로그램을 실행시킵니다. 여기까지 하면 위에서 한 것 똑같은 형태의 그림을 보게 되실 겁니다. 다른점은 이제부터 입니다. 현재 보시고 계신 창을 닫지 마시고, repl도 종료하지 마시고 아래의 가이드를 계속 따라가세요.

src/dynamic.clj 파일을 다음과 같이 고쳐줍시다.

(ns quil-test.dynamic
  (:use quil.core))

(defn setup []
  (smooth)
  (frame-rate 1)
  (background 200))

(defn draw []
  (stroke (random 255) (random 255) (random 255))
  (stroke-weight (random 10))
  (fill (random 255))

  (let [diam (random 100)
        x    (random (width))
        y    (random (height))]
    (ellipse x y diam diam)))

(use :reload 'quil-test.dynamic)

그리고 열려 있는 repl에 다음과 같이 입력해 줍니다. (use :reload 'quil-test.dynamic)

그러면 테두리색이 있는 원들이 나타나기 시작합니다. 이런식으로 런타임에 프로그램을 변환시킬 수 있습니다.


color circles변종 원형이 나타나기 시작했다!


런타임에 실시간으로 프로그램을 마음대로 변환할 수 있다는 것은 엄청난 장점입니다. 코드만으로는 결과물이 어떠한 모양이 될지 알기 어렵기 때문에 무수한 시도를 해볼 필요가 있습니다. 그것을 일일이 실행해야 한다면 어려운 일이 될 것입니다. 하지만 실시간으로 변환할 수 있다면 원하는 결과물을 훨씬 쉽게 만들 수 있습니다. 또 다른 장점도 있습니다. 실시간으로 프로그램을 변환할 수 있기 때문에 화가가 붓과 물감을 바꿔가며 그림을 그리듯 우리도 캔버스에 그림의 형태를 바꿔가면서 그릴 수 있습니다. 라이브 코딩 기능을 사용한다면 화가의 느낌과 굉장히 비슷해 집니다. 진짜로 코드 아티스트가 되어가는 느낌이라고 할까요?

라이브 코딩에 대한 내용을 동영상으로 보시고 싶으시다면 아래의 동영상을 참고하세요.

http://vimeo.com/40764210


마치며

Quil를 이용하면 Clojure를 사용하여 쉽게 그림을 그릴 수 있습니다. 또한 Quil은 파일의 Input, Output 도 지원하고 다양한 이미지 변환 기능도 제공하므로 이미지 프로세싱을 위한 툴로도 사용할 수 있습니다. 이번 포스팅에서는 Quil의 기능들에 대해 간략하게만 집고 넘어갔습니다. 다음에는 Quil의 기본적인 그리기 기능들에 대해 더욱 자세히 알아보도록 하겠습니다.


'프로그래밍 > clojure' 카테고리의 다른 글

Quil [2] 기본적인 스케치 기능들  (0) 2013.02.20
Lein과 함께 클로저 시작하기  (1) 2013.02.19