成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

H5打造3d場景不完全攻略(二): Amazing CSS3D

開發 前端
本文著重介紹如何使用CSS3中的3D變換打造出H5中的3D效果。靈感來源于造物節團隊的3d引擎,因為使用方法比較復雜,也沒有開源的API文檔,于是想自己另外造個輪子,便開始了相關內容的學習和實踐。

前言

對的,本文就是著重介紹如何使用CSS3中的3D變換打造出H5中的3D效果。靈感來源于造物節團隊的3d引擎,因為使用方法比較復雜,也沒有開源的API文檔,于是想自己另外造個輪子,便開始了相關內容的學習和實踐。眾所周知,目前市面上的H5 3D類庫(如Three)、引擎(Egret)、構建工具(kpano、720云)都或存在體積太大、不開源、非免費、學習成本高等問題。對于我們較為熟悉的CSS3,為什么就不對它好好利用一把呢?誠然,CSS3存在我們比較清楚的短板,CSS對平面的渲染能力高,但是對3D建模方面便力不從心了。

我們知道3D的表現形式即讓我們通過平面可從不同角度看到真實物體的展示效果。

在計算機世界里,3D世界是由點組成,兩個點能夠組成一條直線,三個不在一條直線上的點就能夠組成一個三角形面,無數三角形面就能夠組成各種形狀的物體,如下圖。

 

我們通常把這種網格模型叫做Mesh模型。給物體貼上皮膚,或者專業點就叫做紋理,那么這個物體就活靈活現了。最后無數的物體就組成了我們的3D世界。

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就是一個立方體,通過給六個面貼上不同的,邊緣可以無縫貼合的圖片,再將視角伸入盒子內部。可以想象成我們自己站入了一個巨型立方體盒子內部,移動視角便能看到不同的場景。

1、貼圖

來看一張天空盒子的貼圖,剪頭指向的邊緣代表需要無縫貼合的邊。

 

 


從上圖可以看出只要相互貼合的兩個面上的圖像能夠無縫拼接,那么再通過對各個面進行一定的旋轉變換,天空盒子就能被打造出來了。 

那么問題來了,怎么去拍攝制作這樣的圖片呢?這就需要通過一些專業軟件了,比如pano2vr,max等。其實,需要用到這些專業工具打造的全景對畫質和拼合度的要求都非常高了,而單純依靠CSS3中的變化給不了它們很好的體驗。

但我們今天討論的是某些運營活動H5打造的全景,此全景不一定真實存在,或者是和真實場景有一定的比例差距。例如星空、海底。對于這類貼合度可人為改變的全景圖的打造,我們可以采用現有的高清圖片,再經由PS轉換成六面全景圖。

貼一篇文章 Create a Skybox From Photos

其實主要思想是

在一張大圖上勾畫出六個面的選取 >

選擇大圖中某個面的相鄰面將其旋轉到需要拼合的盒子的某個面上,使他們完美貼合 >

得到最合理的六面貼圖后,觀察有無創造出新的邊緣,通過蒙版等工具使他們自然融合。

2、構造貼圖完成就可以創建立方體了。首先將創建好的六個面切割出來,以front、back、left、right…命名標記位置。 

  1. .sence { 
  2.       -webkit-perspective: 1000px; 
  3.     } 
  4.     .cube { 
  5.       width: 500px; 
  6.       height: 500px; 
  7.       margin: 100px auto; 
  8.       transform-style: preserve-3d; 
  9.     } 
  10.     .cube img { 
  11.       width: 130px; 
  12.       height: 130px; 
  13.       position: absolute
  14.     } 
  15.     .cube img:nth-child(1) { 
  16.  
  17.     } 
  18.     .cube img:nth-child(2) { 
  19.       transform:  rotateY(180deg); 
  20.     } 
  21.     .cube img:nth-child(3) { 
  22.       transform:  rotateY(90deg); 
  23.     } 
  24.     .cube img:nth-child(4) { 
  25.       transform:  rotateY(-90deg); 
  26.     } 
  27.     .cube img:nth-child(5) { 
  28.       transform:  rotateX(90deg); 
  29.     } 
  30.     .cube img:nth-child(6) { 
  31.       transform:  rotateX(-90deg);     }  
  1. <div class="sence"
  2.     <div class="cube"
  3.       <img src="img/skybox/front.jpg" alt="" /> 
  4.       <img src="img/skybox/back.jpg" alt="" /> 
  5.       <img src="img/skybox/left.jpg" alt="" /> 
  6.       <img src="img/skybox/right.jpg" alt="" /> 
  7.       <img src="img/skybox/top.jpg" alt="" /> 
  8.       <img src="img/skybox/bottom.jpg" alt="" /> 
  9.     </div> 
  10.   </div>  

準備好6個面,載入貼圖。通過旋轉,使得每個面旋轉到相印的位置。如左邊的面由原本面朝我們的圖片繞Y軸逆時針旋轉90°得到。(注意Y軸逆時針旋轉是正數)

此時會得到下圖這樣的效果:

但是由于每個面的旋轉中心都在其正中位置,因此還不能形成正方體。于是我們需要讓每個面產生一定的位移。

