如何在点击时正确旋转立方体?

4
所以我试图做的基本上是通过点击位于立方体上或旁边漂浮的按钮来旋转一个立方体。目前我把它们保持漂浮状态,因为我试验了很多次,发现这样更容易,但在立方体上放置它们也不是问题。
实际问题是并不是所有的旋转轴都被同等对待。我的意思是,如果我沿着X轴旋转,Y轴和Z轴也会旋转。但如果我沿着Y(或Z)轴旋转,则Z轴(或Y轴)会旋转,但是X轴总是保持不变。
在我的代码中,这意味着无论立方体如何旋转,通过点击红色方块“3”或“4”触发的沿着X轴的旋转将始终使立方体向上或向下旋转,而其他按钮将根据其位置旋转立方体。
不要介意数字1、2、5和6被交换。这只是我能找到的最接近解决方案,但是随机旋转立方体一段时间后总会产生奇怪的移动。
我的代码:

var rotationX = 0;
var rotationY = 0;
var rotationZ = 0;
var rotation = 0;
var translate = 0;

function showDebug() {
    var deBugInfo = '<p>X: '+rotationX + '</p>';
    deBugInfo += '<p>Y: '+rotationY + '</p>';
    deBugInfo += '<p>Z: '+rotationZ + '</p>';
    
    $('#deBug').html(deBugInfo);
}

function cubeRotate() {
    $('#cube').css('transform', 'rotateX('+rotationX+'deg) rotateY('+rotationY+'deg) rotateZ('+rotationZ+'deg)');
    
    showDebug();
}

/*

function buttonsRotate() {
    $('#buttons').css('transform', 'rotate('+rotation+'deg) translate('+0+')');
    
    showDebug();
}

*/

$(function () {

    $('#dir1').on('click', function () {
        //var myStyle = $('#cube').css('transform');
        //console.log(myStyle);
        //rotationY = rotationY - 90;
        rotationY -= 90;
        cubeRotate();
    });
    
    $('#dir2').on('click', function () {
        rotationY += 90;
        cubeRotate();
    });
    
    $('#dir3').on('click', function () {
        rotationX -= 90;
        cubeRotate();
        rotation -= 90;
//        buttonsRotate();
    });
    
    $('#dir4').on('click', function () {
        rotationX += 90;
        cubeRotate();
        rotation += 90;
//        buttonsRotate();
    });
   
    $('#dir5').on('click', function () {
        rotationZ += 90;
        cubeRotate();
    });
    
    $('#dir6').on('click', function () {
        rotationZ -= 90;
        cubeRotate();
    });

});
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

body {
    font-size: 16px;
    font-family: sans-serif;
    width: 100%;
    height: 100%;
    position: absolute;
    -webkit-perspective: 100vmax;
    /* Safari 4-8 */
    -webkit-perspective-origin: 50% 50%;
    /* Safari 4-8 */
    perspective: 100vmax;
    perspective-origin: 50% 50%;
    overflow: hidden;
}

#cube {
    margin: auto;
    position: absolute;
    top: 50%;
    left: 50%;
    transform-style: preserve-3d;
    transition-duration: 0.5s;
}

.cubeface {
    position: absolute;
    height: 60vmin;
    width: 60vmin;
    margin-left: -30vmin;
    margin-top: -30vmin;
    opacity: 0.5;
}

.cubeface:nth-child(1) {
    transform: rotateY(0deg) translateY(0px) translateZ(30vmin);
    background-color: black;
}

.cubeface:nth-child(2) {
    transform: rotateY(90deg) translateY(0px) translateZ(30vmin);
    background-color: #343434;
}

.cubeface:nth-child(3) {
    transform: rotateY(180deg) translateY(0px) translateZ(30vmin);
    background-color: #525252;
}

.cubeface:nth-child(4) {
    transform: rotateY(270deg) translateY(0px) translateZ(30vmin);
    background-color: #818181;
}

.cubeface:nth-child(5) {
    transform: rotateX(90deg) translateZ(30vmin) translateY(0px);
    background-color: #a0a0a0;
}

