Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to place two or more cubes next to each other in the correct perspective using CSS transform?

I have this project setup in Code Sandbox:

Edit Vue Template

Screenshot (cubes won't look like that if you change the viewport size):

Screenshot

Goal:

My goal is to be able to place cubes next to each other or top of each other and keep stacking like filling the back of a truck: Starting from the deep end of the truck, filling the first layer with boxes, then stack on top till ceiling; keep stacking in front of those boxes like that until the truck is full.

Also, if we scale the screen, the cubes' positions should still look like they are next to each other (in my example you can see that is not the case).

We can use Vue or Javascript to calculate things that we cannot calculate using CSS, but let's try to use CSS as much as possible.

Data:

My markup is as such:

<div class="container">
  <div class="cubes-container">
    <!-- for each cube --->
    <div class="cube-wrap" >
        <div class="cube depth cube-isometric">
          <div class="front-pane">cube 1</div>
          <div class="back-pane">back 1</div>
          <div class="top-pane">top 1</div>
          <div class="bottom-pane">bottom 1</div>
          <div class="left-pane">left 1</div>
          <div class="right-pane">right 1</div>
        </div>
    </div>
  </div>
</div>

It was not a good idea to place the cube on the first cube's right side, this only works in certain resolutions:

.cube-wrap:nth-child(2) .cube {
    transform: translate3d(142.5px, 50px, 125px) rotateX(-30deg) rotateY(-45deg);
    transform-style: preserve-3d;
}

The controls I have on the left weren't so great either. They were changing the left and top values of the .cube-wrap. If you input a number you can see the cubes moving. Also, if you add a cube you can see the third one lands on origin. I was going to use these controls to test where the cubes are going to be.

I tried setting the perspective on the container to look at all the cubes from that perspective:

.container {
  position: absolute;
  left: 240px;
  top: 0;
  bottom: 0;
  right: 0;
  background: grey;
  perspective: 1000px;
  perspective-origin: 50% 100px;
}

My cube CSS is as such (removed supporting css like -ms or -moz to save space) I got this cube from https://davidwalsh.name/css-cube

.cube-isometric {
  transform: rotateX(-30deg) rotateY(-45deg);
  transform-origin: 50% 50% 0;
}
/*************** STANDARD CUBE ***************/

.cube {
  position: relative;
  width: 200px;
  margin: 0 auto;
  transform-style: preserve-3d;
  animation: cube-spin 5s infinite linear;
}
.cube div {
  position: absolute;
  width: 200px;
  height: 200px;
  background: rgba(38, 93, 79, 0.87);
  box-shadow: inset 0 0 30px #c7ffb6;
  font-size: 20px;
  text-align: center;
  line-height: 200px;
  color: rgb(255, 255, 255);
  font-family: sans-serif;
  text-transform: uppercase;
}
.depth div.back-pane {
  transform: translateZ(-100px) rotateY(180deg);
}
.depth div.right-pane {
  transform: rotateY(-270deg) translateX(100px);
  transform-origin: top right;
}
.depth div.left-pane {
  transform: rotateY(270deg) translateX(-100px);
  transform-origin: center left;
}
.depth div.top-pane {
  transform: rotateX(-90deg) translateY(-100px);
  transform-origin: top center;
}
.depth div.bottom-pane {
  transform: rotateX(90deg) translateY(100px);
  transform-origin: bottom center;
}
.depth div.front-pane {
  transform: translateZ(100px);
}

How can I correct the perspective to get them to behave correctly? I don't understand where exactly they are supposed to be in the 2d space to create the 3d illusion or what kind of rotation and perspective combination creates that 3d illusion.

like image 247
Logan Avatar asked Dec 10 '18 14:12

Logan


1 Answers

Construct the cubes starting from a face, and building the other faces starting on the same place as the base, but rotating or translating them.

The cubes then can be layout just in 2d space, with flex or whatever is best for you

And just give the container the orientation that you like.

Hover the container to fold the faces and understand better the basic layout

div {
    transform-style: preserve-3d;
    transition: transform 5s;
}

.container:hover .cubebase div {
    transform: rotate(0deg);
}
.container:hover .cubebase .cover {
    transform: transformZ(0px);
}


.cubebase {
    width: 100px;
    height: 100px;
    position: relative;
    background-color: rgba(255,0,0, 0.1);
    box-shadow: inset 0px 0px 5px red;
}
.cubebase:nth-child(2) {
    background-color: rgba(0,255,0, 0.2);
    box-shadow: inset 0px 0px 5px green;
}
.cubebase:nth-child(3) {
    background-color: rgba(0,0,255, 0.2);
    box-shadow: inset 0px 0px 5px blue;
}
.cubebase:nth-child(4) {
    background-color: rgba(200,200,0, 0.3);
    box-shadow: inset 0px 0px 5px brown;
}

.cubebase div {
   width: 100px;
   height: 100px;
   position: absolute;
   background-color: inherit;
   box-shadow: inherit;
   top: 0px;
   left: 0px;
}

div.rface {
    transform: rotateY(90deg);
    transform-origin: right;
}

.lface {
    transform: rotateY(-90deg);
    transform-origin: left;
}

.tface {
    transform: rotateX(90deg);
    transform-origin: top;
}
.bface {
    transform: rotateX(-90deg);
    transform-origin: bottom;
}

.cover {
    transform: translateZ(100px);
}


.container {
    border: solid 1px silver;
    transform: rotateY(20deg) rotateX(190deg);
    perspective: 5000px;
    top: 50px;
    left: 50px;
    position: relative;
    width: 300px;
    display: flex;
    flex-wrap: wrap;
}
<div class="container">
    <div class="cubebase">
        <div class="rface"></div>
        <div class="lface"></div>
        <div class="tface"></div>
        <div class="bface"></div>
        <div class="cover"></div>
    </div>
    <div class="cubebase">
        <div class="rface"></div>
        <div class="lface"></div>
        <div class="tface"></div>
        <div class="bface"></div>
        <div class="cover"></div>
    </div>
    <div class="cubebase">
        <div class="rface"></div>
        <div class="lface"></div>
        <div class="tface"></div>
        <div class="bface"></div>
        <div class="cover"></div>
    </div>
    <div class="cubebase">
        <div class="rface"></div>
        <div class="lface"></div>
        <div class="tface"></div>
        <div class="bface"></div>
        <div class="cover"></div>
    </div>
</div>
like image 154
vals Avatar answered Oct 07 '22 01:10

vals