HTML5 Canvas: элементы, нарисованные с / cached для drawImage, сглаживаются при масштабировании и / или перемещении - PullRequest
6 голосов
/ 07 декабря 2011

Я знаю о случае значений типа float / integer для drawImage 's x и y.Но мне нужна плавная анимация с возможностью кэширования моих фигур.

Например, я хочу нарисовать некоторую сложную фигуру (например, SVG-тигр, преобразованную в команды холста ) на холст всего один раз, а затем переместить ее плавно с помощью ctx.translate иctx.drawImage.Тогда мне нужны значения с плавающей точкой, потому что вместо этого я получаю пошаговое перемещение:

Вот примеры в JSFiddle:

  • One : быстрая скорость, с Math.floor, примененным к translate параметрам (x и y равны времени в секундах, умноженному на 10): анимация странная (последовательная, не плавная).
  • Two : медленная скорость с Math.floor, примененным к translate параметрам (x и y равны времени в секундах): анимация странная (последовательная, не плавная).
  • Три : быстрая скорость, без округления, значения с плавающей запятой (x и y равны времени в секундах, умноженному на 10).Скорость высокая, поэтому анимация выглядит хорошо.
  • Четыре : медленная скорость, без округления, значения с плавающей запятой (x и y равны времени всекунд).Скорость медленная, поэтому анимация выглядит пульсирующей . Почему?

Последний случай меня смущает.Я ошибаюсь в своих попытках и есть возможность заставить этот трюк кэширования работать хорошо?

В Firefox есть свойство canvas с именем mozImageSmoothingEnabled ( see ), но естьэто не поможет в других браузерах.И также удаляет сглаживание путей.

Извлечение кода:

var shapeCanvas = null;
var w = 320, h = 240;
var startTime = 0;

function start() {
    startTime = Date.now();
    var docCanvas = document.getElementById('canvas');
    . . .
    shapeCanvas = document.createElement('canvas');
    . . .
    drawShape(shapeCanvas.getContext('2d'));

    drawNext(docCanvas.getContext('2d'));
}

function drawNext(ctx) {
    var msec = (Date.now() - startTime);
    var time = msec / 1000; // seconds passed from start
    ctx.clearRect(0, 0, w, h);

    ctx.save();
    // the lines to change: time | (time * 10) | Math.floor(time * 10)
    ctx.translate((time < 500) ? Math.floor(time * 10) : 500,
                  (time < 500) ? Math.floor(time * 10) : 500);
    ctx.drawImage(shapeCanvas, 0, 0);
    ctx.restore();

    __nextFrame(function() {
       drawNext(ctx);
    });
}

function drawShape(ctx) {
    . . .
}

Ответы [ 2 ]

4 голосов
/ 02 февраля 2012

Я написал учебник по вашей первой ссылке.

Просто чтобы очистить воздух:

shapeCanvas.style.width = w + 'px';
shapeCanvas.style.height = h + 'px';

на самом деле не стоит делать. Нет смысла устанавливать стиль, если это просто холст в памяти, и вам не стоит устанавливать ширину и высоту стиль холста, он просто запутывает вещи.

То, что Эллисббен сказал в комментарии, в значительной степени соответствует тому, что происходит.

Бьюсь об заклад, можно обойти это несколькими хитрыми способами. Один из способов - убедиться, что он никогда не нарисован на целочисленном пикселе. Другим может быть использование ctx.scale(.99,.99) перед рисованием чего-либо, чтобы оно всегда было сглаженным. Здесь сложно получить согласованное решение, потому что разные реализации сглаживания в разных браузерах различаются.

Вот несколько экспериментов от меня:

http://jsfiddle.net/KYZYT/29/

Первые два - это фигура, нарисованная из холста, а также из PNG

Вторые два - это та же пара, но масштабированная на .99,.99

Последний из них настоящий. Это все еще немного размывает, но выглядит намного резче, чем при использовании изображений.

Ни один из моих экспериментов не привел к прекращению вашей пульсации, по крайней мере, на микроскопическом уровне. Я думаю, что это то, с чем вам придется смириться, если вы хотите анимировать пиксельно-совершенные изображения на полупиксельные пространства.

Если вы действительно чувствуете, что не можете просто рисовать на идеальных пикселях, то ваш (второй) лучший вариант для согласованности - это, вероятно, постоянно находить способ принудительного сглаживания. Убедиться, что вы всегда переводите в нецелое число или слегка его масштабировать, - достойные кандидаты, но могут быть и другие.

Если честно, лучше всего не кэшировать эти анимированные пути до тех пор, пока вам не понадобится их производительность. Кэшируйте стилизованные кнопки и другие статичные вещи, которые вы делаете, но если у вас есть анимированные контуры, которые нужно медленно и точно перемещать и выглядеть очень хорошо, вы могли бы также придерживаться верной вещи по поводу моей оптимизации кэширования, если вы не действительно он нужен и для тех.

2 голосов
/ 06 февраля 2012

Бит бесстыдный, но: я реализовал плавную анимацию в игровом автомате HTML5 с немного хакерским способом.Сгенерированное кэшированное изображение рисуется на небольшом холсте один раз, и затем я использовал translate3d () со стилями -moz-transform / -webkit-transform для холста, чтобы перемещать, зеркально отображать и масштабировать изображение вокруг.*

  1. Создание изображения
  2. Создание содержимого изображения
  3. Создание объекта холста в DOM

Фаза анимации

  1. Очиститьcanvas
  2. Рисование кэшированного изображения на канве
  3. Использование CSS3-преобразований (scale3d и translate3d) для перемещения холста.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...