시작은 짧은 영상 하나였다. 에이전트가 반 고흐의 밤 풍경을 따라 그리는 영상인데, 화면 아래 상태 줄을 보면 네 시간 동안 3만 7천 획쯤 그었다. 따라 그리기가 아니라 자기 그림을 그리게 하면 어떻게 될지, 그 장면을 서비스로 만들 수 있을지 확인해 보려고 PoC를 시작했다.
대부분의 AI 이미지 도구는 프린터처럼 동작한다. 그림을 설명하면 픽셀이 나온다. 여기서는 반대로 했다. 서비스는 캔버스 역할만 한다. 에이전트는 HTTP API로 들어와서 실제 도구로 획을 긋는다. 유화·아크릴·과슈용 강모 붓과 나이프, 안료 12색을 쓰는 수채 붓, 목탄·연필·파스텔이 있고, 헝겊·스펀지·빵·티슈로 그 위를 손본다. 이미지 업로드도, 채우기도, 픽셀 하나를 지정하는 명령도 없고 앞으로도 넣지 않는다.

같은 기록은 같은 그림이 된다
그림 한 점은 이벤트 기록이다. 붓에 물감을 묻히고, 획을 긋고, 노트를 남긴 순서가 NDJSON으로 쌓인다. 엔진은 결정적이다. 난수는 시드에서만 나오고 시계를 읽지 않는다. 물감이 마르는 것도 시간이 아니라 획 수를 기준으로 계산한다. 그래서 같은 기록을 Node와 Chromium·Firefox·WebKit에서 그리면 픽셀이 같고, 테스트는 그 해시를 비교한다.
이 성질 덕분에 다시 보기를 믿을 수 있다. 방문자가 보는 그리는 과정은 벽에 걸린 그림을 만든 과정과 같다. 대신 엔진을 고칠 때마다 옛 기록이 어떻게 그려지는지 관리해야 했다. 붓 종류를 넣으면서 기록 형식을 v2로 올렸는데, 그 전에 그린 v1 그림 네 점은 해시 그대로 다시 그려져야 했다. 지금은 형식 번호마다 기준 해시를 따로 두고 브라우저 세 개에서 대조한다.
물감 섞기는 직접 만들었다. 안료 혼합에 흔히 쓰는 라이브러리는 비상업 라이선스라 쓸 수 없었다.
붓은 털 묶음이다
붓은 털 여러 가닥의 묶음으로 계산하고, 털마다 물감을 따로 머금는다. 획을 그을수록 물감이 줄고, 모자라면 캔버스 천의 높은 결에만 묻어 끊긴다. 젖은 물감 위를 지나가면 아래 색을 집어 간다.
도구는 실제 화방 물건을 기준으로 골랐다. 처음 16개는 둥근 붓·평붓·필버트·부채붓·나이프였다. 그런데 그림 도구가 그보다 훨씬 많다는 이야기가 나왔다. 빵도 있지 않냐는 말에 목탄을 지우는 빵, 가루를 터는 깃털, 문지르는 섀미, 찰필을 넣어 31개가 됐다. 그 다음에는 재료를 넓혔다. 수채는 별도의 유체 시뮬레이션으로 돌린다. 안료 12색은 입자가 가라앉는지, 종이에 착색되는지가 각각 다르고, 마르면서 가장자리가 진해지고 꽃무늬처럼 번지고, 들어내기와 마스킹액도 된다. 목탄·파스텔은 물감 아래 마른 재료 층에 따로 쌓여서 빵으로 지우고 깃털로 털 수 있다. 먹과 한지는 넣지 않았다. 서양화 재료로만 범위를 잡았다.
작업실 화면 왼쪽에는 지금 쓰는 도구가 실물 사진으로 꽂혀 있다. 사진은 GPU 서버에서 투명 배경으로 만들고 붓끝 위치를 마스크로 표시해서, 붓에 물감이 묻으면 그 부분만 색이 바뀐다.



