Adam Robinson
Adam Robinson

Reputation: 125

Merging multiple TextBufferGeometries in a scene

I'm trying to change the following code to use TextBufferGeometry instead of TextGeometry as I feel like it may improve the performance in my use case. The code below works for rendering multiple text elements into my scene however when I change..

let geometry = new THREE.TextGeometry(... to let geometry = new THREE.TextBufferGeometry(...

this code no longer renders text into the scene. I'm unsure of what needs changing in order to make use of TextBufferGeometry

const materialWhite = new THREE.MeshBasicMaterial({ color: 0xffffff, side: THREE.DoubleSide });

const textArray = [
      { text: `Message 12345`, zDistance: 100 },
      { text: `Message 67890`, zDistance: 200 },
      { text: `Message 13579`, zDistance: 300 },
   ];

var singleFontGeometry = new THREE.Geometry();

    for (let index = 0; index < textArray.length; index++) {

      loaderFonts.load('./assets/fonts/Oxanium.json', function(font) {

        let geometry = new THREE.TextGeometry(`${textArray[index].text}`, {
          font: font,
          size: 20,
          height: 1
        });

        let mesh = new THREE.Mesh(geometry, materialWhite);

        mesh.position.set(100, 100, textArray[index].zDistance);

        singleFontGeometry.mergeMesh(mesh);

      });
    }

var meshFont = new THREE.Mesh(singleFontGeometry, materialWhite);

this.scene.add(meshFont);

Upvotes: 0

Views: 1429

Answers (1)

Don McCurdy
Don McCurdy

Reputation: 11970

The code above will require three main changes:

  1. In the loop, create THREE.TextBufferGeometry instances instead of TextGeometry.
  2. Instead of setting a position on each mesh, bake that transform into the geometry before merging, with geometry.translate(...).
  3. Instead of adding geometries to a THREE.Geometry instance, create a merged BufferGeometry instance using BufferGeometryUtils. BufferGeometry does not have a .mergeMesh() method, and .merge() overwrites vertices rather than creating a union, so neither are available here.

Also, but somewhat unrelated to the question, you probably don't want to load the font inside your For-loop, to avoid unnecessary requests. With these changes, the code should look something like this:

import * as THREE from 'three';
import { BufferGeometryUtils } from 'three/examples/jsm/utils/BufferGeometryUtils.js';

var mergedGeometry;

// Load the font once.
loaderFonts.load('./assets/fonts/Oxanium.json', function(font) {

  // Then create a *BufferGeometry for each item of text.
  var geometries = textArray.map(function(text) {
    var geometry = new THREE.TextBufferGeometry(text.text, {
      font: font,
      size: 20,
      height: 1
    });

    // Take each item's unique Z offset, and bake it into the geometry.
    geometry.translate(0, 0, text.zDistance);

    return geometry;
  });

  // Merge all text geometries.
  mergedGeometry = BufferGeometryUtils.mergeBufferGeometries( geometries );

  var mesh = new THREE.Mesh(mergedGeometry, materialWhite);

  // Put the shared x=100,y=100 offset onto the mesh, so it can be changed later.
  mesh.position.set(100, 100, 0);

  scene.add(mesh);

});

^Note that BufferGeometryUtils is not included in the three.js build itself, and must be added to your application separately, like loaders, controls, and other things in the examples/js* folder.

Upvotes: 1

Related Questions