WebGL之sprite精靈效果顯式數字貼圖

  接着前一篇《WebGL實現sprite精靈效果的GUI控件》,咱們繼續開發咱們的數字系統GUI控件,由於這套數字系統是基於sprite效果的,因此數字隨相機轉動而旋轉(永遠面對相機),隨場景縮放而逆向縮放(數字在屏幕上看上去大小不變)。實現sprite效果的核心方法在前一篇文章裏已經詳細說明,這裏再也不贅述,本文要討論的是如何將用戶輸入的數字文本轉變成GUI控件的數字貼圖。請看demo。html

咱們能清楚地看到,在角度測量模式下,咱們動態地繪製了兩條邊的長度數字貼圖和角度大小的數字貼圖。對於咱們來講,計算邊長和夾角是很是簡單的工做,但怎麼把結果數字轉變成對應的圖片呢,這裏鯽魚是經過uv座標和數字圖片一一映射實現的。其實原理很是簡單,鯽魚有一張包含0~9和小數點,角度的°的圖片png,用戶輸入是一串包含0~9,小數點和°的字符串,鯽魚將每個字符都綁定圖片的uv座標,這樣構造出的函數輸入是字符串,返回就是對應輸入字符串的uv座標數組。咱們知道構造紋理texture的貼圖就是利用圖片的uv座標來定位圖片在texture上的位置信息,利用這個原理,鯽魚拿回的uv數組就完成了將一個一個數字貼到一片顯式數字的矩形模型中,用戶看到的就會是一片顯式一串數字的矩形(固然矩形是透明的,用戶只能看到數字)。web

  以上是原理的解釋,咱們先來看一下數字的png圖片長啥樣。數組

