H5打造3d场景 Amazing CSS3D

秋涛小哥_1424

秋涛小哥_1424

2016-11-07

2408人浏览

原创

我们知道3d的表现形式即让我们通过平面可从不同角度看到真实物体的展示效果。

在计算机世界里,3D世界是由点组成,两个点能够组成一条直线,三个不在一条直线上的点就能够组成一个三角形面,无数三角形面就能够组成各种形状的物体,如下图。

892670031-581ee02140c15_articlex.png

Three中模型解析器的原理是将顶点数组将模型的顶点用数组储存起来,再利用three中的face函数取得定点数组中的三个或四个顶点的索引构成空间平面。如此反复,模型就被完整构造出来了。

于是,越复杂的物体就需要越多的网面拼接。而css中是不存在根据坐标建立空间平面的能力的。

(插个题外话,其实css有一个属性与坐标有关,那就是clip-path。这个属性的特性赋予了css3一定的建模能力。实现方法可参考这篇文章 纯clip-path打造的3D模型渲染器)

CSS3实现3D全景

。上篇文章介绍了Web3D的一些表现形式,这里着重谈谈怎么以CSS3实现3D全景。下面会探索Three实现全景的方案,因为WebGL门槛和学习成本还是比较高的,不适于用于快速开发。造物节的CSS3d全景已有文章对其进行了技术探秘,但都未深入谈及具体实现方式。

要清晰理解实现方式,必须对CSS3的transform、perspective有一定的认识。
原理方面的东西我就不深入讲了,大家可以先看看这篇文章,对CSS3D有一个大致的概念。
玩轉 CSS 3D - 原理篇

CSS全景可通过建立柱形或者立方体再通过贴图方式实现。也许会有人问,球体行不行?实际上是不行的,球体模型由无数个极小的平面拼接构成连贯曲面,而CSS缺乏使平面扭曲的属性。球体模型我们可以使用上文提过的Clip-3d建造出,但是,贴图问题就解决不了了。

天空盒子

相信很多打造过或有了解过3d全景的同行们都知道这个概念。实际上Skybox就是一个立方体,通过给六个面贴上不同的,边缘可以无缝贴合的图片,再将视角伸入盒子内部。可以想象成我们自己站入了一个巨型立方体盒子内部,移动视角便能看到不同的场景。

3686196226-57a94a892fcd0_articlex.gif

1、贴图
来看一张天空盒子的贴图,剪头指向的边缘代表需要无缝贴合的边。

892670031-581ee02140c15_articlex.png

从上图可以看出只要相互贴合的两个面上的图像能够无缝拼接,那么再通过对各个面进行一定的旋转变换,天空盒子就能被打造出来了。

那么问题来了,怎么去拍摄制作这样的图片呢?这就需要通过一些专业软件了,比如pano2vr,max等。其实,需要用到这些专业工具打造的全景对画质和拼合度的要求都非常高了,而单纯依靠CSS3中的变化给不了它们很好的体验。

但我们今天讨论的是某些运营活动H5打造的全景,此全景不一定真实存在,或者是和真实场景有一定的比例差距。例如星空、海底。对于这类贴合度可人为改变的全景图的打造,我们可以采用现有的高清图片,再经由PS转换成六面全景图。
贴一篇文章 Create a Skybox From Photos
其实主要思想是
在一张大图上勾画出六个面的选取 >
选择大图中某个面的相邻面将其旋转到需要拼合的盒子的某个面上,使他们完美贴合 >
得到最合理的六面贴图后,观察有无创造出新的边缘,通过蒙版等工具使他们自然融合。

2、构造贴图完成就可以创建立方体了。首先将创建好的六个面切割出来,以front、back、left、right…命名标记位置。

 .sence {      -webkit-perspective: 1000px;    }
    .cube {      width: 500px;      height: 500px;      margin: 100px auto;      transform-style: preserve-3d;    }
    .cube img {      width: 130px;      height: 130px;      position: absolute;    }
    .cube img:nth-child(1) {    }
    .cube img:nth-child(2) {      transform:  rotateY(180deg);    }
    .cube img:nth-child(3) {      transform:  rotateY(90deg);    }
    .cube img:nth-child(4) {      transform:  rotateY(-90deg);    }
    .cube img:nth-child(5) {      transform:  rotateX(90deg);    }
    .cube img:nth-child(6) {      transform:  rotateX(-90deg);    }
<div>
    <div>
      <img>
      <img>
      <img>
      <img>
      <img>
      <img>
    </div>
  </div>

准备好6个面,载入贴图。通过旋转,使得每个面旋转到相印的位置。如左边的面由原本面朝我们的图片绕Y轴逆时针旋转90°得到。(注意Y轴逆时针旋转是正数)

此时会得到下图这样的效果:

892670031-581ee02140c15_articlex.png

但是由于每个面的旋转中心都在其正中位置,因此还不能形成正方体。于是我们需要让每个面产生一定的位移。

贴一张坐标系图以助于大家理解。

