使用three.js创建大小不随着场景变化的文字,需要以下两步:

1、将文字绘制到画布上。

2、创建着色器材质,把文字放到三维场景中。

优点:

1、跟用html实现文字相比,这些文字可以被模型遮挡,更具有三维效果。

2、不会随着场景旋转缩放改变尺寸,不存在远处看不清的情况,适用于三维标注。

效果图:

示例代码1:https://github.com/tengge1/ShadowEditor/blob/master/ShadowEditor.Web/src/object/text/UnscaledText.js

示例代码2:https://gitee.com/tengge1/ShadowEditor/blob/master/ShadowEditor.Web/src/object/text/UnscaledText.js

实现方法

1、使用canvas绘制文字,先用黑色绘制描边,然后用白色绘制文字。黑色描边主要为了让文字在白色背景处能看清。

let context = canvas.getContext('2d');

context.imageSmoothingQuality = 'high';
context.textBaseline = 'middle';
context.textAlign = 'center';
context.lineWidth = 4; let halfWidth = canvas.width / 2;
let halfHeight = canvas.height / 2; // 画描边
context.font = `16px "Microsoft YaHei"`;
context.strokeStyle = '#000';
context.strokeText(text, halfWidth, halfHeight); // 画文字
context.fillStyle = '#fff';
context.fillText(text, halfWidth, halfHeight);

2、 创建着色器材质,将文字正对屏幕,渲染到三维场景中。

let geometry = new THREE.PlaneBufferGeometry();
let material = new THREE.ShaderMaterial({
vertexShader: UnscaledTextVertexShader,
fragmentShader: UnscaledTextFragmentShader,
uniforms: {
tDiffuse: {
value: new THREE.CanvasTexture(canvas)
},
width: {
value: canvas.width
},
height: {
value: canvas.height
},
domWidth: {
value: renderer.domElement.width
},
domHeight: {
value: renderer.domElement.height
}
},
transparent: true
}); let mesh = new THREE.Mesh(geometry, material);

说明:由于canvas上绘制的文字边缘是半透明的,材质要设置成半透明才能实现文字边缘平滑效果。

 
UnscaledTextVertexShader
 
precision highp float;

uniform float width;
uniform float height;
uniform float domWidth;
uniform float domHeight; varying vec2 vUv; void main() {
vUv = uv;
vec4 proj = projectionMatrix * modelViewMatrix * vec4(0.0, 0.0, 0.0, 1.0);
gl_Position = vec4(
proj.x / proj.w + position.x * width / domWidth * 2.0,
proj.y / proj.w + position.y * height / domHeight * 2.0,
proj.z / proj.w,
1.0
);
}

说明:

a、(0.0, 0.0, 0.0)是平面中心世界坐标,左乘modelViewMatrix和projectionMatrix后,得到屏幕坐标系中的坐标。

b、proj.x / proj.w + position.x * width / domWidth * 2.0的意思是把平板中心放到世界坐标系正确位置,让平板显示的宽度恰好等于屏幕上的像素数,避免文字缩放。

c、乘以2.0是因为three.js默认生成的平板宽度和高度是1,屏幕坐标系宽度和高度都是从-1到1,是2。

d、gl_Position.w为1.0时,是正投影,模型大小不随着屏幕深度变化而改变。

 
UnscaledTextFragmentShader
 
precision highp float;

uniform sampler2D tDiffuse;
uniform float width;
uniform float height; varying vec2 vUv; void main() {
// 注意vUv一定要从画布整数坐标取颜色,否则会导致文字模糊问题。
vec2 _uv = vec2(
(floor(vUv.s * width) + 0.5) / width,
(floor(vUv.t * height) + 0.5) / height
); gl_FragColor = texture2D( tDiffuse, _uv );
}

说明:

1、uv坐标一定要恰好对应画布上的像素点,否则会导致文字模糊问题。

 

文字模糊的解决方法

使用three.js或WebGL绘制文字,很容易遇到文字模糊的问题,主要有以下几个方面的原因。
 
 
1、canvas上绘制线条,是从两个像素中心点画的。
 
在整数像素处绘制1px的线条,其实在1px线条两边,都有0.5px半透明的线条,实际绘制了2px。绘制时,一定要从(整数+0.5px)像素开始绘制。
 
具体参考《canvas画布解决1px线条模糊的问题》:https://www.jianshu.com/p/c0970eecd843
 
在上面的代码中,字体大小和线宽都是偶数,不存在这个问题。
 
 
2、根据uv坐标从贴图取色的时候,一定要恰好取到贴图上的整数像素,否则会进行颜色插值,导致模糊。
 
我被这个问题卡了很久,具体现象就是随着视角改变,文字有时候清晰,有时候模糊,一闪一闪的。
 
解决方法就是在片源着色器中对自动插值的uv坐标进行“取整”,恰好取到(整数+0.5像素)。为什么加0.5,看上面《canvas画布解决1px线条模糊的问题》的文章。
 
实现代码:
 
vec2 _uv = vec2(
(floor(vUv.s * width) + 0.5) / width,
(floor(vUv.t * height) + 0.5) / height
);
其中,width和height分别是贴图的宽度和高度。
 
3、gl_Position.xy恰好对应屏幕上的像素点。
 
这是我猜测的一个原因,根据原因2进行修改后,文字不模糊了。所以,这个没有仔细测试。
 
 

参考资料

