I think there is a need for an example of creating text by writing the text on a canvas, then creating a texture from the canvas, then using the texture in a material. It sounds complicated – I spent a lot of time getting this together – but it works well. There is a routine (dcText) which should be of help (actually it does it all).
I tried to offer this to mrdoob’s github (issue #18698), but I didn’t sell it very well.
<!doctype html>
<html>
<!-- Dave Dbarc - this is freely given to threejs.org & https://github.com/mrdoob/three.js
in the hopes that they will modify it to their taste as a text via texture example,
and reference it in https://threejs.org/docs/#manual/en/introduction/Creating-text (item#2).
-->
<head>
<title> threejs Text via Texture Example </title>
<style type="text/css">
</style>
<script src="http://threejs.org/build/three.js"></script>
<script type="text/javascript">
"use strict";
var js3canvas, js3w, js3h;
var renderer, camera, world, piggy, geometry, material, mesh;
window.onload = function() {
init3js(); // the standard 3js stuff
// ======
// The call is dcText(text, worldTextHeight, worldRectangleHeight, fontPixelHeight, fgcolor, bgcolor);.
// The widths are calculated and returned if desired.
// bg is transparent if omitted.
// ====== text#1, "Hello, world" ====== shows basic call
mesh = dcText("Hello, world", 15, 20, 50, 0x000000, 0xcccccc); // text #1, Hello, world
world.add(mesh);
var tmp = mesh.wWorldAll; // is width of rectangle; for later use
// text#2, "TRANSPARENT" ====== transparent
mesh = dcText("TRANSPARENT", 10, 10, 50, 0xff00ff); // text #2, TRANSPARENT
mesh.position.set(0,-12,1); // move geometry up and out
world.add(mesh);
// ====== text#3, "XpiggyX" ====== shows you can customize
piggy = new THREE.Group(); // for rotating sign
world.add(piggy);
mesh = dcText("XpiggyX", 15, 20, 50, 0xffffff, 0x0000ff); // text #3, XpiggyX (descenders)
mesh.ctx.lineWidth = 3; // can add glitter to texture here
mesh.ctx.strokeStyle = "white";
mesh.ctx.strokeRect(3, 3, mesh.wPxAll-6, mesh.hPxAll-6);
piggy.position.set(tmp/2,20,0); // placed at end of "Hello, world"
piggy.add(mesh);
animate();
};
function init3js() { // standard 3js stuff
js3canvas = document.getElementById("js3canvas");
renderer = new THREE.WebGLRenderer( { canvas:js3canvas } );
js3w = js3canvas.width;
js3h = js3canvas.height;
camera = new THREE.PerspectiveCamera(50, js3w/js3h, 1, 200);
camera.position.set(15,0,100);
camera.lookAt(15,0,0);
world = new THREE.Scene();
world.background = new THREE.Color(0x888888);
}
function animate() {
renderer.render( world, camera );
piggy.rotateY(.02);
requestAnimationFrame(animate);
}
function dcText(txt, hWorldTxt, hWorldAll, hPxTxt, fgcolor, bgcolor) { // the routine
// txt is the text.
// hWorldTxt is world height of text in the plane.
// hWorldAll is world height of whole rectangle containing the text.
// hPxTxt is px height of text in the texture canvas; larger gives sharper text.
// The plane and texture canvas are created wide enough to hold the text.
// And wider if hWorldAll/hWorldTxt > 1 which indicates padding is desired.
var kPxToWorld = hWorldTxt/hPxTxt; // Px to World multplication factor
// hWorldTxt, hWorldAll, and hPxTxt are given; get hPxAll
var hPxAll = Math.ceil(hWorldAll/kPxToWorld); // hPxAll: height of the whole texture canvas
// create the canvas for the texture
var txtcanvas = document.createElement("canvas"); // create the canvas for the texture
var ctx = txtcanvas.getContext("2d");
ctx.font = hPxTxt + "px sans-serif";
// now get the widths
var wPxTxt = ctx.measureText(txt).width; // wPxTxt: width of the text in the texture canvas
var wWorldTxt = wPxTxt*kPxToWorld; // wWorldTxt: world width of text in the plane
var wWorldAll = wWorldTxt+(hWorldAll-hWorldTxt); // wWorldAll: world width of the whole plane
var wPxAll = Math.ceil(wWorldAll/kPxToWorld); // wPxAll: width of the whole texture canvas
// next, resize the texture canvas and fill the text
txtcanvas.width = wPxAll;
txtcanvas.height = hPxAll;
if (bgcolor != undefined) { // fill background if desired (transparent if none)
ctx.fillStyle = "#" + bgcolor.toString(16).padStart(6, '0');
ctx.fillRect( 0,0, wPxAll,hPxAll);
}
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.fillStyle = "#" + fgcolor.toString(16).padStart(6, '0'); // fgcolor
ctx.font = hPxTxt + "px sans-serif"; // needed after resize
ctx.fillText(txt, wPxAll/2, hPxAll/2); // the deed is done
// next, make the texture
var texture = new THREE.Texture(txtcanvas); // now make texture
texture.minFilter = THREE.LinearFilter; // eliminate console message
texture.needsUpdate = true; // duh
// and make the world plane with the texture
geometry = new THREE.PlaneGeometry(wWorldAll, hWorldAll);
var material = new THREE.MeshBasicMaterial(
{ side:THREE.DoubleSide, map:texture, transparent:true, opacity:1.0 } );
// and finally, the mesh
var mesh = new THREE.Mesh(geometry, material);
mesh.wWorldTxt = wWorldTxt; // return the width of the text in the plane
mesh.wWorldAll = wWorldAll; // and the width of the whole plane
mesh.wPxTxt = wPxTxt; // and the width of the text in the texture canvas
// (the heights of the above items are known)
mesh.wPxAll = wPxAll; // and the width of the whole texture canvas
mesh.hPxAll = hPxAll; // and the height of the whole texture canvas
mesh.ctx = ctx; // and the 2d texture context, for any glitter
// console.log(wPxTxt, hPxTxt, wPxAll, hPxAll);
// console.log(wWorldTxt, hWorldTxt, wWorldAll, hWorldAll);
return mesh;
}
</script>
</head>
<body>
<canvas id="js3canvas" width="800" height="600"></canvas>
</body>
</html>