- PVSM.RU - https://www.pvsm.ru -

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

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

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

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

демо [2] | первоисточник [3]

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

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

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

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

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

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. Исходный код написанн на coffeescript [5] который немного круче javascript — но скомплилированный код должен быть читабельным. Вы можете забрать весь урок и исходники на github [6].

Демо [2]
Оригинал статьи [3]
Facebook автора [7]
Twitter автора [8]
Потрясающая Javascript библиотека Sylvester [4]
Статья о линейных трансформациях на Wikipedia [9]

Автор: LegoMushroom

Источник [10]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/css3/25475

Ссылки в тексте:

[1] в документацию: http://dev.w3.org/csswg/css3-3d-transforms/#transform-property

[2] демо: http://codepen.io/sol0mka/pen/AobkI

[3] первоисточник: http://9elements.com/html5demos/matrix3d/

[4] Sylvester: http://sylvester.jcoglan.com/

[5] coffeescript : http://coffeescript.org/

[6] github: https://github.com/9elements/Matrix3d-Tutorial

[7] Facebook автора: http://www.facebook.com/9elements

[8] Twitter автора: https://twitter.com/9elements

[9] Статья о линейных трансформациях на Wikipedia: http://en.wikipedia.org/wiki/Linear_transformation#Examples_of_linear_transformation_matrices

[10] Источник: http://habrahabr.ru/post/166751/