javascript
mmx实现图片淡入淡出_JS实现最美的3D宇宙特效
好久沒更新文章了。算下來大概有五個多月了吧。之前本人更新的比較頻繁是因為疫情在家,不能出門,所以有充足的時間來更新文章。之后隨著疫情越來越好轉,本人就出去找工作了,畢竟本人的經濟條件不允許本人閑著,哈哈。之后本人會更新很頻繁的,很抱歉!
這里給各位同僚說一下,本人已經取消了之前所有分享的百度網盤的資料鏈接以及本人之前分享的AIRobot鏈接。之所以這樣,是因為本人最近一段時間有個“大動作“。就是將本人之前所有寫的項目案例和技術知識點的代碼重新封裝一下,并且給出demo示例和環境搭建教程,以便各位想了解或者初學者更容易上手。這些項目案例和技術知識點的代碼會放到我自己開發的一個云平臺中,而且支持遠程調試,到時會免費開放給各位。本人正在用自己的業余時間加班加點的開發我的云平臺,各位敬請期待!嘿嘿!
通過前面寫過的幾篇文章,表現結果是C++處理圖像方面是閱讀量最多的。感覺各位很傾向于圖像操作方面,所以本人之后打算圍繞圖像操作上做一個專欄系列。還有就是本人這次的云平臺中包含的技術類型有網絡,圖像,音視頻,游戲等方面。這些都是本人一個人編寫和維護,里面包含的很多知識點都是本人花了大量的時間整合的,因為網上的知識都是零碎的,所以如果有你感興趣的方面會大大節省各位的時間。
說了半天的廢話,好了,言歸正傳。前幾周,本人在網上看見一個號稱“最美的地球特效”,是用H5實現的(文章末尾給出源碼路徑),離今天已經有好幾年了。本人早在幾年前,也就是讀大學那會,用Direct3D C++分別實現過地球和宇宙效果,但是那會僅僅實現了一個太陽系效果,而且也有些不足之處。現在之所以想實現這個3D宇宙特效,是因為本人想把這個特效放在我的個人網站上。這個效果是基于TreeJS(是一個3D圖形庫,類似Direct3D)編寫的,前端沒有使用任何框架(因為本人比較喜歡造輪子,哈哈)。除了TreeJS外,其他都是純html+js+css代碼和純紋理貼圖實現的。
首先,給各位說明一下TreeJS初始化的過程:1)創建場景;2)創建攝像機并添加至場景;3)創建渲染器、綁定畫布并循環渲染。主要就這么三個主要步驟,其他就是業務邏輯了。所有創建模型都需要添加至場景才可被渲染。有過3D圖像開發的經驗這塊應該都很清楚,就是一些API不一樣而已,如果不清楚的可以自行谷歌科普,因為這塊內容不是本文的重點。
3D環境初始化完畢之后就開始具體的效果邏輯編寫了。本人將這個特效劃分七大部分,一是宇宙爆炸效果;二是星云、星空粒子效果;三是太陽系效果;四是鏡頭拉伸效果;五是猿猴關鍵點動畫效果;六是城市交替效果;七是文本淡入淡出效果。
宇宙爆炸效果
使用一張發白色爆炸紋理貼圖即可,爆炸之前將紋理放在距離攝像機很遠的位置。看上去就是一個白色的點。等到爆炸的時候將紋理的x,y按照一定的速度等比放大,待紋理中的白色遮滿整個屏幕時,在慢慢淡出(如果不懂,見最后文本淡入淡出效果),和下一個效果銜接。
//每幀調用(下面省略了部分路徑代碼) if (universeEffectComponent.titleConfig.zoom < 1500) {universeEffectComponent.titleConfig.zoom += universeEffectComponent.titleConfig.boomSpeed;//放大(這里z軸可以不用縮放,因為是紋理貼圖,是沒有厚度的)universeEffectCdeomponent.titleConfig.obj.scale.x += universeEffectComponent.titleConfig.boomSpeed;universeEffectComponent.titleConfig.obj.scale.y += universeEffectComponent.titleConfig.boomSpeed;universeEffectComponent.titleConfig.obj.scale.z += universeEffectComponent.titleConfig.boomSpeed;universeEffectComponent.titleConfig.boomSpeed *= 1.08;}else {//更新透明度(淡出)for (let i = 0; i < universeEffectComponent.material.title.length; i++) {if (universeEffectComponent.material.title[i].opacity - 0.01 <= 0) {universeEffectComponent.material.title[i].opacity = 1;}else {universeEffectComponent.material.title[i].opacity -= 0.01;}}}星云、星空粒子效果
在實際宇宙中是由許多星星、星云以及其他天體構成。我這里要盡量的模擬的逼真一點。在這個特效中,星星使用了2000顆,星云30片。那么如何將2000顆星星和30片星云,充滿整個宇宙空間呢?一顆一顆、一片一片手動去設置坐標?當然不是,一切都是可控的隨機實現。
首先隨機生成坐標,我需要設置一個三維空間的范圍(x,y,z的閾值),讓隨機出來的坐標只能在這個范圍內。關鍵是這個閾值是多少?需要考慮兩個條件,一是不能離攝像機太近,不然會顯的很大,一看就是一張圖片;二是要在視角范圍內,超出視角的攝像機(即屏幕的畫面)肯定看不到。
其次隨機移動速度、縮放速度、方向、臨界值系數。如果僅僅設置坐標,那么星星和星云都是靜止不動的。為了更加逼真需要在加上移速和縮放屬性。移動速度設置一個移速的范圍(x方向,y方向的移速即可,z方向就不需要了,因為有縮放因子),需要隨機方向(正反方向),不然移動的時候都是朝同一個方向。縮放系數生成和移動速度生成類似,也需要設置一個縮放的范圍(x方向,y方向,z方向無意義,考慮到是紋理貼圖)。這里需要說明一下的是縮放分三種類型,一種不縮放,一種是逐漸縮放,一種是快速縮放(閃爍的星星)。不管移動還是縮放都需要一個最大最小臨界值,否則會出現在朝同一方向無限移動和縮放下去。這不是我想要的效果。所以為了避免出現這種情況,需要累計記錄每個方向的移動變化量和縮放變化量,當累計的移動變化量和縮放變化量高于/低于最大臨界值/最小臨界值時,改變方向即可。
最后是星云特有的,引入了旋轉系數。和上述移動、縮放系數類似。設置旋轉的范圍(x,y,z三個方向)。也需要設置臨界值,是因為渲染的時候會背面剔除,如果不設置臨界值,在有繞X和Y軸旋轉的星云,會可能出現看不見的情況。
如何形成五顏六色的星空?需要2000張不同顏色的星星圖片?當然不是,這樣會造成資源過大,我這里只有十多張星星紋理,和幾張星云紋理,然后在創建材質的時候隨機顏色通道就可以實現五顏六色的紋理材質了。
這里及下面也不給出代碼片段了,因為太多了。都是類似上面的代碼片段。
太陽系效果
首先給各位簡單科普一下太陽系知識,早些時間的太陽系一直是9大星系,分別是水星、金星、地球、火星、木星、土星、天王星、海王星以及冥王星。后來覺得冥王星離太陽太遙遠,就把冥王星劃分出太陽系了,也就是現在的八大星系。這里我模擬的太陽系效果,不是完全按照各行星的體積比例的,如果按照實際比例,那么有的行星幾乎看不見,有的會占滿整個屏幕。所以這里本人只確保了體積的大小順序,然后調整了一個合適比例。本人的太陽系效果,包含一個星云(銀河系),八大行星以及地球專屬的衛星(月球)。各星體的屬性:太陽(即恒星,只有自轉),行星(自轉,圍繞恒星公轉),衛星(自轉,圍繞行星公轉,跟隨行星一起圍繞恒星公轉)。
大概了解了基本星體知識后,就可以開始編代碼了。恒星、行星以及衛星的自轉只需以自身的Y軸旋轉即可。這里就是隨機一下各個星體的自轉速度,在每幀渲染時累計疊加。行星圍繞恒星公轉就稍微比較麻煩,需要設置旋轉軸(就是恒星的Y軸)。衛星圍繞行星和恒星公轉就更麻煩一點,這里需要將行星和衛星添加到一組中,衛星圍繞恒星公轉就和行星公轉一樣了。至于衛星圍繞行星公轉則在單獨計算,和行星圍繞恒星公轉類似。自轉很容易計算,那么公轉如何計算?這里提供兩種方法,一種是通過矩陣或者四元數的方式計算,這里如果對這塊很了解的同僚可以采用這種方式;一種是通過方程式計算,求出各個星體的軌跡方程。然后就能求出星體各個時刻的對應的位置(即世界坐標)。我這里使用的是方程式計算,考慮到行星公轉軌跡有近日點和遠日點之分,所以這里使用橢圓軌跡方程更加準確一點,嘿嘿。這里以恒星(太陽)為中心,并設置各個行星的長短半軸即可構建出橢圓方程。衛星的話,中心則是對應的行星。為了方便程序求解,不要通過橢圓的標準方程(x^2/a^2 + y^2/b^2 = 1)去求,這樣計算量很大而且麻煩;使用橢圓極坐標方程會很方便(x = acos(θ); y = bsin(θ))??紤]到是圍繞Y軸旋轉,而且攝像機的朝向是Z的負半軸。所以將y = bsin(θ)改為z = -bsin(θ)。最后求出來的x,z需要加上恒星/行星的中心坐標,就是行星/衛星的世界坐標了。所以這里我們只需要每幀改變θ(弧度制),就可以求出行星/衛星任意時刻的位置了。
還需要說明星體和軌跡白點是如何生成的?星體是創建一個球體幾何體,然后每個星體對應一種紋理,將紋理材質綁定到球體幾何體上就行了;軌跡白點,是創建的平面模型,設置材質延時為白色即可。至于每個行星的軌跡點數量,根據橢圓的軌跡方程等分就行,這里為了讓軌跡白點效果更好一點,越靠近恒星的軌跡點數量少,越離恒星的軌跡點數量多。
最后說明一點,由于本人這里設置相機的位置是源點(0,0,0),朝向是向z軸負方向的。而且整個太陽系都是和XOZ平面平行的,所以這里渲染的時候會有遮擋關系,不是很好區分各個行星的旋轉軌跡和方向。為了避免這個問題,我這里將整個太陽系包括的模型添加到一組中,整體圍繞X軸順時針旋轉一定角度(比如30度),里面還做了其他運算,這里不做說明。其實有更簡單的方法就是改變攝像機位置和朝向,但是考慮到后面的攝像機鏡頭動畫和粒子位置計算的方便性,本人并未采取這種方式。
鏡頭拉伸效果
鏡頭拉伸主要是用于將鏡頭定位到指定行星上。這里只需要更改攝像機(即鏡頭)的位置和朝向屬性就可以了。先說明一下攝像機的位置改變,就是一個比較簡單的插值方程(pos = (end - start) * factor + start)。因為我是知道攝像機的起點位置(我這里是源點)、終點位置(是指定行星的世界坐標),這里需要注意的是因為鏡頭在運動的過程中,行星也是在運動的,所以需要每幀更新插值方程。行星一直在運動,那么如何判斷鏡頭運動結束?這里我是每幀計算攝相機和行星的距離,當距離小于某個值(該值需要自己設定)時,則鏡頭不再向行星運動,而是和行星保持相對靜止。
在鏡頭運動完后,有時你可能會看見行星并非在行星的視野范圍內。這里是因為攝像機朝向沒有改變的結果。要想行星在屏幕正中央顯示,則需要將攝像機的朝向指向行星的位置(世界坐標)。這里為了讓視野平滑過渡,也是需要做插值運算。已知攝像機的起始朝向(即向量,帶有方向的)、終點朝向(這里需要簡單的運算一下,用行星的世界坐標減去攝像機的世界坐標即可)。這里因為行星和攝像機都是運動的,所以也需要每幀更新插值方程。
鏡頭的綁定效果,玩過rpg游戲的同僚應該知道,其實就是將人物模型綁定一個攝像機,讓攝像機和人物模型相對靜止。我這里的當鏡頭運動到行星附近時就是將鏡頭和行星保持相對靜止,但是為了方便計算,本人在鏡頭和行星相對靜止時,行星不在做公轉運動了。
猿猴關鍵點動畫效果
這個動畫,分為四個子階段。一是淡入和自由運動,二是定點縮放運動,三是浮動縮放運動,四是淡出。這里需要說明的是,這里是2D渲染繪制,本人在這里創建了另一個相機和場景,用于繪制UI的。3D用的透視相機,物體大小會隨離攝像機距離而變大變小;UI用的是正交相機則不會。要想深入了解,請自行科普。
淡入和自由運動
淡入(見文本淡入淡出效果,這里不做說明),自由運動和之前的星星和星云粒子效果類似。設置細胞粒子的閾值范圍,然后隨機坐標和移動速度,然后每幀更新即可。
定點縮放運動
這里說的定點是指會給定一個位置,然后各個細胞粒子朝給定位置運動(也就是做插值運算)。這里的比較麻煩的一點是,如何獲取細胞粒子的位置?因為細胞粒子要過渡到猿猴。本人這里提供兩種方法,第一種方法是使用一些做圖軟件(美圖秀秀、PS)將猿猴的紋理圖片標記一些關鍵點,然后使用類似PS的軟件讀出各個點的位置,并記錄這些關鍵點的相對坐標;第二種也是先要在猿猴的紋理圖片上標記一些關鍵點,然后使用圖像識別的工具程序識別出關鍵點并生成各個點的相對坐標。第一種比較麻煩,不夠靈活;第二種相對簡一些(前提是你得會圖像識別技術,哈哈),很靈活。本人這里就是用的第二種方法,本人用C++寫了一個基于RGB顏色模型分析的簡易圖像識別工具,對我而言開發這個工具成本很小(簡單而且快),所以當然采用第二種方式??s放運動和定點運動類似,指定一個最終的縮放系數,然后每幀做插值運算。
浮動縮放運動
浮動就是通過改變細胞粒子的縮放系數,和方向以及臨界值。和之前的星星和星云類似粒子類似,都是可控的隨機生成。
淡出
見文本淡入淡出效果,這里不做說明
城市交替效果
城市效果其實就是一張張紋理在縮放和透明度漸變的過程。這里為了讓位置方便計算,我將這些紋理是通過UI攝像機渲染的??s放處理和上述說的細胞縮放類似,可控隨機生成一些參數,然后每幀參與運算即可。透明度的漸變(即交替)過程到底是什么樣的?先說明一下,在程序當中都是用不透明度表示的,所以這個過程就是不透明度先變高在變低,類似一個拋物線這樣的過程。交替就是當一張城市紋理的不透明度正在變低時,這時需要繪制另一張城市紋理(不透明度逐漸變高)這樣就表現的是交替效果。
文本淡入淡出效果
為了方便顯示文本淡入淡出效果,我這里是基于jquery實現的。文本的淡入淡出和之前的紋理淡入淡出的渲染器是不同的,文本基于html標簽直接操作。其他紋理圖片是基于canvas畫布標簽的。這里細心的同僚會發現,在canvas(3D渲染區域)標簽內右鍵是沒有刷新的,只有圖片另存為選項。說明canvas標簽實則是一張圖片。
淡入效果如何實現?其實比較簡單,每幀更新紋理的不透明度(從0到1),調整合適更新速度就是這個效果了。
淡出效果如何實現?和淡入效果類似,每幀更新紋理的不透明度(從1到0),調整合適更新速度就是這個效果了。
最后說明一下淡入淡出的巧用,如果在一個場景中有很多物體,但這個場景需要淡入淡出效果。首先最可能想到的辦法就是每幀更新每個物體的不透明度,當然這樣也是可以實現,但是很耗機器性能。這里其實有更好的方式,就是在場景的最上層繪制一張純黑紋理,不透明度由1漸變到0或者由0漸變到1,就是淡入淡出效果了。其實還有很多類似的效果,比如遮罩啊什么的,這些轉場效果在視頻編輯中會常常用到,感興趣的同僚可以去實現一下。
最后
到這里,宇宙3D特效的實現已經講完了。是不是很美,是不是以為是紀錄片的視頻(哈哈,也許是我自作多情)。讓你想不到的是,這其實是純程序實現。
前幾天在嗶站看了一個視頻,一個玩絕地求生的玩家發的。使用兩個C4炸彈炸死了很遠的一個敵人,怎么做的呢?在一摩托車上綁定一個C4炸彈,另一個C4炸彈做為助推器,計算好時間,待摩托車落到指定地方后,綁在摩托車上的C4引爆。要完成這個過程需要精準的計算出C4引爆后的助推摩托車的距離和助推摩托車的到指定位置所需時間。那個玩家講了一堆的數學物理方程。所以懂科學和知識的方法的人,哪怕玩游戲也是很厲害的(哈哈)。其實編程涉及很多數理化知識,不僅僅是編程,生活中也是。就目前很火熱的圖形學和AI技術來說,都是和這些知識有很大的聯系。像數學、物理學、線性代數、概率學以及統計學我們都盡量都多少懂點,不然和這些好玩的技術都無緣了,哈哈。哎,學習這條路,任重而道遠啊,正應了“學好數理化,走遍天下都不怕”那句口號,各位和我一起加油吧!
【說明】:本人的文章都會同步到我的微信公眾號和CSDN上,歡迎大家關注訪問。本人的個人網址也搭建起來了,以后本人的所有的產品都可以通過我的個人網址找到,目前這個宇宙特效是在我的個人網址首頁進行展示(首次加載可能有點慢,因為本人租用的服務器帶寬不高)。
- 微信公眾號:程序員JC
- CSDN:https://blog.csdn.net/Jack_chen8888
- 最美的地球源碼地址:https://github.com/JackGit/xplan/
- 最美的地球預覽地址:http://xplan.jackyang.me/
- 圖形識別工具源碼:https://pan.baidu.com/s/18Hw4D0Sb0aQJHbLTx_2B0w 提取碼 2d0l
- 宇宙特效預覽:https://www.jackchenboss.xyz
- https://www.jackchen.world(正在備案)
- https://www.jackchen.word(正在備案)
總結
以上是生活随笔為你收集整理的mmx实现图片淡入淡出_JS实现最美的3D宇宙特效的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 水果编曲软件FL Studio 20.9
- 下一篇: 基于SpringBoot的websock