rotate3d shorthand

79

Jak łączyć rotateX(50deg) rotateY(20deg) rotateZ(15deg)w skrócie rotate3d()?

Artem Svirskyi
źródło

Odpowiedzi:

314

rotateX(50deg) jest równa rotate3d(1, 0, 0, 50deg)

rotateY(20deg) jest równa rotate3d(0, 1, 0, 20deg)

rotateZ(15deg) jest równa rotate3d(0, 0, 1, 15deg)

Więc...

rotateX(50deg) rotateY(20deg) rotateZ(15deg)

jest równa

rotate3d(1, 0, 0, 50deg) rotate3d(0, 1, 0, 20deg) rotate3d(0, 0, 1, 15deg)


W przypadku generycznego rotate3d(x, y, z, α)masz macierz

ogólna macierz obracania

gdzie

wyjaśnienie


Otrzymujesz teraz macierze dla każdej z 3 rotate3dtransformacji i mnożysz je. A wynikowa macierz jest macierzą odpowiadającą wynikowej pojedynczej rotate3d. Nie jestem pewien, jak łatwo jest wyodrębnić z niego wartości rotate3d, ale z pewnością łatwo jest wyodrębnić te dla pojedynczego matrix3d.


W pierwszym przypadku ( rotateX(50deg)lub rotate3d(1, 0, 0, 50deg)) masz:

x = 1, y = 0,z = 0 ,α = 50deg

Czyli pierwszy wiersz macierzy w tym przypadku to 1 0 0 0 .

Drugi to 0 cos(50deg) -sin(50deg) 0 .

Trzeci 0 sin(50deg) cos(50deg) 0 .

I oczywiście czwarty 0 0 0 1.


W drugim przypadku, masz x = 0, y = 1, z = 0,α = 20deg .

Pierwszy rząd: cos(20deg) 0 sin(20deg) 0.

Drugi rząd: 0 1 0 0 .

Trzeci rząd: -sin(20) 0 cos(20deg) 0 .

Czwarty: 0 0 0 1


W trzecim przypadku, masz x = 0, y = 0, z = 1,α = 15deg .

Pierwszy rząd: cos(15deg) -sin(15deg) 0 0.

Drugi rząd sin(15deg) cos(15deg) 0 0.

A trzeci i czwarty rząd to odpowiednio 0 0 1 0i 0 0 0 1.


Uwaga : być może zauważyłeś, że znaki wartości grzechu dla transformaty rotateY są inne niż dla pozostałych dwóch transformacji. To nie jest błąd w obliczeniach. Powodem tego jest to, że na ekranie oś Y jest skierowana w dół, a nie w górę.


Więc to są trzy 4x4macierze, które musisz pomnożyć, aby uzyskać 4x4macierz dla wynikowej pojedynczej rotate3dtransformacji. Jak powiedziałem, nie jestem pewien, jak łatwo można uzyskać 4 wartości, ale 16 elementów w macierzy 4x4 to dokładnie 16 parametrów matrix3dodpowiednika połączonej transformacji.


EDYCJA :

Właściwie okazuje się, że to całkiem proste ... Obliczasz ślad (sumę elementów przekątnych) macierzy dla rotate3dmacierzy.

4 - 2*2*(1 - cos(α))/2 = 4 - 2*(1 - cos(α)) = 2 + 2*cos(α)

Następnie obliczasz ślad iloczynu trzech 4x4macierzy, zrównujesz wynik z 2 + 2*cos(α)wyodrębnieniem α. Następnie należy obliczyć x, y, z.

W tym konkretnym przypadku, jeśli obliczyłem poprawnie, ślad macierzy wynikający z iloczynu trzech 4x4macierzy będzie wyglądał następująco:

T = 
cos(20deg)*cos(15deg) + 
cos(50deg)*cos(15deg) - sin(50deg)*sin(20deg)*cos(15deg) + 
cos(50deg)*cos(20deg) + 
1

Więc cos(α) = (T - 2)/2 = T/2 - 1to znaczy, że α = acos(T/2 - 1).