.cubeface:nth-child(6) {
    transform: rotateX(-90deg) translateZ(30vmin) translateY(0px);
    background-color: #d8d8d8;
}


.content {
    width: 100%;
    height: 100%;
    position: absolute;
    border-radius: 50%;
    background-color: #a7ff8d;

    color: #f00;
    font-size: 3em;
}

.arrow {
    margin: auto;
    position: absolute;
    left: 50%;
    top: 90vmin;
    width: 5vmin;
    height: 5vmin;

    margin-left: -2.5vmin;
    margin-top: -2.5vmin;

}

.achse {
    height: 2px;
    width: 65vmin;
    background: #f00;
    position: absolute;
    top: 0;
    left: 0;
    transform-origin: 0;
    backface-visibility: visible;
    transform-style: preserve-3d;
}

.achseY {
    background: #0f0;
    transform: rotateZ(-90deg) rotateX(45deg);
}

.achseZ {
    background: #00f;
    transform: rotateY(-90deg) rotateX(45deg);
}

.achseX {
    transform: rotateX(45deg);
}

#deBug {
    background: #000;
    color: #FFF;
    font-size: 2em;
    padding: 1em;
    position: absolute;
    top: 0;
    right: 0;

}

#buttons {
    width: 100%;
    height: 100%;
    z-index: 5;
}

#dir1 {
    margin-left: -27.5vmin;
    background-color: red;
    z-index: 5;

}

#dir2 {
    margin-left: -17.5vmin;
    background-color: red;
    z-index: 5;

}

#dir3 {
    margin-left: -7.5vmin;
    background-color: red;
    z-index: 10;

}

#dir4 {
    margin-left: 2.5vmin;
    background-color: red;
    z-index: 10;

}

#dir5 {
    margin-left: 12.5vmin;
    background-color: red;
    z-index: 5;

}

#dir6 {
    margin-left: 22.5vmin;
    background-color: red;
    z-index: 5;

}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!doctype html>
<html>

<head>

    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">

    <title>Test</title>

    <link rel="stylesheet" href="styles/screen.css">

    <script src="scripts/jquery-3.3.1.min.js"></script>
    <script src="scripts/app.js"></script>

</head>

<body>

    <div id="deBug">

    </div>

    <div class='arrow' id='dir3'>X-</div>
    <div class='arrow' id='dir4'>X+</div>

    <div id="buttons">

        <div class='arrow' id='dir1'>Y-</div>
        <div class='arrow' id='dir2'>Y+</div>
        <div class='arrow' id='dir5'>Z+</div>
        <div class='arrow' id='dir6'>Z-</div>

    </div>

    <div id="cube">

        <div class="cubeface" id="A">

            <div class="content" id="main">

                <p>A</p>

            </div>


            <div class="dir1 right">

            </div>

            <div class="dir2 left">

            </div>

            <div class="dir3 up">

            </div>

            <div class="dir4 down">

            </div>


        </div>

        <div class="cubeface" id="B">

            <div class="content" id="">

                <p>B</p>

            </div>


            <div class="dir1 right">

            </div>

            <div class="dir2 left">

            </div>

            <div class="dir5 up">

            </div>

            <div class="dir6 down">

            </div>


        </div>

        <div class="cubeface" id="C">

            <div class="content" id="">

                <p>C</p>

            </div>


            <div class="dir1 right">

            </div>

            <div class="dir2 left">

            </div>

            <div class="dir4 up">

            </div>

            <div class="dir3 down">

            </div>


        </div>

        <div class="cubeface" id="D">

            <div class="content" id="">

                <p>D</p>

            </div>


            <div class="dir1 right">

            </div>

            <div class="dir2 left">

            </div>

            <div class="dir6 up">

            </div>

            <div class="dir5 down">

            </div>


        </div>

        <div class="cubeface" id="E">

            <div class="content" id="">

                <p>E</p>

            </div>



            <div class="dir6 right">

            </div>

            <div class="dir5 left">

            </div>

            <div class="dir3 up">

            </div>

            <div class="dir4 down">

            </div>


        </div>

        <div class="cubeface" id="F">

            <div class="content" id="">

                <p>F</p>

            </div>


            <div class="dir5 right">

            </div>

            <div class="dir6 left">

            </div>

            <div class="dir3 up">

            </div>

            <div class="dir4 down">

            </div>


        </div>

        <div class="achse achseX"></div>
        <div class="achse achseY"></div>
        <div class="achse achseZ"></div>

    </div>

