Rotate3d стенография

Как объединить rotateX(50deg) rotateY(20deg) rotateZ(15deg) в сокращенном rotate3d()?

Ответ 1

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, α) у вас есть матрица

generic rotate matrix

где

explanation


Теперь вы получаете матрицы для каждого из преобразований 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

So cos(α) = (T - 2)/2 = T/2 - 1, что означает, что α = acos(T/2 - 1).

Ответ 2

Синтаксис:

rotate3d(x, y, z, a)

значения:

  • x Является a <number>, описывающим x-координату вектора, обозначающего ось вращения.
  • y Является a <number>, описывающим y-координату вектора, обозначающего ось вращения.
  • z Является a <number>, описывающим z-координату вектора, обозначающего ось вращения.
  • a Является <angle>, представляющим угол поворота. Положительный угол обозначает вращение по часовой стрелке, отрицательный угол против часовой стрелки.

Как в:

.will-distort{
    transform:rotate3d(10, 10, 10, 45deg);
}

Спрятано здесь

Caniuse здесь

Дополнительные документы об этом

Ответ 3

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

Это работает в chrome:  1. Примените любое преобразование, которое вы хотите к элементу.  2. В следующий раз, когда вы захотите добавить преобразование, добавьте его в вычисленное преобразование:    "window.getComputedStyle(элемент).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>

Ответ 4

Точное значение rotate3d(133,32,58,58deg)

Смотрите fiddle (для хром и Safari, используя -webkit-transform)