HTML坐标不随着屏幕大小改变,使用three.js创建大小不随着场景变化的文字

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

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

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

优点:

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

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

效果图:

e825067cf072ed1928173773aaa465fd.png

实现方法

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 = newTHREE.PlaneBufferGeometry();

let material= newTHREE.ShaderMaterial({

vertexShader: UnscaledTextVertexShader,

fragmentShader: UnscaledTextFragmentShader,

uniforms: {

tDiffuse: {

value:newTHREE.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;

uniformfloatwidth;

uniformfloatheight;

uniformfloatdomWidth;

uniformfloatdomHeight;

varying vec2 vUv;voidmain() {

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;

uniformfloatwidth;

uniformfloatheight;

varying vec2 vUv;voidmain() {//注意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)像素开始绘制。

在上面的代码中,字体大小和线宽都是偶数,不存在这个问题。

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进行修改后,文字不模糊了。所以,这个没有仔细测试。

参考资料

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值