0

0

H5打造3d场景 Amazing CSS3D

高洛峰

高洛峰

发布时间:2016-11-07 17:00:30

|

2408人浏览过

|

来源于php中文网

原创

我们知道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);    }

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

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

892670031-581ee02140c15_articlex.png

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

BlackBox AI
BlackBox AI

AI编程助手,智能对话问答助手

下载

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

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旋转木马
有了这个基础,我们可以写一段函数快速构造柱形全景。

先来看下页面结构




  
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
'; } 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);

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

892670031-581ee02140c15_articlex.png

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

优劣势对比

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

相关专题

更多
Golang gRPC 服务开发与Protobuf实战
Golang gRPC 服务开发与Protobuf实战

本专题系统讲解 Golang 在 gRPC 服务开发中的完整实践,涵盖 Protobuf 定义与代码生成、gRPC 服务端与客户端实现、流式 RPC(Unary/Server/Client/Bidirectional)、错误处理、拦截器、中间件以及与 HTTP/REST 的对接方案。通过实际案例,帮助学习者掌握 使用 Go 构建高性能、强类型、可扩展的 RPC 服务体系,适用于微服务与内部系统通信场景。

8

2026.01.15

公务员递补名单公布时间 公务员递补要求
公务员递补名单公布时间 公务员递补要求

公务员递补名单公布时间不固定,通常在面试前,由招录单位(如国家知识产权局、海关等)发布,依据是原入围考生放弃资格,会按笔试成绩从高到低递补,递补考生需按公告要求限时确认并提交材料,及时参加面试/体检等后续环节。要求核心是按招录单位公告及时响应、提交材料(确认书、资格复审材料)并准时参加面试。

44

2026.01.15

公务员调剂条件 2026调剂公告时间
公务员调剂条件 2026调剂公告时间

(一)符合拟调剂职位所要求的资格条件。 (二)公共科目笔试成绩同时达到拟调剂职位和原报考职位的合格分数线,且考试类别相同。 拟调剂职位设置了专业科目笔试条件的,专业科目笔试成绩还须同时达到合格分数线,且考试类别相同。 (三)未进入原报考职位面试人员名单。

58

2026.01.15

国考成绩查询入口 国考分数公布时间2026
国考成绩查询入口 国考分数公布时间2026

笔试成绩查询入口已开通,考生可登录国家公务员局中央机关及其直属机构2026年度考试录用公务员专题网站http://bm.scs.gov.cn/pp/gkweb/core/web/ui/business/examResult/written_result.html,查询笔试成绩和合格分数线,点击“笔试成绩查询”按钮,凭借身份证及准考证进行查询。

11

2026.01.15

Java 桌面应用开发(JavaFX 实战)
Java 桌面应用开发(JavaFX 实战)

本专题系统讲解 Java 在桌面应用开发领域的实战应用,重点围绕 JavaFX 框架,涵盖界面布局、控件使用、事件处理、FXML、样式美化(CSS)、多线程与UI响应优化,以及桌面应用的打包与发布。通过完整示例项目,帮助学习者掌握 使用 Java 构建现代化、跨平台桌面应用程序的核心能力。

65

2026.01.14

php与html混编教程大全
php与html混编教程大全

本专题整合了php和html混编相关教程,阅读专题下面的文章了解更多详细内容。

36

2026.01.13

PHP 高性能
PHP 高性能

本专题整合了PHP高性能相关教程大全,阅读专题下面的文章了解更多详细内容。

75

2026.01.13

MySQL数据库报错常见问题及解决方法大全
MySQL数据库报错常见问题及解决方法大全

本专题整合了MySQL数据库报错常见问题及解决方法,阅读专题下面的文章了解更多详细内容。

21

2026.01.13

PHP 文件上传
PHP 文件上传

本专题整合了PHP实现文件上传相关教程,阅读专题下面的文章了解更多详细内容。

35

2026.01.13

热门下载

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

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
WEB前端教程【HTML5+CSS3+JS】
WEB前端教程【HTML5+CSS3+JS】

共101课时 | 8.3万人学习

Css3入门视频教程
Css3入门视频教程

共21课时 | 3.8万人学习

兄弟连高洛峰CSS3视频教程
兄弟连高洛峰CSS3视频教程

共20课时 | 4万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号