Как объединить rotateX(50deg) rotateY(20deg) rotateZ(15deg)
в сокращении rotate3d()
?
стенография rotate3d
Ответы (4)
rotateX(50deg)
эквивалентно rotate3d(1, 0, 0, 50deg)
rotateY(20deg)
эквивалентно rotate3d(0, 1, 0, 20deg)
rotateZ(15deg)
эквивалентно rotate3d(0, 0, 1, 15deg)
So...
rotateX(50deg) rotateY(20deg) rotateZ(15deg)
эквивалентно
rotate3d(1, 0, 0, 50deg) rotate3d(0, 1, 0, 20deg) rotate3d(0, 0, 1, 15deg)
Для общего rotate3d(x, y, z, α)
у вас есть матрица
куда
Теперь вы получаете матрицы для каждого из 3 rotate3d
преобразований и перемножаете их. И результирующая матрица — это матрица, соответствующая результирующему одиночному rotate3d
. Не уверен, как легко извлечь из него значения для rotate3d
, но, безусловно, легко извлечь их для одного matrix3d
.
В первом случае (rotateX(50deg)
или rotate3d(1, 0, 0, 50deg)
) у вас есть:
x = 1
, y = 0
, z = 0
, α = 50deg
Итак, первая строка матрицы в данном случае 1 0 0 0
.
Второй - 0 cos(50deg) -sin(50deg) 0
.
Третий 0 sin(50deg) cos(50deg) 0
.
И четвертый, очевидно, 0 0 0 1
.
Во втором случае у вас есть x = 0
, y = 1
, z = 0
, α = 20deg
.
Первый ряд: cos(20deg) 0 sin(20deg) 0
.
Второй ряд: 0 1 0 0
.
Третий ряд: -sin(20) 0 cos(20deg) 0
.
Четвертый: 0 0 0 1
В третьем случае у вас есть x = 0
, y = 0
, z = 1
, α = 15deg
.
Первый ряд: cos(15deg) -sin(15deg) 0 0
.
Второй ряд sin(15deg) cos(15deg) 0 0
.
А третья и четвертая строки — 0 0 1 0
и 0 0 0 1
соответственно.
Примечание: вы могли заметить, что знаки значений sin для преобразования rotateY отличаются от знаков для двух других преобразований. Это не ошибка вычислений. Причина этого в том, что на экране ось Y направлена вниз, а не вверх.
Итак, это три матрицы 4x4
, которые вам нужно перемножить, чтобы получить матрицу 4x4
для результирующего одиночного преобразования rotate3d
. Как я уже сказал, я не уверен, насколько легко получить 4 значения, но 16 элементов в матрице 4x4 — это в точности 16 параметров matrix3d
эквивалента цепного преобразования.
ИЗМЕНИТЬ:
На самом деле, оказывается, это довольно просто... Вы вычисляете след (сумму диагональных элементов) матрицы для матрицы rotate3d
.
4 - 2*2*(1 - cos(α))/2 = 4 - 2*(1 - cos(α)) = 2 + 2*cos(α)
Затем вы вычисляете трассировку для произведения трех матриц 4x4
, приравниваете результат к 2 + 2*cos(α)
и извлекаете α
. Затем вы вычисляете x
, y
, z
.
В этом конкретном случае, если я правильно вычислил, след матрицы, полученной в результате произведения трех матриц 4x4
, будет:
T =
cos(20deg)*cos(15deg) +
cos(50deg)*cos(15deg) - sin(50deg)*sin(20deg)*cos(15deg) +
cos(50deg)*cos(20deg) +
1
Итак, cos(α) = (T - 2)/2 = T/2 - 1
означает, что α = acos(T/2 - 1)
.
[x,y,z]
нормализован, то есть только если длина вектора Math.sqrt(x*x + y*y + z*z)
равна единице. Если он не нормализован, его можно легко преобразовать в нормализованную, разделив каждый x
, y
и z
на их длину.
- person Jose Rui Santos; 02.02.2014
css
? matrix3d(1, 0, 0, 0, 0, 0.642788, -0.766044, 0, 0, 0.766044, 0.642788, 0, 0, 0, 0, 1)
jsfiddle.net/k35o1s27/1
- person Alvaro; 04.10.2016
1 0 0 0
) — это значения в 1-м столбце, следующие 4 (0, .642788, -.766044, 0
) — это значения во 2-м столбце и так далее. Здесь значения, которые вы указали, соответствуют ситуации rotateX
в моем ответе выше. .64
— это cos
вашего угла, -.76
— это sin
. Эти знаки помещают его между -90°
и 0°
. Вы можете получить точное значение с помощью α = Math.atan2(-.76, .64)
. Тогда у вас есть rotate3d(1, 0, 0, αrad)
. Или вы можете преобразовать α
в градусы: α *= 180/Math.PI
- person Ana; 03.11.2016
rotate3d(1,1,1,acos(T/2 - 1))
? Мне также любопытно, что происходит с такими значениями, как rotateX(180deg)
=)
- person thednp; 31.01.2020
Синтаксис:
rotate3d(x, y, z, a)
Ценности:
x
Является<number>
, описывающим x-координату вектора, обозначающего ось вращения.y
Является<number>
, описывающим координату y вектора, обозначающего ось вращения.z
Является<number>
, описывающим z-координату вектора, обозначающего ось вращения.a
Является<angle>
, представляющим угол поворота. Положительный угол обозначает вращение по часовой стрелке, отрицательный угол — против часовой стрелки.
Как в :
.will-distort{
transform:rotate3d(10, 10, 10, 45deg);
}
Дополнительные документы по этому поводу а>
rotate3d
, а не определение rotate3d
.
- person Ana; 04.03.2013
В зависимости от того, что вы пытаетесь сделать, этот «хак» может вам помочь. Допустим, вы делаете анимацию и хотите добавлять преобразование за преобразованием и так далее, и вы не хотите, чтобы CSS выглядел так, как будто он выполняет сотни преобразований:
Это работает в Chrome: 1. Примените любое преобразование, которое вы хотите, к элементу. 2. В следующий раз, когда вы захотите добавить преобразование, добавьте его к вычисляемому преобразованию: «window.getComputedStyle(element).transform» — но обязательно поместите новое преобразование слева. 3. Теперь ваше преобразование будет выглядеть как «rotateZ(30deg) matrix3d(......). 4. В следующий раз, когда вы захотите добавить еще одно преобразование, повторите процесс — Chrome всегда сокращает преобразование до обозначения matrix3d.
TL; DR- примените любые преобразования, которые вы хотите, а затем получите вычисленное преобразование matrix3d.
Этот трюк также позволяет вам быстро (то есть, не занимаясь математикой самостоятельно) создать функцию, которая вращает объект относительно вашей системы отсчета в любом направлении. См. образец ниже:
EDIT: я также добавил переводы xyz. Используя это, было бы очень легко размещать объекты в определенных трехмерных местах с учетом определенной ориентации. Или... представьте себе куб, который подпрыгивает и меняет свою ось вращения с каждым отскоком в зависимости от того, как он приземляется!
var boxContainer = document.querySelector('.translator'),
cube = document.getElementById('cube'),
optionsContainer = document.getElementById('options');
var dims = ['x', 'y', 'z'];
var currentTransform;
var currentTranslate;
var init = function () {
optionsContainer.querySelector('.xRotation input')
.addEventListener('input', function (event) {
if (currentTransform != 'none') {
var newTransform = 'rotateX(' + (360 - event.target.value) + 'deg) ' + currentTransform;
} else {
var newTransform = 'rotateX(' + (360 - event.target.value) + 'deg)';
}
cube.style.transform = newTransform;
}, false);
optionsContainer.querySelector('.yRotation input')
.addEventListener('input', function (event) {
if (currentTransform != 'none') {
var newTransform = 'rotateY(' + (360 - event.target.value) + 'deg) ' + currentTransform;
} else {
var newTransform = 'rotateY(' + (360 - event.target.value) + 'deg)';
}
cube.style.transform = newTransform;
}, false);
optionsContainer.querySelector('.zRotation input')
.addEventListener('input', function (event) {
if (currentTransform != 'none') {
var newTransform = 'rotateZ(' + (360 - event.target.value) + 'deg) ' + currentTransform;
} else {
var newTransform = 'rotateZ(' + (360 - event.target.value) + 'deg)';
}
cube.style.transform = newTransform;
}, false);
optionsContainer.querySelector('.xTranslation input')
.addEventListener('input', function (event) {
if (currentTranslate != 'none') {
var newTransform = 'translateX(' + (100 - event.target.value) + 'px) ' + currentTranslate;
} else {
var newTransform = 'translateX(' + (100 - event.target.value) + 'px)';
}
boxContainer.style.transform = newTransform;
}, false);
optionsContainer.querySelector('.yTranslation input')
.addEventListener('input', function (event) {
if (currentTranslate != 'none') {
var newTransform = 'translateY(' + (100 - event.target.value) + 'px) ' + currentTranslate;
} else {
var newTransform = 'translateY(' + (100 - event.target.value) + 'px)';
}
boxContainer.style.transform = newTransform;
}, false);
optionsContainer.querySelector('.zTranslation input')
.addEventListener('input', function (event) {
if (currentTranslate != 'none') {
var newTransform = 'translateZ(' + (500 - event.target.value) + 'px) ' + currentTranslate;
} else {
var newTransform = 'translateZ(' + (500 - event.target.value) + 'px)';
}
boxContainer.style.transform = newTransform;
}, false);
reset();
};
function reset() {
currentTransform = window.getComputedStyle(cube).transform;
currentTranslate = window.getComputedStyle(boxContainer).transform;
optionsContainer.querySelector('.xRotation input').value = 360;
optionsContainer.querySelector('.yRotation input').value = 360;
optionsContainer.querySelector('.zRotation input').value = 360;
optionsContainer.querySelector('.xTranslation input').value = 100;
optionsContainer.querySelector('.yTranslation input').value = 100;
optionsContainer.querySelector('.zTranslation input').value = 500;
}
window.addEventListener('DOMContentLoaded', init, false);
document.addEventListener('mouseup', reset, false);
.translator
{
height: 200px;
position: absolute;
width: 200px;
transform-style: preserve-3d;
}
.threeSpace
{
height: 200px;
moz-perspective: 1200px;
o-perspective: 1200px;
perspective: 200px;
position: absolute;
transform-origin: 50px 50px 100px;
webkit-perspective: 1200px;
width: 100px;
perspective-origin: 100px 25px;
transform-style: preserve-3d;
}
#pointer{
position:relative;
height:2px;
width:2px;
top:25px;
left:100px;
background:blue;
z-index:9999;
}
#cube
{
height: 100%;
moz-transform-origin: 90px 110px 0px;
moz-transform-style: preserve-3d;
o-transform-origin: 90px 110px 0px;
o-transform-style: preserve-3d;
position: absolute;
transform-origin: 90px 110px 0px;
transform-style: preserve-3d;
webkit-transform-origin: 90px 110px 0px;
webkit-transform-style: preserve-3d;
width: 100%;
}
#cube .midPoint{
position:absolute;
top:48px;
left:48px;
height:1px;
width:1px;
background:green;
}
#cube figure
{
border: 2px solid black;
color: white;
display: block;
font-size: 60px;
font-weight: bold;
height: 96px;
line-height: 96px;
position: absolute;
text-align: center;
width: 96px;
/* transform-style: preserve-3d; */
}
#cube .front
{
background: hsl(0, 100%, 50%);
}
#cube .back
{
background: hsl(60, 100%, 50%);
}
#cube .right
{
background: hsl(120, 100%, 50%);
}
#cube .left
{
background: hsl(180, 100%, 50%);
}
#cube .top
{
background: hsl(240, 100%, 50%);
}
#cube .bottom
{
background: hsl(300, 100%, 50%);
}
#cube .front
{
moz-transform: translateZ(50px);
o-transform: translateZ(50px);
transform: translateZ(50px);
webkit-transform: translateZ(50px);
}
#cube .back
{
moz-transform: rotateX(-180deg) translateZ(50px);
o-transform: rotateX(-180deg) translateZ(50px);
transform: rotateX(-180deg) translateZ(50px);
webkit-transform: rotateX(-180deg) translateZ(50px);
}
#cube .right
{
moz-transform: rotateY(90deg) translateZ(50px);
o-transform: rotateY(90deg) translateZ(50px);
transform: rotateY(90deg) translateZ(50px);
webkit-transform: rotateY(90deg) translateZ(50px);
}
#cube .left
{
moz-transform: rotateY(-90deg) translateZ(50px);
o-transform: rotateY(-90deg) translateZ(50px);
transform: rotateY(-90deg) translateZ(50px);
webkit-transform: rotateY(-90deg) translateZ(50px);
}
#cube .top
{
moz-transform: rotateX(90deg) translateZ(50px);
o-transform: rotateX(90deg) translateZ(50px);
transform: rotateX(90deg) translateZ(50px);
webkit-transform: rotateX(90deg) translateZ(50px);
}
#cube .bottom
{
moz-transform: rotateX(-90deg) translateZ(50px);
o-transform: rotateX(-90deg) translateZ(50px);
transform: rotateX(-90deg) translateZ(50px);
webkit-transform: rotateX(-90deg) translateZ(50px);
}
#options{
position:absolute;
width:80%;
top:40%;
}
#options input
{
width: 60%;
}
<body>
<div class="threeSpace">
<div id="pointer"></div>
<div class="translator">
<div id="cube">
<figure class="front"><div class='midPoint'></div></figure>
<figure class="back"></figure>
<figure class="right"></figure>
<figure class="left"></figure>
<figure class="top"></figure>
<figure class="bottom"></figure>
</div>
</div>
</div>
<section id="options">
<p class="xRotation">
<label>xRotation</label>
<input type="range" min="0" max="720" value="360" data-units="deg" />
</p>
<p class="yRotation">
<label>yRotation</label>
<input type="range" min="0" max="720" value="360" data-units="deg" />
</p>
<p class="zRotation">
<label>zRotation</label>
<input type="range" min="0" max="720" value="360" data-units="deg" />
</p>
<p class="xTranslation">
<label>xTranslation</label>
<input type="range" min="0" max="200" value="100" data-units="deg" />
</p>
<p class="yTranslation">
<label>yTranslation</label>
<input type="range" min="0" max="200" value="100" data-units="deg" />
</p>
<p class="zTranslation">
<label>zTranslation</label>
<input type="range" min="0" max="1000" value="500" data-units="deg" />
</p>
</section>
</body>
Точное значение rotate3d(133,32,58,58deg)
См. скрипку (для Chrome и Safari используйте -webkit-transform)