Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is my 3d cube not rotating as expected?

I'm doing a 3d dice that rotates when you swipe its face. The problem is that it is acting really weird on some cases. For example, if you run the snippet and swipe left two times then swipe down, it does a crazy rotation...

Here is the code:

$(function() {
  
  var X = 0,
    Y = 0;
  
  var hammertime = new Hammer($(".thirdDimension")[0], {domEvents: true});
  
  hammertime.get('swipe').set({ direction: Hammer.DIRECTION_ALL });
  
  function rotate(what) {
    switch (what) {
      case "X":
        $(".cube").css("transform", "rotateX(" + X + "deg) rotateY(" + Y +"deg)");
        break;
      case "Y":
        $(".cube").css("transform", "rotateY(" + Y +"deg) rotateX(" + X + "deg)");
        break;
    }
    $("#debug").html($("#debug").html() + $(".cube").attr("style") + "<br>").scrollTop($("#debug")[0].scrollHeight);
  }
  
  $(".thirdDimension").on("swipeleft", function(e){
    Y -= 90;
    rotate("Y");
  });

  $(".thirdDimension").on("swiperight", function(e){
    Y += 90;
    rotate("Y");
  });
  
  $(".thirdDimension").on("swipeup", function(e){
    X += 90;
    rotate("X");
  });
  
  $(".thirdDimension").on("swipedown", function(e){
    X -= 90;
    rotate("X");
  });
  
});
* {
  box-sizing: border-box;
}
html, body {
  height: 100%;
  font-family: sans-serif;
}
.tableContainer, .vcenter {
  height: 100%;
  width: 100%;
}
.tableContainer {
  display: table;
}
.vcenter {
  height: 100%;
  display: table-cell;
  vertical-align: middle;
}
.thirdDimension {
  perspective: 500px;
	perspective-origin: 50% 100px;
}
.cube {
  margin: 0 auto;
  position: relative;
	width: 200px;
  height: 200px;
	transform-style: preserve-3d;
}
.cube div {
	position: absolute;
	width: 200px;
	height: 200px;
  box-shadow: inset 0 0 30px black;
  font-size: 72pt;
  padding-top: 35px;
  text-align: center;
  background-color: black;
}

.right {
  transform: rotateY(-270deg) translateX(100px);
	transform-origin: top right;
}
.left {
	transform: rotateY(270deg) translateX(-100px);
	transform-origin: center left;
}
.up {
	transform: rotateX(90deg) translateY(-100px);
	transform-origin: top center;
}
.down {
	transform: rotateX(-90deg) translateY(100px);
	transform-origin: bottom center;
}
.front {
	transform: translateZ(100px);
}
.back {
	transform: translateZ(-100px) rotateY(180deg);
}
.cube {
  -webkit-transition: .3s all linear;
  cursor: pointer;
}
.cube div:after {
  display: block;
  position: absolute;
  width: 100px;
  height: 100px;
  content: "";
  border: 1px solid;
}
.front:after {
  top: 0;
  right: 0;
  background-color: green;
}
.back:after {
  bottom: 0;
  right: 0;
  background-color: blue;
}
.right:after {
  top: 0;
  left: 0;
  background-color: red;
}
.left:after {
  bottom: 0;
  left: 0;
  background-color: DarkOrange;
}
.up:after {
  right: 0;
  bottom: 0;
  background-color: white;
}
.down:after {
  bottom: 0;
  left: 0;
  background-color: yellow;
}
#debug {
  position: fixed;
  background-color: cyan;
  overflow: auto;
  height: 50px;
  width: 100%;
}
/*
.cube {
  animation: linear 5s rotate infinite;
}
@-webkit-keyframes rotate {
  0% {
    transform: rotateX(0deg) rotateY(0deg);
  }
  100% {
    transform: rotateX(360deg) rotateY(720deg);
  }
}
*/
<script src="https://cdnjs.cloudflare.com/ajax/libs/hammer.js/2.0.8/hammer.min.js"></script>
<script src="https://code.jquery.com/jquery-2.2.4.min.js"></script>
<div id='debug'></div>
<div class='tableContainer'>
  <div class='vcenter'>
    <div class='thirdDimension'>
      <div class='cube'>
        <div class='up'></div>
        <div class='front'></div>
        <div class='right'></div>
        <div class='left'></div>
        <div class='back'></div>
        <div class='down'></div>
      </div>
    </div>
  </div>
