I am trying to build a box where I can draw the images myself through a canvas element. Here is what I have so far:
The thing is, I do not want the canvas image to repeat every face, I want to be unique and render it contantly, so if you see, the “Hello world” text is being cut after the edge, I want it to render fully in the next face.
Is that possible using a simple BoxGeometry and MeshBasic material?
This is what I have tried so far.
const ratio = devicePixelRatio;
drawingCanvas.width = 600 * ratio;
drawingCanvas.height = 600 * ratio;
drawingCanvas.style.width = `${600}px`;
drawingCanvas.style.height = `${600}px`;
const ctx = drawingCanvas.getContext("2d");
if (ctx) {
ctx.scale(ratio, ratio);
ctx.fillStyle = "white";
ctx.fillRect(0, 0, 600, 600);
ctx.fillStyle = "blue";
ctx.font = "80px Arial";
ctx.fillText("Hello World", 600 / 2 - 15, 600 / 2 - 15);
}
const map = new THREE.CanvasTexture(
drawingCanvas,
THREE.UVMapping,
);
const cube = new THREE.Mesh(
new THREE.BoxGeometry(200, 200, 200),
new THREE.MeshBasicMaterial({
map,
})
);
You need to change the UV coordinates of your cube vertices accordingly. I’m not sure what the syntax is but you need to assign a custom array of UVs for each face of the cube, something like this (top and bottom faces not included):
const forntFaceUvs = [
new Vector2(0, 0),
new Vector2(0.25, 0),
new Vector2(0, 1),
new Vector2(0.25, 1)
];
const rightFaceUVs = [
new Vector2(0.25, 0),
new Vector2(0.5, 0),
new Vector2(0.25, 1),
new Vector2(0.5, 1)
];
const backFaceUVs = [
new Vector2(0.5, 0),
new Vector2(0.75, 0),
new Vector2(0.5, 1),
new Vector2(0.75, 1)
];
const leftFaceUVs = [
new Vector2(0.75, 0),
new Vector2(1, 0),
new Vector2(0.75, 1),
new Vector2(1, 1)
];
You also need to make sure the canvas aspect ratio is wide enough so the text doesn’t get distorted.
Yeah this is what I was thinking, do you know how to modify the UV for BoxGeometry? Because I personally didn’t find a way for it yet…
You can play with the Texture’s wrap
, repeat
, and offset
Something like this example.
//...
const texture = new THREE.CanvasTexture(canvas);
texture.wrapS = THREE.RepeatWrapping;
texture.repeat.set(1, 1);
//...
function animation( time ) {
texture.offset.x -= 0.01;
renderer.render( scene, camera );
}
There are several approaches, some of them are already mentioned above:
- modify the texture coordinates of box vertices, by changing the buffer attribute called
'uv'
- define separate texture for each side of the box and use an array of materials
- use texture
repeat
and offset
to show specific part of the canvas on each side
- use a fake box (a cylinder with 4 sides), because its texture coordinates are OK
Here is a demo of the 4-th approach. Note, that I provide it only as a reference. Personally, I’d prefer the first approach.
https://codepen.io/boytchev/full/VwNoLPJ

1 Like