892670031-581ee02140c15_articlex.png

现在首先让front位移到应该到的位置,由于全景图的镜头在立方体内部,因此,可以想象一下,我们需要将图片往后移动。移动距离很明显为立方体边长的一半。在这里是65px。得到下图结果。

.cube img:nth-child(1) {    
  transform: translateZ(-65px); 
     }

892670031-581ee02140c15_articlex.png

照这样看,是不是back位移为translateZ(65px),left为translateX(-65px),top translateY(-65px)呢?但结果并不是我们想要的。

892670031-581ee02140c15_articlex.png

重新看回上文空间坐标系的那张贴图,我们会发现,平面旋转后,其对应的三个轴的位置也改变了。如图片绕Y旋转后,Z轴指向为屏幕的水平方向。绕X旋转后,Z轴指向垂直方向。因此我们很容易发现,其实要将贴面移动到正确的位置,都只需要让他们translateZ(-width/2px)就可以了。

892670031-581ee02140c15_articlex.png

为了让大家容易理解,我这里设置了一个较大的perspective。要想得到全景的效果,我们将镜头拉近让它进入到box里面就可以了。

892670031-581ee02140c15_articlex.png

接下来绑定手势,就可以让它动起来啦。

部分代码:

viewer.on('touchstart', function(e) {
    x1 = e.targetTouches[0].pageX; - $(this).offset().left;
    y1 = e.targetTouches[0].pageY; - $(this).offset().top;
});

viewer.on('touchmove',function(){
    var dist_x = x2 - x1,
        dist_y = y2 - y1,
        deg_x = Math.atan2(dist_y, perspective) / Math.PI * 180,
        deg_y = -Math.atan2(dist_x, perspective) / Math.PI * 180,
        i,
        c_x_deg += deg_x;
        c_y_deg += deg_y;
        
    cube.css('transform', 'rotateX(' + deg_x + 'deg) rotateY(' + deg_y + 'deg)');
})

Math.atan2(y,x) 方法:得到从 x 轴到点 (x,y) 之间的角度。对于空间左边系比较难理解,大家可以想象成一张以空间Z轴为Y轴的平面绕X轴正方向旋转的角度即为cube绕空间Y轴旋转的角度。

柱形

柱形全景也不算复杂。关于圆柱形的打造方法,大家可以参考下这篇文章CSS3 3D transforms系列教程-3D旋转木马
有了这个基础,我们可以写一段函数快速构造柱形全景。

先来看下页面结构

<style>
  body {
    height: 100%;
    overflow: hidden;
  }
    .scene {
      width: 100%;
      height: 1170px;
      transform: translateX(-50%) translateY(-50%);
      top: 50%;
      left: 50%;
      position: absolute;
    }
    .cube {
      transform-style: preserve-3d;
      height: 100%;
      width: 100%;
      margin: 0px auto;
    }
    .cube_bg {
      transform-style: preserve-3d;
      height: 100%;
      width: 128px;
      margin: 0px auto;
    }
    .cube_bg div {
      height: 100%;
      
      /* 这里为圆柱形的每个面都设定了同样的背景图 那么在建造柱形时不再需要手动切图 */
      background-image: url("img/zao/zao.png");
      
      background-repeat: no-repeat;
      position: absolute;
      top: 0;
    }
</style>
  <div>
    <div>
      <div>
        <!--
        这里是柱形全景背景贴图
        -->
      </div>
      <div>
        <!--
        这里是柱形全景中的小元件
        -->
      </div>
    </div>
  </div>
function creCylinder(lenZ,pieceWid,angle,slice){

    /* 
    pieceWid 表示单个柱形块状宽度
    angle表示柱形内角
    slice表示有多少个面拼接 
    slice越多,拼合的面越接近曲面
    */
    
  var l = pieceWid*slice; // 画布全长
  var ag = angle/slice // 旋转角度

  var html = '';

  /*
    设置每个面的旋转角度和位移 因为要分割成多个面,所以应该为每个面的背景图设置不同的`background-position`
    */

  for(var i=0,len=slice;i<len>';
  }

    return html;
}

