Adding text in three.js over some object - three.js

I am facing difficulty in adding text to my three.js script. I have searched a lot but wherever i find a working model, it uses a previous version of three.js and thus i am not able to use it. Also textgeometry seems to not work. I wish to add 3d text and not 2d.

You should always check three.js's official examples. There are many hints with latest three.js for you.
http://threejs.org/examples/#webgl_geometry_text
http://threejs.org/examples/#webgl_geometry_text_earcut
http://threejs.org/examples/#webgl_geometry_text_pnltri
First, you need to load a font file with new THREE.FontLoader. The font file is supposed to be in JS file, like http://threejs.org/examples/fonts/optimer_bold.typeface.js. You can convert your font to JS with http://gero3.github.io/facetype.js/
var font;
var loader = new THREE.FontLoader();
loader.load( 'path/to/fontfile.js', function ( response ) {
font = response;
} );
Then make a text geometry with new THREE.TextGeometry class using the font.
var textGeo = new THREE.TextGeometry( text, {
font: font,
size: size,
height: height,
curveSegments: curveSegments,
bevelThickness: bevelThickness,
bevelSize: bevelSize,
bevelEnabled: bevelEnabled,
material: 0,
extrudeMaterial: 1
});
Then, make a mesh
new THREE.Mesh( textGeo, material );

Related

How to control size and color of textGeometry with dat.gui?

