rotateX(50deg) rotateY(20deg) rotateZ(15deg)
を短縮形rotate3d()
に組み合わせる方法は?
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, α)
の場合、行列があります
どこ
これで、3つの_rotate3d
_変換のそれぞれの行列を取得し、それらを乗算します。そして、結果のマトリックスは、結果の単一の_rotate3d
_に対応するマトリックスです。 _rotate3d
_の値をそこから抽出するのは簡単ではありませんが、単一の_matrix3d
_の値を抽出するのは簡単です。
最初の場合(rotateX(50deg)
またはrotate3d(1, 0, 0, 50deg)
)には、次のものがあります。
_x = 1
_、_y = 0
_、_z = 0
_、_α = 50deg
_
したがって、この場合の行列の最初の行は_1 0 0 0
_です。
2番目は0 cos(50deg) -sin(50deg) 0
です。
3番目の0 sin(50deg) cos(50deg) 0
。
そして4番目は明らかに_0 0 0 1
_です。
2番目のケースでは、_x = 0
_、_y = 1
_、_z = 0
_、_α = 20deg
_があります。
最初の行:cos(20deg) 0 sin(20deg) 0
。
2番目の行:_0 1 0 0
_。
3行目:-sin(20) 0 cos(20deg) 0
。
4番目:_0 0 0 1
_
3番目のケースでは、_x = 0
_、_y = 0
_、_z = 1
_、_α = 15deg
_があります。
最初の行:cos(15deg) -sin(15deg) 0 0
。
2番目の行sin(15deg) cos(15deg) 0 0
。
そして、3行目と4行目はそれぞれ_0 0 1 0
_と_0 0 0 1
_です。
注:あなたはrotateYのsin値の符号に気づいたかもしれません変換は、他の2つの変換とは異なります。計算の間違いではありません。これは、画面の場合、y軸が上ではなく下を向いているためです
したがって、これらは、結果として得られる単一の_4x4
_変換の_4x4
_マトリックスを取得するために乗算する必要がある3つの_rotate3d
_マトリックスです。私が言ったように、4つの値を取り出すことがどれほど簡単かはわかりませんが、4x4マトリックスの16個の要素は、チェーン変換の_matrix3d
_相当の16個のパラメーターです。
[〜#〜] edit [〜#〜]:
実際、それは非常に簡単です... _rotate3d
_マトリックスのマトリックスのトレース(対角要素の合計)を計算します。
4 - 2*2*(1 - cos(α))/2 = 4 - 2*(1 - cos(α)) = 2 + 2*cos(α)
次に、3つの_4x4
_行列の積のトレースを計算し、結果を2 + 2*cos(α)
と同等にし、_α
_を抽出します。次に、x
、y
、z
を計算します。
この特定の場合、正しく計算すれば、3つの_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)
です。
構文:
rotate3d(x, y, z, a)
値:
x
は<number>
回転軸を示すベクトルのx座標を記述します。y
は<number>
回転軸を示すベクトルのy座標を記述します。z
は<number>
回転軸を示すベクトルのz座標を記述します。a
は<angle>
は回転の角度を表します。正の角度は時計回りの回転を示し、負の角度は反時計回りの回転を示します。のように :
.will-distort{
transform:rotate3d(10, 10, 10, 45deg);
}
あなたがしようとしていることに依存しますが、この「ハック」はあなたを助けることができます。アニメーションを実行していて、変換などの後に変換を追加し、CSSが100の変換を実行しているように見せたくないとしましょう。
これはクロムで動作します。1.必要な変換を要素に適用します。 2.次に変換を追加する場合は、計算された変換に追加します: "window.getComputedStyle(element).transform"-ただし、新しい変換は必ず左側に配置してください。 3.これで、変換は「rotateZ(30deg)matrix3d(......)のようになります。4.次の変換を追加する場合は、プロセスを繰り返します-Chrome常に減少matrix3d表記への変換。
TL; DR-必要な変換を適用して、計算されたmatrix3d変換を取得します。
また、このトリックを使用すると、参照フレームに対して任意の方向にオブジェクトを回転させる機能をすばやく(つまり、自分で計算することなく)作成できます。以下のサンプルを参照してください。
[〜#〜] edit [〜#〜]: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>
正確な値はrotate3d(133,32,58,58deg)
です
fiddle (chromeおよびSafari、-webkit-transformを使用)を参照してください)