playcanvas / engine

JavaScript game engine built on WebGL, WebGPU, WebXR and glTF
https://playcanvas.com
MIT License
9.36k stars 1.32k forks source link

Add a 3D text mesh geometry creator #2689

Closed probitaille closed 3 years ago

probitaille commented 3 years ago

This feature is a request that were asked multiple times in the forum.

See my last post about it here: 3d text geometry generator

Description

The need for this feature is to be able to generate a 3D text geometry constructed by providing a string of text and other parameters like:

Examples

Other engines can also do it:

Image

image

willeastcott commented 3 years ago

This would be super-cool. I guess it breaks down into two parts:

willeastcott commented 3 years ago

More generally, it would be cool to replicate the type of modifiers you find in apps like 3DS Max. e.g.

willeastcott commented 3 years ago

So this looks like a good library to use to extract the font outlines:

https://github.com/opentypejs/opentype.js

48KB gzipped.

willeastcott commented 3 years ago

Basically, you can load any TTF and then, for each glyph, query a set of path 'commands' as follows:

https://github.com/opentypejs/opentype.js#path-commands

With that outline, we should be able to tesselate the path and then extrude it.

willeastcott commented 3 years ago

Progress so far: I've used opentype.js and earcut to implement this:

textmesh

To do:

willeastcott commented 3 years ago

More progress:

image

Tessellation problems remain for: A, B, D, d, e, g and q (for an Arial TrueType font).

willeastcott commented 3 years ago

In case anybody would like to examine my progress in more detail, the project is here:

https://playcanvas.com/project/755330/overview/3d-text

The script is here:

https://playcanvas.com/editor/code/755330?tabs=41164910

Any suggestions/help would be definitely appreciated. 😄

LeXXik commented 3 years ago

I like this! I defeinitely need more spare time though... Going to fork it and help with removing Bezier.js dependency and use pc.Curve instead.

willeastcott commented 3 years ago

I'm not convinced pc.Curve will give as good results as Bezier.js. This is because the LUT generation (point sampling the curve) of Bezier.js samples the points based on curve's rate of change (if that's the right phrase). 😄 pc.Curve only allows you to sample based on time.

I think the priorities are to make the tessellation robust. Then we can figure out how to extrude the mesh.

The current problems with tessellation are probably because I'm not telling Earcut where the holes are in the characters (notice all problem characters have holes - despite some characters with holes tessellating fine). I believe that character holes have an anticlockwise path winding, versus a clockwise winding for outer paths. Maybe it's possible to do an area calculation of the path and do a test against zero. If anyone has a better idea, I'm open to suggestions.

willeastcott commented 3 years ago

I've confirmed that Earcut does what we need if you tell it which paths are holes:

image

willeastcott commented 3 years ago

All characters now tessellate correctly:

image

Next:

Normal generation isn't quite as simple as I would have hoped. pc.calculateNormals doesn't take hard edges into account. It can only generated smooth normals, which isn't what we want in this case. So we'll need a solution for that.

mvaligursky commented 3 years ago

I assume you want to keep the front face flat regarding the normals? Perhaps all you need to do here is to duplicate those vertices (do not share them with the extruded size faces) so they can have independent normals. That should make it compatible with calculateNormals function - it should not smooth the edge as there is no shared vertex / edge.

willeastcott commented 3 years ago

Sure. But what about the sides. 😉

mvaligursky commented 3 years ago

What look are you after? What should be smooth? I guess in general what needs to be done that for each vertex where you don't want smoothing, the vertex needs to be duplicated between faces that share it.

image

In the example - if you want smooth edge in the middle, you need to create 4 vertices in total and two triangles to use them. If you want the edge to be sharp, you duplicate those two shared vertices and end up with 6 vertices, and each triangle would reference its vertex.

willeastcott commented 3 years ago

I'd probably want to be able to specify a crease angle above which the vertex would be split and you'd get a hard edge. Probably >30 degress perhaps?

willeastcott commented 3 years ago

Getting there:

image

willeastcott commented 3 years ago

Normals now correctly calculated:

playcanvas-text-mesh

willeastcott commented 3 years ago

Getting similar to the screenshot originally posted for this issue:

image

Beveling the text geometry is the main difference that would still need to be implemented (if you want that).

willeastcott commented 3 years ago

Added kerning support:

kerning

Maksims commented 3 years ago

Emoji?

willeastcott commented 3 years ago

😭

image

mvaligursky commented 3 years ago

maybe in a different font?

Maksims commented 3 years ago

I can imagine a game built using Emoji models.

willeastcott commented 3 years ago

Oh actually:

image

The code was handling UTF-16 wrong. Sooo, looks like the sides have reversed winding, but otherwise kinda almost works. I'm wondering if the TTF file has the stroke color. If that's there, I should be able to color meshes correctly.

willeastcott commented 3 years ago

Added support for alignment:

alignment

willeastcott commented 3 years ago

Quick experiment applying a custom shader chunk to the font's material:

plasma2