Ana
źródło
6
tak, nawet nie wiem, jak to sprawdzić. Miałem taki zamiar, dopóki nie zobaczyłem grzechu. ponieważ otworzyło mi to umysł. kiedy zobaczyłem grzech. krzyczeć asa bazy
Andrew Luhring
1
@AndrewLuhring Amazing.
aendrew
1
Zauważ, że macierz obrotu ma zastosowanie tylko wtedy, gdy [x,y,z]wektor jest znormalizowany, to znaczy tylko wtedy, gdy długość wektora Math.sqrt(x*x + y*y + z*z)wynosi jeden. Jeżeli nie jest to znormalizowane, można łatwo przekształcić w znormalizowanej drugim, nurkowanie każdego x, yoraz zich długość.
Jose Rui Santos
Musisz mieć tytuł magistra matematyki. Dzięki za ten wiersz, Ana!
Ida,
@ Andrew: nie martw się, grzech zwycięża wielu z nas ... westchnij.
David mówi, że przywróć Monice
15

Składnia:

rotate3d(x, y, z, a)

Wartości:

  • x To <number>opis współrzędnej x wektora oznaczającego oś obrotu.
  • y To <number>opis współrzędnej y wektora oznaczającego oś obrotu.
  • z Jest to <number>opis współrzędnej z wektora oznaczającego oś obrotu.
  • a Jest <angle>reprezentowanie kąta obrotu. Kąt dodatni oznacza obrót w prawo, a kąt ujemny w kierunku przeciwnym do ruchu wskazówek zegara.

Jak w :

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

Bawiłem się tutaj

Możesz go tutaj użyć

Więcej dokumentów na ten temat

Milche Patern
źródło
6
Może jestem gruba, ale myślę, że prosi o algorytm, który przejdzie od łańcuchowej transformacji do pojedynczej rotate3d, a nie do definicji rotate3d.
Ana,
3
Myślę, że chce wiedzieć, jak połączyć rotateX (50 stopni) rotateY (20 stopni) rotateZ (15 stopni) w skrócie rotate3d () w CSS
Milche Patern
7

W zależności od tego, co próbujesz zrobić, ten „hack” może ci pomóc. Załóżmy, że robisz animację i chcesz dodać transformację po transformacji i tak dalej, i nie chcesz, aby CSS wyglądał tak, jakby wykonywał setki transformacji:

Działa to w chrome: 1. Zastosuj dowolną transformację do elementu. 2. Następnym razem, gdy będziesz chciał dodać transformację, dodaj ją do obliczonej transformacji: „window.getComputedStyle (element) .transform” - ale pamiętaj, aby umieścić nową transformację po lewej stronie. 3. Teraz twoja transformacja będzie wyglądać jak "rotateZ (30deg) matrix3d ​​(......). 4. Następnym razem, gdy chcesz dodać kolejną transformację, powtórz proces - Chrome zawsze redukuje transformacje do notacji matrix3d.

TL; DR - zastosuj dowolne transformacje, a następnie uzyskaj obliczoną transformację matrix3d.

Ta sztuczka pozwala również szybko (to znaczy bez wykonywania żadnych działań matematycznych samodzielnie) wykonać funkcję, która obraca obiekt w dowolnym kierunku względem ramki odniesienia. Zobacz przykład poniżej:

EDYCJA : Dodałem również tłumaczenia xyz. Korzystając z tego, bardzo łatwo byłoby umieszczać obiekty w określonych lokalizacjach 3D, mając na uwadze określone orientacje. Albo ... wyobraź sobie sześcian, który odbija się i zmienia swoją oś obrotu przy każdym odbiciu w zależności od tego, jak wyląduje!

	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>

Roman Rekhler
źródło
To jeden z najbardziej przydatnych postów wszechczasów, dziękuję
damiano celent
3

Dokładna wartość to rotate3d(133,32,58,58deg)

Zobacz skrzypce (dla Chrome i Safari, używając -webkit-transform)

Bigood
źródło
12
Jak dokładnie to obliczasz?
Ana,
1
@Ana ja nie, dlatego twoja odpowiedź jest 10x lepsza :)
Bigood