LoginSignup
2
1

More than 5 years have passed since last update.

Canvasに描画したデータをThree.jsのShaderMaterialで読み込んでみる

Posted at

何をしたかったのか

canvasに描画したアニメーションをThree.jsで読み込みたいと思いました。MeshBasicMaterialを使えば、できるのですが、それだと、canvas一つにつき、一つのTextureしか作れないので、canvasに複数描画をして位置で分割して利用をしたらいいと思ったのですが、Three.jsでspritesheetを利用する方法がそこまでリファレンスがないので自分で作らないといけないので、shadermaterialを使ってglslを自分で書く必要がありました。なので、shadermaterialを使うところまで書きました。

実装した内容

qiita.rb


    window.addEventListener('load', init);

    function init() {

      // サイズを指定
      var width = 960;
      var height = 540;

      // レンダラーを作成
      var renderer = new THREE.WebGLRenderer({
        canvas: document.querySelector('#myCanvas')
      });
      renderer.setPixelRatio(window.devicePixelRatio);
      renderer.setSize(width, height);

      // シーンを作成
      var scene = new THREE.Scene();

      // カメラを作成
      var camera = new THREE.PerspectiveCamera(45, width / height,0.1,10000);
      camera.position.set(0, 0, +1000);

      // 箱を作成
      var geometry = new THREE.BoxGeometry(400, 400, 400);
      var material  = new THREE.ShaderMaterial({
            vertexShader: document.getElementById('vs').textContent,
            fragmentShader: document.getElementById('fs').textContent,
            transparent: true,
            depthWrite:   true,
            uniforms: {
                  "map": {
                      type: 't',
                      value: SOURCE.drawingAnim()
                  },
            },
            side:THREE.DoubleSide
      });
      /*
      = new THREE.MeshBasicMaterial({
        transparent: true,
        map: drawingAnim(),
        side:THREE.DoubleSide

      });*/
      //= new THREE.MeshNormalMaterial();
      //document.getElementById('drawCanvas');
      const box = new THREE.Mesh(geometry, material);
      //box.material.map.needsUpdate = true;
      box.doubleSided = true;
      scene.add(box);

      tick();

      // 毎フレーム時に実行されるループイベントです
      var count = 0;
      function tick() {
        count++;
        SOURCE.next();
        //box.material.map = drawingAnim();
        box.material.uniforms.map.value.needsUpdate = true;
        //box.material.uniforms.map = drawingAnim();
        box.rotation.x += 0.01;
        box.position.z = 200*Math.sin(0.1*count);
        box.rotation.y += 0.01;
        box.rotation.z += 0.01;

        renderer.render(scene, camera); // レンダリング

        requestAnimationFrame(tick);
      }
    }

htmlの方は

qiita.rb
<canvas id="myCanvas"></canvas>
<!-- drawCanvasの方をmyの方の素材として利用をする。 -->
<canvas id="drawCanvas" width="512" height="512"></canvas>

こんな感じでそして、canvasへの描画は

qiita.rb
var SOURCE = {
  init:function(){

  },
  cnum:0,
  ctx:null,
  canvas:null,
  drawingAnim:function(){
    this.cnum++;
    this.canvas = document.getElementById('drawCanvas');
    if ( ! this.canvas || ! this.canvas.getContext ) { return false; }
    this.ctx = this.canvas.getContext('2d');
    this.ctx.clearRect(0, 0, 512, 512)
    this.ctx.beginPath();
    //this.ctx.fillStyle = 'rgb(255, 0, 0)'; // 
    //this.ctx.fillRect(50, 50, 400, 400);
    this.ctx.fillStyle = 'rgb(144, 187, 89)'; // 
    this.ctx.fillRect(0, 0, 200+200*Math.sin(0.1*this.cnum), 200+200*Math.sin(0.01*this.cnum));
    return new THREE.Texture(this.canvas);
  },
  next:function(){
    this.cnum++;
    this.ctx = this.canvas.getContext('2d');
    this.ctx.clearRect(0, 0, 512, 512)
    this.ctx.beginPath();
    this.ctx.fillStyle = 'rgb(144, 187, 89)'; // 
    this.ctx.fillRect(0, 0, 200+200*Math.sin(0.1*this.cnum), 200+200*Math.sin(0.01*this.cnum));
    this.ctx.fillStyle = 'rgb(255, 0, 0)'; // 
    this.ctx.fillRect(0, 0, 200, 200);
  }
}

こんな感じにした。
glsl部分は

qiita.rb
<script id="vs" type="x-shader/x-vertex">
varying vec2 vUv;
void main() {
vUv = uv; 
    gl_Position = projectionMatrix * modelViewMatrix * vec4(position,1.0);
 }
</script>
<script id="fs" type="x-shader/x-fragment">
    uniform sampler2D map;
    varying vec2 vUv;
    void main() {

        gl_FragColor = texture2D( map, vUv );
    }
</script>

これで立方体だが表面がうにょうにょ動くのが完成しました

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1