Load font into global variable - efficiency

In a project I have a larger number of texts that change dynamically.

I have solved this so far with canvas texture. For comparison I have now tried ShapeGeometry. For this I placed a line between the canvas text in my BeginnerExample - step 11 .

2021-11-08 12.05.33

I find it is a better result, especially when the camera is very close or a bit further away. I want to test it in my project.

I have programmed a small test example for this purpose.
DynamicChangeableText (See next post - improvement!)

2021-11-08 17.29.54

See below for code.

To change the text dynamically, I need the font in a global variable. I remembered that you can make an appropriate assignment after the loading process is finished, but I could not find an appropriate example.

While searching I saw some suggested solutions, but they seem too elaborate or complicated for my simple case.

I have found a simple solution, but I am not sure if it is performant, because an unnecessary check remains in the animate function.

Is there another very simple and more efficient solution?



<!DOCTYPE html>
<!-- https://discourse.threejs.org/t/load-font-into-global-variable-efficiency/31608 -->
<head>
    <title> DynamicChangeableText </title>
    <meta charset="utf-8" />
    <style>
    body {
        margin: 0;
    }
    </style>
</head>
<body> </body>

<script src="../js/three.min.134.js"></script>
<script src="../js/OrbitControls.134.js"></script>
<script src="../js/FontLoader.134.js"></script>
<script>

// @author hofk

const scene = new THREE.Scene();

const camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 0.1, 1000 );
camera.position.set( 0, 0, 3 );

const renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setClearColor( 0xfdfde2, 1 );

document.body.appendChild( renderer.domElement );

const controls = new THREE.OrbitControls( camera, renderer.domElement );
 
const fontLoader = new THREE.FontLoader( );	
let textsGeometry = [];
let text = [];
let ft = { type: null };
let change = false;
            // https://threejs.org/examples/fonts/helvetiker_regular.typeface.json
fontLoader.load( 'helvetiker_regular.typeface.json', font => ft = font );
 
console.log( 'global 0', ft );


animate( );

function animate( ) {

    requestAnimationFrame( animate );
    
    if ( ft.type === 'Font' && !change ) {
    
      console.log( 'global 1', ft);
      change = true;
      initText( );

    }
    
    if ( ft.type === 'Font' && change ) {
        
       changeText( )
        
    }

    renderer.render( scene, camera );
    
}

function initText( ) { // 1000 text lines

  for ( let i = 0; i < 1000  ; i ++ ) {
    
    const textsShapes = ft.generateShapes( 'initial text    >>> ' + i , 0.04 );
    textsGeometry[ i ] = new THREE.ShapeGeometry( textsShapes );    
    const textsMaterial = new THREE.MeshBasicMaterial( { color: 0x000000, side: THREE.DoubleSide } ); 
    text[ i ] = new THREE.Mesh( textsGeometry[ i ], textsMaterial );
    text[ i ].position.set( 0, -20 + i / 20 , 0 );
    scene.add( text[ i ]); 
  
  }
  
}

function changeText( ) { // change some text lines dynamically

    for ( let i = 390; i < 410; i ++ ) {

        const textShp = ft.generateShapes( 'new text     >>> ' + i + ' random ' + Math.random( ), 0.035 );
        textsGeometry[ i ].dispose( );     
        text[ i ].geometry = new THREE.ShapeGeometry( textShp );
        text[ i ].geometry.needsUpdate = true;
    
    }
    
}

</script>
</html>

I took a closer look at the loaders. With DefaultLoadingManager.onLoad things become clearer and possibly a bit more performant.

The animate function is simpler.
At DynamicChangeableText now the new version.

The modified part of the code:


THREE.DefaultLoadingManager.onLoad = function ( ) {

	console.log( 'Loading Complete!');
    change = true;
    initText( );
    
};
            // https://threejs.org/examples/fonts/helvetiker_regular.typeface.json
fontLoader.load( 'helvetiker_regular.typeface.json', font => ft = font );

 
console.log( 'global 0', ft );


animate( );

function animate( ) {

    requestAnimationFrame( animate );   
    if( change ) changeText( );
    renderer.render( scene, camera );
    
}

===================================

UPDATE:

The simplest things are often only found at the end.
One thinks much too complicated and crosswise.

The solution now under the original link DynamicChangeableText

The full code:

<!DOCTYPE html>
<!-- https://discourse.threejs.org/t/load-font-into-global-variable-efficiency/31608 -->
<head>
    <title> DynamicChangeableText </title>
    <meta charset="utf-8" />
    <style>
    body {
        margin: 0;
    }
    </style>
</head>
<body> </body>

<script src="../js/three.min.134.js"></script>
<script src="../js/OrbitControls.134.js"></script>
<script src="../js/FontLoader.134.js"></script>
<script>

// @author hofk

const scene = new THREE.Scene();

const camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 0.1, 1000 );
camera.position.set( 0, 0, 3 );

const renderer = new THREE.WebGLRenderer( { antialias: true } );
renderer.setSize( window.innerWidth, window.innerHeight );
renderer.setClearColor( 0xfdfde2, 1 );

document.body.appendChild( renderer.domElement );

const controls = new THREE.OrbitControls( camera, renderer.domElement );
 
const fontLoader = new THREE.FontLoader( );	
let textsGeometry = [];
let text = [];
 
THREE.DefaultLoadingManager.onLoad = function ( ) {
 
    initText( );
    animate( );
    
};
            // https://threejs.org/examples/fonts/helvetiker_regular.typeface.json
fontLoader.load( 'helvetiker_regular.typeface.json', font => ft = font );

function animate( ) {

    requestAnimationFrame( animate );   
    changeText( );
    renderer.render( scene, camera );
    
}

function initText( ) { // 1000 text lines

  for ( let i = 0; i < 1000  ; i ++ ) {
    
    const textsShapes = ft.generateShapes( 'initial text    >>> ' + i , 0.04 );
    textsGeometry[ i ] = new THREE.ShapeGeometry( textsShapes );    
    const textsMaterial = new THREE.MeshBasicMaterial( { color: 0x000000, side: THREE.DoubleSide } ); 
    text[ i ] = new THREE.Mesh( textsGeometry[ i ], textsMaterial );
    text[ i ].position.set( 0, -20 + i / 20 , 0 );
    scene.add( text[ i ]); 
  
  }
  
}

function changeText( ) { // change some text lines dynamically

    for ( let i = 390; i < 410; i ++ ) {

        const textShp = ft.generateShapes( 'new text     >>> ' + i + ' random ' + Math.random( ), 0.035 );
        textsGeometry[ i ].dispose( );     
        text[ i ].geometry = new THREE.ShapeGeometry( textShp );
        text[ i ].geometry.needsUpdate = true;
    
    }
    
}

</script>
</html>
1 Like