steveOw steveOw - 4 months ago 54
HTML Question

THREE.js How to stop truncation of text in texture made from 2D canvas

It seems quite common for people to use this 2d canvas texture method for producing text billboards, sprites, overlays in THREE.js scenes as an alternative to making textures from imported image files e.g. Lee Stemkoski's example.

However when I try such method for text strings longer than a few characters the text in the finished graphic object is truncated.

Here is a JSFiddle

Here is the relevant code

function F_Text_Plane_Make_wo_box(text)

{
var canvas1 = document.createElement('canvas');
var context1 = canvas1.getContext('2d');
context1.font = "Bold 40px Arial";
context1.fillStyle = "rgba(155,0,200,0.95)";
context1.fillText(text, 0, 50);

var texture1 = new THREE.Texture(canvas1);
texture1.needsUpdate = true;

var material1 = new THREE.MeshBasicMaterial
( { map: texture1, side:THREE.DoubleSide } );
material1.transparent = true;

var mesh1 = new THREE.Mesh(
new THREE.PlaneGeometry(canvas1.width, canvas1.height),
material1
);
return mesh1;
}


It occurs in Chrome, Opera and Firefox on Windows7 laptop.

UPDATE

Thanks to West Langley for clarifying matters. It appears that we can't easily and automatically construct a plane which contains the supplied text string and no trailing white space. This limitation can be worked around using transparency or a fixed-width destination container.

Here is a JSFiddle

Here is relevant code

//=============================================================================
function F_Text_onto_Plane(text, Tbox_width, Tbox_depth)

{

var canvas1 = document.createElement('canvas');
var context1 = canvas1.getContext('2d');

canvas1.width = Tbox_width; canvas1.height = Tbox_depth;

context1.font = "Bold 40px Arial"; //... font as big and simple as possible so graphics look smooth

var metric = context1.measureText(text);
var text_len_pixels = metric.width;

//------------ Backing Rectangle ------------
context1.fillStyle = "rgba(255,255,255,0.95)"; //... White
//..x1,y1, x2,y2 origin in top left corner x increasing rightwards, y increasing downwards.
context1.fillRect(0,0, Tbox_width, Tbox_depth); //... rectangle matches the Tbox_width and Tbox_depth

context1.fillStyle = "rgba(255,255,0,0.95)"; //... Yellow, probably change to white in practice.
context1.fillRect(0,0,5+text_len_pixels+5,Tbox_depth); //... very good fit to the particular text

//------------- Paint the Text onto canvas ----------------
context1.fillStyle = "rgba(0,0,0,1)";//... Black.
context1.fillText(text , 0+5, Tbox_depth-5);//... text string, start_x, start_y (start point is bottom left of first character).

//------------------------------------------------
//... canvas contents will be used for a texture
//... note this takes the everything within the canvas area, including the canvas background.
var texture1 = new THREE.Texture(canvas1);
texture1.needsUpdate = true;

var material1 = new THREE.MeshLambertMaterial( { map: texture1, side:THREE.DoubleSide } );
material1.transparent = true;

var mesh1 = new THREE.Mesh(
new THREE.PlaneGeometry(Tbox_width, Tbox_depth),
material1 );

//... can scale the plane e.g. mesh1.scale.set(100,50,1.0);
//... alert ("Checkout: http://stackoverflow.com/questions/4532166/how-to-capture-a-section-of-a-canvas-to-a-bitmap?lq=1");
//... can use .lookat to make plane face a single camera in the scene.
//... can use THREE.js Sprite to make plane look at all cameras in the scene.

return mesh1;


}

Answer

You need to set the canvas width:

var canvas1 = document.createElement( 'canvas' );
canvas1.width = 512;
canvas1.height = 64;

var texture1 = new THREE.Texture( canvas1 );
texture1.needsUpdate = true;

var material1 = new THREE.MeshLambertMaterial( {  map: texture1, side:THREE.DoubleSide, transparent = true } );

Now, when you create your mesh geometry, you specify its size in world units, not in pixels:

var mesh1 = new THREE.Mesh( new THREE.PlaneGeometry( 1024, 128 ), material1 );

three.js r.70

Comments