</body>

</html>

我尝试给每个元素都添加“transform-style:preserve-3d”,但没有成功。 我认为在立方体按钮上可能更有效,但这是以后需要回答的问题,而不是这里的主题。

如果有人知道如何平等地处理所有轴线,请告诉我,我正在慢慢变得疯狂:D

谢谢!

编辑:

2018_04_18: 也尝试设置转换原点,但没有成功。

2018_04_19: 更新了代码段,使按钮不再旋转,而是固定,因此您可以始终单击它们。

2018_04_20:

我发现了两个pencode的示例,可能会有所帮助(它们都通过鼠标拖动立方体来工作,我不确定这是否与问题有关)...

  1. https://codepen.io/jordizle/pen/haIdo/ 这个立方体具有良好的外观,可以自动旋转侧面,以便可以正确读取。 但是,如果将其旋转到1或6面,它会显示与我的立方体相同的问题,因为它根本无法向左或向右旋转。

  2. https://codepen.io/ge1doot/pen/PqZKbv 在这个示例中,问题似乎已解决。 无论立方体的位置如何,您都可以朝任何方向旋转它。(我不需要拆分它的功能)我的问题是我看不出他们使用的脚本之间的区别,因此我不知道为什么第二个完美地旋转,但我有一种感觉这是正确的轨迹。 如果有人能够比较它们并解决这个谜团,那就太好了;)


1
转换原点?https://developer.mozilla.org/zh-CN/docs/Web/CSS/transform-origin - August
1
我也试过了。谢谢你的提问,我忘记在上面添加它了。 - Anton Feirer
2个回答

2
相对旋转 - 轴随立方体一同旋转。

function rotate(axis, degrees) {
    cube.outerHTML = `<div class='gimbal' id='container' style="transition: all 0.5s; transform-style: preserve-3d; transform: rotate${axis}(0deg); position: relative; transition-timing-function: ease-in-out; width: 0; height: 0; transform-origin: 50vw 50vh;">${cube.outerHTML}</div>`;
    window.setTimeout(function () {
        container.style.transform = `rotate${axis}(${degrees}deg)`;
        container.removeAttribute('id');
    }, 10);
}
$('#dir1').on('click', function () {
    rotate('Y', '90');
});

$('#dir2').on('click', function () {
    rotate('Y', '-90');
});

$('#dir3').on('click', function () {
    rotate('X', '90');
});

$('#dir4').on('click', function () {
    rotate('X', '-90');
});

$('#dir5').on('click', function () {
    rotate('Z', '90');
});

$('#dir6').on('click', function () {
    rotate('Z', '-90');
});
rotate('X', '0');
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

html, body {
    font-size: 16px;
    font-family: sans-serif;
    width: 100%;
    height: 100%;
    -webkit-perspective: 100vmax;
    /* Safari 4-8 */
    -webkit-perspective-origin: 50% 50%;
    /* Safari 4-8 */
    perspective: 100vmax;
    perspective-origin: 50% 50%;
    overflow: hidden;
}

#cube {
    margin: auto;
    position: absolute;
    top: 50vh; left: 50vw;
    transform-style: preserve-3d;
}

.cubeface {
    position: absolute;
    height: 60vmin;
    width: 60vmin;
    margin-left: -30vmin;
    margin-top: -30vmin;
    opacity: 0.5;
}

.cubeface:nth-child(1) {
    transform: rotateY(0deg) translateY(0px) translateZ(30vmin);
    background-color: black;
}

.cubeface:nth-child(2) {
    transform: rotateY(90deg) translateY(0px) translateZ(30vmin);
    background-color: #343434;
}

.cubeface:nth-child(3) {
    transform: rotateY(180deg) translateY(0px) translateZ(30vmin);
    background-color: #525252;
}

.cubeface:nth-child(4) {
    transform: rotateY(270deg) translateY(0px) translateZ(30vmin);
    background-color: #818181;
}

