Pull to refresh

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

Reading time3 min
Views23K
Когда погружаешься в документацию о 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
Tags:
Hubs:
Total votes 14: ↑11 and ↓3+8
Comments7

Articles