貼一張坐標系圖以助于大家理解。

現在首先讓front位移到應該到的位置,由于全景圖的鏡頭在立方體內部,因此,可以想象一下,我們需要將圖片往后移動。移動距離很明顯為立方體邊長的一半。在這里是65px。得到下圖結果。

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

 


 

 照這樣看,是不是back位移為translateZ(65px),left為translateX(-65px),top translateY(-65px)呢?但結果并不是我們想要的。

重新看回上文空間坐標系的那張貼圖,我們會發現,平面旋轉后,其對應的三個軸的位置也改變了。如圖片繞Y旋轉后,Z軸指向為屏幕的水平方向。繞X旋轉后,Z軸指向垂直方向。因此我們很容易發現,其實要將貼面移動到正確的位置,都只需要讓他們translateZ(-width/2px)就可以了。

為了讓大家容易理解,我這里設置了一個較大的perspective。要想得到全景的效果,我們將鏡頭拉近讓它進入到box里面就可以了。

 接下來綁定手勢,就可以讓它動起來啦。

部分代碼:

  1. viewer.on('touchstart'function(e) { 
  2.     x1 = e.targetTouches[0].pageX; - $(this).offset().left
  3.     y1 = e.targetTouches[0].pageY; - $(this).offset().top
  4. }); 
  5.  
  6. viewer.on('touchmove',function(){ 
  7.     var dist_x = x2 - x1, 
  8.         dist_y = y2 - y1, 
  9.         deg_x = Math.atan2(dist_y, perspective) / Math.PI * 180, 
  10.         deg_y = -Math.atan2(dist_x, perspective) / Math.PI * 180, 
  11.         i, 
  12.         c_x_deg += deg_x; 
  13.         c_y_deg += deg_y; 
  14.          
  15.     cube.css('transform''rotateX(' + deg_x + 'deg) rotateY(' + deg_y + 'deg)'); 
  16. }) 

 Math.atan2(y,x) 方法:得到從 x 軸到點 (x,y) 之間的角度。對于空間左邊系比較難理解,大家可以想象成一張以空間Z軸為Y軸的平面繞X軸正方向旋轉的角度即為cube繞空間Y軸旋轉的角度。

柱形

柱形全景也不算復雜。關于圓柱形的打造方法,大家可以參考下這篇文章CSS3 3D transforms系列教程-3D旋轉木馬

有了這個基礎,我們可以寫一段函數快速構造柱形全景。