I found out that I could use dat.gui to control size and color of textGeometry besides changing color and size for every other scene through editing .js file. But probably bad architecture of my code, I am not able to control or even add gui folder to the scene. It probably has something to do with FontLoader that I'm using.
I tried placing dat.gui inside and outside my textGeometry creation function, none of them worked. As far as I understood, every time size or color changes it should dispose and remove the created mesh to create a new one with the new color/size parameters (i also update for every each keydown event to create a new mesh so that's my thought).
textGeometry, textMesh, textMaterial etc. are defined in global
function textCreation() {
const fontLoader = new FontLoader();
fontLoader.load(
"node_modules/three/examples/fonts/droid/droid_sans_bold.typeface.json",
(droidFont) => {
textGeometry = new TextGeometry(initText, { //initText variable gets updated with each keydown
size: 5,
height: 2,
font: droidFont,
parameters: {
size: 5,
height: 2,
},
});
textMaterial = new THREE.MeshBasicMaterial({ color: 0xff0000 });
textMesh = new THREE.Mesh(textGeometry, textMaterial);
group = new THREE.Group();
group.add(textMesh);
scene.add(group);
}
And here is the dat.gui controller that I tried to place in and out of this function.
let textFolder = gui.addFolder("Text Controls");
textFolder.add(textGeometry, "size", 10, 20).onChange(function () {
textGeometry.setSize(textGeometry.size);
// Probably dispose and remove old mesh from scene and create mesh with these new parameters
});
textFolder.addColor(textGeometry, "color").onChange(function () {
textGeometry.setColor(textGeometry.color);
I couldn't manage to add ANY dat.gui controller without breaking the scene. By the way I'm kinda new to JavaScript and three.JS so further explanations are welcome if there are any.
textGeometry.setSize(textGeometry.size);
This does not work since there isn't a setSize() method. You have to call dispose() on the existing geometry and then create a new one based on your updated parameters. You then assign the new geometry to your text mesh. So something like:
const params = {
color: '#ffffff',
size: 5
};
textFolder.add(params, "size", 10, 20).onChange(function (value) {
textGeometry.dispose();
textGeometry = new TextGeometry(initText, {
size: value,
height: 2,
font: droidFont
});
textMesh.geometry = textGeometry;
});
The material's color can be changed without creating a new object.
textFolder.addColor(params, 'color').onChange(function (value) {
textMaterial.color.set(value);
});

Change Extrude Amount textGeometry Three.js

I've added text to my scene using the code from https://threejs.org/docs/#api/geometries/TextGeometry
I cannot figure out how to change the extrude depth, which is much "thicker" than I would like. Here is the exact code I am using:
var loader = new THREE.FontLoader();
loader.load( 'fonts/font.json', function ( font ) {
var textGeometry = new THREE.TextGeometry( 'WELCOME', {
font: font,
size: 4,
height: 8,
amount: 8,//attempt to change the depth but doesn't work
} );
Is it possible to change the extrude amount for a text geometry?
Applying height and amount at the same time does not work. amount is an option for ExtrudeGeometry whereas height is intended for TextGeometry.
TextGeometry uses internally ExtrudeGeometry for geometry generation. In this context, height is mapped to amount.
three.js R92

Support for Farsi/Arabic texts in Three.js

I need to show some text in Persian/Arabic language. I loaded a font including characters and I used TextGeometry to create a text on the scene:
var loader = new THREE.FontLoader();
loader.load('B Zar_Regular.js', function (font) {
var textGeo = new THREE.TextGeometry('سلام!', {
font: font,
size: 1,
height: 0.05,
curveSegments: 12,
});
var material = new THREE.MeshNormalMaterial();
var textMesh = new THREE.Mesh(textGeo, material);
textMesh.position.x = 15;
scene.add(textMesh);
});
I was expecting to see سلام! but the output was:
letters are separated and order of characters is reversed mistakenly. After all it seems threejs do not support rtl languages. Am I right or I missed something? Is there any workaround as a quick solution? Thanks.
First of all I found very useful blog post here by Chris Loer. He has written a plugin (mapbox-gl-rtl-text.js) that solves the problem.
Usage example:
var rtlText = require('mapbox-gl-rtl-text');
var arabicString = "سلام";
var shapedArabicText = rtlText.applyArabicShaping(arabicString);
var readyForDisplay = rtlText.processBidirectionalText(shapedArabicText, []);
PS: When I used this plugin with common Farsi fonts some of letters was not shown so I add some extra code to fix it.
RtlTextHelper.farsify("سلام");
Usage example:
private createTextMesh(font, text) {
var shapedText = RtlTextHelper.farsify(text);
var fontSize = 0.3;
var textHieght = 0.2;
var material = new THREE.MeshBasicMaterial({
color: this.colors.label.normal,
side: THREE.DoubleSide
});
var textGeo = new THREE.TextGeometry(shapedText, {
font: font,
size: fontSize,
height: 0.05,
curveSegments: 12
});
var textMesh = new THREE.Mesh(textGeo, material);
textGeo.computeBoundingBox();
var box = new THREE.Box3().setFromObject(textMesh);
var textLength = box.max.x;
return {
mesh: textMesh,
hieght: textHieght,
font: {
size: fontSize
},
length: textLength
};
}
This is a complex problem. Ligatures, the calligraphic strokes which connect letters, most familiar to western readers as a component of cursive English, is not optional in Arabic. Ligatures are intrinsic to the language, changing the meaning and formality of the text. The font.js class is designed to take each letter (glyph) one by one and convert it to a shape path. This doesn't work in Arabic because joining rules are complex depending on specific letter combinations.
I do not believe there is a fix that can be put in place in three.js. Although I would be anxious to know what the potential solution is as mentioned by O.P.
It may be possible to convert isolated letters to final Arabic ligatured forms via this script, or maybe this one among others. The final presentation forms might then be sent to Three.js for display so that the ligature joins are handled already and three.js receives the final ligatured forms rather than the isolated glyphs.
It may be a simpler task to convert text to svg paths using a text to path converter and then using the SVGLoader.js in three.js to load the letters as paths for extrusion. But this would have to be tested to ensure the conversion of text to a path handles Arabic at all and then if it does, the ligature joins will also need to be checked for accuracy.

Change font-family for texture text in three.js

I use plugin «threex.dynamictexture.js» in my app and have some trouble with loading my font (I have trouble even using existing helvetiker_bold.typeface.json ). I use the following pattern:
function loadFont() {
var loader = new THREE.FontLoader();
loader.load('/threejs/fonts/helvetiker_bold.typeface.json', function (font) {
dynamicTexture = new THREEx.DynamicTexture(canvasWrapper.offsetWidth,canvasWrapper.offsetHeight);
// dynamicTexture.context.font = 'bolder 90px Helvetiker';
var geometry2 = new THREE.SphereGeometry( 5, 100, 100);
var material2 = new THREE.MeshBasicMaterial({
map : dynamicTexture.texture
});
var mesh2 = new THREE.Mesh( geometry2, material2 );
console.log(font);
dynamicTexture.texture.needsUpdate = true;
mesh2.position.set(10, 10, 10);
scene.add( mesh2 );
dynamicTexture.drawText('Hello', 100, 300, 'black', 'bolder 90px helvetiker');
});
}
After that I can see rendered text texture on my geometry, but the font-family is still the default. And if I use Arial instead Helvetiker(or helvetiker) the rendered text become Arial.
I looked everywhere, but found only about TextGeometry solution. By the way I could load my font-family using TextGeometry loader.
Can you help me? Thanks!
Seems you mix up system fonts with three.js fonts.
helvetiker_bold.typeface.json has nothing in common with Helvetiker.ttf. It's intended to be used for TextGeometry. To draw with "Helvetiker" on a canvas, you have to add/install Helvetiker.ttf to the fonts on your system.
If you use it for yourself, it's okay if you find and install the font you need. But the other users, who don't have such font on their system, will see writings with the default font.
The solution is to find a font from standard system fonts which is more or less similar to Helvetiker (or the font you would like to use/see).

Transparant spritesheet animation for webgl

I'm just getting started with webgl and was trying to make an animation based on a spritesheet. I've found an example and changed the spritesheet to my own. However even though I removed the white background, saved it as a transparant png, the animation still shows up with a white background.
This is the example I used:
http://stemkoski.github.io/Three.js/Texture-Animation.html
Is there any way how I can get rid off the white background?
Thanks in advance.
EDIT:
var runnerTexture = new THREE.ImageUtils.loadTexture( 'images/run.png' );
annie = new TextureAnimator( runnerTexture, 10, 1, 10, 75 ); // texture, #horiz, #vert, #total, duration.
var runnerMaterial = new THREE.MeshBasicMaterial( { map: runnerTexture, side:THREE.DoubleSide } );
var runnerGeometry = new THREE.PlaneGeometry(50, 50, 1, 1);
var runner = new THREE.Mesh(runnerGeometry, runnerMaterial);
runner.position.set(-150,25,0);
scene.add(runner);
To support PNGs with an alpha-channel, you have to modify the MeshBasicMaterial accordingly: There is an attribute 'transparent' which you could set to 'true'.
Try using the following line instead:
var runnerMaterial = new THREE.MeshBasicMaterial( { map: runnerTexture, side:THREE.DoubleSide, transparent: true } );
See also the reference from Material:
.transparent
Defines whether this material is transparent. This has an effect on
rendering as transparent objects need special treatment and are
rendered after non-transparent objects. For a working example of this
behaviour, check the WebGLRenderer code. When set to true, the extent
to which the material is transparent is controlled by setting opacity.

Resources