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

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


person Artem Svirskyi    schedule 04.03.2013    source источник


Ответы (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).

person Ana    schedule 04.03.2013
comment
да я даже не знаю как это проверить. Я полностью собирался, пока не увидел грех. Потому что это открыло мой разум. когда я увидел грех. крик туз базы - person Andrew Luhring; 21.08.2013
comment
@ЭндрюЛюринг Удивительно. - person aendrew; 21.11.2013
comment
Обратите внимание, что матрица поворота применима, только если вектор [x,y,z] нормализован, то есть только если длина вектора Math.sqrt(x*x + y*y + z*z) равна единице. Если он не нормализован, его можно легко преобразовать в нормализованную, разделив каждый x, y и z на их длину. - person Jose Rui Santos; 02.02.2014
comment
Вы должны иметь степень магистра изящных искусств по математике. Спасибо за стихотворение, Анна! - person Ida; 21.03.2014
comment
@Эндрю: не волнуйся, грех берет верх над многими из нас... вздох. - person David says reinstate Monica; 06.11.2014
comment
ты меня иногда пугаешь... @Ана - person Tanker; 06.03.2015
comment
Эпический отличный полный ответ на это! Я не мог просить больше, большое спасибо за это. - person Sijav; 23.03.2015
comment
Как насчет получения значения rotate3d из матрицы (которая кажется однострочной), возвращаемой методом jquery 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
comment
@Alvaro Альваро Это не одна строка. Первые 4 значения (1 0 0 0) — это значения в 1-м столбце, следующие 4 (0, .642788, -.766044, 0) — это значения во 2-м столбце и так далее. Здесь значения, которые вы указали, соответствуют ситуации rotateX в моем ответе выше. .64 — это cos вашего угла, -.76 — это sin. Эти знаки помещают его между -90° и . Вы можете получить точное значение с помощью α = Math.atan2(-.76, .64). Тогда у вас есть rotate3d(1, 0, 0, αrad). Или вы можете преобразовать α в градусы: α *= 180/Math.PI - person Ana; 03.11.2016
comment
@ Ана, да, верно. Но я обнаружил, что невозможно получить точное значение, а относительное. Кстати, сумасшедшие конференции вы делаете! - person Alvaro; 03.11.2016
comment
MDN говорит: В отличие от вращений в 2D-плоскости, композиция 3D-вращений обычно не коммутативна. Другими словами, порядок применения поворотов влияет на результат. Означает ли это, что существуют 3D-повороты, которые нельзя указать с помощью rotate3d? Из этого ответа и другой документации видно, что rotate3d вращается в порядке x, затем y, затем z. Но я не могу найти пример, где порядок размеров имеет значение. - person jamess; 11.09.2018
comment
@ Ана, означает ли это, что в данном конкретном случае ожидаемое сокращение - rotate3d(1,1,1,acos(T/2 - 1))? Мне также любопытно, что происходит с такими значениями, как rotateX(180deg) =) - person thednp; 31.01.2020
comment
Как удалить вращение для дочернего элемента родителя, к которому применено вращение? Пожалуйста, проверьте это jsfiddle.net/L9nefum0/1. Синее поле — это поле для справки. Я хочу сбросить вращение для красного поля. - person Temp O'rary; 03.02.2021

Синтаксис:

rotate3d(x, y, z, a)

Ценности:

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

Как в :

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

Поиграл здесь

Можно использовать здесь

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

person Milche Patern    schedule 04.03.2013
comment
Может быть, я туплю, но я думаю, что он просит алгоритм перехода от цепного преобразования к одному rotate3d, а не определение rotate3d. - person Ana; 04.03.2013
comment
Я думаю, он хочет знать, как комбинировать rotateX(50deg) rotateY(20deg) rotateZ(15deg) в сокращении rotate3d() в CSS - person Milche Patern; 05.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>

person Roman Rekhler    schedule 07.03.2015
comment
Это один из самых полезных постов, спасибо - person damiano celent; 24.07.2016

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

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

person Bigood    schedule 04.03.2013
comment
Как именно вы его вычисляете? - person Ana; 04.03.2013
comment
@ Ана, нет, поэтому твой ответ в 10 раз лучше :) - person Bigood; 24.02.2015