【Three.js】Chapter 13 3D Text 3D Text

13. 3D Text 3D text

introduce

We've covered enough of the basics to create some nice looking effects. For our first serious project, we're going to fork a developer ilithya's work ( https://www.ilithya.rocks/ ), which has a large 3D text in the middle of the scene, with lots of geometry floating around the text.
This work is a great example of what is possible in the early days of learning Three.js. It's simple, efficient, and the effects look great.
Three.js already supports 3D text geometry through the TextGeometry class. The problem is that you have to specify a font first, and that font has to be in a specific json format called typeface.
We will not involve issues related to copyright authorization of digital fonts. After you use the downloaded fonts, you must guarantee the right to use the fonts when using the fonts, or the copyright of the fonts is free for developers to use.

how to get the font

There are many ways to get fonts in typeface format. First, you can convert your fonts using a converter like this: https://gero3.github.io/facetype.js/ . You have to provide a file and click the convert button.
You can also node_modulesfind the fonts in the Three.js library examples in the folder. /node_modules/three/examples/fonts/You can put these fonts in /static/a folder, or you can import them directly in your javascript files, since they are json and .jsonfiles in Vite .jsare supported like :

import typefaceFont from 'three/examples/fonts/helvetiker_regular.typeface.json'

We mix the two techniques by opening /node_modules/three/examples/fonts/, fetching helvetiker_regular.typeface.jsonfiles and LICENSEfiles and putting them into /static/fonts/folders (you need to create fontsfolders).
Now just write at the end of the base URL to access the /fonts/helvetiker_regular.typeface.jsonfont.

load font

To load fonts we have to use a new loader class called FontLoader .
This class THREEis not available in variables. OrbitControlsImport it as we did in the previous lessons :

import {
    
     FontLoader } from 'three/examples/jsm/loaders/FontLoader.js'

This loader works like TextureLoader. Add the following code after that section textureLoader(don't forget to change the path if you're using a different font):

/**
 * Fonts
 */
const fontLoader = new FontLoader()

fontLoader.load(
    '/fonts/helvetiker_regular.typeface.json',
    (font) =>
    {
    
    
        console.log('loaded')
    }
)

Enter your console and find that it is printed 'loaded'. If not, check the previous steps and search the console for potential errors. We can now access the font
by using the variable inside the function . Unlike TextureLoader , we have to write the rest of the code in the success callback of this function.font

create geometry

As we said before, we will use TextGeometry to create geometry.
Just like FontLoader , we need to import it:

import {
    
     TextGeometry } from 'three/examples/jsm/geometries/TextGeometry.js'

Note the example code on the documentation page; the values ​​are much larger than in our scenario.
Make sure to write the code inside the success callback function:

fontLoader.load(
    '/fonts/helvetiker_regular.typeface.json',
    (font) =>
    {
    
    
        const textGeometry = new TextGeometry(
            'Hello Three.js',
            {
    
    
                font: font,
                size: 0.5,
                height: 0.2,
                curveSegments: 12,
                bevelEnabled: true,
                bevelThickness: 0.03,
                bevelSize: 0.02,
                bevelOffset: 0,
                bevelSegments: 5
            }
        )
        const textMaterial = new THREE.MeshBasicMaterial()
        const text = new THREE.Mesh(textGeometry, textMaterial)
        scene.add(text)
    }
)


You should get a white 3D text that needs improvement.
First, comment out the code for the cube. Its purpose is to make sure everything works.

If you want to see some cool meshes to add wireframe: trueto your materials.

const textMaterial = new THREE.MeshBasicMaterial({
    
     wireframe: true })


You can now see that the geometry was generated with many triangles. Creating text geometry is long and difficult for computers. curveSegmentsAvoid doing this too many times and bevelSegmentskeep the geometry as low as possible by reducing polys and attributes.
Remove once you are satisfied with the geometry rendering detail level wireframe.

center text

There are several ways to center text. One way is to use boundaries. Bounds are information associated with geometry that tells what space that geometry occupies. It can be a box or a sphere.

You can't actually see these borders, but it helps Three.js easily calculate whether an object is on screen or not, and if it's not, the object won't even be rendered. This is called frustum culling, but it's not the topic of this lesson.
What we want is to use this bounds to know the size of the geometry and re-center it. By default, Three.js uses sphere bounds. What we want is a box boundary, to be more precise. To do this, we can ask Three.js computeBoundingBox()to calculate this box bounds by calling geometry:

textGeometry.computeBoundingBox()

We can boundingBoxcheck this box using geometry properties.

console.log(textGeometry.boundingBox)