.cubeface:nth-child(5) {
    transform: rotateX(90deg) translateZ(30vmin) translateY(0px);
    background-color: #a0a0a0;
}

.cubeface:nth-child(6) {
    transform: rotateX(-90deg) translateZ(30vmin) translateY(0px);
    background-color: #d8d8d8;
}


.content {
    width: 100%;
    height: 100%;
    position: absolute;
    border-radius: 50%;
    background-color: #a7ff8d;

    color: #f00;
    font-size: 3em;
}

.arrow {
    margin: auto;
    position: absolute;
    left: 50%;
    top: 90vmin;
    width: 5vmin;
    height: 5vmin;

    margin-left: -2.5vmin;
    margin-top: -2.5vmin;

}

.achse {
    height: 2px;
    width: 65vmin;
    background: #f00;
    position: absolute;
    top: 0;
    left: 0;
    transform-origin: 0;
    backface-visibility: visible;
    transform-style: preserve-3d;
}

.achseY {
    background: #0f0;
    transform: rotateZ(-90deg) rotateX(45deg);
}

.achseZ {
    background: #00f;
    transform: rotateY(-90deg) rotateX(45deg);
}

.achseX {
    transform: rotateX(45deg);
}

#deBug {
    background: #000;
    color: #FFF;
    font-size: 2em;
    padding: 1em;
    position: absolute;
    top: 0;
    right: 0;

}

#buttons {
    width: 100%;
    height: 100%;
    z-index: 5;
}

#dir1 {
    margin-left: -27.5vmin;
    background-color: red;
    z-index: 5;

}

#dir2 {
    margin-left: -17.5vmin;
    background-color: red;
    z-index: 5;

}

#dir3 {
    margin-left: -7.5vmin;
    background-color: red;
    z-index: 10;

}

#dir4 {
    margin-left: 2.5vmin;
    background-color: red;
    z-index: 10;

}

#dir5 {
    margin-left: 12.5vmin;
    background-color: red;
    z-index: 5;

}

#dir6 {
    margin-left: 22.5vmin;
    background-color: red;
    z-index: 5;

}
<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width,initial-scale=1">

        <title>Test</title>

        <link rel="stylesheet" href="styles/screen.css">

        <script src="scripts/jquery-3.3.1.min.js"></script>
        <script src="scripts/app.js"></script>
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    </head>

    <body>

        <div id="cube" class="gimbal">

            <div class="cubeface" id="A">

                <div class="content" id="main">

                    <p>A</p>

                </div>


                <div class="dir1 right">

                </div>

                <div class="dir2 left">

                </div>

                <div class="dir3 up">

                </div>

                <div class="dir4 down">

                </div>


            </div>

            <div class="cubeface" id="B">

                <div class="content" id="">

                    <p>B</p>

                </div>


                <div class="dir1 right">

                </div>

                <div class="dir2 left">

                </div>

                <div class="dir5 up">

                </div>

                <div class="dir6 down">

                </div>


            </div>

            <div class="cubeface" id="C">

                <div class="content" id="">

                    <p>C</p>

                </div>


                <div class="dir1 right">

                </div>

                <div class="dir2 left">

                </div>

                <div class="dir4 up">

                </div>

                <div class="dir3 down">

                </div>


            </div>

            <div class="cubeface" id="D">

                <div class="content" id="">

                    <p>D</p>

                </div>


                <div class="dir1 right">

                </div>

                <div class="dir2 left">

                </div>

                <div class="dir6 up">

                </div>

                <div class="dir5 down">

                </div>


            </div>

            <div class="cubeface" id="E">

                <div class="content" id="">

                    <p>E</p>

                </div>



                <div class="dir6 right">

                </div>

                <div class="dir5 left">

                </div>

                <div class="dir3 up">

                </div>

                <div class="dir4 down">

                </div>


            </div>

            <div class="cubeface" id="F">

                <div class="content" id="">

                    <p>F</p>

                </div>


                <div class="dir5 right">

                </div>

                <div class="dir6 left">

                </div>

                <div class="dir3 up">

                </div>

                <div class="dir4 down">

                </div>


            </div>
        </div>
        
        <div id="buttons">
            <div class='arrow' id='dir1'>Y+</div>
            <div class='arrow' id='dir2'>Y-</div>
            <div class='arrow' id='dir3'>X+</div>
            <div class='arrow' id='dir4'>X-</div>
            <div class='arrow' id='dir5'>Z+</div>
            <div class='arrow' id='dir6'>Z-</div>
        </div>
    </body>
