Когда погружаешься в документацию о 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 для математических операций с матрицами).
Единичная матрица
Эта матрица не делает ничего! 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 который немного круче javascript — но скомплилированный код должен быть читабельным. Вы можете забрать весь урок и исходники на github.
Демо
Оригинал статьи
Facebook автора
Twitter автора
Потрясающая Javascript библиотека Sylvester
Статья о линейных трансформациях на Wikipedia
Автор: LegoMushroom