Подтвердить что ты не робот

Почему изображения теряют качество после поворота контекста?

Я делаю шутер сверху вниз, который опирается на аватар, который всегда поворачивается, указывая на курсор мыши. Я достигаю поворота следующим образом:

//Rendering.
context.save(); //Save the context state, we're about to change it a lot.

context.translate(position[0] + picture.width/2, position[1] + picture.height/2); //Translate the context to the center of the image.
context.rotate(phi); //Rotate the context by the object phi.
context.drawImage(picture.image, -picture.width/2, -picture.height/2); //Draw the image at the appropriate position (center of the image = [0, 0]).

context.restore(); //Get the state back.

Когда значение phi равно нулю, изображение отображается в обычном качестве, с острыми краями и обнаруживаемыми пикселями. Но, когда я устанавливаю значение phi на ненулевое значение (фактически, когда оно не 0, Pi/2, Pi, Pi+Pi/2 или 2Pi), изображение теряет остроту, и отдельные пиксели могут больше не видно, потому что они размыты.

Вот скриншот (извините за общее плохое качество снимка экрана, но я думаю, что разница более чем заметна):

enter image description here

Это, ну, немного неприемлемо. Я не могу иметь изображения всегда размыты! Почему это происходит и могу ли я его решить?

4b9b3361

Ответ 1

Вы можете попробовать

context.imageSmoothingEnabled = false;

См. docs:

context.imageSmoothingEnabled [= значение]

Возвращает, будет ли шаблон заполняться, а метод drawImage() будет пытаться сгладить изображения, если им придется их перемасштабировать (в отличие от просто изображений с большими пикселями).

Можно установить, чтобы изменить, сглаживаются ли изображения (true) или нет (false).

Если вам нужен настоящий эффект ретро-стиля с пиксельным эффектом, вам нужно вручную создать повернутые изображения спрайтов на несколько углов, найдите соответствующий спрайт для текущего значения phi и нарисуйте его без вращения. Это, очевидно, требует значительного количества произведений искусства!

Ответ 2

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

Так что для любого изображения, как предложено выше, используйте округление, чтобы привязать к полному пикселю.

context.translate(Math.floor(img.width/2), Math.floor(img.height/2));

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

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

Согласно этому сообщению об ошибке Chromium, вам может повезти, если они еще не исправили его. Прочитайте, и вы узнаете, что Ян Хиксон, скорее всего, возражал против того, чтобы сглаживать рисование изображений необязательно.

Ответ 3

(picture.width/2, picture.height/2) точка не всегда будет работать.

(Math.floor(picture.width/2) + 0.5, Math.floor(picture.height/2) + 0.5) должен помочь.

Ответ 4

Ну, на самом деле это то, что вы не можете обойти

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

Но как только вы поворачиваете изображение на угол, отличный от кратного на 90 градусов, вам нужно интерполировать. Как следствие, вы получаете это сглаживание. Если вас интересует теория, вы можете искать книгу по компьютерной графике или обработке изображений.

Для конкретного случая вращения изображения вы можете взглянуть на эту статью, http://bigwww.epfl.ch/publications/unser9502.html

Ответ 5

Только совет: я не знаю, если вы просто изучаете Canvas programimg, но вы можете использовать ImpactJs, чтобы помочь вам построить ретро-игра.