</html>


全局旋转 - 轴不随立方体旋转。

function rotate(axis, degrees) {
    let outermostRotator = $('body > .gimbal').get(0);
    outermostRotator.outerHTML = `<div class='gimbal' id='container' style="transition: all 0.5s; transform-style: preserve-3d; transform: rotate${axis}(0deg); position: relative; transition-timing-function: ease-in-out; width: 0; height: 0; transform-origin: 50vw 50vh;">${outermostRotator.outerHTML}</div>`;
    window.setTimeout(function () {
        container.style.transform = `rotate${axis}(${degrees}deg)`;
        container.removeAttribute('id');
    }, 10);
}
$('#dir1').on('click', function () {
    rotate('Y', '90');
});

$('#dir2').on('click', function () {
    rotate('Y', '-90');
});

$('#dir3').on('click', function () {
    rotate('X', '90');
});

$('#dir4').on('click', function () {
    rotate('X', '-90');
});

$('#dir5').on('click', function () {
    rotate('Z', '90');
});

$('#dir6').on('click', function () {
    rotate('Z', '-90');
});
rotate('X', '0');
* {
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}

html, body {
    font-size: 16px;
    font-family: sans-serif;
    width: 100%;
    height: 100%;
    -webkit-perspective: 100vmax;
    /* Safari 4-8 */
    -webkit-perspective-origin: 50% 50%;
    /* Safari 4-8 */
    perspective: 100vmax;
    perspective-origin: 50% 50%;
    overflow: hidden;
}

#cube {
    margin: auto;
    position: absolute;
    top: 50vh; left: 50vw;
    transform-style: preserve-3d;
}

.cubeface {
    position: absolute;
    height: 60vmin;
    width: 60vmin;
    margin-left: -30vmin;
    margin-top: -30vmin;
    opacity: 0.5;
}

.cubeface:nth-child(1) {
    transform: rotateY(0deg) translateY(0px) translateZ(30vmin);
    background-color: black;
}

.cubeface:nth-child(2) {
    transform: rotateY(90deg) translateY(0px) translateZ(30vmin);
    background-color: #343434;
}

.cubeface:nth-child(3) {
    transform: rotateY(180deg) translateY(0px) translateZ(30vmin);
    background-color: #525252;
}

.cubeface:nth-child(4) {
    transform: rotateY(270deg) translateY(0px) translateZ(30vmin);
    background-color: #818181;
}

.cubeface:nth-child(5) {
    transform: rotateX(90deg) translateZ(30vmin) translateY(0px);
    background-color: #a0a0a0;
}

.cubeface:nth-child(6) {
    transform: rotateX(-90deg) translateZ(30vmin) translateY(0px);
    background-color: #d8d8d8;
}


.content {
    width: 100%;
    height: 100%;
    position: absolute;
    border-radius: 50%;
    background-color: #a7ff8d;

    color: #f00;
    font-size: 3em;
}

.arrow {
    margin: auto;
    position: absolute;
    left: 50%;
    top: 90vmin;
    width: 5vmin;
    height: 5vmin;

    margin-left: -2.5vmin;
    margin-top: -2.5vmin;

}

.achse {
    height: 2px;
    width: 65vmin;
    background: #f00;
    position: absolute;
    top: 0;
    left: 0;
    transform-origin: 0;
    backface-visibility: visible;
    transform-style: preserve-3d;
}

.achseY {
    background: #0f0;
    transform: rotateZ(-90deg) rotateX(45deg);
}

.achseZ {
    background: #00f;
    transform: rotateY(-90deg) rotateX(45deg);
}

.achseX {
    transform: rotateX(45deg);
}