function renderPano(pieceWid,angle,slice){

    var vw = $(window).width();

    var RADIAN = 0.017453293; // 弧度制 将角度转成弧度

    var innerAngle = angle/(2*slice); //内角,用来计算translateZ

    // 这里的原理和上文旋转木马链接一致
    var lenZ = -(pieceWid/2)*Math.tan((90-innerAngle)*RADIAN);

    /*  
        因为默认是由画布的最左端开始旋转 所以处于我们面前的是画布的最左端和最右端及其连接处
        要想画布中央显示再我们面前,这里需要给cube_bg加上一定的绕Y旋转角度
    */
    var rotate = ((angle/slice)*(slice-1))/2,
        perspective = -lenZ-5;

    var cube_bg = $('.cube_bg'),
        scene = $('.scene');

    var cylinder = creCylinder(lenZ,pieceWid,angle,slice);

    cube_bg.html(cylinder).css('transform','rotateY('+rotate+'deg)');
    scence.css('-webkit-perspective',perspective+'px');
    
    //最后调用一下
    renderPano(128,360,20);</len>

这里解释一下perspective为什么要设成 -lenZ-5
看一张图,上面的lenZ即translateZ值,为负值。
perspective为镜头到屏幕的距离,因为此时镜头在柱体内部,因此不能看到柱体后面的图像。
当perspective值为-lenZ值时,正好柱体back面能与镜头在同一平面上,为了避免它有一定的机率遮挡镜头,我们可以将镜头拉近一些。便设成了-lenZ-5。这个时候就能保证镜头处于柱体内部,同时也能更广角度地观察到柱体全景。

892670031-581ee02140c15_articlex.png

大家可以复制代码体验一下。这里的背景图我选用的是自己拼合成的造物节背景图。

优劣势对比

相信大家也有体会,天空盒制造起来会相对的简单,并且天空和地面都能被考虑进去。但是由于面面间的贴合角度太大,若物体正好处于相互贴合的两个面,会给人一种被拦腰折断的感觉。而柱形图对这种情况有了比较好的解决,但是天空和地面的贴图就比较困难了,一般情况下只能通过给scene添加背景图片模拟。


前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
Go-Zero API开发使用教程
Go-Zero API开发使用教程

本专题聚焦Go-Zero的API开发,拆解.api描述文件的语法结构、路由与分组定义、参数绑定与校验规则,说明统一响应体、JWT鉴权、跨域与接口文档生成的落地方式,并给出网关聚合与接口测试的实践建议。

2026.11.12

80

15

Go-Zero安装与goctl环境配置教程
Go-Zero安装与goctl环境配置教程

本专题围绕Go-Zero的安装与工具链配置展开,讲清Go版本要求、goctl安装方式、代理镜像、protoc依赖与环境变量设置,说明多版本共存、升级回退与CI流水线安装的做法,并整理安装阶段的常见报错与验证步骤。

2026.11.12

60

15

Go-Zero零基础入门教程
Go-Zero零基础入门教程

本专题整理Go-Zero的入门知识,从框架定位、环境准备到跑通第一个API服务,讲清目录分层、配置加载、日志与中间件的基本用法,并对比Gin、Kratos的差异,帮助Go开发者建立整体认知,判断它是否适合当前项目。

2026.11.12

40

15

Postman身份认证怎么配置
Postman身份认证怎么配置

本专题从实际API接口调试场景出发,讲解Postman身份认证的完整配置流程,包括常见认证协议介绍、授权参数设置、访问令牌填写、OAuth 2.0授权及认证失败排查,帮助用户正确完成接口授权与访问验证。

2026.11.06

140

12

Postman请求头Headers怎么设置
Postman请求头Headers怎么设置

围绕Postman HTTP请求头配置展开,讲解Headers选项的具体使用方式,包括Key和Value参数填写、请求头信息添加、常见Header字段设置及请求头修改方法,帮助用户解决接口调试过程中遇到的请求头配置问题。

2026.11.06

120

13

Postman接口请求发送教程
Postman接口请求发送教程

详细介绍Postman接口请求的创建与发送方法,涵盖GET和POST请求、URL配置、请求参数、Headers请求头、Body请求体设置以及响应结果查看,帮助用户掌握Postman接口请求的完整操作流程。

2026.11.06

120

10

DBeaver怎么导入数据
DBeaver怎么导入数据

DBeaver数据导入专题,整理Excel、CSV、SQL、TXT等常见文件的数据导入方法,涵盖目标数据库选择、数据表创建、字段映射、数据类型设置及导入参数配置等操作,帮助用户将本地文件中的数据写入数据库,并了解批量导入、重复数据处理和导入失败等常见问题的解决方法。

2026.11.05

100

12

DBeaver安全防护教程大全
DBeaver安全防护教程大全

DBeaver安全防护专题,围绕数据库连接安全、账号密码保护和访问权限管理展开,整理SSL/TLS加密连接、SSH隧道、数据库凭据保存及证书验证等配置方法,同时介绍敏感信息保护、远程连接风险和高权限账号使用等注意事项,帮助用户提高数据库日常管理的安全性。

2026.11.05

80

12

DBeaver连接创建与配置教程
DBeaver连接创建与配置教程

本专题聚焦DBeaver数据库连接配置与管理,覆盖从新建连接、选择数据库类型到填写连接参数和验证连接的完整流程。针对MySQL、PostgreSQL、SQL Server等常见数据库,整理相应的连接设置方法,并提供驱动缺失、认证失败和连接异常等问题的排查方向。

2026.11.04

100

16

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
热门推荐
/
最新课程
phpStudy极速入门视频教程
phpStudy极速入门视频教程

共6课时 | 54.7万人学习

独孤九贱(4)_PHP视频教程
独孤九贱(4)_PHP视频教程

共89课时 | 134.3万人学习