关于three.js中添加文字的方式

本文介绍了一种使用Three.js中的粒子系统实现3D场景中文字显示的方法,避免了使用外部字体库带来的性能开销,并提供了具体实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

网上资料大部分是通过引入外部font库进行文字效果的载入,但是在实际运行的时候发现非常占用资源。于是不得不想另一种方法。

于是想到了three.js中的粒子系统。这当中有个很gay的骚操作是下面这个函数。

var particleMaterial = new THREE.SpriteCanvasMaterial( {

            color: 0x000000,
            program: function ( context ) {

                context.beginPath();
                context.font="bold 20px Arial";
                context.fillStyle="#058";
                context.transform(-1,0,0,1,0,0);
                context.rotate(Math.PI);
                context.fillText( wordFont , 0, 0 );

            }

上面的函数当中,可以传入一个canvas对象。恩,对。如果你想载入文字,写到canvas里就够啦,你还可以画小h图哦。


附上源代码:

ps:代码中最后的注释部分是外部加载字体的方式。有知道的大神请告诉我这么loader为啥贼卡。还有为什么context中文字fillText初始是镜像倒转的?又费了一点劲给它倒腾回来。可能涉及到坐标的原因,同样希望大神告知。

<!DOCTYPE html>
<html lang="en">
<head>
    <title>three.js measute_length</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
    <style>
        body {
            font-family: Arial;
            background-color: #f0f0f0;
            margin: 0px;
            overflow: hidden;
        }
    </style>
</head>
<body>

<script src="js/three.js"></script>

<script src="js/Projector.js"></script>
<script src="js/CanvasRenderer.js"></script>

<script src="js/OrbitControls.js"></script>

<script src="js/stats.min.js"></script>

<script>

    var container, stats;
    var camera, scene, renderer;
    var particleMaterial;

    var raycaster;
    var mouse;

    var objects = [];
    var points = [];

    init();
    animate();

    function init() {

        container = document.createElement( 'div' );
        document.body.appendChild( container );

        camera = new THREE.PerspectiveCamera( 70, window.innerWidth / window.innerHeight, 1, 10000 );
        camera.position.set( 0, 400, 700 );

        scene = new THREE.Scene();

        var geometry = new THREE.BoxGeometry( 100, 100, 100 );

        for ( var i = 0; i < 10; i ++ ) {

            var object = new THREE.Mesh( geometry, new THREE.MeshBasicMaterial( { color: Math.random() * 0xffffff, opacity: 0.5 } ) );
            object.position.x = Math.random() * 800 - 400;
            object.position.y = Math.random() * 800 - 400;
            object.position.z = Math.random() * 800 - 400;

            object.scale.x = Math.random() * 2 + 1;
            object.scale.y = Math.random() * 2 + 1;
            object.scale.z = Math.random() * 2 + 1;

            object.rotation.x = Math.random() * 2 * Math.PI;
            object.rotation.y = Math.random() * 2 * Math.PI;
            object.rotation.z = Math.random() * 2 * Math.PI;

            scene.add( object );

            objects.push( object );

        }

        var PI2 = Math.PI * 2;
        particleMaterial = new THREE.SpriteCanvasMaterial( {

            color: 0x000000,
            program: function ( context ) {

                context.beginPath();
                context.arc( 0, 0, 0.5, 0, PI2, true );
                context.fill();

            }

        } );

        raycaster = new THREE.Raycaster();
        mouse = new THREE.Vector2();

        renderer = new THREE.CanvasRenderer();
        renderer.setClearColor( 0xf0f0f0 );
        renderer.setPixelRatio( window.devicePixelRatio );
        renderer.setSize( window.innerWidth, window.innerHeight );
        container.appendChild( renderer.domElement );

        stats = new Stats();
        container.appendChild( stats.dom );

        document.addEventListener( 'mousedown', onDocumentMouseDown, false );
        document.addEventListener( 'touchstart', onDocumentTouchStart, false );

        window.addEventListener( 'resize', onWindowResize, false );
        var controls = new THREE.OrbitControls(camera);  //camera control
        controls.addEventListener('change', render);

    }

    function onWindowResize() {

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

        renderer.setSize( window.innerWidth, window.innerHeight );

    }

    function onDocumentTouchStart( event ) {

        event.preventDefault();

        event.clientX = event.touches[0].clientX;
        event.clientY = event.touches[0].clientY;
        onDocumentMouseDown( event );

    }

    function onDocumentMouseDown( event ) {

        event.preventDefault();

        mouse.x = ( event.clientX / renderer.domElement.clientWidth ) * 2 - 1;
        mouse.y = - ( event.clientY / renderer.domElement.clientHeight ) * 2 + 1;

        raycaster.setFromCamera( mouse, camera );

        //射线原理拾取目标
        var intersects = raycaster.intersectObjects( objects );

        if ( intersects.length > 0 ) {

            //创建粒子,便于标识点击位置
            var particle = new THREE.Sprite( particleMaterial );
            particle.position.copy( intersects[ 0 ].point );
            particle.scale.x = particle.scale.y = 1;
            scene.add( particle );

            //保存选中点
            points.push( intersects[ 0 ].point );

            if( points.length >1 ) {

                var p2 = points[points.length-1];
                var p1 = points[points.length-2];

                //动画的形式画线
                drawLine( p1, p2);
            }

        }

    }

    function animate() {

        requestAnimationFrame( animate );

        render();
        stats.update();

    }

    function render() {

        renderer.render( scene, camera );

    }

    function drawLine( p1, p2) {

        var directionVector = new THREE.Vector3();
        var p3 = new THREE.Vector3();
        directionVector.x = p2.x - p1.x;
        directionVector.y = p2.y - p1.y;
        directionVector.z = p2.z - p1.z;

        var length = Math.sqrt( directionVector.x * directionVector.x
            + directionVector.y * directionVector.y
            + directionVector.z * directionVector.z);

        var text = Math.round( length ) + "m";


        var flag = 1;
        var id = setInterval(function () {
            if (flag == 11) {
                clearInterval(id);
                flag = 1;
            } else {

                var geometry = new THREE.Geometry();
                var material = new THREE.LineBasicMaterial( { opacity:1,color:0x000000 } );

                geometry.vertices.push(p1);

                p3.x = p1.x + (directionVector.x/10) * flag;
                p3.y = p1.y + (directionVector.y/10) * flag;
                p3.z = p1.z + (directionVector.z/10) * flag;

                geometry.vertices.push(p1);
                geometry.vertices.push(p3);

                var geo = new THREE.Line(geometry, material);

                scene.add(geo);

                flag++;
            }

        }, 10);

        initText( text, p2 );

    }

//    var font;
//    var loader = new THREE.FontLoader();
//    loader.load('js/optimer_bold.typeface.json',function(response) {
//         font = response;

//    });
    function initText( wordFont, p1){

        var particleMaterial = new THREE.SpriteCanvasMaterial( {

            color: 0x000000,
            program: function ( context ) {

                context.beginPath();
                context.font="bold 20px Arial";
                context.fillStyle="#058";
                context.transform(-1,0,0,1,0,0);
                context.rotate(Math.PI);
                context.fillText( wordFont , 0, 0 );

            }

        } );

        var particle = new THREE.Sprite( particleMaterial );
        particle.position.copy( p1 );
        particle.rotation.x = Math.PI/2;
//      particle.lookAt( camera );
        scene.add( particle );

//            var textGeometry = new THREE.TextGeometry(wordFont,{
//                "font": font,
//                "size" : 10,
//                "height" : 0,
//                "color" : 0x000000
//            })
//
//            var text = new THREE.Mesh( textGeometry, new THREE.MeshBasicMaterial( { color: 0x000000 } ) );
//
//
//            text.position.x = p1.x + 2;
//            text.position.y = p1.y + 2;
//            text.position.z = p1.z + 2;
//            text.lookAt(camera.position);
//            scene.add(text);

    }

</script>

</body>
</html>


效果如下




博客才开始写没多久,风格还没统一。先凑合着看呗

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值