#deBug {
    background: #000;
    color: #FFF;
    font-size: 2em;
    padding: 1em;
    position: absolute;
    top: 0;
    right: 0;

}

#buttons {
    width: 100%;
    height: 100%;
    z-index: 5;
}

#dir1 {
    margin-left: -27.5vmin;
    background-color: red;
    z-index: 5;

}

#dir2 {
    margin-left: -17.5vmin;
    background-color: red;
    z-index: 5;

}

#dir3 {
    margin-left: -7.5vmin;
    background-color: red;
    z-index: 10;

}

#dir4 {
    margin-left: 2.5vmin;
    background-color: red;
    z-index: 10;

}

#dir5 {
    margin-left: 12.5vmin;
    background-color: red;
    z-index: 5;

}

#dir6 {
    margin-left: 22.5vmin;
    background-color: red;
    z-index: 5;

}
<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width,initial-scale=1">

        <title>Test</title>

        <link rel="stylesheet" href="styles/screen.css">

        <script src="scripts/jquery-3.3.1.min.js"></script>
        <script src="scripts/app.js"></script>
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    </head>

    <body>

        <div id="cube" class="gimbal">

            <div class="cubeface" id="A">

                <div class="content" id="main">

                    <p>A</p>

                </div>


                <div class="dir1 right">

                </div>

                <div class="dir2 left">

                </div>

                <div class="dir3 up">

                </div>

                <div class="dir4 down">

                </div>


            </div>

            <div class="cubeface" id="B">

                <div class="content" id="">

                    <p>B</p>

                </div>


                <div class="dir1 right">

                </div>

                <div class="dir2 left">

                </div>

                <div class="dir5 up">

                </div>

                <div class="dir6 down">

                </div>


            </div>

            <div class="cubeface" id="C">

                <div class="content" id="">

                    <p>C</p>

                </div>


                <div class="dir1 right">

                </div>

                <div class="dir2 left">

                </div>

                <div class="dir4 up">

                </div>

                <div class="dir3 down">

                </div>


            </div>

            <div class="cubeface" id="D">

                <div class="content" id="">

                    <p>D</p>

                </div>


                <div class="dir1 right">

                </div>

                <div class="dir2 left">

                </div>

                <div class="dir6 up">

                </div>

                <div class="dir5 down">

                </div>


            </div>

            <div class="cubeface" id="E">

                <div class="content" id="">

                    <p>E</p>

                </div>



                <div class="dir6 right">

                </div>

                <div class="dir5 left">

                </div>

                <div class="dir3 up">

                </div>

                <div class="dir4 down">

                </div>


            </div>

            <div class="cubeface" id="F">

                <div class="content" id="">

                    <p>F</p>

                </div>


                <div class="dir5 right">

                </div>

                <div class="dir6 left">

                </div>

                <div class="dir3 up">

                </div>

                <div class="dir4 down">

                </div>


            </div>
        </div>
        
        <div id="buttons">
            <div class='arrow' id='dir1'>Y+</div>
            <div class='arrow' id='dir2'>Y-</div>
            <div class='arrow' id='dir3'>X+</div>
            <div class='arrow' id='dir4'>X-</div>
            <div class='arrow' id='dir5'>Z+</div>
            <div class='arrow' id='dir6'>Z-</div>
        </div>
    </body>
</html>


1
谢谢回答!(对于晚回复我很抱歉) 在这个论坛里它似乎完美地工作了,但是如果我将它复制到我的项目中,按钮就不会响应。这可能与导入的库或您使用的不同逗号有关吗? - Anton Feirer

1
你遇到的问题是由欧拉角顺序引起的。基本上,它决定了计算最终旋转时轴的使用顺序。
CSS变换的欧拉角顺序是最常见的:X、Y、Z。
首先计算X轴,因此它总是固定在其静止位置。你无法在CSS中更改欧拉角顺序。即使可以,欧拉角顺序的第一个轴也始终会"不被平等对待"。
欧拉旋转的另一个问题是万向锁。在你的演示中,单击X、单击Y和单击Z。现在尝试旋转X和Z。它们是相同的!你刚刚遇到了万向锁,这是非常难以解决的,仅使用CSS无法修复。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接