easy-three

create.canvas

create.canvas(proc, props : Object) : Texture

proc - テクスチャを描画するための関数。引数に2Dコンテキストとキャンバスが渡されます。 (デフォルト : () => { })
props - 設定オブジェクト。
  • size (Number | Array) : 平面のサイズ (デフォルト : 1)。
  • resolution (Number) : 平面の解像度 (デフォルト : 100)。
  • transparent (Boolean) : 平面の透過設定 (デフォルト : true)。
  • material (String) : 平面のマテリアル (デフォルト : "Basic")。

その他のプロパティは、create.plane の設定と同じです。

キャンバス要素を用いて作成したテクスチャを適用した平面を作成します。

平面のオブジェクトにテクスチャを表示する場合に使用します。
平面以外にキャンバステクスチャを適用したい場合は create.canvasTexture を使用してください。

create.canvas は、create.canvasTexture で作成したテクスチャを、create.plane に適用して返す関数です。

動的な変更

作成したテクスチャは、 update メソッドで動的に変更することができます。
update メソッドの引数に、テクスチャを変更するための関数(引数はコンテキストとキャンバス)を渡すと、テクスチャが更新されます。

const plane = create.canvas();

plane.update((ctx, canvas) => {
  ctx.fillStyle = "red";
  ctx.fillRect(0, 0, canvas.width, canvas.height);
})

作成したテクスチャの userData.context からコンテキストを取得して、直接描画することもできます。
ただし、直接描画した場合は、テクスチャの更新が反映されないため、update() を呼び出す必要があります。
また、userData.canvas からキャンバス要素を取得することもできます。

const plane = create.canvas();
const ctx = plane.userData.context;
const canvas = plane.userData.canvas;

ctx.fillStyle = "red";
ctx.fillRect(0, 0, canvas.width, canvas.height);
plane.update()

コードの例

キャンバステクスチャを適用した平面

描画していない部分を透過するかどうかは、optiontransparent プロパティで設定できます。

const { camera, create, animate, THREE } = init()
camera.position.set(0, 0, 3);

create.ambientLight();
create.directionalLight();
create.sky()

const plane1 = create.canvas(
  (ctx) => {
    ctx.fillStyle = "red";
    ctx.fillRect(50, 50, 100, 100);
    ctx.fillStyle = "green";
    ctx.fillRect(100, 100, 100, 100);
    ctx.fillStyle = "blue";
    ctx.fillRect(150, 150, 100, 100);
  },
  {
    size: 1,
    resolution: 300,
    position: [-1, 0, 0],
  }
);

const plane2 = create.canvas(
  (ctx) => {
    ctx.fillStyle = "red";
    ctx.fillRect(50, 50, 100, 100);
    ctx.fillStyle = "green";
    ctx.fillRect(100, 100, 100, 100);
    ctx.fillStyle = "blue";
    ctx.fillRect(150, 150, 100, 100);
  },
  {
    size: 1,
    resolution: 300,
    transparent: false,
    position: [1, 0, 0],
  }
);

animate(({ delta }) => {
  plane1.rotation.x += delta;
  plane1.rotation.y += delta;
  plane2.rotation.x += delta;
  plane2.rotation.y += delta;
});

描画内容の変更1

update メソッドで描画内容を変更することで、テクスチャの見た目を動的に変えることができます。

const { camera, create, animate } = init()
camera.position.set(0, 0, 2);

create.ambientLight();
create.directionalLight();
create.sky();

const plane = create.canvas();

const draw = (ctx, canvas, frameCount) => {
  ctx.save();
  // clear
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  // translate to center
  ctx.translate(canvas.width / 2, canvas.height / 2);
  // draw rainbow circles
  const maxR = Math.ceil(Math.hypot(canvas.width, canvas.height) / 2);
  for (let r = maxR; r > 0; r -= 10) {
    ctx.beginPath();
    ctx.arc(0, 0, r, 0, Math.PI * 2);
    ctx.fillStyle = `hsla(${(r * 2 - frameCount * 5) % 360}, 100%, 50%, 0.1)`;
    ctx.fill();
  }
  ctx.restore();
}


animate(({delta, frameCount}) => {
  plane.rotation.x += delta;
  plane.rotation.y += delta;
  plane.update((ctx, canvas) => draw(ctx, canvas, frameCount));
});

描画内容の変更2

複数の描画用関数を用意し、update メソッドの引数に渡す関数を切り替えることで、描画内容を変更することができます。

const { camera, create, animate } = init()
camera.position.set(0, 0, 2);

create.ambientLight();
create.directionalLight();
create.sky();

const plane = create.canvas();

const draw1 = (ctx, canvas) => {
  ctx.save();
  // red frame
  ctx.fillStyle = "red";
  ctx.fillRect(0, 0, canvas.width, canvas.height);
  ctx.clearRect(2, 2, canvas.width - 4, canvas.height - 4);
  // text
  ctx.fillStyle = "black";
  ctx.font = "18px Arial"
  ctx.textAlign = "center";
  ctx.textBaseline = "middle";
  ctx.fillText("easy-three", canvas.width / 2, canvas.height / 2);
  ctx.restore();
}

const draw2 = (ctx, canvas) => {
  ctx.save();
  // clear
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  // translate to center
  ctx.translate(canvas.width / 2, canvas.height / 2);
  // draw rainbow circles
  const maxR = Math.ceil(Math.hypot(canvas.width, canvas.height) / 2);
  for (let r = maxR; r > 0; r -= 2) {
    ctx.beginPath();
    ctx.arc(0, 0, r, 0, Math.PI * 2);
    ctx.fillStyle = `hsl(${(r * 2) % 360}, 100%, 50%)`;
    ctx.fill();
  }
    ctx.restore();
}

plane.update(draw1);

animate(({delta, frameCount}) => {
  plane.rotation.x += delta;
  plane.rotation.y += delta;

  switch (true) {
    case frameCount % 180 === 0:
      plane.update(draw1);
      break;
    case frameCount % 90 === 0:
      plane.update(draw2);
      break;
  }
});