결함은 그림이 찾았다
엔진 작업은 대부분 명세보다 그림에서 출발했다. 단위 테스트가 다 통과해도 그림을 그려 보면 이상한 곳이 나왔다.
수채를 처음 연결하고 호숫가를 그려 봤다. 기술적으로는 다 동작했는데 그림은 벡터 일러스트처럼 보였다. 하늘과 물이 딱딱한 가로 띠로 나뉘었고, 워시 안은 단색 채우기 같았고, 넓게 적시면 위쪽부터 먼저 말랐다. 젖은 띠끼리 양방향으로 섞이게 하고, 워시 안에 농도 얼룩과 종이 울음을 넣고, 넓은 젖은 면은 천천히 마르게 고쳤다.
나이프 시험지에서는 산이 계단진 CG 피라미드처럼, 바위는 상자처럼 나왔다. 그림 전체가 금속을 두들겨 만든 양각처럼 번쩍였다. 요철에 비추는 조명이 너무 강했다. 갤러리 조명처럼 평평하고 무광인 조명으로 바꾸고 고친 정도를 숫자로 쟀다. 풍경 한 점에서 하늘 요철의 표준편차가 0.367에서 0.068로, 하늘 가운데 번쩍이는 면의 비율이 80.9%에서 1.3%로 줄었다. 그 대가로 전체 렌더 시간은 두 배쯤 늘었다.
젖은 바탕에 그리는 풍경 기법도 넣었다. 붓을 세로로 찍어 덤불을 만들고 가는 선으로 가지를 긋는 방식인데, 우리 엔진은 점을 하나씩 찍는 구조라 결과가 기계적이었다. 기록 형식을 v3로 올리고 붓 상태를 다시 설계했다. 붓이 물감을 획에서 획으로 들고 다니고, 쓸수록 더러워지고, 씻는 동작이 따로 있다. 끝에만 묻히거나 한쪽 모서리에만 묻힐 수 있고, 한 붓에 두 색을 묻힐 수도 있다. 묽은 물감, 붓 각도, 두드릴 때마다 다르게 갈라지는 털 뭉치도 넣었다. 유화는 한 세션 동안 계속 젖어 있다.

이 풍경을 그린 에이전트는 첫 165획을 캔버스 위에서 도구 시험에 썼다. 다시 보기를 틀면 초반 내내 시험 자국이 보였다. 그 뒤로는 도구 시험을 별도의 연습 캔버스에서 하게 했다.
스크립트로 찍은 2만 획도 그림인가
처음 그림 네 점은 에이전트가 명령줄 도구로 그렸다. 정물 20,243획, 인물 7,183획, 풍경 23,462획, 추상 826획이었고, 네 점 모두 획의 95~99.9%가 에이전트가 직접 짠 스크립트에서 나왔다. 그림은 나왔지만 질문이 하나 남았다. 위치를 조금씩 흔들어 가며 점 천 개를 뿌리는 반복문도 그리기라고 할 수 있을까.
래스터 이미지에서 획을 뽑는 것은 처음부터 막았다. 사진, 생성 이미지, 장면을 렌더해서 픽셀을 샘플링하는 방식 모두 해당한다. 거기에 간격이 고른 반복과 대량 생성 루프도 금지했다. 동작 하나를 긋고, 보고, 다시 정하는 방식으로 그려야 한다. 이 규칙으로 그린 다음 세 점은 수채 정물 378획, 인물 462획, 추상 110획이었다. 획 수는 스크립트로 그린 그림의 몇십 분의 일인데, 그림으로서는 이쪽이 더 읽혔다.

그날 저녁 방향이 하나 더 정해졌다. 구도와 채색이 단조롭다는 피드백이 나왔고, 결론은 서비스가 정하지 않는다는 쪽이었다. 서비스는 캔버스와 도구, 물감의 물리, 기록, 벽만 맡는다. 무엇을 어떻게 그릴지, 구도와 화풍은 화가 에이전트가 정한다. 그러면 바깥의 에이전트가 들어와 그릴 수 있어야 했고, 같은 날 그 입구를 만들었다. 다음 글에서 이어 쓴다.
