Как комбинировать rotateX(50deg) rotateY(20deg) rotateZ(15deg)
стенографию rotate3d()
?
Как комбинировать rotateX(50deg) rotateY(20deg) rotateZ(15deg)
стенографию rotate3d()
?
Ответы:
rotateX(50deg)
эквивалентно rotate3d(1, 0, 0, 50deg)
rotateY(20deg)
эквивалентно rotate3d(0, 1, 0, 20deg)
rotateZ(15deg)
эквивалентно rotate3d(0, 0, 1, 15deg)
Так...
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, α)
вас есть матрица
где
Теперь вы получаете матрицы для каждого из трех 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
по их длине.
Синтаксис:
rotate3d(x, y, z, a)
Значения:
x
Является ли <number>
описания х-координата вектора , обозначающего ось вращения.y
Является ли <number>
описания у-координату вектора , обозначающего ось вращения.z
Является ли <number>
описывающий г-координата вектора , обозначающий ось вращения.a
Является <angle>
представляющая угол поворота. Положительный угол означает вращение по часовой стрелке, отрицательный угол - против часовой стрелки.Как в :
.will-distort{
transform:rotate3d(10, 10, 10, 45deg);
}
rotate3d
, а не для определения rotate3d
.
В зависимости от того, что вы пытаетесь сделать, этот «хакерский прием» может вам помочь. Допустим, вы выполняете анимацию и хотите добавить преобразование после преобразования и так далее, и вы не хотите, чтобы CSS выглядел так, как будто он выполняет сотни преобразований:
Это работает в Chrome: 1. Примените любое преобразование к элементу. 2. В следующий раз, когда вы захотите добавить преобразование, добавьте его к вычисленному преобразованию: «window.getComputedStyle (element) .transform», но не забудьте поместить новое преобразование слева. 3. Теперь ваше преобразование будет выглядеть как «rotateZ (30deg) matrix3d (......). 4. В следующий раз, когда вы захотите добавить еще одно преобразование, повторите процесс - Chrome всегда сокращает преобразования до нотации matrix3d.
TL; DR - примените любые преобразования, которые вы хотите, а затем получите вычисленное преобразование matrix3d.
Этот трюк также позволяет вам быстро (то есть без выполнения каких-либо математических расчетов) создать функциональность, которая поворачивает объект по отношению к вашей системе отсчета в любом направлении. См. Образец ниже:
РЕДАКТИРОВАТЬ : Я также добавил переводы 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>