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 ...
随机推荐
- Ext 向Ext.form.ComboBox()中添加列表的分类
1.静态 [javascript] view plaincopy var staticComboBox = new Ext.form.ComboBox({ fieldLabel:'回访结果', ...
- Joinpoint继承体系-笔记
Joinpoint继承层次图: 由上图可以知道的所有的接口的实现都在ReflectiveMethodInvocation这个类中.ConstructorInvocation接口只有一个方法,这个方法的 ...
- 1834. [ZJOI2010]网络扩容【费用流】
Description 给定一张有向图,每条边都有一个容量C和一个扩容费用W.这里扩容费用是指将容量扩大1所需的费用. 求: 1.在不扩容的情况下,1到N的最大流: 2.将1到N的最大流增加K所需 ...
- Eclipse的PHP插件PHPEclipse安装和使用
PHP有很多相当不错的开发工具,如Zend Studio.NetBeans.phpdesigner等,但对于习惯Java编程的程序猿们来说,最常用的还要属Eclipse.那么Eclipse能用于PHP ...
- 'vue-cli-service' 不是内部或外部命令,也不是可运行的程序 或批处理文件。
首先把 node_modules 文件夹删除 然后运行以下命令: cnpm install 这样就可以正常运行
- 20155314 2016-2017-2 《Java程序设计》第9周学习总结
20155314 2016-2017-2 <Java程序设计>第9周学习总结 教材学习内容总结 了解JDBC架构 掌握JDBC架构 掌握反射与ClassLoader 了解自定义泛型和自定义 ...
- Node.js 连接 MongoDB-7
先安装模块: npm install --save mongodb 当然,首先你要打开mongodb服务端: mongod --bind_ip 127.0.0.1 创建数据库 要在 MongoDB 中 ...
- IS服务器下做301永久重定向设置方法
以前也没怎么关注301重定向,第一因为没有网站要重定向,第二对于不带www的域名我都是用的转发到带www的域名. 不过一场风波之后,很多服务商已经不提供转发服务了,虽说易名现在还可以享用到免费的转发服 ...
- python logging模块日志回滚TimedRotatingFileHandler
# coding=utf-8 import logging import time import os import logging.handlers import re def logger(app ...
- Kafka设计解析(六)Kafka高性能架构之道
转载自 技术世界,原文链接 Kafka设计解析(六)- Kafka高性能架构之道 本文从宏观架构层面和微观实现层面分析了Kafka如何实现高性能.包含Kafka如何利用Partition实现并行处理和 ...