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

79

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

Артем Свирский
источник

Ответы:

314

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).

Ана
источник
6
да, я даже не знаю, как это проверить. Я полностью собирался это сделать, пока не увидел грех. Потому что это открыло мне глаза. когда я увидел грех. shoutout ace of base
Эндрю Люринг
1
@AndrewLuhring Потрясающе.
aendrew
1
Обратите внимание, что матрица поворота применима, только если [x,y,z]вектор нормализован, то есть, только если длина вектора Math.sqrt(x*x + y*y + z*z)равна единице. Если он не нормализованы, он легко может быть преобразован в нормализованной, ныряя каждого x, yи zпо их длине.
Хосе Руи Сантос
Вы должны иметь степень магистра изящных искусств по математике. Спасибо за это стихотворение, Ана!
Ida
@ Андрей: не волнуйся, грех одолевает многих из нас ... вздох.
Дэвид просит восстановить Монику
15

Синтаксис:

rotate3d(x, y, z, a)

Значения:

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

Как в :

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

Возился здесь

Caniuse это здесь

Больше документов об этом

Милче Патерн
источник
6
Может быть, я толстый, но я думаю, что он просит алгоритм перейти от цепного преобразования к одиночному rotate3d, а не для определения rotate3d.
Ана,
3
Я думаю, он хочет знать, как объединить rotateX (50deg) rotateY (20deg) rotateZ (15deg) в сокращенную запись rotate3d () в CSS
Milche Patern 05
7

В зависимости от того, что вы пытаетесь сделать, этот «хакерский прием» может вам помочь. Допустим, вы выполняете анимацию и хотите добавить преобразование после преобразования и так далее, и вы не хотите, чтобы 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>

Роман Рехлер
источник
Это один из самых полезных постов на свете, спасибо
Дамиано Селент
3

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

См. Скрипку (для Chrome и Safari, используя -webkit-transform)

Bigood
источник
12
Как именно это вычислить?
Ana
1
@Ana Я не знаю, поэтому твой ответ в 10 раз лучше :)
Bigood