rotate3d taquigrafía

79

¿Cómo combinar rotateX(50deg) rotateY(20deg) rotateZ(15deg)en taquigrafía rotate3d()?

Artem Svirskyi
fuente

Respuestas:

314

rotateX(50deg) es equivalente a rotate3d(1, 0, 0, 50deg)

rotateY(20deg) es equivalente a rotate3d(0, 1, 0, 20deg)

rotateZ(15deg) es equivalente a rotate3d(0, 0, 1, 15deg)

Entonces...

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

es equivalente a

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


Para un genérico rotate3d(x, y, z, α), tienes la matriz

matriz de rotación genérica

dónde

explicación


Ahora obtienes las matrices para cada una de las 3 rotate3dtransformadas y las multiplicas. Y la matriz resultante es la matriz correspondiente al sencillo resultante rotate3d. No estoy seguro de lo fácil que es extraer los valores rotate3dde él, pero seguro que es fácil extraerlos para uno solo matrix3d.


En el primer caso ( rotateX(50deg)o rotate3d(1, 0, 0, 50deg)), tienes:

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

Entonces, la primera fila de la matriz en este caso es 1 0 0 0 .

El segundo es 0 cos(50deg) -sin(50deg) 0 .

El tercero 0 sin(50deg) cos(50deg) 0 .

Y el cuarto es obviamente 0 0 0 1 .


En el segundo caso, tiene x = 0, y = 1,z = 0 ,α = 20deg .

Primera fila: cos(20deg) 0 sin(20deg) 0 .

Segunda fila: 0 1 0 0 .

Tercera fila: -sin(20) 0 cos(20deg) 0 .

Cuarto: 0 0 0 1


En el tercer caso, tiene x = 0, y = 0,z = 1 ,α = 15deg .

Primera fila: cos(15deg) -sin(15deg) 0 0 .

Segunda fila sin(15deg) cos(15deg) 0 0 .

Y la tercera y la cuarta fila son 0 0 1 0y 0 0 0 1respectivamente.


Nota : puede haber notado que los signos de los valores sin para la transformada rotateY son diferentes a los de las otras dos transformadas. No es un error de cálculo. La razón de esto es que, en la pantalla, el eje Y apunta hacia abajo, no hacia arriba.


Entonces, estas son las tres 4x4matrices que necesita multiplicar para obtener la 4x4matriz de la rotate3dtransformación simple resultante . Como dije, no estoy seguro de lo fácil que puede ser sacar los 4 valores, pero los 16 elementos de la matriz 4x4 son exactamente los 16 parámetros del matrix3dequivalente de la transformación encadenada.


EDITAR :

En realidad, resulta que es bastante fácil ... Calcula la traza (suma de elementos diagonales) de la matriz para la rotate3dmatriz.

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

Luego calcula la traza para el producto de las tres 4x4matrices, equipara el resultado con lo 2 + 2*cos(α)que extrae α. A continuación, a calcular x, y, z.

En este caso particular, si calculé correctamente, la traza de la matriz resultante del producto de las tres 4x4matrices será:

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

Entonces cos(α) = (T - 2)/2 = T/2 - 1, lo que significa eso α = acos(T/2 - 1).

Ana
fuente
6
sí, ni siquiera sé cómo comprobar eso. Lo iba a hacer totalmente hasta que vi el pecado. porque abrió mi mente cuando vi el pecado. grito as de base
Andrew Luhring
1
@AndrewLuhring Increíble.
aendrew
1
Tenga en cuenta que la matriz de rotación es aplicable solo si el [x,y,z]vector está normalizado, es decir, solo si la longitud del vector Math.sqrt(x*x + y*y + z*z)es uno. Si no se normaliza, fácilmente se puede convertir en un uno normalizado, por buceo de cada x, yy zpor su longitud.
Jose Rui Santos
Debes tener una Maestría en Bellas Artes en Matemática. ¡Gracias por este poema, Ana!
Ida
@Andrew: no te preocupes, el pecado se apodera de muchos de nosotros ... suspiro.
David dice reinstalar a Monica
15

Sintaxis:

rotate3d(x, y, z, a)

Valores:

  • x Es un <number> descripción de la coordenada x del vector que denota el eje de rotación.
  • y Es una <number>descripción de la coordenada y del vector que denota el eje de rotación.
  • z Es una <number>descripción de la coordenada z del vector que denota el eje de rotación.
  • a Es una <angle>representación del ángulo de rotación. Un ángulo positivo denota una rotación en el sentido de las agujas del reloj, un ángulo negativo en el sentido contrario a las agujas del reloj.

Como en :

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

Jugado aquí

Puedo usarlo aquí

Más documentos al respecto

Milche Patern
fuente
6
Tal vez sea grueso, pero creo que está pidiendo un algoritmo para pasar de la transformación encadenada a una única rotate3d, no la definición de rotate3d.
Ana
3
Creo que quiere saber cómo combinar rotateX (50deg) rotateY (20deg) rotateZ (15deg) en forma abreviada rotate3d () en CSS
Milche Patern
7

Depende de lo que intente hacer, este 'truco' podría ayudarlo. Digamos que está haciendo una animación, y quiere agregar transformación tras transformación y así sucesivamente, y no quiere que el CSS parezca que está haciendo cientos de transformaciones:

Esto funciona en Chrome: 1. Aplique cualquier transformación que desee a un elemento. 2. La próxima vez que desee agregar una transformación, agréguela a la transformación calculada: "window.getComputedStyle (element) .transform", pero asegúrese de poner la nueva transformación a la izquierda. 3. Ahora su transformación se vería como "rotateZ (30deg) matrix3d ​​(......). 4. La próxima vez que desee agregar otra transformación, repita el proceso - Chrome siempre reduce las transformaciones a la notación matrix3d.

TL; DR: aplique las transformaciones que desee y luego obtenga la transformación matrix3d ​​calculada.

Este truco también te permite rápidamente (es decir, sin hacer ningún cálculo por ti mismo) crear una funcionalidad que gire un objeto con respecto a tu marco de referencia en cualquier dirección. Vea la muestra a continuación:

EDITAR : También he agregado traducciones xyz. Con esto, sería muy fácil colocar objetos en ubicaciones 3D específicas con orientaciones específicas en mente. O ... ¡imagina un cubo que rebota y cambia su eje de giro con cada rebote dependiendo de cómo aterrice!

	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
fuente
Esta es una de las publicaciones más útiles de la historia, gracias
Damiano celent
3

El valor exacto es rotate3d(133,32,58,58deg)

Ver el violín (para Chrome y Safari, usando -webkit-transform)

Bigood
fuente
12
¿Cómo se calcula exactamente ?
Ana
1
@Ana No, por eso tu respuesta es 10 veces mejor :)
Bigood