JavaScript를 사용하여 유사한 행렬의 가상 배경 만들기

때때로 나는 평소와 다른 일을 하고 현실을 도피하는 일을 해야 한다. 특히 도전적인 시기에 나쁜 소식이 많다.
현재의 가상 환경에서 나는 매우 멋있는 일은 나의 OBS 행렬과 유사한 가상 배경을 설정하는 것이라고 생각한다.내가 첫 번째 영화를 보고 프로그래밍을 시작한 이래로 (이 두 영화는 모두 아주 오래된 일이다.) 나는 이런 매트릭스 효과를 스스로 실현하고 싶어서 해 보기로 결정했다.
나는 자바스크립트를 나의 실현 언어로 선택했다. 왜냐하면 가시화 결과를 얻기 쉽기 때문이다. 나의 자바스크립트는 매우 낡아서 약간 복습해야 한다.
계속 읽지 않으려면 public Git Repository 로 이동하여 결과를 볼 수 있습니다.

첫 번째 시도: HTML 요소


나의 첫 번째 시도는 전혀 성능적인 고려가 없었고, 단지 자바스크립트의 애니메이션 기능을 이용하여 실험과 학습의 공간을 주었다.
나는 첫 번째 버전을 보완하지 못했다. 그것은 진실하고 거칠고 추악한 것이다. 나는 구글에서 검색, 시도, 탐색을 해서 매우 기쁘다.
첫 번째 시도
주요 문제 중 하나는 HTML 요소를 사용하여 입자 애니메이션을 설정하는 것입니다.이것은 매우 비싼 계산이지 좋은 선택이 아니다.하지만 이것은 나에게 좋은 첫걸음이다. 왜냐하면 나는 문제 분야와 언어에 관한 지식을 많이 배웠기 때문이다.

두 번째 시도: 캔버스 입자


다음 단계는 Canvas 요소와 2D 컨텍스트를 사용하는 것입니다.캔버스를 사용하면 HTML 요소와 모든 비용을 처리하지 않고... 캔버스에 직접 그릴 수 있습니다.
여러 MatrixChar 객체를 포함할 수 있는 클래스 MatrixRow를 만들었습니다. 각 객체는 직접 그리거나 구성할 수 있습니다.모든 Matrix Chars는 100% 불투명도로 시작하여 시간이 지날수록 희미해진다.
이 기술의 성능이 훨씬 좋아서 나는 크기, 속도 등 방면에서 임의화를 진행하였는데 결과가 매우 좋다.
function render(time) {
    context.fillStyle="#000000";
    context.fillRect(0, 0, wi, hi);

    matrixRows.forEach(mRow => {
        mRow.draw(context, time);
    });

    matrixRows = matrixRows.filter(elem => {return elem.chars.length > 0 || elem.curY < hi});

    if ( time - prev > 50 && matrixRows.length < maxRows ) {
        prev = time;
        matrixRows.push(new MatrixRow(Math.random()*wi-10));
    }
    requestAnimationFrame(render);
}

초 Attmept
그래서 사실 나는 입자계통해를 선택했다.문제는 입자(= 매트릭스 샤르)를 많이 처리해야 한다는 것이다. 때로는 한 번에 15000개를 처리해야 한다.
활약이 그다지 뛰어나지 않다.이것도 아마도 내 쪽에서 가장 좋은 실현이 아니기 때문일 것이다. 나는'진실'입자 시스템의 실현 방식이 다르다는 것을 안다.마찬가지로 메모리 라이브러리에서 녹슬고 불완전한 버전을 찾을 수 있다. 그럼에도 불구하고 그것은 나에게 내가 어디로 가고 싶은지에 대한 많은 지식을 가르쳐 주었다.
그 외에 결과가 완전히 매트릭스 효과와 같지는 않다.

세 번째 시도: 화포층 담입 담출


