Transform matrix3d: matrix3d() — CSS: Cascading Style Sheets

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

Когда погружаешься в документацию о 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, Firefox 10+ и IE 10. Префиксы можно посмотреть здесь caniuse.com/transforms3d. Демо работает только в -webkit- и написанно на coffeescript который немного круче javascript — но скомплилированный код должен быть читабельным. Вы можете забрать весь урок и исходники на github.

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

Метод Matrix3D.Transform (System.Windows.Media.Media3D) | Microsoft Узнайте

Редактировать

Твиттер LinkedIn Фейсбук Электронное письмо

  • Артикул

Определение

Пространство имен:
Система.Windows.Media.Media3D
Сборка:
PresentationCore.
dll

Важный

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

Преобразует указанный Point3D, массив объектов Point3D, Point4D, массив объектов Point4D, Vector3D или массив объектов Vector3D с помощью текущего Matrix3D.

Перегрузки

Преобразование (Point3D)

Преобразует указанный Point3D с помощью Matrix3D и возвращает результат.

Преобразовать(Точка3D[])

Преобразует указанные объекты Point3D в массив с помощью Matrix3D.

Преобразование (Point4D)

Преобразует указанный Point4D с помощью Matrix3D и возвращает результат.

Преобразование (Point4D [])

Преобразует указанные объекты Point4D в массиве с помощью Matrix3D и возвращает результат.

Преобразование (Vector3D)

Преобразует указанный Vector3D с помощью этого Matrix3D.

Преобразование (Vector3D [])

Преобразует указанные объекты Vector3D в массиве с помощью этого Matrix3D.

Преобразование (Point3D)

Преобразовать(Точка3D[])

Преобразование (Point4D)

Преобразование (Point4D [])

Преобразование (Vector3D)

Преобразование (Vector3D [])

Вычисление преобразований CSS matrix3d ​​

Я очищал некоторые старые заметки со своей предыдущей работы и нашел несколько математических каракулей для вычисления преобразований CSS и решил поделиться ими. Для некоторого контекста я работал над страницей с изображением, которое выглядело так:

Я хотел добавить пасхальное яйцо, где я мог бы использовать экраны этих устройств для отображения произвольных вещей.

Я думал, что это будет просто вопрос перемещения пикселей с помощью перевода/поворота/масштабирования/и т. д. с использованием преобразований CSS, но не смог добиться идеального выравнивания.

Разочарованный, я вместо этого попытался решить ее аналитически. Это означает, что для любой заданной формы мне нужно найти перспективное преобразование, которое деформирует элемент в эту форму. Как только это решено, легко написать вспомогательный скрипт WYSIWYG для вывода CSS. Вот окончательный результат:

См. Pen ifnqH Франклина Та (@fta) на CodePen.

См. код на вкладке coffeescript. Или вставьте этот текст в консоль, чтобы попробовать его на любой странице с jQuery. Вам нужно будет изменить селектор на любой элемент, к которому вы хотите добавить точки.

Используя это, вы можете перетаскивать предметы в любую форму (выпуклый четырехугольник):

Бла-бла-бла-бла-бла-бла-бла-бла-бла

В итоге я ни для чего не использовал это, но надеюсь, что кому-то еще это покажется полезным!

В оставшейся части этого поста будет объяснено, как получить уравнение для преобразования, так как я помню, что тогда я не смог найти много об этом. Глядя на код, вы увидите, что основная логика состоит всего из нескольких строк для настройки и решения системы линейных уравнений. Теперь мы увидим, как вывести эту систему.

Допустим, у нас есть 4 угла элемента, который мы хотим преобразовать, \((x_i, y_i)\), где \(i \in {0, 1, 2, 3}\), и мы хотим сопоставить каждый \((x_i, y_i)\) к некоторому \((u_i, v_i)\). Согласно документам matrix3d, преобразование, которое мы хотим, представляет собой однородную матрицу, поэтому мы должны представлять каждую точку, используя однородные координаты. В однородных координатах точка \((x, y)\) представляется как \((k x, k y, k)\) для любого \(k \neq 0\). Например, \((3, 2, 1)\) и \((6, 4, 2)\) представляют точку \((3, 2)\).

Таким образом, матрица преобразования \(H\), которую мы хотим найти, должна удовлетворять

$$
\underbrace{
\begin{pmatrix}
h_0 & h_1 & h_2 \\
h_3 & h_4 & h_5 \\
h_6 & h_7 & h_8 \\
\end{pmatrix}
}_{H}
\begin{pmatrix}
x_i \\
y_i \\
1 \\
\end{pmatrix}
= k_i
\begin{ pmatrix}
u_i \\
v_i \\
1 \\
\end{pmatrix}
$$

для каждого \(i\), где известными являются \(x_i, y_i, u_i, v_i\).

