Skip to content Skip to sidebar Skip to footer

Three.js/webgl And 2d Canvas -- Passing Getimagedata() Array Into Three.datatexture()

I'm new to WebGL (and 3D graphics in general) and am using three.js. What I want to do is create multiple textures from a 2D canvas, and use them to render multiple meshes, each wi

Solution 1:

Three.js initializes lazily so theoretically you could init your textures by calling renderer.render

"use strict";

var camera;
var scene;
var renderer;
var group;

init();
animate();

functioninit() {
  renderer = newTHREE.WebGLRenderer({canvas: document.querySelector("canvas")});

  camera = newTHREE.PerspectiveCamera(70, 1, 1, 1000);
  camera.position.z = 300;
  scene = newTHREE.Scene();
  
  group = newTHREE.Object3D();
  scene.add(group);

  var geometry = newTHREE.BoxGeometry(50, 50, 50);

  var ctx = document.createElement("canvas").getContext("2d");
  ctx.canvas.width = 128;
  ctx.canvas.height = 128;

  for (var y = 0; y < 3; ++y) {
    for (var x = 0; x < 3; ++x) {
      ctx.textAlign = "center";
      ctx.textBaseline = "middle";
      ctx.fillStyle = "rgb(" + (x * 127) + ",192," + (y * 127) + ")"  ;
      ctx.fillRect(0, 0, 128, 128);
      ctx.fillStyle = "white";
      ctx.font = "60px sans-serif";
      ctx.fillText(x + "x" + y, 64, 64);

      var texture = newTHREE.Texture(ctx.canvas);
      texture.needsUpdate = true;
      texture.flipY = true;
      var material = newTHREE.MeshBasicMaterial({
        map: texture,
      });
      var mesh = newTHREE.Mesh(geometry, material);
      group.add(mesh);
      mesh.position.x = (x - 1) * 100;
      mesh.position.y = (y - 1) * 100;
      
      // render to force three to init the texture
      renderer.render(scene, camera);
    }
  }
}

functionresize() {
  var width = renderer.domElement.clientWidth;
  var height = renderer.domElement.clientHeight;
  if (renderer.domElement.width !== width || renderer.domElement.height !== height) {
    renderer.setSize(width, height, false);
    camera.aspect = width / height;
    camera.updateProjectionMatrix();
  }
}

functionanimate() {
  resize();
  group.rotation.x += 0.005;
  group.rotation.y += 0.01;

  renderer.render(scene, camera);
  requestAnimationFrame(animate);
}
body { margin: 0; }
canvas { width: 100vw; height: 100vh; display: block; }
<scriptsrc="https://cdnjs.cloudflare.com/ajax/libs/three.js/r79/three.min.js"></script><canvas></canvas>

You can also call renderer.setTexture(texture, slot) which works but is arguably the wrong thing to do as based on both the name, docs, and signature of the function there's no guarantee this will work in the future.

"use strict";

var camera;
var scene;
var renderer;
var group;

init();
animate();

functioninit() {
  renderer = newTHREE.WebGLRenderer({canvas: document.querySelector("canvas")});

  camera = newTHREE.PerspectiveCamera(70, 1, 1, 1000);
  camera.position.z = 300;
  scene = newTHREE.Scene();
  
  group = newTHREE.Object3D();
  scene.add(group);

  var geometry = newTHREE.BoxGeometry(50, 50, 50);

  var ctx = document.createElement("canvas").getContext("2d");
  ctx.canvas.width = 128;
  ctx.canvas.height = 128;

  for (var y = 0; y < 3; ++y) {
    for (var x = 0; x < 3; ++x) {
      ctx.textAlign = "center";
      ctx.textBaseline = "middle";
      ctx.fillStyle = "rgb(" + (x * 127) + ",192," + (y * 127) + ")"  ;
      ctx.fillRect(0, 0, 128, 128);
      ctx.fillStyle = "white";
      ctx.font = "60px sans-serif";
      ctx.fillText(x + "x" + y, 64, 64);

      var texture = newTHREE.Texture(ctx.canvas);
      texture.needsUpdate = true;
      texture.flipY = true;
      var material = newTHREE.MeshBasicMaterial({
        map: texture,
      });
      var mesh = newTHREE.Mesh(geometry, material);
      group.add(mesh);
      mesh.position.x = (x - 1) * 100;
      mesh.position.y = (y - 1) * 100;
      
      // make three init the texturevar slot = 0; // doesn't matter what slot as we're not 
      renderer.setTexture(texture, slot);
    }
  }
}

functionresize() {
  var width = renderer.domElement.clientWidth;
  var height = renderer.domElement.clientHeight;
  if (renderer.domElement.width !== width || renderer.domElement.height !== height) {
    renderer.setSize(width, height, false);
    camera.aspect = width / height;
    camera.updateProjectionMatrix();
  }
}

functionanimate() {
  resize();
  group.rotation.x += 0.005;
  group.rotation.y += 0.01;

  renderer.render(scene, camera);
  requestAnimationFrame(animate);
}
body { margin: 0; }
canvas { width: 100vw; height: 100vh; display: block; }
<scriptsrc="https://cdnjs.cloudflare.com/ajax/libs/three.js/r79/three.min.js"></script><canvas></canvas>

As for flipping use texture.flipY = true;

Post a Comment for "Three.js/webgl And 2d Canvas -- Passing Getimagedata() Array Into Three.datatexture()"