1、基于three.js的开源三维场景编辑器:https://github.com/tengge1/ShadowEditor
2、canvas画布解决1px线条模糊的问题:https://www.jianshu.com/p/c0970eecd843
 
 
 

使用three.js创建大小不随着场景变化的文字的更多相关文章

  1. Qt QLabel 大小随内容自动变化 && 内容填充整个label空间

    图1:label的本身大小 图2:给label设置文字,不做任何别的设置 ui->label->setText(QObject::tr("current font is %1&q ...

  2. 第一章 用three.js创建你的第一个3D场景

    第一章 用three.js创建你的第一个3D场景 到官网下载three.js的源码和示例. 创建HTML框架界面 第一个示例的代码如下: 01-basic-skeleton.html 位于 Learn ...

  3. 使用three.js创建3D机房模型-分享一

    序:前段时间公司一次研讨会上,一市场部同事展现了同行业其他公司的3D机房,我司领导觉得这个可以研究研究,为了节约成本,我们在网上大量检索,最后找到一位前辈的博文[TWaver的技术博客],在那篇博文的 ...

  4. Spring boot+Thymeleaf+easyui集成:js创建组件页面报错

    开发工具:Ideal 使用场景:Demo 前提:       环境:Spring boot +Thymeleaf+easyui 引入thymeleaf模板引擎 <html lang=" ...

  5. 使用webgl(three.js)创建3D机房,3D机房微模块详细介绍(升级版二)

    序: 上节课已经详细描述了普通机房的实现过程,文章地址(https://www.cnblogs.com/yeyunfei/p/10473021.html) 紧接着上节课的内容 我们这节可来详细讲解机房 ...

  6. 使用webgl(three.js)创建3D机房(升级版)-普通机房

    序: 目前市面上的数据中心主要分两大类,一类属于普通数据中心,机柜按照XY轴 有序排放,一类属于微模块集合的数据中心,多个机柜组合而成的微模块.  本节课主要详细讲解普通数据中心的可视化展示,浏览器直 ...

  7. 用Backbone.js创建一个联系人管理系统(五)

    原文: Build a Contacts Manager Using Backbone.js: Part 5 这是这系列教程最后一部分了. 之前所有的增删改都在前端完成. 这部分我们要把Contact ...

  8. 使用 iosOverlay.js 创建 iOS 风格的提示和通知

    iosOverlay.js 用于在 Web 项目中实现 iOS 风格的通知和提示效果.为了防止图标加载的时候闪烁,你需要预加载的图像资源.不兼容 CSS 动画的浏览器需要 jQuery 支持.浏览器兼 ...

  9. Dynamics.js - 创建逼真的物理动画的 JS 库

    Dynamics.js 是一个用来创建物理动画 JavaScript 库.你只需要把dynamics.js引入你的页面,然后就可以激活任何 DOM 元素的 CSS 属性动画,也可以用户 SVG 属性. ...

随机推荐

  1. CentOS7.5模板机配置

    CentOS7.5模板机配置 标签(空格分隔): linux学习知识整理 Mr.Wei's notes! 人一定要有梦想,没有梦想那根咸鱼有什么区别: 即便自己成为了一条咸鱼,也要成为咸鱼里最咸的那一 ...

  2. Magicodes.IE已支持导出Word、Pdf和Html

    关于Magicodes.IE 导入导出通用库,通过导入导出DTO模型来控制导入和导出,支持Excel.Word.Pdf和Html. GitHub地址:https://github.com/xin-la ...

  3. ES6对象简洁语法

    对象(object)是 JavaScript 最重要的数据结构.ES6 对它进行了重大升级,本章介绍数据结构本身的改变及语法应用细节. 1.属性的简洁表示法 ◆ ES6 允许直接写入变量和函数,作为对 ...

  4. 爬虫基本库的使用---urllib库

    使用urllib---Python内置的HTTP请求模块 urllib包含模块:request模块.error模块.parse模块.robotparser模块 发送请求 使用 urllib 的 req ...

  5. ThinkCMF 框架上的任意内容包含漏洞

    0x01  背景 ThinkCMF是一款基于PHP+MYSQL开发的中文内容管理框架,底层采用ThinkPHP3.2.3构建. ThinkCMF提出灵活的应用机制,框架自身提供基础的管理功能,而开发者 ...

  6. CSPS模拟99

    555我原型笔录 T1 不会线段树维护单调栈被dalao们踩爆 T2 我要实现这样一个东西: 已知a,b,c,使a=a-b,b=b-c 结果我把代码弄成这样: b=b-c;a=a-b; 然后就被dal ...

  7. 创建linux系统下的虚拟机

    1.打开VMware软件 2.创建新的虚拟机 3.下一步 4.点击 稍后安装操作系统——下一步 5.选择   其中版本 我的镜像是这个版本所以选择这个 6.下一步  设置虚拟机名称  要保存的位置 7 ...

  8. .NET后端知识汇总

    C#.net系列后端知识点汇总(也有些许数据库.svn等),他山之石. 1..net相关技术:XML.webservice.SOAP,其中webservice使用三大技术:XML.SOAP.WSDL. ...

  9. (二十六)golang--切片

    基本介绍: 切片是数组的引用: 切片的使用和数组类似: 切片的长度是可以变化的: 切片的定义 var a []int,注意和数组定义的区别: 切片不仅可以使用len函数,还有cap函数来计算切片的容量 ...

  10. JQury自动切换图片

    [标签]Jquery图片自动切换<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "ht ...