Обратите внимание, что \(H\), удовлетворяющее этому требованию, не уникально. Например, вы можете масштабировать \(H\) на некоторую константу, и результирующая матрица по-прежнему будет правильно отображать точки (поскольку вы также можете масштабировать \(k_i\) на ту же величину и по-прежнему представлять ту же однородную точку). Таким образом, предполагая \(h_8 \neq 0\) (см. сноску [1] ), мы всегда должны иметь возможность масштабировать обе стороны до \(h_8 = 1\), что немного упростит нам задачу:

$$
\begin{pmatrix}
h_0 & h_1 & h_2 \\
h_3 & h_4 & h_5 \\
h_6 & h_7 & 1 \\
\end{pmatrix}
\begin{pmatrix}
x_i \\
y_i \\
1 \\
\ end{pmatrix}
= k_i
\begin{pmatrix}
u_i \\
v_i \\
1 \\
\end{pmatrix}
$$

Теперь мы должны попытаться привести его к виду, который мы можем решить . Умножая получаем:

$$
\begin{align*}
x_i h_0 + y_i h_1 + h_2 & = k_i u_i \\
x_i h_3 + y_i h_4 + h_5 & = k_i v_i \\
x_i h_6 + y_i h_7 + 1 & = k_i \\
\end{align*}
$$

От \(k_i\) можно избавиться, подставив его из третьего в первые два уравнения:

$ $
\begin{align*}
x_i h_0 + y_i h_1 + h_2 & = u_i x_i h_6 + u_i y_i h_7 + u_i \\
x_i h_3 + y_i h_4 + h_5 & = v_i x_i h_6 + v_i y_i h_7 + v_i \\
\end{align*}
$$

Помните, что мы пытаемся найти \(h_i\), поэтому мы должны попытаться разделить их:

$$
\begin{array}{rcccl}
x_i h_0 + y_i h_1 + h_2 & & — u_i x_i h_6 — u_i y_i h_7 = u_i \\
& x_i h_3 + y_i h_4 + h_5 & — v_i x_i h_6 — v_i y_i h_7 = v_i \\
\end{array}
$$

Что в матричной записи:

$$
\begin{pmatrix}
x_i & y_i & 1 & 0 & 0 & 0 & -u_i x_i & -u_i y_i \\
0 & 0 & 0 & x_i & y_i & 1 & -v_i x_i & -v_i y_i \\
\end{pmatrix}
\begin{pmatrix}
h_0 \\
h_1 \\
h_2 \\
h_3 \\
h_4 \\
h_5 \\
h_6 \\
h_7 \\
\end{pmatrix} = \begin{pmatrix}
u_i \\
v_i \\
\end{pmatrix}
$$

Поскольку у нас есть 4 таких отображения, мы можем записать их так:

$$
\begin{pmatrix}
x_0 & y_0 & 1 & 0 & 0 & 0 & -u_0 x_0 & -u_0 y_0 \ \
0 & 0 & 0 & x_0 & y_0 & 1 & -v_0 x_0 & -v_0 y_0 \\
x_1 & y_1 & 1 & 0 & 0 & 0 & -u_1 x_1 & -u_1 y_1 \\
0 & 0 & 0 & x_1 & y_1 & 1 & -v_1 x_1 & -v_1 y_1 \\
x_2 & y_2 & 1 & 0 & 0 & 0 & -u_2 x_2 & -u_2 y_2 \\
0 & 0 & 0 & x_2 & y_2 & 1 & -v_2 x_2 & -v_2 y_2 \\
x_3 & y_3 & 1 & 0 & 0 & 0 & -u_3 x_3 & -u_3 y_3 \\
0 & 0 & 0 & x_3 & y_3 & 1 & -v_3 x_3 & -v_3 y_3 \\
\end{pmatrix}
\begin{pmatrix}
h_0 \\
h_1 \\
h_2 \\
h_3 \
h_4 \
h_5 \
h_6 \
h_7 \
\ end{pmatrix} = \begin{pmatrix}
u_0 \
v_0 \
u_1 \
v_1 \ 901 \\
v_2 \\
u_3 \\
v_3 \\
\end{pmatrix}
$$

На этом мы закончили, потому что это в форме \(Ah = b\), так что мы можем просто бросить это в библиотека матричной алгебры для решения \(h\). Он должен выдать \(h_i\), что позволит нам восстановить желаемое преобразование:

$$
H =
\begin{pmatrix}
h_0 & h_1 & h_2 \\
h_3 & h_4 & h_5 \\
h_6 & h_7 & h_8 \\
\end{pmatrix}
$$

Последняя проблема заключается в том, что matrix3d ​​фактически принимает матрица 4 на 4, а не 3 на 3. Поскольку нам не нужны значения \(z\) (поскольку все наши точки находятся в одной плоскости, \(z=0\)) мы можем просто сделать \( z\) отображать обратно на себя. Вот так:

\[
\begin{pmatrix}
h_0 & h_1 & 0 & h_2 \\
h_3 & h_4 & 0 & h_5 \\
0 & 0 & 1 & 0 \\
h_6 & h_7 & 0 & h_8 \\
\end{pmatrix}
\]

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

Когда я впервые сделал это, я не знал, что искать в Google, поэтому мне пришлось выводить это вручную.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *