Затерянная документация или transform: matrix3d [перевод]

  • Tutorial
Когда погружаешься в документацию о CSS3 transform: matrix3d, находишь короткое определение «Задает 3D трансформацию как матрицу 4х4.», сопровождаемое определением функции в виде:

matrix3d(m00, m01, m02, m03,
m10, m11, m12, m13,
m20, m21, m22, m23,
m30, m31, m31, m33)


И если не являешься Богом математики, скорее всего, внутри возникает беспокойство о недостатке документации, за которым следует вопрос, как создать по-настоящему крутую штуку? Описанный подход не претендует называться математическим или полным — я всего лишь пытаюсь заполнить маленькую брешь документации.

демо | первоисточник

Немного линейной алгебры


Всякая комплексная трансформация может быть представленна тремя базовыми:

Поворот (rotate)
Масштабирование (scale)
Перемещение (translate)

Эти 3 базовых преобразования могут быть совмещены в одну огромную всеобъемлющую матрицу трансформации. Пока все просто, но как перейти от 3 базовых этапов к тому необузданному списку параметров, который нужен для matrix3d? Давайте начнем с самой простой матрицы в математике (чтобы упростить себе жизнь я использую Sylvester для математических операций с матрицами).

Единичная матрица

image

Эта матрица не делает ничего! Nil! Null! Nada! Ни один пиксель не пострадал! Я разделил эту матрицу на 2 секции. Красная секция это область где описываются Поворот (Rotate) и Масштабирование (Scale). В желтой секции описывается cдвиг или перемещение (translate). Остальные параметры используются очень редко, за исключением понастоящему странных FX демок в LSD стиле.

Мы начнем созданием матрицы масштабирования, умножив единичную матрицу на коэффициент масштабирования.
scaleMatrix = indentityMatrix.multiply(s)

Матрица масштабирования

scaleMatrix = $M([
[s,0,0,0],
[0,s,0,0],
[0,0,s,0],
[0,0,0,s]
])

Так как мы не хотим трансформировать координаты перемещения (translate), давайте заменим последний параметр масштабирования на 1:

scaleMatrix = $M([
[s,0,0,0],
[0,s,0,0],
[0,0,s,0],
[0,0,0,1]
])

Матрицы поворота (Rotate)


Поворот может осуществляться вокруг собственной оси X, Y, Z на заданный угол. Давайте примем значения углов для каждой оси как a, b, c. Соотвествующие матрицы, представляющие такую трансформацию:

rotationXMatrix = $M([
[1,0,0,0],
[0,Math.cos(a), Math.sin(-a), 0],
[0,Math.sin(a), Math.cos( a), 0],
[0,0,0,1]
])

rotationYMatrix = $M([
[Math.cos( b), 0, Math.sin(b),0],
[0,1,0,0],
[Math.sin(-b), 0, Math.cos(b), 0],
[0,0,0,1]
])

rotationZMatrix = $M([
[Math.cos( c), Math.sin(-c), 0, 0],
[Math.sin( c), Math.cos( c), 0, 0],
[0,0,1,0],
[0,0,0,1]
])

Каждая матрица описывает поворот вокруг одной оси.

Матрица перемещения (translate)

translationMatrix = $M([
[1,0,0,0],
[0,1,0,0],
[0,0,1,0],
[tx,ty,tz,1]
])

Матрица перемещения не затрагивает большенство пикселей, но добавляет значения tx, ty и tz к результирующему вектору направления.

Веселье


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

tM = rotationXMatrix
.x(rotationYMatrix)
.x(rotationZMatrix)
.x(scaleMatrix)
.x(translationMatrix)

И в конце применим трансформацию к изображению:
s = «matrix3d(»
s += tM.e(1,1).toFixed(10) + "," + tM.e(1,2).toFixed(10) + "," + tM.e(1,3).toFixed(10) + "," + tM.e(1,4).toFixed(10) + ","
s += tM.e(2,1).toFixed(10) + "," + tM.e(2,2).toFixed(10) + "," + tM.e(2,3).toFixed(10) + "," + tM.e(2,4).toFixed(10) + ","
s += tM.e(3,1).toFixed(10) + "," + tM.e(3,2).toFixed(10) + "," + tM.e(3,3).toFixed(10) + "," + tM.e(3,4).toFixed(10) + ","
s += tM.e(4,1).toFixed(10) + "," + tM.e(4,2).toFixed(10) + "," + tM.e(4,3).toFixed(10) + "," + tM.e(4,4).toFixed(10)
s += ")"

document.getElementById('darth-vader').style['-webkit-transform'] = s

Предостережения


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

Второе — CSS не поддерживает научную форму числа (например 123е-15) в качестве параметров — поэтому нужно использовать toFixed(numberOfDigits) чтобы нормализовать их.

Среда разработки

Подход работает в -webkit- браузерах, таких как Chrome или Safari, Firefox 10+ и IE 10. Префиксы можно посмотреть здесь caniuse.com/transforms3d. Демо работает только в -webkit- и написанно на coffeescript который немного круче javascript — но скомплилированный код должен быть читабельным. Вы можете забрать весь урок и исходники на github.

Демо
Оригинал статьи
Facebook автора
Twitter автора
Потрясающая Javascript библиотека Sylvester
Статья о линейных трансформациях на Wikipedia
  • +8
  • 17.8k
  • 7
Share post
AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 7

    0
    Вращение вокруг произвольной оси добавьте (задаётся угол a и направление оси — x, y, z). Пользы от вращений вокруг координатных осей не так много.
      0
      спасибо! поправил
      +1
      1. Используйте топик-перевод.
      2. Актуальная спецификация: www.w3.org/TR/css3-transforms/ (2d и 3d объединили, кстати)
      3. В спецификации есть специальный раздел про матрицы: Mathematical Description of Transform Functions
      4. Как-то что ли неэтично приводить примеры, работающие только в webkit, если они могут работать и в других браузерах добавлением префиксов.
        0
        << Как-то что ли неэтично приводить примеры, работающие только в webkit, если они могут работать и в других браузерах добавлением префиксов.
        Почему? Наоборот, логично приводить примеры только в беспрефиксной форме. Всегда так делают, чтобы статью не захламлять.
          +1
          Я про пример в статье, который webkit-only, ну и по тексту встречается:
          document.getElementById('darth-vader').style['-webkit-transform'] = s
          0
          1. Пробовал не хватает кармы)
          2. Спасибо, почему-то потянуло на драфт. в первоисточнике ссылка на документацию Safari, поменял на свой страх и риск. developer.apple.com/library/safari/#documentation/appleapplications/reference/SafariCSSRef/Articles/Functions.html
          3. Спасибо!
          4. Поправил среду разработки, спасибо. Это ведь перевод, многое хотелось изменить, но хотелось сделать именно перевод.
          0
          Вопрос автору:
          У меня после применения матрицы перемещения дает какой-то странный поворот, в отличии от того же translate3d.
          И если я в translate3d пишу сдвиги в пикселях, то в матрицу приходится писать значения порядков на 8 меньше.
          Сэмпл jsbin.com/hezelifiwu/edit?js,output
          Что я делаю не так? :)

          Only users with full accounts can post comments. Log in, please.