先來看下頁面結構 

  1. <style> 
  2.   body { 
  3.     height: 100%; 
  4.     overflow: hidden; 
  5.   } 
  6.     .scene { 
  7.       width: 100%; 
  8.       height: 1170px; 
  9.       transform: translateX(-50%) translateY(-50%); 
  10.       top: 50%; 
  11.       left: 50%; 
  12.       position: absolute
  13.     } 
  14.     .cube { 
  15.       transform-style: preserve-3d; 
  16.       height: 100%; 
  17.       width: 100%; 
  18.       margin: 0px auto; 
  19.     } 
  20.     .cube_bg { 
  21.       transform-style: preserve-3d; 
  22.       height: 100%; 
  23.       width: 128px; 
  24.       margin: 0px auto; 
  25.     } 
  26.     .cube_bg div { 
  27.       height: 100%; 
  28.        
  29.       /* 這里為圓柱形的每個面都設定了同樣的背景圖 那么在建造柱形時不再需要手動切圖 */ 
  30.       background-image: url("img/zao/zao.png"); 
  31.        
  32.       background-repeat: no-repeat; 
  33.       position: absolute
  34.       top: 0; 
  35.     } 
  36. </style> 
  37.  
  38. <body> 
  39.   <div class="scene"
  40.     <div class="cube"
  41.       <div class="cube_bg"
  42.         <!-- 
  43.         這里是柱形全景背景貼圖 
  44.         --> 
  45.       </div> 
  46.       <div class="cube_item"
  47.         <!-- 
  48.         這里是柱形全景中的小元件 
  49.         --> 
  50.       </div> 
  51.     </div> 
  52.   </div> 
  53. </body>  
  1. function creCylinder(lenZ,pieceWid,angle,slice){ 
  2.  
  3.     /*  
  4.     pieceWid 表示單個柱形塊狀寬度 
  5.     angle表示柱形內角 
  6.     slice表示有多少個面拼接  
  7.     slice越多,拼合的面越接近曲面 
  8.     */ 
  9.      
  10.   var l = pieceWid*slice; // 畫布全長 
  11.   var ag = angle/slice // 旋轉角度 
  12.  
  13.   var html = ''
  14.  
  15.   /* 
  16.     設置每個面的旋轉角度和位移 因為要分割成多個面,所以應該為每個面的背景圖設置不同的`background-position` 
  17.     */ 
  18.  
  19.   for(var i=0,len=slice;i<len;i++){ 
  20.     html+='<div style="transform: rotateY(-'+ag*i+'deg) '
  21.           'translateZ('+lenZ+'px);'
  22.           'width:'+(pieceWid)+'px;'
  23.           'background-position: -'+(i*pieceWid)+'px 0;'
  24.           'background-size: '+(l)+'px 100%;"></div>'
  25.   } 
  26.  
  27.     return html; 
  28.  
  29. function renderPano(pieceWid,angle,slice){ 
  30.  
  31.     var vw = $(window).width(); 
  32.  
  33.     var RADIAN = 0.017453293; // 弧度制 將角度轉成弧度 
  34.  
  35.     var innerAngle = angle/(2*slice); //內角,用來計算translateZ 
  36.  
  37.     // 這里的原理和上文旋轉木馬鏈接一致 
  38.     var lenZ = -(pieceWid/2)*Math.tan((90-innerAngle)*RADIAN); 
  39.  
  40.     /*   
  41.         因為默認是由畫布的最左端開始旋轉 所以處于我們面前的是畫布的最左端和最右端及其連接處 
  42.         要想畫布中央顯示再我們面前,這里需要給cube_bg加上一定的繞Y旋轉角度 
  43.     */ 
  44.     var rotate = ((angle/slice)*(slice-1))/2, 
  45.         perspective = -lenZ-5; 
  46.  
  47.     var cube_bg = $('.cube_bg'), 
  48.         scene = $('.scene'); 
  49.  
  50.     var cylinder = creCylinder(lenZ,pieceWid,angle,slice); 
  51.  
  52.     cube_bg.html(cylinder).css('transform','rotateY('+rotate+'deg)'); 
  53.     scence.css('-webkit-perspective',perspective+'px'); 
  54.      
  55.     //最后調用一下 
  56.     renderPano(128,360,20);  

這里解釋一下perspective為什么要設成 -lenZ-5

看一張圖,上面的lenZ即translateZ值,為負值。

perspective為鏡頭到屏幕的距離,因為此時鏡頭在柱體內部,因此不能看到柱體后面的圖像。

當perspective值為-lenZ值時,正好柱體back面能與鏡頭在同一平面上,為了避免它有一定的機率遮擋鏡頭,我們可以將鏡頭拉近一些。便設成了-lenZ-5。這個時候就能保證鏡頭處于柱體內部,同時也能更廣角度地觀察到柱體全景。

 大家可以復制代碼體驗一下。這里的背景圖我選用的是自己拼合成的造物節背景圖。

優劣勢對比

相信大家也有體會,天空盒制造起來會相對的簡單,并且天空和地面都能被考慮進去。但是由于面面間的貼合角度太大,若物體正好處于相互貼合的兩個面,會給人一種被攔腰折斷的感覺。而柱形圖對這種情況有了比較好的解決,但是天空和地面的貼圖就比較困難了,一般情況下只能通過給scene添加背景圖片模擬。

責任編輯:龐桂玉 來源: segmentfault
相關推薦

2016-04-07 09:46:50

H5VR3d

2011-05-17 10:37:54

Windows 8

2021-06-23 06:30:14

H5 移動端前端開發

2017-07-12 23:08:03

白鷺引擎

2022-11-11 14:46:57

CSS3D 視圖

2012-02-27 10:00:50

HTML 5

2013-01-30 16:15:40

adobeHTML5css3

2011-06-27 09:47:37

HTML 5

2011-06-24 13:58:06

CSS3HTML5

2021-05-06 07:26:55

CSS 文字動畫技巧

2011-10-06 13:30:45

宏碁投影儀

2018-10-29 21:30:11

聯想

2012-11-26 12:51:44

木材3D打

2021-11-08 06:02:17

CSS 技巧代碼重構

2015-04-27 15:35:42

Cocos3D場景編輯器

2025-01-07 13:19:48

模型AI訓練

2009-02-12 10:12:00

NAT配置

2023-09-01 09:30:22

Three.js3D 圖形庫

2011-05-26 10:08:14

2024-12-10 15:17:11

點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 久久aⅴ乱码一区二区三区 亚洲欧美综合精品另类天天更新 | 久久久久国产一级毛片高清网站 | 久久精品中文字幕 | 久久久精品网站 | 国产玖玖 | 99精品国自产在线 | 国产成人99久久亚洲综合精品 | 亚洲一区二区三区欧美 | 一区二区久久电影 | 欧美日韩在线精品 | 一区二区三区四区不卡 | 在线观看中文字幕视频 | 国产精品视频一区二区三区, | 亚洲精品视频久久 | www.蜜桃av.com| 欧美精品日韩精品国产精品 | 精品亚洲一区二区三区 | 久久精品一级 | 欧美一区二区三区在线观看视频 | 毛片一级片| 东京av男人的天堂 | 亚洲免费大片 | 日韩中文一区 | 91成人午夜性a一级毛片 | 自拍偷拍亚洲欧美 | 久久久成人动漫 | 综合久久99| 久久小视频 | 日韩成人一区 | 天天干免费视频 | 久一久| 成人欧美日韩一区二区三区 | 久久久久久国产精品久久 | 午夜寂寞影院列表 | 雨宫琴音一区二区在线 | 日韩在线不卡视频 | 91亚洲国产亚洲国产 | 亚洲成人午夜在线 | 91久久久久久久久久久 | 一道本一区二区 | 中文字幕一区二区三区四区五区 |