43 - three.js 笔记 - 使用 Sprite 精灵创建文字标签

Sprite精灵在计算机图形学中指包含在场景中的二维动画和图像,即sprite是一个永远朝向相机的平面,类似广告牌,没有z轴的概念,并且sprite不接受阴影。
示例:http://ithanmang.com/threeJs/home/201808/20180815/03-sprite-text.html

示例创建一个三维坐标轴,使用canvas绘制字体,并作为纹理加入到spritemap属性中,从而创建出二维字体标签,用来显示信息,并且可以跟随坐标轴缩放和移动。
这里写图片描述
首先,通过canvas绘制出圆角矩形,并且矩形的大小随文字的多少而改变,关于canvas的知识可以去http://www.runoob.com/html/html5-canvas.html 学习。

/* 绘制圆角矩形 */
    function roundRect(ctx, x, y, w, h, r) {

        ctx.beginPath();
        ctx.moveTo(x+r, y);
        ctx.lineTo(x+w-r, y);
        ctx.quadraticCurveTo(x+w, y, x+w, y+r);
        ctx.lineTo(x+w, y+h-r);
        ctx.quadraticCurveTo(x+w, y+h, x+w-r, y+h);
        ctx.lineTo(x+r, y+h);
        ctx.quadraticCurveTo(x, y+h, x, y+h-r);
        ctx.lineTo(x, y+r);
        ctx.quadraticCurveTo(x, y, x+r, y);
        ctx.closePath();
        ctx.fill();
        ctx.stroke();

    }

然后,绘制文字精灵,并返回创建出的sprite

/* 创建字体精灵 */
function makeTextSprite(message, parameters) {

    if ( parameters === undefined ) parameters = {};

    let fontface = parameters.hasOwnProperty("fontface") ?
        parameters["fontface"] : "Arial";

    /* 字体大小 */
    let fontsize = parameters.hasOwnProperty("fontsize") ?
        parameters["fontsize"] : 18;

    /* 边框厚度 */
    let borderThickness = parameters.hasOwnProperty("borderThickness") ?
        parameters["borderThickness"] : 4;

    /* 边框颜色 */
    let borderColor = parameters.hasOwnProperty("borderColor") ?
        parameters["borderColor"] : { r:0, g:0, b:0, a:1.0 };

    /* 背景颜色 */
    let backgroundColor = parameters.hasOwnProperty("backgroundColor") ?
        parameters["backgroundColor"] : { r:255, g:255, b:255, a:1.0 };

    /* 创建画布 */
    let canvas = document.createElement('canvas');
    let context = canvas.getContext('2d');

    /* 字体加粗 */
    context.font = "Bold " + fontsize + "px " + fontface;

    /* 获取文字的大小数据,高度取决于文字的大小 */
    let metrics = context.measureText( message );
    let textWidth = metrics.width;

    /* 背景颜色 */
    context.fillStyle   = "rgba(" + backgroundColor.r + "," + backgroundColor.g + ","
        + backgroundColor.b + "," + backgroundColor.a + ")";

    /* 边框的颜色 */
    context.strokeStyle = "rgba(" + borderColor.r + "," + borderColor.g + ","
        + borderColor.b + "," + borderColor.a + ")";
    context.lineWidth = borderThickness;

    /* 绘制圆角矩形 */
    roundRect(context, borderThickness/2, borderThickness/2, textWidth + borderThickness, fontsize * 1.4 + borderThickness, 6);

    /* 字体颜色 */
    context.fillStyle = "rgba(0, 0, 0, 1.0)";
    context.fillText( message, borderThickness, fontsize + borderThickness);

    /* 画布内容用于纹理贴图 */
    let texture = new THREE.Texture(canvas);
    texture.needsUpdate = true;

    let spriteMaterial = new THREE.SpriteMaterial({ map: texture } );
    let sprite = new THREE.Sprite( spriteMaterial );

    console.log(sprite.spriteMaterial);

    /* 缩放比例 */
    sprite.scale.set(10,5,0);

    return sprite;

}

