zoukankan      html  css  js  c++  java
  • 使用three.js创建大小不随着场景变化的文字

    使用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)
            },
             {
                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
     
     
     
  • 相关阅读:
    Android studio开发找不到HttpClient问题
    Android studio开发找不到HttpClient问题
    互联网应用之传递HTTP参数
    互联网应用之传递HTTP参数
    计算机组成原理
    计算机组成原理
    【NYOJ】[40]公约数和公倍数
    【NYOJ】[40]公约数和公倍数
    【NYOJ】[39]水仙花数
    【NYOJ】[39]水仙花数
  • 原文地址:https://www.cnblogs.com/tengge/p/11979854.html
Copyright © 2011-2022 走看看