WebGL之sprite精靈效果顯式數字貼圖
接著前一篇《 WebGL實現sprite精靈效果的GUI控制元件 》,我們繼續開發我們的數字系統GUI控制元件,因為這套數字系統是基於sprite效果的,所以數字隨相機轉動而旋轉(永遠面對相機),隨場景縮放而逆向縮放(數字在螢幕上看上去大小不變)。實現sprite效果的核心方法在前一篇文章裡已經詳細說明,這裡不再贅述,本文要討論的是如何將使用者輸入的數字文字轉變成GUI控制元件的數字貼圖。請看demo。
我們能清楚地看到,在角度測量模式下,我們動態地繪製了兩條邊的長度數字貼圖和角度大小的數字貼圖。對於我們來說,計算邊長和夾角是非常簡單的工作,但怎麼把結果數字轉變成對應的圖片呢,這裡鯽魚是通過uv座標和數字圖片一一對映實現的。其實原理非常簡單,鯽魚有一張包含0~9和小數點,角度的°的圖片png,使用者輸入是一串包含0~9,小數點和°的字串,鯽魚將每一個字元都繫結圖片的uv座標,這樣構造出的函式輸入是字串,返回就是對應輸入字串的uv座標陣列。我們知道構造紋理texture的貼圖就是利用圖片的uv座標來定點陣圖片在texture上的位置資訊,利用這個原理,鯽魚拿回的uv陣列就完成了將一個一個數字貼到一片顯式數字的矩形模型中,使用者看到的就會是一片顯式一串數字的矩形(當然矩形是透明的,使用者只能看到數字)。
以上是原理的解釋,我們先來看一下數字的png圖片長啥樣。
這張就是包含數字和小數點和°的png圖片,注意它是正方形的,且尺寸是2的冪次方。這兩點前者是為了優化webgl的材質渲染,後者是為了能被webgl的材質所識別。為了做成正方形,我們用空白填充。好了,接下來我們來看看程式碼,關於uv貼圖的對映和texture繫結圖片,我們先來看uv對映。
1 /** 2* 字型檔 3* */ 4 let TextImage = function(){ 5this._library = { 6ZERO_UV:[0, 1, 0, 0.75, 0.25, 1, 0.25, 0.75], 7ONE_UV:[0, 0.75, 0, 0.5, 0.25, 0.75, 0.25, 0.5], 8TWO_UV:[0, 0.5, 0, 0.25, 0.25, 0.5, 0.25, 0.25], 9THREE_UV:[0, 0.25, 0, 0, 0.25, 0.25, 0.25, 0], 10FOUR_UV:[0.25, 1, 0.25, 0.75, 0.5, 1, 0.5, 0.75], 11FIVE_UV:[0.25, 0.75, 0.25, 0.5, 0.5, 0.75, 0.5, 0.5], 12SIX_UV:[0.25, 0.5, 0.25, 0.25, 0.5, 0.5, 0.5, 0.25], 13SEVEN_UV:[0.25, 0.25, 0.25, 0, 0.5, 0.25, 0.5, 0], 14EIGHT_UV:[0.5, 1, 0.5, 0.75, 0.75, 1, 0.75, 0.75], 15NINE_UV:[0.5, 0.75, 0.5, 0.5, 0.75, 0.75, 0.75, 0.5], 16DOT_UV:[0.5, 0.5, 0.5, 0.25, 0.75, 0.5, 0.75, 0.25], 17DEGREE_UV:[0.5, 0.25, 0.5, 0, 0.75, 0.25, 0.75, 0] 18}; 19 }; 20 21 TextImage.prototype.constructor = TextImage; 22 TextImage.prototype = { 23 24/** 25* 通過輸入文字返回圖片,小數點後保留3位 26* text:輸入的文字 27* */ 28getImagesByText:function(text){ 29text = this.changeUnit(0.001, text); 30text = this.keepEffectNum(3, text); 31text = text.toString(); 32//逐字元匹配圖片 33let imgUVs = []; 34for(let i=0; i<text.length; i++){ 35let imgUV = this.match(text[i]); 36imgUVs = imgUVs.concat(imgUV); 37} 38return imgUVs; 39}, 40 41/** 42* 通過輸入角度返回圖片,小數點後保留3位 43* angle:輸入的文字 44* */ 45getAngleImagesByText:function(angle){ 46angle = this.keepEffectNum(3, angle); 47angle = angle.toString(); 48angle = angle + "#"; 49//逐字元匹配圖片 50let imgUVs = []; 51for(let i=0; i<angle.length; i++){ 52let imgUV = this.match(angle[i]); 53imgUVs = imgUVs.concat(imgUV); 54} 55return imgUVs; 56}, 57 58/** 59* 單位換算 60* ratio:換算率 61* text:輸入的值 62* */ 63changeUnit:function(ratio, text){ 64return ratio * text; 65}, 66 67/** 68* 小數點後儲存n位 69* effect:有效數字 70* text:原始數字 71* */ 72keepEffectNum:function(effect, text){ 73return text.toFixed(effect); 74}, 75 76/** 77* 匹配字元和圖片 78* char:字元 79* */ 80match:function(char){ 81let imgUV = undefined; 82if(char === "0"){ 83imgUV = this._library.ZERO_UV; 84}else if(char === "1"){ 85imgUV = this._library.ONE_UV; 86}else if(char === "2"){ 87imgUV = this._library.TWO_UV; 88}else if(char === "3"){ 89imgUV = this._library.THREE_UV; 90}else if(char === "4"){ 91imgUV = this._library.FOUR_UV; 92}else if(char === "5"){ 93imgUV = this._library.FIVE_UV; 94}else if(char === "6"){ 95imgUV = this._library.SIX_UV; 96}else if(char === "7"){ 97imgUV = this._library.SEVEN_UV; 98}else if(char === "8"){ 99imgUV = this._library.EIGHT_UV; 100}else if(char === "9"){ 101imgUV = this._library.NINE_UV; 102}else if(char === "."){ 103imgUV = this._library.DOT_UV; 104}else if(char === "#"){ 105imgUV = this._library.DEGREE_UV; 106} 107return imgUV; 108} 109 }; 110 111 module.exports = TextImage;
我們看到這個TextImage類擁有一個this._library字型檔,其中每一個數字都綁定了一串uv座標,即圖片中每一個數字的左上角->左下角->右下角->右上角逆時針繞向的4組座標值。在match函式中通過函式輸入引數的字元來返回對應的uv座標陣列。這就是數字繫結uv的原理。再來看我們拿到uv陣列怎麼繫結到材質物件中去。請看下面程式碼。
1 /** 2* 建立幾何 3* viewer:檢視對像 4* textNode:文位元組點 5* width:寬 6* height:高 7* position:位置座標 8* imgUVs:圖片uv陣列 9* texture:數字紋理 10* */ 11addGeometry:function(viewer, textNode, width, height, position, imgUVs, texture){ 12//頂點快取 13let w = width; 14let h = height; 15//縮放比 16let scaleRatio = 1; 17scaleRatio = this.againstScale(position, viewer); 18w = w*scaleRatio; 19h = h*scaleRatio; 20//頂點陣列 21let vertices = []; 22//首先確定有幾張圖片 23let imgNum = imgUVs.length/8; 24if(imgNum !== 0){ 25for(let i=0; i<imgNum; i++){ 26vertices.push(w*i, h, 0, w*i, 0, 0, w*(i+1), h, 0, w*(i+1), 0, 0); 27} 28} 29let array = new Float32Array(vertices); 30let vertexBuffer = new BufferArray(BufferArray.ARRAY_BUFFER, array, 3); 31//索引快取 32let indices = []; 33if(imgNum !== 0){ 34for(let i=0; i<imgNum; i++){ 35indices.push(4*i, 4*i+1, 4*i+3, 4*i+3, 4*i+2, 4*i); 36} 37} 38let index = new Int8Array(indices); 39let indexBuffer = new BufferArray(BufferArray.ELEMENT_ARRAY_BUFFER, index, index.length); 40//繪製圖元 41let prim = new DrawElements(Primitives.TRIANGLES, indexBuffer); 42//幾何物件 43let geom = new Geometry(); 44geom.setBufferArray('Vertex', vertexBuffer); 45geom.setPrimitive(prim); 46//紋理座標 47let uv = new Float32Array(imgUVs); 48let uvBuffer = new BufferArray(BufferArray.ARRAY_BUFFER, uv, 2); 49geom.setBufferArray('Texture', uvBuffer); 50//將texture加入geometry 51geom.getStateSet(true).addAttribute(texture, StateAttribute.OVERRIDE); 52//圖片背景透明 53let bf = new BlendFunc(BlendFunc.SRC_ALPHA, BlendFunc.ONE_MINUS_SRC_ALPHA); 54geom.getStateSet(true).addAttribute(bf, StateAttribute.OVERRIDE); 55//幾何物件加入根節點 56textNode.addChild(geom); 57//將textNode的位置平移到position位置 58let translateMat = Mat4.MemoryPool.alloc(); 59Mat4.fromTranslation(translateMat, position); 60Mat4.copy(textNode._matrix, translateMat); 61//根據主相機視口調整模型旋轉,保證文字總是面向相機 62this.computeMatrix4MainCamera(textNode._matrix, viewer); 63//析構 64Mat4.MemoryPool.free(translateMat); 65},
我們看到,我們的uv轉成BufferArray後被geometry物件所接收,let uv = new Float32Array(imgUVs); let uvBuffer = new BufferArray(BufferArray.ARRAY_BUFFER, uv, 2); geom.setBufferArray('Texture', uvBuffer);通過這三行程式碼,我們的幾何體物件裡就包含了材質資訊,鯽魚接下來很歡快地發現,數字貼圖完整地繪製到模型節點中去了。
以上就是對數字GUI組建的完整說明,謝謝同學們的關注與支援,鯽魚和大家一起進步,鯽魚和同學們下週再見。
本文系原創,如需引用,請註明出處: https://www.cnblogs.com/ccentry/p/10322832.html