CSS 旋转3d速记
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15207351/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
rotate3d shorthand
提问by Artem Svirskyi
How to combine rotateX(50deg) rotateY(20deg) rotateZ(15deg)
in shorthand rotate3d()
?
如何rotateX(50deg) rotateY(20deg) rotateZ(15deg)
速记组合rotate3d()
?
回答by Ana
rotateX(50deg)
is equivalent to rotate3d(1, 0, 0, 50deg)
rotateX(50deg)
相当于 rotate3d(1, 0, 0, 50deg)
rotateY(20deg)
is equivalent to rotate3d(0, 1, 0, 20deg)
rotateY(20deg)
相当于 rotate3d(0, 1, 0, 20deg)
rotateZ(15deg)
is equivalent to rotate3d(0, 0, 1, 15deg)
rotateZ(15deg)
相当于 rotate3d(0, 0, 1, 15deg)
So...
所以...
rotateX(50deg) rotateY(20deg) rotateZ(15deg)
rotateX(50deg) rotateY(20deg) rotateZ(15deg)
is equivalent to
相当于
rotate3d(1, 0, 0, 50deg) rotate3d(0, 1, 0, 20deg) rotate3d(0, 0, 1, 15deg)
rotate3d(1, 0, 0, 50deg) rotate3d(0, 1, 0, 20deg) rotate3d(0, 0, 1, 15deg)
For a generic rotate3d(x, y, z, α)
, you have the matrix
对于泛型rotate3d(x, y, z, α)
,你有矩阵
where
在哪里
You now get the matrices for each of the 3 rotate3d
transforms and you multiply them. And the resulting matrix is the matrix corresponding to the resulting single rotate3d
. Not sure how to easy it is to extract the values for rotate3d
out of it, but it's sure easy to extract those for a single matrix3d
.
您现在获得了 3 个rotate3d
变换中的每一个的矩阵,然后将它们相乘。生成的矩阵是与生成的 single 对应的矩阵rotate3d
。不确定从中提取值有多容易rotate3d
,但肯定很容易提取单个matrix3d
.
In the first case (rotateX(50deg)
or rotate3d(1, 0, 0, 50deg)
), you have:
在第一种情况(rotateX(50deg)
或rotate3d(1, 0, 0, 50deg)
)中,您有:
x = 1
, y = 0
, z = 0
, α = 50deg
x = 1
, y = 0
, z = 0
,α = 50deg
So the first row of the matrix in this case is 1 0 0 0
.
所以在这种情况下矩阵的第一行是1 0 0 0
。
The second one is 0 cos(50deg) -sin(50deg) 0
.
第二个是0 cos(50deg) -sin(50deg) 0
。
The third one 0 sin(50deg) cos(50deg) 0
.
第三个0 sin(50deg) cos(50deg) 0
。
And the fourth one is obviously 0 0 0 1
.
而第四个显然是0 0 0 1
。
In the second case, you have x = 0
, y = 1
, z = 0
, α = 20deg
.
在第二种情况下,您有x = 0
, y = 1
, z = 0
, α = 20deg
。
First row: cos(20deg) 0 sin(20deg) 0
.
第一行:cos(20deg) 0 sin(20deg) 0
。
Second row: 0 1 0 0
.
第二行:0 1 0 0
。
Third row: -sin(20) 0 cos(20deg) 0
.
第三行:-sin(20) 0 cos(20deg) 0
。
Fourth: 0 0 0 1
第四: 0 0 0 1
In the third case, you have x = 0
, y = 0
, z = 1
, α = 15deg
.
在第三种情况下,您有x = 0
, y = 0
, z = 1
, α = 15deg
。
First row: cos(15deg) -sin(15deg) 0 0
.
第一行:cos(15deg) -sin(15deg) 0 0
。
Second row sin(15deg) cos(15deg) 0 0
.
第二排sin(15deg) cos(15deg) 0 0
。
And the third and the fourth row are 0 0 1 0
and 0 0 0 1
respectively.
第三行0 0 1 0
和第四行0 0 0 1
分别是和。
Note: you may have noticed that the signs of the sin values for the rotateY transform are different than for the other two transforms. It's not a computation mistake. The reason for this is that, for the screen, you have the y-axis pointing down, not up.
注意:您可能已经注意到,rotateY 变换的 sin 值的符号与其他两个变换的不同。这不是计算错误。这样做的原因是,对于屏幕,y 轴是向下的,而不是向上的。
So these are the three 4x4
matrices that you need to multiply in order to get the 4x4
matrix for the resulting single rotate3d
transform. As I've said, I'm not sure how easy it can be to get the 4 values out, but the 16 elements in the 4x4 matrix are exactly the 16 parameters of the matrix3d
equivalent of the chained transform.
所以这些是4x4
您需要相乘的三个矩阵,以获得4x4
结果单个rotate3d
变换的矩阵。正如我所说的,我不确定获取 4 个值有多容易,但是 4x4 矩阵中的 16 个元素正是matrix3d
链式变换等效项的16 个参数。
EDIT:
编辑:
Actually, it turns out it's pretty easy... You compute the trace (sum of diagonal elements) of the matrix for the rotate3d
matrix.
实际上,事实证明这很容易……您可以计算矩阵的rotate3d
矩阵的迹(对角线元素的总和)。
4 - 2*2*(1 - cos(α))/2 = 4 - 2*(1 - cos(α)) = 2 + 2*cos(α)
4 - 2*2*(1 - cos(α))/2 = 4 - 2*(1 - cos(α)) = 2 + 2*cos(α)
You then compute the trace for the product of the three 4x4
matrices, you equate the result with 2 + 2*cos(α)
you extract α
. Then you compute x
, y
, z
.
然后计算三个4x4
矩阵的乘积的迹线,将结果等同于2 + 2*cos(α)
您的 extract α
。然后计算x
, y
, z
。
In this particular case, if I computed correctly, the trace of the matrix resulting from the product of the three 4x4
matrices is going to be:
在这种特殊情况下,如果我计算正确,由三个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
, which means that α = acos(T/2 - 1)
.
所以cos(α) = (T - 2)/2 = T/2 - 1
,这意味着α = acos(T/2 - 1)
。
回答by Milche Patern
Syntax:
句法:
rotate3d(x, y, z, a)
Values:
价值观:
x
Is a<number>
describing the x-coordinate of the vector denoting the axis of rotation.y
Is a<number>
describing the y-coordinate of the vector denoting the axis of rotation.z
Is a<number>
describing the z-coordinate of the vector denoting the axis of rotation.a
Is an<angle>
representing the angle of the rotation. A positive angle denotes a clockwise rotation, a negative angle a counter-clockwise one.
x
是<number>
描述表示旋转轴的向量的 x 坐标。y
是<number>
描述表示旋转轴的向量的 y 坐标。z
是<number>
描述表示旋转轴的向量的 z 坐标。a
是<angle>
代表旋转的角度。正角表示顺时针旋转,负角表示逆时针旋转。
Like in :
像 :
.will-distort{
transform:rotate3d(10, 10, 10, 45deg);
}
回答by Roman Rekhler
Depends on what you are trying to do, this 'hack' could help you. Let's say you are doing animation, and you want add transformation after transformation and so on, and you don't want the CSS to look like it's doing 100's of transformations:
取决于你想要做什么,这个“黑客”可以帮助你。假设您正在制作动画,并且您希望在转换后添加转换等等,并且您不希望 CSS 看起来像是在执行 100 次转换:
This works in chrome: 1. Apply whatever transform you want to an element. 2. Next time you want to add a transform, add it to the computed transform: "window.getComputedStyle(element).transform" - but make sure to put the new transform to the left. 3. Now your transform would look like "rotateZ(30deg) matrix3d(......). 4. Next time you want to add another transform, repeat the process - Chrome always reduces the transforms to matrix3d notation.
这适用于 chrome: 1. 将您想要的任何变换应用于元素。2. 下次要添加变换时,将其添加到计算变换:“window.getComputedStyle(element).transform” - 但确保将新变换放在左侧。3. 现在你的变换看起来像 "rotateZ(30deg) matrix3d(......). 4. 下次你想添加另一个变换时,重复这个过程 - Chrome 总是将变换减少到 matrix3d 表示法。
TL;DR- apply whatever transforms you want, and then get the computed matrix3d transformation.
TL;DR- 应用您想要的任何变换,然后获得计算的 matrix3d 变换。
This trick also lets you quickly (that is, without doing any math by yourself) make a functionality that rotates an object with respect to your reference frame in any direction. See the sample below:
这个技巧还可以让您快速(即,无需自己进行任何数学运算)创建一个功能,该功能可以相对于您的参考系在任何方向上旋转对象。请参阅下面的示例:
EDIT: I have added xyz translations as well. Using this, it would be very easy to place objects in specific 3d locations with specific orientations in mind. Or...imagine a cube that bounces and changes it's spin axis with each bounce depending on how it lands!
编辑:我也添加了 xyz 翻译。使用它,可以很容易地将对象放置在具有特定方向的特定 3d 位置。或者……想象一个立方体,它会弹跳并根据着陆方式在每次弹跳时改变它的自旋轴!
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>