나의 세 번째 시도는 친애하는 친구 벤의 계발을 받은 것이다. 그는 나에게 계속 다른 불투명도로 모든 약간 보이는 문자를 그리지 말라고 건의했다. 나는 단지 새로운 Y 위치에서 모든 문자의 첫 번째'명중'을 그릴 수 있을 뿐, 매번 전체 장면에 투명한 검은색 직사각형을 그릴 수 있을 뿐이다.
"새"캐릭터가 가장 밝습니다. 장면을 그릴 때마다 이전 캐릭터에 검은색이 추가됩니다.
이렇게 하면 나는 유사한 효과에 도달할 수 있지만, 필요한 계산의 일부분만 진행할 수 있다.
나는 실제 매트릭스 효과처럼 보이기 위해 무대를 울타리화했다.문자는 격자에만 나타나서 중첩을 방지합니다.
function initCanvas(stage) {
    stage.width = wi;
    stage.height = hi;

    gridHorizontal = Math.floor(wi/(fontSize-6));
    gridVertical = Math.floor(hi/(fontSize));

    context.fillStyle="#000000";
    context.fillRect(0, 0, wi, hi);
}

function initChar() {
    var char = {
        x: (Math.floor(Math.random()*gridHorizontal)),
        y: 0,
        tickTime: Math.random()*50+50,
        lastTick: performance.now(),
        char: getRandomHexChar()
    }
    return char;
}
애니메이션을 더욱 재미있게 하기 위해 제가 하는 또 다른 일은 무작위로 그려진 문자의 밝기를 늘리는 것입니다.
function addBrightness( rgb, brightness ) {
    var multiplier = (100+brightness)/100;
    var result = {};
    result.r = rgb.r * multiplier;
    result.g = rgb.g * multiplier;
    result.b = rgb.b * multiplier;
    return result;
}
추적할 문자 그룹을 관리하는 매우 경제적인 방법을 찾았습니다. 매번 보이는 문자 (Y가 무대 높이보다 낮음) 로 새로운 그룹을 만드는 것이 아니라 그룹을 다시 구성하여 유효한 문자를 위로 이동하고 그룹에 남은 요소를 차단하는 것입니다.
var iOut = 0;
for ( var i = 0; i < chars.length; i++ ) {
        var c = chars[i];
        if ( c.y < gridVertical ) {
            chars[iOut++] = c;
        }
...
}
chars.length = iOut;
이것은 JavaScript에서 가능합니다. - 다른 언어에서는 그룹의 길이를 조작하기 어려울 수 있습니다.)
최종 렌더링 방법은 다음과 같습니다.
function render(time) {
    // Draw a transparent, black rect over everything
    // But not each time
    if ( time - prev > 50 ) {
        context.fillStyle="rgba(0,0,0,"+alphaMask+")";
        context.fillRect(0, 0, wi, hi);
        prev = time;
    }

    // Setup Context Font-Style
    context.font = 'bold 20px Consolas';
    context.textAlign = 'center';
    context.textBaseline = 'middle';

    var iOut = 0;
    for ( var i = 0; i < chars.length; i++ ) {
        var c = chars[i];
        if ( c.y < gridVertical ) { // If Char is still visible
            chars[iOut++] = c; // put it further-up in the array

            // Add a bit more random brightness to the char
            var color = addBrightness({r: 100, g:200, b:100}, Math.random()*70);
            context.fillStyle = "rgb("+color.r+","+color.g+","+color.b+")";
            context.fillText(c.char, c.x*(fontSize-6), c.y*(fontSize));

            // Only move one y-field down if the randomized TickTime is reached
            if ( time - c.lastTick > c.tickTime) {
                c.y++;
                c.lastTick = time;
                // New y-field means new Char, too
                c.char = getRandomHexChar();
            }
        }
    }
    chars.length = iOut; // Adjust array to new length. 
    //Every visible char is moved to a point before this, the rest is cut off

    var newChars = 0;
    while (chars.length < maxRunningChars && newChars < 3) {
        chars.push(initChar());
        newChars++;
    }

    requestAnimationFrame(render);
}
다시 한 번, 랜덤화를 많이 추가했습니다. 저는 maxRunningChars의 제한도 포함했습니다.
그러나 나는 현재의 최종 결과에 대해 매우 만족한다.
세 번 시도

OBS에 통합


OBS에서 가장 멋진 점은 브라우저 소스를 추가할 수 있다는 것입니다.그것이 있으면 나는 나의 Matrix 사이트를 직접 무대 위에 놓을 수 있다.

이것이 바로 시도 3의 실제 효과이다.

좋은 웹페이지 즐겨찾기