How to render canvas element with no repeat? Box UV mapping

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 );
}

I quess all you need is here: javascript - THREE.js generate UV coordinate - Stack Overflow.

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

image

1 Like