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映射。
/**
* 字库
* */
let TextImage = function(){
this._library = {
ZERO_UV:[0, 1, 0, 0.75, 0.25, 1, 0.25, 0.75],
ONE_UV:[0, 0.75, 0, 0.5, 0.25, 0.75, 0.25, 0.5],
TWO_UV:[0, 0.5, 0, 0.25, 0.25, 0.5, 0.25, 0.25],
THREE_UV:[0, 0.25, 0, 0, 0.25, 0.25, 0.25, 0],
FOUR_UV:[0.25, 1, 0.25, 0.75, 0.5, 1, 0.5, 0.75],
FIVE_UV:[0.25, 0.75, 0.25, 0.5, 0.5, 0.75, 0.5, 0.5],
SIX_UV:[0.25, 0.5, 0.25, 0.25, 0.5, 0.5, 0.5, 0.25],
SEVEN_UV:[0.25, 0.25, 0.25, 0, 0.5, 0.25, 0.5, 0],
EIGHT_UV:[0.5, 1, 0.5, 0.75, 0.75, 1, 0.75, 0.75],
NINE_UV:[0.5, 0.75, 0.5, 0.5, 0.75, 0.75, 0.75, 0.5],
DOT_UV:[0.5, 0.5, 0.5, 0.25, 0.75, 0.5, 0.75, 0.25],
DEGREE_UV:[0.5, 0.25, 0.5, 0, 0.75, 0.25, 0.75, 0]
};
}; TextImage.prototype.constructor = TextImage;
TextImage.prototype = { /**
* 通过输入文字返回图片,小数点后保留3位
* text:输入的文字
* */
getImagesByText:function(text){
text = this.changeUnit(0.001, text);
text = this.keepEffectNum(3, text);
text = text.toString();
//逐字符匹配图片
let imgUVs = [];
for(let i=0; i<text.length; i++){
let imgUV = this.match(text[i]);
imgUVs = imgUVs.concat(imgUV);
}
return imgUVs;
}, /**
* 通过输入角度返回图片,小数点后保留3位
* angle:输入的文字
* */
getAngleImagesByText:function(angle){
angle = this.keepEffectNum(3, angle);
angle = angle.toString();
angle = angle + "#";
//逐字符匹配图片
let imgUVs = [];
for(let i=0; i<angle.length; i++){
let imgUV = this.match(angle[i]);
imgUVs = imgUVs.concat(imgUV);
}
return imgUVs;
}, /**
* 单位换算
* ratio:换算率
* text:输入的值
* */
changeUnit:function(ratio, text){
return ratio * text;
}, /**
* 小数点后保存n位
* effect:有效数字
* text:原始数字
* */
keepEffectNum:function(effect, text){
return text.toFixed(effect);
}, /**
* 匹配字符和图片
* char:字符
* */
match:function(char){
let imgUV = undefined;
if(char === "0"){
imgUV = this._library.ZERO_UV;
}else if(char === "1"){
imgUV = this._library.ONE_UV;
}else if(char === "2"){
imgUV = this._library.TWO_UV;
}else if(char === "3"){
imgUV = this._library.THREE_UV;
}else if(char === "4"){
imgUV = this._library.FOUR_UV;
}else if(char === "5"){
imgUV = this._library.FIVE_UV;
}else if(char === "6"){
imgUV = this._library.SIX_UV;
}else if(char === "7"){
imgUV = this._library.SEVEN_UV;
}else if(char === "8"){
imgUV = this._library.EIGHT_UV;
}else if(char === "9"){
imgUV = this._library.NINE_UV;
}else if(char === "."){
imgUV = this._library.DOT_UV;
}else if(char === "#"){
imgUV = this._library.DEGREE_UV;
}
return imgUV;
}
}; module.exports = TextImage;
我们看到这个TextImage类拥有一个this._library字库,其中每一个数字都绑定了一串uv坐标,即图片中每一个数字的左上角->左下角->右下角->右上角逆时针绕向的4组坐标值。在match函数中通过函数输入参数的字符来返回对应的uv坐标数组。这就是数字绑定uv的原理。再来看我们拿到uv数组怎么绑定到材质对象中去。请看下面代码。
/**
* 创建几何
* viewer:视图对像
* textNode:文字节点
* width:宽
* height:高
* position:位置坐标
* imgUVs:图片uv数组
* texture:数字纹理
* */
addGeometry:function(viewer, textNode, width, height, position, imgUVs, texture){
//顶点缓存
let w = width;
let h = height;
//缩放比
let scaleRatio = 1;
scaleRatio = this.againstScale(position, viewer);
w = w*scaleRatio;
h = h*scaleRatio;
//顶点数组
let vertices = [];
//首先确定有几张图片
let imgNum = imgUVs.length/8;
if(imgNum !== 0){
for(let i=0; i<imgNum; i++){
vertices.push(w*i, h, 0, w*i, 0, 0, w*(i+1), h, 0, w*(i+1), 0, 0);
}
}
let array = new Float32Array(vertices);
let vertexBuffer = new BufferArray(BufferArray.ARRAY_BUFFER, array, 3);
//索引缓存
let indices = [];
if(imgNum !== 0){
for(let i=0; i<imgNum; i++){
indices.push(4*i, 4*i+1, 4*i+3, 4*i+3, 4*i+2, 4*i);
}
}
let index = new Int8Array(indices);
let indexBuffer = new BufferArray(BufferArray.ELEMENT_ARRAY_BUFFER, index, index.length);
//绘制图元
let prim = new DrawElements(Primitives.TRIANGLES, indexBuffer);
//几何对象
let geom = new Geometry();
geom.setBufferArray('Vertex', vertexBuffer);
geom.setPrimitive(prim);
//纹理坐标
let uv = new Float32Array(imgUVs);
let uvBuffer = new BufferArray(BufferArray.ARRAY_BUFFER, uv, 2);
geom.setBufferArray('Texture', uvBuffer);
//将texture加入geometry
geom.getStateSet(true).addAttribute(texture, StateAttribute.OVERRIDE);
//图片背景透明
let bf = new BlendFunc(BlendFunc.SRC_ALPHA, BlendFunc.ONE_MINUS_SRC_ALPHA);
geom.getStateSet(true).addAttribute(bf, StateAttribute.OVERRIDE);
//几何对象加入根节点
textNode.addChild(geom);
//将textNode的位置平移到position位置
let translateMat = Mat4.MemoryPool.alloc();
Mat4.fromTranslation(translateMat, position);
Mat4.copy(textNode._matrix, translateMat);
//根据主相机视口调整模型旋转,保证文字总是面向相机
this.computeMatrix4MainCamera(textNode._matrix, viewer);
//析构
Mat4.MemoryPool.free(translateMat);
},
我们看到,我们的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
WebGL之sprite精灵效果显式数字贴图的更多相关文章
- WebGL实现sprite精灵效果的GUI控件
threejs已经有了sprite插件,这就方便了three的用户,直接可以使用threejs的sprite插件来制作GUI模型.sprite插件是阿里的lasoy老师改造过的,这个很厉害,要学习一哈 ...
- GC与显式内存管理
C++复兴的话题至今已被鼓吹两年有余,Herb Sutter和Bjarne Stroustrup等大牛们也为C++带来了大步伐的革新.然而,从这两年的效果而言,C++的复兴并没有发生.一方面随着世界经 ...
- 显式锁(三)读写锁ReadWriteLock
前言: 上一篇文章,已经很详细地介绍了 显式锁Lock 以及 其常用的实现方式- - ReetrantLock(重入锁),本文将介绍另一种显式锁 - - 读写锁ReadWriteLock. ...
- 浅析SQL查询语句未显式指定排序方式,无法保证同样的查询每次排序结果都一致的原因
本文出处:http://www.cnblogs.com/wy123/p/6189100.html 标题有点拗口,来源于一个开发人员遇到的实际问题 先抛出问题:一个查询没有明确指定排序方式,那么,第二次 ...
- 并发编程 19—— 显式的Conditon 对象
Java并发编程实践 目录 并发编程 01—— ThreadLocal 并发编程 02—— ConcurrentHashMap 并发编程 03—— 阻塞队列和生产者-消费者模式 并发编程 04—— 闭 ...
- (转载)Android理解:显式和隐式Intent
Intent分两种:显式(Explicit intent)和隐式(Implicit intent). 一.显式(设置Component) 显式,即直接指定需要打开的activity对应的类. 以下多种 ...
- 【PL/SQL练习】显式游标
cursor --------需要用户先定义,在select时,可以用于处理多行记录 1.declare 声明一个游标 2.open cursor (隐式游标自动open) 3.fetch curs ...
- c# implicit explicit关键字(隐式和显式数据类型转换)
implicit关键字用于声明隐式的用户定义类型转换运算符.(explicit反之)explicit则用于显示转换用户自定义类型.static implicit operator target_typ ...
- IOS动画隐式,显式,翻页
// ViewController.m // IOS动画0817 // // Created by 张艳锋 on 15/8/17. // Copyright (c) 2015年 张艳锋. Al ...
随机推荐
- 2018.08.31 10:57 swift 学习心得
其实我一直很喜欢swift,我觉得Xcode很先进,买了一台MacBook就可以操作了,蛮好的. var str = "Hello, playground" var myVaria ...
- 【Alpha】Daily Scrum Meeting——blog1
团队成员 吴吉键 201421122007(组长) 魏修祺 201421122008 孙劲林 201421122022 1. 会议当天照片 忘记拍了,能补上不? 2. 每个人的工作 3. 燃尽图
- 破解myeclipse10失败的一个奇葩原因
昨天开发用的myeclipse10突然弹窗提示我要激活,我清楚的记得安装时候已经破解并且看到激活信息了. 翻遍搜索出来的文章,改systemid之类的也试过了,问题依旧存在,很是绝望. 今早过来机灵了 ...
- IO多路复用(select)
select在操作系统内部,维护了一个for循环,检测对象是否变化.select在各种平台都可使用,但效率不高.select对监听的个数是有限制的(1024) poll与select相同,但是没有监听 ...
- Codeforces gym 101343 J.Husam and the Broken Present 2【状压dp】
2017 JUST Programming Contest 2.0 题目链接:Codeforces gym 101343 J.Husam and the Broken Present 2 J. Hu ...
- python统计磁盘使用情况
#coding:utf-8import os; def SortList(item): return item[1]; def ReadSize(fileName): return flo ...
- regex_search
在regex_match()里边只能看到regex和输入的字符串是不是全部匹配上了,匹配上了就返回true,否则false.然而他不能返回匹配到的子字符串:regex_search()和regex_m ...
- Docker实战(六)之使用Dockerfile创建镜像
Dockervile是一个文本格式的配置文件,用户可以使用Dockerfile来快速创建自定义镜像. 1.基本结构 Dockerfile由一行行命令语句组成,并且支持以#开头的注释行. 一般而言,Do ...
- 集合之HashSet
在前篇博文中(java提高篇(二三)-----HashMap)详细讲解了HashMap的实现过程,对于HashSet而言,它是基于HashMap来实现的,底层采用HashMap来保存元素.所以如果对H ...
- 【转】Android 4.0 Launcher2源码分析——启动过程分析
Android的应用程序的入口定义在AndroidManifest.xml文件中可以找出:[html] <manifest xmlns:android="http://schemas. ...