文章目录
1.本文主要内容
Three.js有关内容也是属于Web三维可视化监控系统搭建的一部分,但是考虑到这里只是专注于Threejs有关内容的介绍,因此把标题改成了Threejs的补充,将常用的模块进行单独介绍。当然,后面还能补充什么内容,我还没想好。
码云示例仓库地址,考虑到国内访问gayhub的速度,我就放在码云上了。运行其中的sprite_test.html即可尝试sprite效果。点击立方体可以显示标签,再次点击相同标签可以关闭标签。
2.Sprite介绍
sprite直接翻译过来就是精灵。它的特性是,永远正对相机平面。不像广告牌,可以绕到后面看看,绕到侧面看看,它永远会正对着你。所以我们可以用它来显示一些标签,比如在可视化监控系统中,就可以显示传感器的数据,下图所示,可以用来显示温度,当改变观看角度,标签也会随之改变角度。
3.Threejs中Sprite的相关函数使用
显示文字主要分为如下几个步骤:用自带的canvas画出边框、填字;将canvas的纹理作为sprite的材质创建sprite;将sprite添加入场景scene中。
下面的代码主要参考了这篇博文,我懒得复制粘贴了,如果需要直接复制代码的,跳到那篇博文直接复制就好了
4.封装好的Sprite相关内容的使用
在码云示例仓库地址中,我已经封装好了一个three_sprite_utils.js,虽然其中的内容以抄来的为主吧。
4.1 管理已创建的sprite对象
我在前人的基础上加入了切换显示的功能,也就是我的应用背景是点击一下某个物体,就出现对应的文字,再点击一下,就隐藏。比方说在可视化场景中,点击温度计,就出现当前温度;再点击温度计,就隐藏当前温度。
要实现这样的功能,就需要用一个数组去管理sprite。
var spriteInfoItem = {'objItem':_obj, 'spriteItem':newSprite};
three_sprite_utils_vars.spriteInfoStorage.push(spriteInfoItem);
首先我们创建一个字典对象,具有两个键值,分别用于存储sprite的标识符和sprite本身。sprite标识符可以设置为点击的3D模型本身(例如在3D场景中),或者设置为一段字符串(例如在VR场景中,点击温度传感器,我就可以设置为’temperature’),在创建sprite对象时,将其放入sprite管理数组中。
4.2 切换显示/隐藏sprite
在请求切换显示/隐藏sprite时,首先要通过标识符查找是否已经创建过这个sprite,注意这里要通过标识符找,有人会认为,那我通过sprite找不行吗?原理上行得通,但是实际如果我们能记下和区分出之前点击过的每个sprite对应哪个物体,那我们还管理sprite干啥!直接把它从场景中移除不就好了吗!就好像我们都知道妈妈有一种神奇的能力叫做,你要用电吹风,找半天找不到电吹风,于是问她电吹风怎么不见了,她就会说:
不是在xx房间xx格子上吗?
你一去看,还真是,虽然刚刚好像也找过这个地方,老妈的话总是像变戏法一样。
我们就是这样一个丢三落四的人,妈妈就是我们的保管员,如果我们找不到电吹风,就问她电吹风在哪,于是我们就得到了电吹风。如果你成为了妈妈,心里一清二楚东西都放在哪,那还用得着问别人吗??
好了,言归正传。如果通过标识符找到了之前创建的sprite,我们就把它从当前的场景中移除。如果没有,我们就将它添加到当前的场景中。
4.3 更新sprite
除了切换显示和隐藏,还需要对旧的文字进行更新。比如说之前温度是38°,现在36.5了,那就需要更新文字。这里直接贴代码了,只需要告诉这个函数新的字符串是什么,已创建的精灵的标识符是什么即可。更新的方法是将旧的精灵材质销毁,并且创建新的材质赋值给它。
function UpdateText(_str, attachedObject) {
var spriteMaterial = getSpriteMaterial(_str);
var spriteObj = findSprite(attachedObject);
if(spriteObj){
if(spriteObj.material) spriteObj.material.dispose();
spriteObj.material = null;
spriteObj.material = spriteMaterial;
}
else{
console.error("three_sprite_utils update text error!");
}
}
4.4 具体使用方法
使用很简单,三句话搞定。这个函数的三个参数分别是所需显示的字,所需显示的位置,标识符。
需要注意的是,switch这个函数,是会返回创建的sprite的,需要手动添加。但是如果之前的sprite已经存在,则会直接从场景中删除。好久没跑过这个程序,我都不记得自己当年怎么写的了,搞了半天场景中也没有,原来是要手动添加。
当年这么做的考虑是,比方说我点击了温度计,就要出来当时的温度。而实时温度是需要通过定时任务与后台交互的,所以switch的返回值就顺带可以告诉我们之前是否有创建过相关的标签精灵,如果创建过,那我点击之后关闭标签的同时,还要把定时任务也关闭了。
在定时任务中,要记得获取新的传感器信息后,更新文字。
var newSprite = SwitchSprite("38℃", selectedMesh.position, selectedMesh)
if(newSprite != null){
//说明之前未创建,需要将新的sprite添加到scene中,并且打开定时任务
scene.add(newSprite);
setInterval(...);
}
else{
clearInterval(...);
}