Задать вопрос

Как сделать эффект текста на кривой безье?

Добрый день!
Я хочу сделать возможность добавлять приведенный ниже эффект для текста (использую html canvas для графики).
676bcaabb25df869104502.png
Писать буду сам, без использования внешних библиотек. Я научался рисовать сплайн из двух плавно соединенных кривых безье. Теперь пытаюсь разобраться какая математика стоит за таким эффектом текста на ленте.
Буду благодарен за помощь.
  • Вопрос задан
  • 419 просмотров
Подписаться 5 Сложный 7 комментариев
Пригласить эксперта
Ответы на вопрос 2
hint000
@hint000
у админа три руки
Нужно понять два возможных пути. Растровая деформация букв и векторная деформация. Векторная представляется мне настолько сложнее растровой (раз в сто), что даже не хочется думать о возможной её реализации (хотя результат может стоить таких усилий).

Растровый вариант довольно очевидный: кривая должна быть выражена в параметрической форме (x=x(t), y=y(t)); нарисуем букву без деформации в буфер (массив пикселей), затем будем пробегать такие значения t, чтобы (приблизительно) попадать в x(t)=n, n+1, n+2, n+3,.. Одновременно будем получать некие значения y(t).
Для t1 копируем первый столбец пикселей из буфера в позицию int(x(t1)), int(y(t1)).
Для t2 копируем второй столбец пикселей из буфера в позицию int(x(t2)), int(y(t2)).
И т.д.
Ещё раз подчеркну условие: нужно, чтобы x(t1), x(t2), и т.д. отличались приблизительно (с желаемой точностью) на единицу (в любую сторону), этого нетрудно добиться, уменьшая шаг t. Так мы будем каждый раз продвигаться на 1 пиксель по горизонтали вправо или влево.
Т.е. вы просто копируете столбики пикселей, и каждый из столбиков может быть смещён относительно предыдущего. Можно не только текст, но и любую растровую картинку так деформировать.
Ответ написан
sfi0zy
@sfi0zy
Creative frontend developer
На картинках мы видим эффект, в котором есть только вертикальные смещения букв по ходу движения. Нет никаких поворотов, растяжений, и.т.д. Только сдвиг по одной оси. Это упрощает задачу, сводя ее суть к описанному в соседнем ответе, но дальше вы там куда-то ушли в сторону трансформаций и горы масок. Это все сложно для восприятия и производительность будет оставлять желать лучшего. В контексте JS и 2D-канвасов можно пойти другим, более традиционным, путем:

  1. Определить разумную максимальную длину текста в пикселях.
  2. Сделать канвас этого размера, залить белым.
  3. Нарисовать на нем черный текст стандартным методом, чтобы он занимал 100% ширины. Подгонка текста по ширине - типовая задача, легко гуглится.
  4. Достать содержимое канваса в виде imageData. На этом этапе у нас есть текстура с нарисованным текстом.
  5. Сделать второй канвас, на котором пользователь работает. Залить белым.
  6. Достать его imageData или создать новую под его размер.
  7. Взять кривую в формате x(t), y(t). Пройти циклом по t. Разумный шаг определяется в зависимости от длины кривой на канвасе, он должен давать смещение не больше 1 по x. Для абсолютной надежности можно сделать шаг меньше, и на каждой итерации проверять, сместились ли мы. Своего рода трассировка луча по кривой.
  8. Сопоставить диапазон t и координату u в текстуре с текстом. Проход по t должен логически соответствовать проходу по горизонтали по всей текстуре.
  9. На каждой итерации цикла взять столбец из imageData текстуры с текущим u, скопировать его в imageData рабочего канваса по координатам x, y. Копируем не 1 в 1, а с учетом масштабирования, которое мы уже знаем из соотношений t и u, чтобы сохранить пропорции букв. С учетом наложений вероятно имеет смысл копировать только черное, не перекрашивая черное обратно в белое.
  10. Обновить imageData рабочего канваса.
  11. При обновлении данных повторять от п.6. Вероятно будет хорошей идеей не создавать imageData каждый раз заново, чтобы не перевыделять память под нее каждый раз.

Очевидно, что тут будут циклы в циклах, что тоже не идеально, хотя оверхед будет заметно меньше, чем у бесконечных вызовов штатных методов канваса для рисований текста и его обрезания. В целом для таких вещей можно было бы использовать webgl, чтобы происходящее с п.6 уже происходило в шейдерах и распараллеливалось. Но вполне вероятно, что и так сойдет.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы