【帶着canvas去流浪(12)】用Three.js製做簡易的MARVEL片頭動畫(上)

示例代碼託管在: http://www.github.com/dashnowords/blogs

博客園地址:《大史住在大前端》原創博文目錄html

華爲雲社區地址:【你要的前端打怪升級指南】前端

動圖效果可點擊查看:gif動圖效果示例git

一. 大做業說明

通讀完上一篇博文中說起的教程,以爲應該搞個大做業鞏固一下所學的知識,想起剛上映的漫威宇宙第三階段收官之做《蜘蛛俠·英雄遠征》,因而決定仿一個MARVEL的片頭動畫做爲three.js的課後練習,使用的版本是R104版本。本節先來解決視頻貼圖的問題。github

二.基本思路

簡易片頭動畫的實現思路以下,除了正常的舞臺元素外,須要背景音樂,使用THREE.AudioLoader就能夠從後後臺加載音樂,舞臺中主要的實體元素是MARVEL這幾個字母的立體模型,可使用THREE.TextGeometry來進行建模(【Three.js繪製字體模型】),它要求先載入字體文件,而後才能實例化,參考官方文檔的實現就能夠了。有了字體模型之後,還須要一些影片素材貼在字體模型上,THREE.VideoTexture能夠解決這個問題(【Three.js使用VideoTexture實現視頻Video更新紋理】),它能夠將HTML中的<video>標籤引入的資源做爲表面紋理經過材料實例的map參數與之關聯在一塊兒,而後貼在幾何體表面,最後要解決的問題就是鏡頭的變化了,看過漫威電影的同窗都知道,片頭動畫最後一部分的畫面先是鏡頭後退,而後MARVEL幾個字母逐漸翻轉過來,這個效果的實現方式不少,能夠調整相機參數,也能夠調整物體參數,建議本身動手時各類方法都嘗試一下。爲了熟悉更多特性,筆者本身在實現中使用正交相機,經過調整正交相機的視場寬度來模擬鏡頭後退動畫(在透視相機下能夠直接調整相機的Z軸座標實現相似的效果),而後經過設置幾何體的位移和旋轉來模擬鏡頭的移動。express

三.視頻紋理表面修復——UV映射

3.1 問題描述

圖片描述

整個大做業中最難處理的就是視頻紋理貼圖的部分,因此本篇先來搞定這個知識點。若是使用THREE.js提供的Geometry基本不會遇到什麼問題,例如上圖中的示例,就將視頻素材貼在了立方體的各個面上,然而當你使用其餘帶有一些自定義性質的幾何體實例,好比本身畫了一個shape而後拉伸成爲拉伸體,或者本次大做業中須要使用的TextGeometry字體模型時。視頻貼圖就直接失效了。一樣尺寸的立方體,若是用THREE.BoxGeometry來生成實例,表面就能夠直接貼視頻,若是使用shape畫一個矩形再拉伸成一樣尺寸的實體,視頻就沒法正常覆蓋在模型表面,以下圖所示:npm

圖片描述

仔細看你會發現圖片邊界的地方有發光的條,將細節放大後能夠看到下面的場景:canvas

圖片描述

能夠看到,視頻實際上的確是覆蓋在立方體表面了,但只是佔了很小的一塊,因此須要針對這種狀況進行模型紋理修復,使視頻能夠覆蓋幾何體的單個表面。數組

3.2 紋理貼圖的基本原理-UV映射

Three.js中,幾何體是經過的特徵構建起來的,若是將一個幾何體實例對象在控制檯打印出來,就能夠看到存儲端點座標信息的vertexs和存儲面信息的faces數組。當你構建一個立方體時,會發現它的faces屬性數組中有12個面的信息,由於Three.js中默認使用三角面片來構建幾何體,一個矩形表面須要用兩個三角面片來構建,(你能夠將立方體材料material中傳入 wireframe:true來看到立方體的線框圖),faces數組中每個面中存儲的是構建這個三角面的3個點的位置信息。app

紋理貼圖座標也稱爲UV座標,它的貼圖原理是這樣的,首先將貼圖素材x軸和y軸的長度以0-1來標記,那麼使用3個座標範圍在[0~1,0~1]的點就能夠在圖形素材中以三角形剪裁出須要的部分,同理使用4個座標範圍在[0~1,0~1]的點,就能夠在圖形素材中以四邊形剪裁出須要的部分,以此類推,以下圖所示:ide

圖片描述

右圖中白色三角形的三個頂點在歸一化座標系中的座標值已經列出,將[0.2,0.2],[0.2,0.8],[0.7,0.2]這三個座標點信息填充到對應的UV映射數組中後,Three.js就會用這個三角形區域來對一個三角面進行貼圖。因爲默認面是三角面,因此咱們經過實例化3個THREE.Vector2(x,y)對象來表示從素材中截取的三角形區域,獲得了素材後要如何將它與三角面的頂點座標對應起來呢?這就引出了本節中的關鍵概念——UV映射矩陣

大部分高大上的概念都離不開一個土掉渣的實現, UV映射矩陣也不例外。

因爲貼圖素材是三個點,幾何體某個三角面也是有三個頂點,若是不限制索引,那麼就可能存在不少種貼圖結果:

圖片描述

爲了保證貼圖素材的方向,它們之間就有存在一個對應關係,不然最後渲染的紋理可能就是倒着的或者旋轉90°的圖像,因此UV映射矩陣中存儲的依然是上例中右圖的三個點,但默認索引和構成幾何體指定面的三個頂點的索引相對應,這就惟一限定了截取表面到幾何體三角面的貼圖樣式。

3.3 關鍵示例代碼

完整的示例能夠從附件或開頭處的github代碼倉中獲取,示例是一個express工程,npm install裝一下依賴,跑起來以後訪問localhost:3333就能夠看到。

//重構UV Mapping
function rebuildUVMapping() {    
    //在紋理素材上標記關鍵點
    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];

    //背面
    //生成網格時材料能夠傳數組,materialIndex能夠爲不一樣面指定不一樣的材質,本例中對應不一樣的視頻片斷
    geometry.faces[0].materialIndex = 4; 
    geometry.faces[1].materialIndex = 4;
    //重構UV映射關係矩陣
    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]];

    //標記uv映射是可更新的
    geometry.uvsNeedUpdate = true;
}

四.小結

視頻紋理是本例中最難的部分了,下一篇中筆者將構建字體模型,並加入鏡頭轉換,完成整個預期的動畫,敬請關注,也但願感興趣的小夥伴一塊兒交流。

相關文章
相關標籤/搜索