当前位置: 首页 > news >正文

透过3D立方体深入理解perspective和translateZ的关系

前言

对于js全景图向往已久,貌似从16年开始看到的。当时自己还是一个小菜鸡(虽然现在也不是大佬),由于工作原因前端的很多方面都没有及时了解,现在恶补中。。。

准备工作

了解transform中的一些基本概念,比如:

rotate 旋转

translate 定义 2D 转换

translateZ 定义 3D 转换

perspective 为 3D 转换元素定义透视视图。

transform-style: preserve-3d; 指定子元素定位在三维空间内。另外,该属性是非继承的。

要开始讲咯~

有一个立方体的demo放在我的github中,如图:

demo链接在这里

源码链接


立方体原理

立方体我们大家都知道,是由六个的正方形组成的正多面体。如下图:


全景图

这里我们用全景图来举例,帮助我们理解perspective和translateZ。

全景图的组成方式有两种,分别是 立方体、球体(棱柱),我们这里使用的是立方体来举例。

这里我还没有搞明白球体棱柱的区别, 所以等我理解以后,咱们后面再说


制作立方体

一、制作6个面

因为立方体是由6个正方形组成,所以我们先来制作它的组成部分,最后再进行组装。

我们这里用face来当做面,而top、bottom、left、right、after、first来分别代表上、下、左、右、前、后几个面。

这里我们的视角正对着first

我们定义了一个窗口stage、透视盒子ctx 和 立方体容器facelist。

我们先将窗口定义为800*800相对页面垂直居中

我们先将立方体定义为宽高为800px; 接下来将每个面的宽高也定义为800px, 并给予每个面一个不同的颜色用以区分。

代码如下:

<!DOCTYPE html>
<html lang="zh">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>立方体全景</title>
  <style>
    * {
      margin: 0;
      padding: 0;
    }

    html,
    body {
      height: 100%;
      overflow: hidden;
    }
    
    .stage {
      width: 800px;
      height: 800px;
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
    }
    
    .face {
      width: 800px;
      height: 800px;
    }
    
    .top {
      background: green;
    }

    .bottom {
      background: yellow;
    }

    .after {
      background: red;
    }

    .left {
      background: black;
    }

    .right {
      background: blue;
    }

    .first {
      background: blueviolet;
    }
  </style>
</head>

<body>
  <div class='stage'>
    <div class='ctx'>
      <div class='facelist'>
        <div class='face top'>1</div>
        <div class='face bottom'>2</div>
        <div class='face after'>3</div>
        <div class='face left'>4</div>
        <div class='face right'>5</div>
        <div class='face first'>6</div>
      </div>
    </div>
  </div>

  <script>

  </script>
</body>

</html>
复制代码

二、组合

到这里我们立方体的6个面制作完成,但是他们是一次排列在页面中,并不是我们想要的;

接下来让我们将他们先放在一起。给face添加position: absolute;

这样他们是重合在一起的,我们需要这样操作:

1. 把它们旋转到对应的角度
比如:

.top的面我们将它绕X轴旋转90度;

.left的面我们将它绕Y轴旋转90度;

···
复制代码

图片摘自 思否

<!DOCTYPE html>
<html lang="zh">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>立方体全景</title>
  <style>
    * {
      margin: 0;
      padding: 0;
    }

    html,
    body {
      height: 100%;
      overflow: hidden;
    }

    .stage {
      width: 800px;
      height: 800px;
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
    }

    .face {
      width: 800px;
      height: 800px;
      position: absolute;
    }

    .top {
      background: green;
      transform: rotateX(90deg);
    }

    .bottom {
      background: yellow;
      transform: rotateX(90deg);
    }

    .after {
      background: red;
      transform: rotateX(0deg);
    }

    .left {
      background: black;
      transform: rotateY(90deg);
    }

    .right {
      background: blue;
      transform: rotateY(90deg);
    }

    .first {
      background: blueviolet;
      transform: rotateY(0deg);
    }
  </style>
</head>

<body>
  <div class='stage'>
    <div class='ctx'>
      <div class='facelist'>
        <div class='face top'>1</div>
        <div class='face bottom'>2</div>
        <div class='face after'>3</div>
        <div class='face left'>4</div>
        <div class='face right'>5</div>
        <div class='face first'>6</div>
      </div>
    </div>
  </div>

  <script>

  </script>
</body>

</html>

复制代码

旋转后的图形 应该是这样的

这样看起来好像什么都没有变化,我们来看看这个图:

把每个面都重叠在黑色的原点就是他的实际模样,也就是说现在还不是一个立方体

因为他们的中心都是重合的,如何将它们变成立方体呢?看下面的步骤

2. 将他们按照对应的边长通过translateZ推开
由于我们这里是立方体,所以直接就是正方形的边长  在这里也就是±400px

给它们设置上对应的translateZ值,让多个面往不同方向平移,直到组成一个完整的立方体。
复制代码
<!DOCTYPE html>
<html lang="zh">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>立方体全景</title>
  <style>
    * {
      margin: 0;
      padding: 0;
    }

    html,
    body {
      height: 100%;
      overflow: hidden;
    }

    .stage {
      width: 800px;
      height: 800px;
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
    }

    .face {
      width: 800px;
      height: 800px;
      position: absolute;
    }

    .top {
      background: green;
      transform: rotateX(90deg) translateZ(400px);
    }

    .bottom {
      background: yellow;
      transform: rotateX(90deg) translateZ(-400px);
    }

    .after {
      background: red;
      transform: rotateX(0deg) translateZ(-400px);
    }

    .left {
      background: black;
      transform: rotateY(90deg) translateZ(-400px);
    }

    .right {
      background: blue;
      transform: rotateY(90deg) translateZ(400px);
    }

    .first {
      background: blueviolet;
      transform: rotateY(0deg) translateZ(400px);
    }
  </style>
