Как повернуть изображение - манипулирование пикселями холста?

Я использую getImageData и putImageData для рисования на холсте из буферного холста. Я использую эти методы, потому что у меня есть большое количество частиц, и они обеспечивают наилучшую производительность. Теперь я хотел бы добавить вращение частиц, но у меня с этим проблемы. Вот jsfiddle, который использует матрицу преобразования для вращения. Как вы можете видеть на картинке (или скрипке), в полученном изображении есть дыры, которых я ожидал от использования этой матрицы.

nx = ~~ (xx * Math.cos(angle) + yy * Math.sin(angle) + cx);
ny = ~~ (xx * Math.sin(angle) - yy * Math.cos(angle) + cy);

Но я не знаю, как сделать это лучше, особенно когда я ищу эффективное решение?


демонстрация jsfiddle

Изображение - квадрат после поворота (квадрат используется как простое тело):

квадрат после поворота


В настоящее время моя резервная копия представляет собой процедурно сгенерированную анимацию спрайтов, которая заранее подготовлена ​​со стандартными состояниями холста: сохранить -> перевести -> повернуть -> восстановить.

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


person Vico Lemp    schedule 24.03.2016    source источник
comment
Я быстро проверяю старые проекты, но сейчас я не уверен, как я с этим справился. Я знаю, что я пошел на какой-то компромисс и накачал производительность в какой-то другой области. Я думаю, что одна из вещей, которые я использовал, заключалась в том, чтобы просто пререндерить каждое новое процедурно созданное изображение в его собственный холст и использовать стандартную функцию поворота холста, чтобы получить все кадры, необходимые для анимации этого конкретного объекта. По сути, я подготовил спрайты на лету настолько заранее, насколько это было возможно, при этом убедившись, что уничтожаю другие спрайты, которые нельзя было переназначить.   -  person Vico Lemp    schedule 18.01.2017
comment
Все в порядке, я получал белые / пустые пиксели посередине и не знал, что делать, я не смог решить и удалил вращение из своей игры на холсте.   -  person eri0o    schedule 18.01.2017
comment
Что ж, я бы посоветовал вам просто использовать вращение холста. Это довольно эффективно, и если вы используете аппаратное ускорение, вы вообще его не почувствуете, если только не попадете в огромное количество спрайтов. Тем не менее, я бы сначала проверил, можете ли вы получить лучшие результаты с одним большим холстом и рутиной сохранения-транс-гнит-остатка или с несколькими меньшими только для каждого из ваших спрайтов - или, по крайней мере, с несколькими отдельными холстами для изображений разного размера - и вращение их там с той же процедурой, а затем просто рисование с этих холстов на ваш основной (я думаю, что холсты на изображение дали гораздо более быстрый результат).   -  person Vico Lemp    schedule 18.01.2017


Ответы (1)


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

введите здесь описание изображения

Здесь вы можете увидеть эффект. Желтые точки — это центры пикселя, которые находят «домашнее» местоположение пикселя (т. е. там, где будет находиться большая часть влияния). Затем вам нужно выяснить, какой процент ячейки этого пикселя (основная синяя/белая сетка) покрыт исходным пикселем (черный прямоугольник, окружающий желтую точку). Как только вы выясните влияние домашнего местоположения, вам нужно повторить этот процесс для 8 окружающих пикселей по отношению к текущему пикселю в исходном изображении. В вашем текущем коде вы используете верхний левый угол каждого пикселя, чтобы найти домашний пиксель для нового изображения. Вы должны использовать центр пикселя.

Поскольку несколько итераций могут повлиять на один и тот же пиксель, вам нужно будет вычислить преобразование в буфере, прежде чем рисовать его в окончательном изображении. Для пикселей в преобразовании, которые не полностью покрыты пикселями исходного изображения, определите процент покрытого пикселя и используйте его, чтобы повлиять на альфа-канал. Вам нужно будет позаботиться о том, чтобы при применении пикселей к конечному изображению вы учитывали альфа-часть и смешивали с тем, что уже есть.

person Nick Larsen    schedule 24.03.2016
comment
...ваша картинка стоит тысячи слов, хороший четкий ответ! - person markE; 24.03.2016
comment
Спасибо, я тоже думал об этом, хотя, я должен был больше подчеркнуть, что производительность здесь является ключевым моментом. Я использую 2D-холст, поэтому количество шагов/вычислений в этом случае значительно сокращает анимацию 10000 частиц. Но я все еще пытаюсь выяснить путь, который проходит, я думаю, наполовину по одной дороге и наполовину по другой ;-). В любом случае большое спасибо за то, что убедили меня в том, что эта точка зрения действительно поднимает моральный дух :-). - person Vico Lemp; 24.03.2016
comment
Если производительность является вашей главной заботой, я ожидаю, что встроенная функциональность (сохранить-›перевести-›повернуть-›восстановить) на самом деле будет самой быстрой, которую вы получите, потому что реализация встроенной функции не ограничиваются javascript и могут использовать аппаратные возможности. Конечно, есть несколько простых приемов, которые вы могли бы сделать, чтобы улучшить производительность, например. разрешите только N возможных углов поворота, а затем просто вставьте одно и то же повернутое изображение во все его разные места. Если у вас есть 10 000 разных изображений, вам придется попробовать другие вещи. - person Nick Larsen; 24.03.2016
comment
Да, я на самом деле делаю что-то подобное, как вы только что отметили, но когда я использую методы холста, как вы упомянули, я едва могу нарисовать несколько тысяч частиц с движением. Но я собираю все, что вы упомянули, и комбинирую это с чем-то еще, надеюсь, если это сработает, но я никогда раньше этого не делал, поэтому я упираюсь в стену больше, чем хотелось бы :-). Спасибо, я так благодарен за ваш совет. - person Vico Lemp; 24.03.2016