자바스크립트 생성기로 생성 예술 만들기

경력 프로그래밍 및 관리 작업 외에도 자유 시간을 창의적인 코딩에 사용합니다. 대부분은 programming music with SuperCollider이지만 최근에는 시각 예술에도 참여했습니다.

초기 프로젝트 구조



이 프로젝트의 기본 아이디어는 색상을 서로 무작위로 변형하여 색상 간의 관계를 연구하는 것입니다. 이를 수행하는 프로그램은 색상 및 프레임 실행 수인 프로그램 프레임의 배열입니다. 초기 반복에서 어레이의 용량은 5입니다.

function generateProgram() {
    var numberOfFrames = 500;
    var numberOfIterations = 5000;
    var previousIteration = 0;
    var program = [];
    for (var i = 0; i < numberOfFrames; i++) {
        var currentIteration = randomInt(numberOfIterations) + previousIteration;
        program[i] = {
            color: randomHsl(),
            latestIteration: currentIteration
        }
        previousIteration = currentIteration;
    }
    return program;
}


RGB의 임의 색상이 매우 유사하게 보이고 결과가 미학적으로 만족스럽지 않기 때문에 HSL 형식으로 색상을 생성합니다.

프로그램 실행은 캔버스에서 몇 개의 임의 지점을 선택하고 현재 프로그램 프레임의 색상과 혼합하는 무한 루프입니다. 목표 반복 횟수에 도달하면 다음 프로그램 프레임으로 전환합니다.

function executeProgram(program) {
    var points = getInitialCanvas(program);
    drawOnCanvas(points);
    var iteration = 0;
    var currentProgramFrameIndex = 0;
    var currentProgramFrame = program[currentProgramFrameIndex];
    function run() {
        setTimeout(function() {
            for (var k = 0; k < 10; k++) {
                window.requestAnimationFrame(run);
                iteration++;
                var i = randomInt(height)-1;
                var j = randomInt(width)-1;
                points[i][j] = blendColors(points[i][j], currentProgramFrame.color);
                if (iteration == currentProgramFrame.latestIteration
                        && currentProgramFrameIndex !== program.length - 1) {
                    currentProgramFrameIndex++;
                    currentProgramFrame = program[currentProgramFrameIndex];
                }
                drawPointOnCanvas(i, j, points[i][j]);
            }
        }, 1);
    }
    run();
}


window.requestAnimationFrame 메서드를 사용하여 애니메이션을 예약하도록 브라우저에 지시하고 있음을 관찰할 수 있습니다. 이 메서드는 애니메이션을 그릴 시간이 되었을 때 실행될 콜백을 받아들입니다. 따라서 run 메서드를 콜백으로 호출하여 효과적으로 무한 루프를 생성하고 있습니다.

무한 루프가 캔버스 다시 그리기를 차단하지 않도록 하기 위해 setTimeout 함수 내에서 각 반복을 호출합니다.

생성기 사용



이 접근 방식의 명백한 단점은 프레임 수가 제한되어 있다는 것입니다. 대신 애니메이션이 영원히 지속되기를 원합니다. 가능한 방법 중 하나는 generators을 통해 각각의 새 프로그램 프레임을 제공하는 것입니다.

변경 사항은 매우 간단합니다. 프로그램을 프레임 배열로 생성하는 대신 요청 시 새 프레임을 반환하는 생성기 함수를 정의합니다.

function* generateProgram()  {
    while (true) {
        var numberOfIterations = 5000;
        var program = [];
        var currentIteration = randomInt(numberOfIterations)
        program = {
            color: randomHsl(),
            latestIteration: currentIteration
        }
        previousIteration = currentIteration;
        yield program;
    }
}


프레임을 요청하기 위해 함수를 호출한 다음 next 메서드를 호출하여 생성기 개체를 인스턴스화합니다.

var programGenerator = generateProgram()
var program = programGenerator.next().value;


이제 이전 프로그램이 완료되면 각 프로그램 프레임을 요청할 수 있습니다.

function executeProgram(program) {
    var points = getInitialCanvas(program);
    drawOnCanvas(points);
    var iteration = 0;
    function run() {
        setTimeout(function() {
            for (var k = 0; k < 10; k++) {
                window.requestAnimationFrame(run);
                iteration++;
                var i = randomInt(height)-1;
                var j = randomInt(width)-1;
                points[i][j] = blendColors(points[i][j], program.color);
                if (iteration == program.latestIteration) {
                    program = programGenerator.next().value
                }
                drawPointOnCanvas(i, j, points[i][j]);
            }
        }, 1);
    }
    run();

}


참고: 메모리 누수 수정



이 프로그램에 충분히 오랫동안 주의를 기울이면 점점 더 많은 메모리를 소비하기 시작한다는 것을 알 수 있습니다.

내 Firefox devtools에서 메모리 프로필을 검사하면 기본 할당 소스가 setTimeout 기능임을 알 수 있습니다.


requestAnimationFrame에 대한 호출이 map of animation frame callbacks에 누적되는 것으로 나타났습니다. 그리고 브라우저가 콜백 맵의 성장을 따라가지 못하면 크기가 커지기 시작하여 점점 더 많은 메모리를 소비합니다.

따라서 해결 방법은 제한 시간을 늘리는 것만큼 간단합니다.

좋은 웹페이지 즐겨찾기