Làm thế nào để kết hợp rotateX(50deg) rotateY(20deg) rotateZ(15deg)
trong tốc ký rotate3d()
?
Làm thế nào để kết hợp rotateX(50deg) rotateY(20deg) rotateZ(15deg)
trong tốc ký rotate3d()
?
Câu trả lời:
rotateX(50deg)
tương đương với rotate3d(1, 0, 0, 50deg)
rotateY(20deg)
tương đương với rotate3d(0, 1, 0, 20deg)
rotateZ(15deg)
tương đương với rotate3d(0, 0, 1, 15deg)
Vì thế...
rotateX(50deg) rotateY(20deg) rotateZ(15deg)
tương đương với
rotate3d(1, 0, 0, 50deg) rotate3d(0, 1, 0, 20deg) rotate3d(0, 0, 1, 15deg)
Đối với một cái chung rotate3d(x, y, z, α)
, bạn có ma trận
Ở đâu
Bây giờ bạn nhận được các ma trận cho mỗi rotate3d
phép biến đổi trong số 3 phép biến đổi và bạn nhân chúng lên. Và ma trận kết quả là ma trận tương ứng với đơn kết quả rotate3d
. Không chắc làm thế nào để dễ dàng trích xuất các giá trị rotate3d
từ nó, nhưng chắc chắn là dễ dàng để trích xuất các giá trị đó cho một lần matrix3d
.
Trong trường hợp đầu tiên ( rotateX(50deg)
hoặc rotate3d(1, 0, 0, 50deg)
), bạn có:
x = 1
, y = 0
, z = 0
,α = 50deg
Vì vậy, hàng đầu tiên của ma trận trong trường hợp này là 1 0 0 0
.
Cái thứ hai là 0 cos(50deg) -sin(50deg) 0
.
Cái thứ ba 0 sin(50deg) cos(50deg) 0
.
Và điều thứ tư rõ ràng là 0 0 0 1
.
Trong trường hợp thứ hai, bạn có x = 0
, y = 1
, z = 0
, α = 20deg
.
Hàng đầu tiên: cos(20deg) 0 sin(20deg) 0
.
Hàng thứ hai: 0 1 0 0
.
Hàng thứ ba: -sin(20) 0 cos(20deg) 0
.
Thứ tư: 0 0 0 1
Trong trường hợp thứ ba, bạn có x = 0
, y = 0
, z = 1
, α = 15deg
.
Hàng đầu tiên: cos(15deg) -sin(15deg) 0 0
.
Hàng thứ hai sin(15deg) cos(15deg) 0 0
.
Và hàng thứ ba và thứ tư là 0 0 1 0
và 0 0 0 1
tương ứng.
Lưu ý : bạn có thể nhận thấy rằng các dấu hiệu của giá trị sin đối với biến đổi xoayY khác với hai biến đổi còn lại. Đó không phải là một sai lầm tính toán. Lý do cho điều này là đối với màn hình, bạn có trục y hướng xuống chứ không phải hướng lên.
Vì vậy, đây là ba 4x4
ma trận mà bạn cần nhân để có được 4x4
ma trận cho kết quả rotate3d
biến đổi đơn . Như tôi đã nói, tôi không chắc việc lấy ra 4 giá trị dễ dàng như thế nào, nhưng 16 phần tử trong ma trận 4x4 chính xác là 16 tham số matrix3d
tương đương của phép biến đổi chuỗi.
CHỈNH SỬA :
Trên thực tế, hóa ra nó khá dễ dàng ... Bạn tính dấu vết (tổng các phần tử đường chéo) của ma trận cho rotate3d
ma trận.
4 - 2*2*(1 - cos(α))/2 = 4 - 2*(1 - cos(α)) = 2 + 2*cos(α)
Sau đó, bạn tính toán dấu vết cho tích của ba 4x4
ma trận, bạn cân bằng kết quả với 2 + 2*cos(α)
bạn trích xuất α
. Sau đó, bạn tính toán x
, y
, z
.
Trong trường hợp cụ thể này, nếu tôi tính toán chính xác, dấu vết của ma trận tạo ra từ tích của ba 4x4
ma trận sẽ là:
T =
cos(20deg)*cos(15deg) +
cos(50deg)*cos(15deg) - sin(50deg)*sin(20deg)*cos(15deg) +
cos(50deg)*cos(20deg) +
1
Vì vậy cos(α) = (T - 2)/2 = T/2 - 1
, có nghĩa là vậy α = acos(T/2 - 1)
.
[x,y,z]
vectơ được chuẩn hóa, tức là chỉ khi độ dài vectơ Math.sqrt(x*x + y*y + z*z)
là một. Nếu nó không được bình thường, nó có thể dễ dàng được chuyển đổi thành một bình thường, bởi lặn mỗi x
, y
và z
theo chiều dài của họ.
Cú pháp:
rotate3d(x, y, z, a)
Giá trị:
x
Là một <number>
mô tả tọa độ x của vector biểu thị trục quay.y
Là một <number>
mô tả tọa độ y của vector biểu thị trục quay.z
Là một <number>
mô tả tọa độ z của vector biểu thị trục quay.a
Là một <angle>
đại diện cho góc quay. Góc dương biểu thị sự quay theo chiều kim đồng hồ, góc âm biểu thị chiều quay ngược chiều kim đồng hồ.Giống như trong :
.will-distort{
transform:rotate3d(10, 10, 10, 45deg);
}
rotate3d
, không phải cho định nghĩa rotate3d
.
Tùy thuộc vào những gì bạn đang cố gắng làm, 'hack' này có thể giúp bạn. Giả sử bạn đang làm hoạt ảnh và bạn muốn thêm chuyển đổi sau khi chuyển đổi, v.v. và bạn không muốn CSS trông giống như đang thực hiện 100 lần biến đổi:
Điều này hoạt động trong chrome: 1. Áp dụng bất kỳ biến đổi nào bạn muốn cho một phần tử. 2. Lần tới khi bạn muốn thêm một biến đổi, hãy thêm nó vào biến đổi được tính toán: "window.getComputedStyle (element) .transform" - nhưng hãy đảm bảo đặt biến đổi mới ở bên trái. 3. Bây giờ biến đổi của bạn trông giống như "xoayZ (30deg) matrix3d (......). 4. Lần tới khi bạn muốn thêm một biến đổi khác, hãy lặp lại quy trình - Chrome luôn giảm các biến đổi thành ký hiệu matrix3d.
TL; DR- áp dụng bất kỳ phép biến đổi nào bạn muốn và sau đó nhận được phép biến đổi ma trận3d được tính toán.
Thủ thuật này cũng cho phép bạn nhanh chóng (nghĩa là, không cần tự mình làm bất kỳ phép toán nào) tạo một chức năng xoay một đối tượng liên quan đến hệ quy chiếu của bạn theo bất kỳ hướng nào. Xem mẫu bên dưới:
CHỈNH SỬA : Tôi cũng đã thêm các bản dịch xyz. Sử dụng điều này, sẽ rất dễ dàng để đặt các đối tượng ở các vị trí 3d cụ thể với các hướng cụ thể trong tâm trí. Hoặc ... tưởng tượng một khối lập phương nảy lên và thay đổi trục quay của nó với mỗi lần trả lại tùy thuộc vào cách nó tiếp đất!
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>