The result is an object named Box3 that has one minproperty and one maxproperty. The min0 is not what we expected. This is due bevelThicknessand bevelSize, but we can ignore it for now.
Now that we have measures, we can move objects. We don't move the mesh, but the whole geometry. This way, the mesh will still be centered in the scene, and the text geometry will also be centered within our mesh.
To do this, we can translate(...)use the method on the geometry immediately after the method computeBoundingBox():

textGeometry.translate(
    - textGeometry.boundingBox.max.x * 0.5,
    - textGeometry.boundingBox.max.y * 0.5,
    - textGeometry.boundingBox.max.z * 0.5
)


The text is centered, but if you want to be very precise, you should also subtract bevelSizeis 0.02:

textGeometry.translate(
    - (textGeometry.boundingBox.max.x - 0.02) * 0.5, // Subtract bevel size
    - (textGeometry.boundingBox.max.y - 0.02) * 0.5, // Subtract bevel size
    - (textGeometry.boundingBox.max.z - 0.03) * 0.5  // Subtract bevel thickness
)

What we're doing here can actually center()be done faster by calling a method on the geometry:

textGeometry.center()

Much easier, no? The purpose of our handwritten centering is to understand boundary and frustum culling .

Add matcap material

Time to add a cool material to our text. We'll MeshMatcapMaterialreplace MeshBasicMaterial with because it looks cooler and performs better.
First, let's choose a matcapTexture. We'll use the ones located /static/textures/matcaps/in the folder matcaps, but feel free to use your own matcaps.
You can also download one from this repository https://github.com/nidorx/matcaps . Don't spend too much time choosing it! If not for personal use, make sure you have the copyright to use it. You don't need high resolution textures, 256x256it should be more than enough.
We can now load textures using the TextureLoader we already have in our code:

const matcapTexture = textureLoader.load('/textures/matcaps/1.png')

We can now replace the ugly MeshBasicMaterial with the beautiful MeshMatcapMaterial and use our matcapTexturevariables with properties:matcap

const textMaterial = new THREE.MeshMatcapMaterial({
    
     matcap: matcapTexture })


You should be able to render a lovely text with a cool material on it.

add object

Let's add floating objects. To do this, we will create a donut inside the loop function.
In the success function, right after that textsection, add the loop function:

for(let i = 0; i < 100; i++)
{
    
    
    
}

We could do this outside of the success function, but we need to create the text and the object together for good reasons, as you'll see later.
In this loop, create a TorusGeometry (like the technical name for a donut) with the same material as the text and the Mesh :

for(let i = 0; i < 100; i++)
{
    
    
    const donutGeometry = new THREE.TorusGeometry(0.3, 0.2, 20, 45)
    const donutMaterial = new THREE.MeshMatcapMaterial({
    
     matcap: matcapTexture })
    const donut = new THREE.Mesh(donutGeometry, donutMaterial)
    scene.add(donut)
}


You should get 100 donuts in one place.
Let's add some randomness to their positions:

donut.position.x = (Math.random() - 0.5) * 10
donut.position.y = (Math.random() - 0.5) * 10
donut.position.z = (Math.random() - 0.5) * 10


You should scatter 100 donuts on the field.
Add randomness to rotation. There is no need to rotate all 3 axes, and since the donut is symmetrical, a half turn is enough:

donut.rotation.x = Math.random() * Math.PI
donut.rotation.y = Math.random() * Math.PI


The donut should rotate in all directions.
Finally, we can add randomness to the scale. x, y, zBe careful though; we need to use the same value for all 3 axes ( ):

const scale = Math.random()
donut.scale.set(scale, scale, scale)

optimization

Our code is not optimal. As we saw in the previous lesson, we can use the same material on multiple meshes , but we can also use the same geometry to save performance.
Move thedonutGeometrythe thedonutMaterialsum out of the loop:

const donutGeometry = new THREE.TorusGeometry(0.3, 0.2, 20, 45)
const donutMaterial = new THREE.MeshMatcapMaterial({
    
     matcap: matcapTexture })

for(let i = 0; i < 100; i++)
{
    
    
    // ...
}

You should get the same result, but we can go further. textThe material of donutis the same as that of .
Let's delete donutMaterial, rename textMaterialbymaterialand use it for thetextand donut:

const material = new THREE.MeshMatcapMaterial({
    
     matcap: matcapTexture })
                
// ...

const text = new THREE.Mesh(textGeometry, material)

// ...

for(let i = 0; i < 100; i++)
{
    
    
    const donut = new THREE.Mesh(donutGeometry, material)
    
    // ...
}

We could go ahead and optimize, but there's a whole class on optimization, so hold that for now.

more optimization

You can add more shapes, animate them, or even experiment with others if you want matcaps.

Guess you like

Origin blog.csdn.net/m0_68324632/article/details/131151984