</head>

<body>
  <div class='stage'>
    <div class='ctx'>
      <div class='facelist'>
        <div class='face top'>1</div>
        <div class='face bottom'>2</div>
        <div class='face after'>3</div>
        <div class='face left'>4</div>
        <div class='face right'>5</div>
        <div class='face first'>6</div>
      </div>
    </div>
  </div>

  <script>

  </script>
</body>

</html>
复制代码
3. 加上3D效果

我们给ctx盒子加上3D属性 让3D变得立体化

···
    .ctx {
      /* 3d视角 */
      transform-style: preserve-3d;
    }
···
复制代码
4.将我们的视角推到中心点

先调整stage的视距,将我们的眼睛(视角)调整到ctx的first面的位置

这个时候我们距离after面有800px的距离 离ctx的面有400px的距离

然后我们将ctx这个透视盒子向外推1/2width的距离 也就是400px,将我们的眼睛(视角)置于中心

不理解的童鞋 请注意看下面的单独讲解;

  .stage {
      width: 800px;
      height: 800px;
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      /* 从何处(哪里)查看一个元素的角度 */
      /* 从当前视角到对应面的距离  在这里是 stage到ctx的距离 */
      perspective: 400px;
      /* 调整角度 */
      /* perspective-origin: 50% 100%; */
    }

    .ctx {
      /* 3d视角 */
      transform-style: preserve-3d;

      /* 把视角推到中心 */
      transform: translateZ(400px) rotateY(0deg);
    }
复制代码

三、完事

这样我们已经将一个3D立方体做出来了 并且把我们的视角放在了这个立方体内部的中心点。

我们可以通过 改变 perspective-origin 的值来观察整个立方体

调整角度,在不同角度看到的立方体,有助于更快的理解perspective。

单独讲解perspective和translateZ

我呢找到了一个帮助我理解的图片:

这里Z指的就是 translateZ ,d指的是 perspective

这里我们要知道,Z轴向外为正值。

所以总结下就是:

  • perspective是指 从当前视角到所看平面的距离
  • translateZ指的是 从所看平面到推进视角之间的距离,大白话就是从当前距离 把你看的拉进或者拉远的距离
  • 人的视角在3D投影效果中是 近大远小

重中之重

理解 近大远小眼睛与平面的透视关系 也就是上面那张图!!!

结语

这些东西对于初学css 3D的人来说可能理解起来比较吃力;

对于大部分人来说,其实只靠读文章是不可能完全理解的;

所以还有一句名言警句送给大家:

实践是检验真理的唯一标准

希望大家可以一直以实践为主、阅读为辅,自己真正理解的才是自己的。谢谢!

转载于:https://juejin.im/post/5caea0295188251b1c724746

相关文章:

  • 深入理解静态代理与JDK动态代理
  • 常见漏洞解析
  • [转] 谈谈前端异常捕获与上报
  • Apache Tomcat 8.5.40 与 7.0.94 发布
  • 不要一棍子打翻所有黑盒模型,其实可以让它们发挥作用 ...
  • 线程同步利与弊,线程同步的前提
  • 宾利慕尚创始人典藏版国内首秀,2025年前实现全系车型电动化 | 2019上海车展 ...
  • Python数据类型、运算符、语句、循环
  • 激活效能,CODING 敏捷研发模块上线
  • cmd中subst的使用
  • [MySQL光速入门]003 留点作业...
  • C# - 为值类型重定义相等性
  • Es6初级入门(一)
  • thinkphp+redis实现秒杀,缓存等功能
  • (JS基础)String 类型
  • 230. Kth Smallest Element in a BST
  • Elasticsearch 参考指南(升级前重新索引)
  • Hibernate最全面试题
  • IDEA 插件开发入门教程
  • Java 实战开发之spring、logback配置及chrome开发神器(六)
  • Koa2 之文件上传下载
  • Redash本地开发环境搭建
  • Selenium实战教程系列(二)---元素定位
  • Spring Cloud Feign的两种使用姿势
  • Vue2 SSR 的优化之旅
  • vue--为什么data属性必须是一个函数
  • XML已死 ?
  • 给初学者:JavaScript 中数组操作注意点
  • 七牛云假注销小指南
  • 入门到放弃node系列之Hello Word篇
  • 移动端唤起键盘时取消position:fixed定位
  • 译有关态射的一切
  • 走向全栈之MongoDB的使用
  • FaaS 的简单实践
  • UI设计初学者应该如何入门?
  • ​中南建设2022年半年报“韧”字当头,经营性现金流持续为正​
  • #图像处理
  • $$$$GB2312-80区位编码表$$$$
  • (007)XHTML文档之标题——h1~h6
  • (1)虚拟机的安装与使用,linux系统安装
  • (16)Reactor的测试——响应式Spring的道法术器
  • (pojstep1.3.1)1017(构造法模拟)
  • (zhuan) 一些RL的文献(及笔记)
  • (二)Linux——Linux常用指令
  • (翻译)terry crowley: 写给程序员
  • (十三)Maven插件解析运行机制
  • (转)程序员技术练级攻略
  • (转)重识new
  • **登录+JWT+异常处理+拦截器+ThreadLocal-开发思想与代码实现**
  • .NET Core IdentityServer4实战-开篇介绍与规划
  • .net mvc 获取url中controller和action
  • .NET 自定义中间件 判断是否存在 AllowAnonymousAttribute 特性 来判断是否需要身份验证
  • .net/c# memcached 获取所有缓存键(keys)
  • @ModelAttribute注解使用
  • @PreAuthorize注解