這張就是包含數字和小數點和°的png圖片,注意它是正方形的,且尺寸是2的冪次方。這兩點前者是爲了優化webgl的材質渲染,後者是爲了能被webgl的材質所識別。爲了作成正方形,咱們用空白填充。好了,接下來咱們來看看代碼,關於uv貼圖的映射和texture綁定圖片,咱們先來看uv映射。緩存

  1 /**
  2  * 字庫
  3  * */
  4 let TextImage = function(){
  5     this._library = {
  6         ZERO_UV:[0, 1, 0, 0.75, 0.25, 1, 0.25, 0.75],
  7         ONE_UV:[0, 0.75, 0, 0.5, 0.25, 0.75, 0.25, 0.5],
  8         TWO_UV:[0, 0.5, 0, 0.25, 0.25, 0.5, 0.25, 0.25],
  9         THREE_UV:[0, 0.25, 0, 0, 0.25, 0.25, 0.25, 0],
 10         FOUR_UV:[0.25, 1, 0.25, 0.75, 0.5, 1, 0.5, 0.75],
 11         FIVE_UV:[0.25, 0.75, 0.25, 0.5, 0.5, 0.75, 0.5, 0.5],
 12         SIX_UV:[0.25, 0.5, 0.25, 0.25, 0.5, 0.5, 0.5, 0.25],
 13         SEVEN_UV:[0.25, 0.25, 0.25, 0, 0.5, 0.25, 0.5, 0],
 14         EIGHT_UV:[0.5, 1, 0.5, 0.75, 0.75, 1, 0.75, 0.75],
 15         NINE_UV:[0.5, 0.75, 0.5, 0.5, 0.75, 0.75, 0.75, 0.5],
 16         DOT_UV:[0.5, 0.5, 0.5, 0.25, 0.75, 0.5, 0.75, 0.25],
 17         DEGREE_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      * */
 28     getImagesByText:function(text){
 29         text = this.changeUnit(0.001, text);
 30         text = this.keepEffectNum(3, text);
 31         text = text.toString();
 32         //逐字符匹配圖片
 33         let imgUVs = [];
 34         for(let i=0; i<text.length; i++){
 35             let imgUV = this.match(text[i]);
 36             imgUVs = imgUVs.concat(imgUV);
 37         }
 38         return imgUVs;
 39     },
 40 
 41     /**
 42      * 經過輸入角度返回圖片,小數點後保留3位
 43      * angle:輸入的文字
 44      * */
 45     getAngleImagesByText:function(angle){
 46         angle = this.keepEffectNum(3, angle);
 47         angle = angle.toString();
 48         angle = angle + "#";
 49         //逐字符匹配圖片
 50         let imgUVs = [];
 51         for(let i=0; i<angle.length; i++){
 52             let imgUV = this.match(angle[i]);
 53             imgUVs = imgUVs.concat(imgUV);
 54         }
 55         return imgUVs;
 56     },
 57 
 58     /**
 59      * 單位換算
 60      * ratio:換算率
 61      * text:輸入的值
 62      * */
 63     changeUnit:function(ratio, text){
 64         return ratio * text;
 65     },
 66 
 67     /**
 68      * 小數點後保存n位
 69      * effect:有效數字
 70      * text:原始數字
 71      * */
 72     keepEffectNum:function(effect, text){
 73         return text.toFixed(effect);
 74     },
 75 
 76     /**
 77      * 匹配字符和圖片
 78      * char:字符
 79      * */
 80     match:function(char){
 81         let imgUV = undefined;
 82         if(char === "0"){
 83             imgUV = this._library.ZERO_UV;
 84         }else if(char === "1"){
 85             imgUV = this._library.ONE_UV;
 86         }else if(char === "2"){
 87             imgUV = this._library.TWO_UV;
 88         }else if(char === "3"){
 89             imgUV = this._library.THREE_UV;
 90         }else if(char === "4"){
 91             imgUV = this._library.FOUR_UV;
 92         }else if(char === "5"){
 93             imgUV = this._library.FIVE_UV;
 94         }else if(char === "6"){
 95             imgUV = this._library.SIX_UV;
 96         }else if(char === "7"){
 97             imgUV = this._library.SEVEN_UV;
 98         }else if(char === "8"){
 99             imgUV = this._library.EIGHT_UV;
100         }else if(char === "9"){
101             imgUV = this._library.NINE_UV;
102         }else if(char === "."){
103             imgUV = this._library.DOT_UV;
104         }else if(char === "#"){
105             imgUV = this._library.DEGREE_UV;
106         }
107         return 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      * */
11     addGeometry:function(viewer, textNode, width, height, position, imgUVs, texture){
12         //頂點緩存
13         let w = width;
14         let h = height;
15         //縮放比
16         let scaleRatio = 1;
17         scaleRatio = this.againstScale(position, viewer);
18         w = w*scaleRatio;
19         h = h*scaleRatio;
20         //頂點數組
21         let vertices = [];
22         //首先肯定有幾張圖片
23         let imgNum = imgUVs.length/8;
24         if(imgNum !== 0){
25             for(let i=0; i<imgNum; i++){
26                 vertices.push(w*i, h, 0, w*i, 0, 0, w*(i+1), h, 0, w*(i+1), 0, 0);
27             }
28         }
29         let array = new Float32Array(vertices);
30         let vertexBuffer = new BufferArray(BufferArray.ARRAY_BUFFER, array, 3);
31         //索引緩存
32         let indices = [];
33         if(imgNum !== 0){
34             for(let i=0; i<imgNum; i++){
35                 indices.push(4*i, 4*i+1, 4*i+3, 4*i+3, 4*i+2, 4*i);
36             }
37         }
38         let index = new Int8Array(indices);
39         let indexBuffer = new BufferArray(BufferArray.ELEMENT_ARRAY_BUFFER, index, index.length);
40         //繪製圖元
41         let prim = new DrawElements(Primitives.TRIANGLES, indexBuffer);
42         //幾何對象
43         let geom = new Geometry();
44         geom.setBufferArray('Vertex', vertexBuffer);
45         geom.setPrimitive(prim);
46         //紋理座標
47         let uv = new Float32Array(imgUVs);
48         let uvBuffer = new BufferArray(BufferArray.ARRAY_BUFFER, uv, 2);
49         geom.setBufferArray('Texture', uvBuffer);
50         //將texture加入geometry
51         geom.getStateSet(true).addAttribute(texture, StateAttribute.OVERRIDE);
52         //圖片背景透明
53         let bf = new BlendFunc(BlendFunc.SRC_ALPHA, BlendFunc.ONE_MINUS_SRC_ALPHA);
54         geom.getStateSet(true).addAttribute(bf, StateAttribute.OVERRIDE);
55         //幾何對象加入根節點
56         textNode.addChild(geom);
57         //將textNode的位置平移到position位置
58         let translateMat = Mat4.MemoryPool.alloc();
59         Mat4.fromTranslation(translateMat, position);
60         Mat4.copy(textNode._matrix, translateMat);
61         //根據主相機視口調整模型旋轉,保證文字老是面向相機
62         this.computeMatrix4MainCamera(textNode._matrix, viewer);
63         //析構
64         Mat4.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組建的完整說明,謝謝同窗們的關注與支持,鯽魚和你們一塊兒進步,鯽魚和同窗們下週再見。post

  本文系原創,如需引用,請註明出處:http://www.javashuo.com/article/p-ahxlazhh-ht.html優化

相關文章
相關標籤/搜索