目錄
* 一. 大作業(yè)說明 <https://www.cnblogs.com/dashnowords/p/11216540.html#一.-大作業(yè)說明>
* 二.基本思路 <https://www.cnblogs.com/dashnowords/p/11216540.html#二.基本思路>
* 三.視頻紋理表面修復(fù)——UV映射
<https://www.cnblogs.com/dashnowords/p/11216540.html#三.視頻紋理表面修復(fù)uv映射>
* 3.1 問題描述 <https://www.cnblogs.com/dashnowords/p/11216540.html#問題描述>
* 3.2 紋理貼圖的基本原理-UV映射
<https://www.cnblogs.com/dashnowords/p/11216540.html#紋理貼圖的基本原理-uv映射>
* 3.3 關(guān)鍵示例代碼 <https://www.cnblogs.com/dashnowords/p/11216540.html#關(guān)鍵示例代碼>
* 四.小結(jié) <https://www.cnblogs.com/dashnowords/p/11216540.html#四.小結(jié)>
示例代碼托管在:http://www.github.com/dashnowords/blogs
<https://github.com/dashnowords/blogs/tree/master/Demo/threejs-demo/%E5%B8%A6%E7%9D%80canvas%E5%8E%BB%E6%B5%81%E6%B5%AA%EF%BC%8812%EF%BC%89-demo>
博客園地址:《大史住在大前端》原創(chuàng)博文目錄 <https://www.cnblogs.com/dashnowords/p/10127926.html>
華為云社區(qū)地址:【你要的前端打怪升級指南】
<https://bbs.huaweicloud.com/blogs/8ae7e6420a4611e9bd5a7ca23e93a891>
一. 大作業(yè)說明
通讀完上一篇博文中提及的教程,覺得應(yīng)該搞個大作業(yè)鞏固一下所學(xué)的知識,想起剛上映的漫威宇宙第三階段收官之作《蜘蛛俠·英雄遠(yuǎn)征》,于是決定仿一個MARVEL
的片頭動畫作為three.js的課后練習(xí),使用的版本是R104版本。本節(jié)先來解決視頻貼圖的問題。
二.基本思路
簡易片頭動畫的實現(xiàn)思路如下,除了正常的舞臺元素外,需要背景音樂,使用THREE.AudioLoader就可以從后后臺加載音樂,舞臺中主要的實體元素是
MARVEL這幾個字母的立體模型,可以使用THREE.TextGeometry來進(jìn)行建模(【Three.js繪制字體模型】
<https://blog.csdn.net/qq_30100043/article/details/75947750>
),它要求先載入字體文件,然后才能實例化,參考官方文檔的實現(xiàn)就可以了。有了字體模型以后,還需要一些影片素材貼在字體模型上,THREE.VideoTexture
可以解決這個問題(【Three.js使用VideoTexture實現(xiàn)視頻Video更新紋理】
<https://blog.csdn.net/qq_30100043/article/details/80275413>),它可以將HTML中的<video>
標(biāo)簽引入的資源作為表面紋理通過材料實例的map
參數(shù)與之關(guān)聯(lián)在一起,然后貼在幾何體表面,最后要解決的問題就是鏡頭的變化了,看過漫威電影的同學(xué)都知道,片頭動畫最后一部分的畫面先是鏡頭后退,然后MARVEL
幾個字母逐漸翻轉(zhuǎn)過來,這個效果的實現(xiàn)方式很多,可以調(diào)整相機(jī)參數(shù),也可以調(diào)整物體參數(shù),建議自己動手時各種方法都嘗試一下。為了熟悉更多特性,筆者自己在實現(xiàn)中使用正交相機(jī),通過調(diào)整正交相機(jī)的視場寬度來模擬鏡頭后退動畫(在透視相機(jī)下可以直接調(diào)整相機(jī)的Z軸坐標(biāo)實現(xiàn)類似的效果),然后通過設(shè)置幾何體的位移和旋轉(zhuǎn)來模擬鏡頭的移動。
三.視頻紋理表面修復(fù)——UV映射
3.1 問題描述
整個大作業(yè)中最難處理的就是視頻紋理貼圖的部分,所以本篇先來搞定這個知識點。如果使用THREE.js提供的Geometry
基本不會遇到什么問題,例如上圖中的示例,就將視頻素材貼在了立方體的各個面上,然而當(dāng)你使用其他帶有一些自定義性質(zhì)的幾何體實例,比如自己畫了一個shape
然后拉伸成為拉伸體,或者本次大作業(yè)中需要使用的TextGeometry字體模型時。視頻貼圖就直接失效了。同樣尺寸的立方體,如果用
THREE.BoxGeometry來生成實例,表面就可以直接貼視頻,如果使用shape
畫一個矩形再拉伸成同樣尺寸的實體,視頻就無法正常覆蓋在模型表面,如下圖所示:
仔細(xì)看你會發(fā)現(xiàn)圖片邊界的地方有發(fā)光的條,將細(xì)節(jié)放大后可以看到下面的場景:
可以看到,視頻實際上的確是覆蓋在立方體表面了,但只是占了很小的一塊,所以需要針對這種情況進(jìn)行模型紋理修復(fù),使視頻可以覆蓋幾何體的單個表面。
3.2 紋理貼圖的基本原理-UV映射
在Three.js中,幾何體是通過點和面的特征構(gòu)建起來的,如果將一個幾何體實例對象在控制臺打印出來,就可以看到存儲端點坐標(biāo)信息的vertexs和存儲面信息的
faces數(shù)組。當(dāng)你構(gòu)建一個立方體時,會發(fā)現(xiàn)它的faces屬性數(shù)組中有12個面的信息,因為Three.js
中默認(rèn)使用三角面片來構(gòu)建幾何體,一個矩形表面需要用兩個三角面片來構(gòu)建,(你可以將立方體材料material中傳入 wireframe:true
來看到立方體的線框圖),faces數(shù)組中每一個面中存儲的是構(gòu)建這個三角面的3個點的位置信息。
紋理貼圖坐標(biāo)也稱為UV
坐標(biāo),它的貼圖原理是這樣的,首先將貼圖素材x軸和y軸的長度以0-1來標(biāo)記,那么使用3個坐標(biāo)范圍在[0~1,0~1]的點就可以在圖形素材中以三角形
剪裁出需要的部分,同理使用4個坐標(biāo)范圍在[0~1,0~1]的點,就可以在圖形素材中以四邊形剪裁出需要的部分,以此類推,如下圖所示:
右圖中白色三角形的三個頂點在歸一化坐標(biāo)系中的坐標(biāo)值已經(jīng)列出,將[0.2,0.2],[0.2,0.8],[0.7,0.2]這三個坐標(biāo)點信息填充到對應(yīng)的UV
映射數(shù)組中后,Three.js就會用這個三角形區(qū)域來對一個三角面進(jìn)行貼圖。由于默認(rèn)面是三角面,所以我們通過實例化3個THREE.Vector2(x,y)
對象來表示從素材中截取的三角形區(qū)域,得到了素材后要如何將它與三角面的頂點坐標(biāo)對應(yīng)起來呢?這就引出了本節(jié)中的關(guān)鍵概念——UV映射矩陣。
大部分高大上的概念都離不開一個土掉渣的實現(xiàn),UV映射矩陣也不例外。
由于貼圖素材是三個點,幾何體某個三角面也是有三個頂點,如果不限制索引,那么就可能存在很多種貼圖結(jié)果:
為了保證貼圖素材的方向,它們之間就有存在一個對應(yīng)關(guān)系,否則最后渲染的紋理可能就是倒著的或者旋轉(zhuǎn)90°的圖像,所以UV映射矩陣
中存儲的依然是上例中右圖的三個點,但默認(rèn)索引和構(gòu)成幾何體指定面的三個頂點的索引相對應(yīng),這就唯一限定了截取表面到幾何體三角面的貼圖樣式。
3.3 關(guān)鍵示例代碼
完整的示例可以從附件或開頭處的github代碼倉中獲取,示例是一個express工程,npm install裝一下依賴,跑起來之后訪問
localhost:3333就可以看到。
//重構(gòu)UV Mapping function rebuildUVMapping() { //在紋理素材上標(biāo)記關(guān)鍵點 let pos = [ new
THREE.Vector2(0,0.1), new THREE.Vector2(1,0.1), new THREE.Vector2(1,0.9), new
THREE.Vector2(0,0.9), ] //uv映射的紋理存放在幾何體實例的下面這個屬性中 let uvs =
geometry.faceVertexUvs[0]; //背面
//生成網(wǎng)格時材料可以傳數(shù)組,materialIndex可以為不同面指定不同的材質(zhì),本例中對應(yīng)不同的視頻片段
geometry.faces[0].materialIndex = 4; geometry.faces[1].materialIndex = 4;
//重構(gòu)UV映射關(guān)系矩陣 uvs[0] = [pos[1], pos[0], pos[3]]; uvs[1] = [pos[3], pos[2],
pos[1]]; //正面 geometry.faces[2].materialIndex = 0;
geometry.faces[3].materialIndex = 0; uvs[2] = [pos[3], pos[0], pos[1]]; uvs[3]
= [pos[1], pos[2], pos[3]]; //標(biāo)記uv映射是可更新的 geometry.uvsNeedUpdate = true; }
四.小結(jié)
視頻紋理是本例中最難的部分了,下一篇中筆者將構(gòu)建字體模型,并加入鏡頭轉(zhuǎn)換,完成整個預(yù)期的動畫,敬請關(guān)注,也希望感興趣的小伙伴一起交流。
熱門工具 換一換