使用sprite可以用来显示模型的信息,当然使用div和平面也可以显示。

完整示例代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Sprite 粒子(精灵)创建文字</title>
    <style>
        body {
            margin: 0;
            overflow: hidden;/* 溢出隐藏 */
        }
    </style>
    <script src="../../libs/build/three-r93.js"></script>
    <script src="../../libs/examples/js/Detector.js"></script>
    <script src="../../libs/examples/js/libs/dat.gui.min.js"></script>
    <script src="../../libs/examples/js/libs/stats.min.js"></script>
    <script src="../../libs/examples/js/controls/OrbitControls.js"></script>
</head>
<body>
<script>

    let scene, camera, renderer, controls, points;
    let stats = initStats();

    /* 场景 */
    function initScene() {

        scene = new THREE.Scene();

    }

    /* 相机 */
    function initCamera() {

        camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 10000);
        camera.position.set(20, 10, 50);
        camera.lookAt(new THREE.Vector3(0, 0, 0));

    }

    /* 渲染器 */
    function initRender() {

        renderer = new THREE.WebGLRenderer({antialias: true});
        renderer.setSize(window.innerWidth, window.innerHeight);

        document.body.appendChild(renderer.domElement);

    }

    /* 灯光 */
    function initLight() {



    }

    /* 控制器 */
    function initControls() {

        controls = new THREE.OrbitControls(camera, renderer.domElement);

        /* 属性参数默认 */

    }

    /* 场景中的内容 */
    function initContent() {

        let dirX = new THREE.Vector3( 1, 0, 0 );
        let dirY = new THREE.Vector3( 0, 1, 0 );
        let dirZ = new THREE.Vector3( 0, 0, 1 );

        let origin = new THREE.Vector3( 0, 0, 0 );
        let length = 10;

        let arrowHelperX = new THREE.ArrowHelper( dirX, origin, length, 0xff0000 );
        let arrowHelperY = new THREE.ArrowHelper( dirY, origin, length, 0x00ff00 );
        let arrowHelperZ = new THREE.ArrowHelper( dirZ, origin, length, 0x0000ff );
        scene.add( arrowHelperX );
        scene.add( arrowHelperY );
        scene.add( arrowHelperZ );

        /* 原点 */
        let spriteOrigin = makeTextSprite( " vector3(0, 0, 0) ",
            {
                fontsize: 20,
                borderColor: {r:255, g:0, b:0, a:0.4},/* 边框黑色 */
                backgroundColor: {r:255, g:255, b:255, a:0.9}/* 背景颜色 */
            } );
        spriteOrigin.center = new THREE.Vector2(0, 0);
        scene.add( spriteOrigin );
        spriteOrigin.position.set(0, -5, 0);

        let spriteY = makeTextSprite( "Y",
            {
                fontsize: 20,
                borderColor: {r:255, g:0, b:0, a:0.4},/* 边框黑色 */
                backgroundColor: {r:255, g:255, b:255, a:0.9}/* 背景颜色 */
            } );
        spriteY.center = new THREE.Vector2(0, 0);
        scene.add( spriteY );
        spriteY.position.set(0, 6, 0);

        let spriteX = makeTextSprite( "X",
            {
                fontsize: 20,
                borderColor: {r:255, g:0, b:0, a:0.4},/* 边框黑色 */
                backgroundColor: {r:255, g:255, b:255, a:0.9}/* 背景颜色 */
            } );
        spriteX.center = new THREE.Vector2(0, 0);
        scene.add( spriteX );
        spriteX.position.set(10, -5, 0);

        let spriteZ = makeTextSprite( "Z",
            {
                fontsize: 20,
                borderColor: {r:255, g:0, b:0, a:0.4},/* 边框黑色 */
                backgroundColor: {r:255, g:255, b:255, a:0.9}/* 背景颜色 */
            } );
        spriteZ.center = new THREE.Vector2(0, 0);
        scene.add( spriteZ );
        spriteZ.position.set(0, -5, 10);

    }

    /* 创建字体精灵 */
    function makeTextSprite(message, parameters) {

        if ( parameters === undefined ) parameters = {};

        let fontface = parameters.hasOwnProperty("fontface") ?
            parameters["fontface"] : "Arial";

        /* 字体大小 */
        let fontsize = parameters.hasOwnProperty("fontsize") ?
            parameters["fontsize"] : 18;

        /* 边框厚度 */
        let borderThickness = parameters.hasOwnProperty("borderThickness") ?
            parameters["borderThickness"] : 4;

        /* 边框颜色 */
        let borderColor = parameters.hasOwnProperty("borderColor") ?
            parameters["borderColor"] : { r:0, g:0, b:0, a:1.0 };

        /* 背景颜色 */
        let backgroundColor = parameters.hasOwnProperty("backgroundColor") ?
            parameters["backgroundColor"] : { r:255, g:255, b:255, a:1.0 };

        /* 创建画布 */
        let canvas = document.createElement('canvas');
        let context = canvas.getContext('2d');

        /* 字体加粗 */
        context.font = "Bold " + fontsize + "px " + fontface;

        /* 获取文字的大小数据,高度取决于文字的大小 */
        let metrics = context.measureText( message );
        let textWidth = metrics.width;

        /* 背景颜色 */
        context.fillStyle   = "rgba(" + backgroundColor.r + "," + backgroundColor.g + ","
            + backgroundColor.b + "," + backgroundColor.a + ")";

        /* 边框的颜色 */
        context.strokeStyle = "rgba(" + borderColor.r + "," + borderColor.g + ","
            + borderColor.b + "," + borderColor.a + ")";
        context.lineWidth = borderThickness;

        /* 绘制圆角矩形 */
        roundRect(context, borderThickness/2, borderThickness/2, textWidth + borderThickness, fontsize * 1.4 + borderThickness, 6);

        /* 字体颜色 */
        context.fillStyle = "rgba(0, 0, 0, 1.0)";
        context.fillText( message, borderThickness, fontsize + borderThickness);

        /* 画布内容用于纹理贴图 */
        let texture = new THREE.Texture(canvas);
        texture.needsUpdate = true;

        let spriteMaterial = new THREE.SpriteMaterial({ map: texture } );
        let sprite = new THREE.Sprite( spriteMaterial );

        console.log(sprite.spriteMaterial);

        /* 缩放比例 */
        sprite.scale.set(10,5,0);

        return sprite;

    }

    /* 绘制圆角矩形 */
    function roundRect(ctx, x, y, w, h, r) {

        ctx.beginPath();
        ctx.moveTo(x+r, y);
        ctx.lineTo(x+w-r, y);
        ctx.quadraticCurveTo(x+w, y, x+w, y+r);
        ctx.lineTo(x+w, y+h-r);
        ctx.quadraticCurveTo(x+w, y+h, x+w-r, y+h);
        ctx.lineTo(x+r, y+h);
        ctx.quadraticCurveTo(x, y+h, x, y+h-r);
        ctx.lineTo(x, y+r);
        ctx.quadraticCurveTo(x, y, x+r, y);
        ctx.closePath();
        ctx.fill();
        ctx.stroke();

    }


    /* 性能插件 */
    function initStats() {

        let stats = new Stats();

        document.body.appendChild(stats.domElement);

        return stats;

    }

    /* 窗口变动触发 */
    function onWindowResize() {

        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();
        renderer.setSize(window.innerWidth, window.innerHeight);

    }

    /* 数据更新 */
    function update() {

        stats.update();

    }

    /* 初始化 */
    function init() {

        initScene();
        initCamera();
        initRender();
        initLight();
        initControls();
        initContent();

        /* 监听事件 */
        window.addEventListener('resize', onWindowResize, false);

    }

    /* 循环渲染 */
    function animate() {

        requestAnimationFrame(animate);
        renderer.render(scene, camera);
        update();

    }

    /* 初始加载 */
    (function () {
        console.log("three init start...");

        init();
        animate();

        console.log("three init send...");
    })();

</script>
</body>
</html>

猜你喜欢

转载自blog.csdn.net/ithanmang/article/details/81774094