接着前一篇《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(){ 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;