rotateX(50deg) rotateY(20deg) rotateZ(15deg)
속기 결합하는 방법 rotate3d()
?
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
변환 각각에 대한 행렬을 얻고 곱합니다. 그리고 결과 행렬은 결과 single에 해당하는 행렬입니다 rotate3d
. 값을 추출하는 것이 얼마나 쉬운 지 확실하지 rotate3d
않지만 단일 .NET에 대한 값 을 추출하는 것은 쉽습니다 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
입니다.
참고 : rotateY 변환에 대한 sin 값의 부호가 다른 두 변환에 대한 것과 다르다는 것을 알 수 있습니다. 계산 실수가 아닙니다. 그 이유는 화면의 경우 y 축이 위쪽이 아닌 아래쪽을 가리 키기 때문입니다.
따라서 이들은 결과 단일 변환에 대한 행렬 4x4
을 얻기 위해 곱해야하는 세 개의 행렬입니다 . 내가 말했듯이 4 개의 값을 얻는 것이 얼마나 쉬운 지 잘 모르겠지만, 4x4 행렬의 16 개 요소는 정확히 연결 변환에 해당 하는 16 개의 매개 변수입니다 .4x4
rotate3d
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)
.
[x,y,z]
벡터가 정규화 된 경우, 즉 벡터 길이 Math.sqrt(x*x + y*y + z*z)
가 1 인 경우에만 적용 할 수 있습니다. 가 정상화되지 않으면 쉽게 다이빙 각에 의해, 정규화 된 하나에 변환 할 수 있습니다 x
, y
그리고 z
그 길이에 의해.
통사론:
rotate3d(x, y, z, a)
값 :
x
A는 <number>
묘화 회전축을 나타내는 벡터의 X 좌표를.y
A는 <number>
(가) 회전축 선을 나타내는 벡터의 y 좌표를 나타내는.z
A는 <number>
(가) 회전축 선을 나타내는 벡터의 Z 좌표를 설명.a
가 <angle>
회전의 각도를 나타내는이. 양의 각도는 시계 방향 회전을, 음의 각도는 시계 반대 방향을 나타냅니다.다음과 같이 :
.will-distort{
transform:rotate3d(10, 10, 10, 45deg);
}
rotate3d
정의가 아닌 체인 변환에서 단일으로 이동하는 알고리즘을 요구하고 있다고 생각 rotate3d
합니다.
수행하려는 작업에 따라이 '해킹'이 도움이 될 수 있습니다. 애니메이션을하고 있고 변형 후 변형 등을 추가하고 CSS가 100 번의 변형을 수행하는 것처럼 보이기를 원하지 않는다고 가정 해 보겠습니다.
이것은 크롬에서 작동합니다. 1. 요소에 원하는 변형을 적용합니다. 2. 다음에 변환을 추가하려면 계산 된 변환에 추가하십시오. "window.getComputedStyle (element) .transform"-새 변환을 왼쪽에 두십시오. 3. 이제 변환은 "rotateZ (30deg) matrix3d (......)와 같습니다. 4. 다음에 다른 변환을 추가하려면 프로세스를 반복하십시오. Chrome은 항상 변환을 matrix3d 표기법으로 줄입니다.
TL; DR- 원하는 변환을 적용한 다음 계산 된 matrix3d 변환을 가져옵니다.
이 트릭을 사용하면 어떤 방향 으로든 기준 좌표계를 기준으로 개체를 회전하는 기능을 빠르게 (즉, 혼자서 수학하지 않고도) 만들 수 있습니다. 아래 샘플을 참조하십시오.
편집 : 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>