</div>

EDIT: This link: http://greensock.com/forums/topic/7811-3d-rotation-fixed-axsis/ says that the order of the rotations matter. I changed my code slightly but it keeps rotating unexpectedly...

like image 603
Filipe Teixeira Avatar asked Jul 15 '16 16:07

Filipe Teixeira


People also ask

How do you rotate a cube to stand on a corner?

Yes, here's one of several ways to do it. Select the box, then select the rotate tool, Rotate the box 45 degrees on the Y axis, then Rotate the Box 45 degrees on the X axis and you have what you were looking for.


Video Answer


2 Answers

First: Settings the transform different ways for either "X" or "Y" was causing the massive spinning. I changed them both to:

$(".cube").css("transform", "rotateX(" + X + "deg) rotateY(" + Y +"deg)");

If believe you wish for the cube to always spin in the direction of the swipe. Continue reading if so or if not , all you needed to change was the above code.


Second: When you spin the cube you are changing the orientation. The x-axis is never messed up but the y-axis and z-axis are switching without you really noticing.

Now you can to add rotateZ to the mix:

$(".cube").css("transform", "rotateX(" + X + "deg) rotateY(" + Y +"deg) rotateZ(" + Z + "deg)");

I have changed the code here in this CodePen to provide an example. I have not completed it because I have revealed the issue, but do not have the time to perfect it.

$(function() {

    var X = 0,
      Y = 0,
      Z = 0;

    var hammertime = new Hammer($(".thirdDimension")[0], {domEvents: true});

  hammertime.get('swipe').set({ direction: Hammer.DIRECTION_ALL });

  function rotate() {
      $(".cube").css("transform", "rotateX(" + X + "deg) rotateY(" + Y +"deg) rotateZ(" + Z + "deg)");
      $("#debug").html($("#debug").html() + $(".cube").attr("style") + "<br>").scrollTop($("#debug")[0].scrollHeight);
  }

  $(".thirdDimension").on("swipeleft", function(e){
      //Y -= 90;
      check(-90);
      rotate();
  });

  $(".thirdDimension").on("swiperight", function(e){
      //Y += 90;
    check(90);
    rotate();
  });

  $(".thirdDimension").on("swipeup", function(e){
      X += 90;
      rotate();
  });

  $(".thirdDimension").on("swipedown", function(e){
      X -= 90;
      rotate();
  });

  function check(num) {
      var temp = Math.abs(X % 360);
          switch (temp) {
              case 0:
                  console.log(temp);
                  Y += num;
                  break;
              case 90:
                  console.log(temp);
                  Z -= num
                  break;
              case 180:
                  console.log(temp);
                  Y -= num;
                  break;
             case 270:
                 console.log(temp);
                 Z -= num;
                 break;
          }
    }

});

You need to check the y-axis (Math.abs(Y % 360))) and possibly the z-axis and rotate either the y-axis and z-axis (+- 90) accordingly.

This mostly works, but needs fine tuning in determining the correct axis to rotate. Good luck.

like image 111
theblindprophet Avatar answered Oct 12 '22 23:10

theblindprophet


Your problem is more how you have conceptualized rotation than any coding mistakes.

If you rotateY(90), then rotateX(90) - then by the time you get to rotateX(90), your X axis has rotated by 90 degrees, so it is no longer left to right, but into/out of screen. So your thing will look like it's doing a 2d rotate in that particular instance.

And to take it further, if the user now swipes left to right, they are actually swiping along the Z axis, and you need to rotate Z.

To fix this, you need to keep track of the rotation you have done and map the user interface to the cube in a more dynamic way. Swiping left to right doesn't always mean rotate Y, it means rotate along the axis that is currently oriented left to right.

I suggest you find a rubik's cube or similar, and label the sides per axis (e.g. Red side is X axis), simulate the swiping, and then that should make things more clear, as you'll see those axis move around the cube.

like image 43
binderbound Avatar answered Oct 12 '22 23:10

binderbound