3
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

reglとReactでWebGLのシェーダを簡単に扱う

Last updated at Posted at 2020-03-14

reglとは

WebGLでお絵描きをしたいとき、大きく分けて以下の2つの方向性がある。1

  • three.jsなどの高レベルなライブラリを使う
  • GLSLでシェーダを記述し、WebGL APIをそのまま扱う

後者のようにGLSLを扱えると自由度が高い一方で、WebGL APIに関連して "おまじない" 的なコードが大量に必要になってしまうという問題があった。

この記事で扱う regl は、WebGLのwrapperに相当する。初見でもWebGL APIと1:1に対応づけられる程度には原型を維持することで自由度を担保しつつ、大量の "おまじない" や煩雑な状態管理を単純化し、コードの可読性を大幅に向上してくれる。

公式GitHubではFunctional WebGLと謳っているが、おそらく「変数を入れると(GLSLに基づいて)描画が得られる」ことを指してFunctionalと言っているのだと思われる。ReactでいうところのstatelessなFunction Componentみたいなイメージか。

Reactでreglを扱う

GitHubにいくつかサンプルコードがあるものの、Reactで扱っている例はググってもあまり見当たらなかった。Reactでのシンプルなコードを以下に記載する。

このコードには基本的なシェーダの扱いとアニメーションの方法が含まれており、静止した三角形の色が時間とともに変化する。

Samnple.js
import React, { useEffect } from "react";
import createRegl from "regl";


const Sample = () => {
  const regl = createRegl(); // No arguments: create a full screen canvas

  const drawTriangle = regl({
    frag: `
    precision mediump float;
    uniform vec4 color;
    void main() {
      gl_FragColor = color;
    }`,

    vert: `
    precision mediump float;
    attribute vec2 position;
    void main() {
      gl_Position = vec4(position, 0, 1);
    }`,

    attributes: {
      position: [[0, -1], [-1, 0.5], [1, 1]] // No need to flatten
    },

    uniforms: {
      color: regl.prop("color")
    },
    // Number of vertices to draw in this command
    count: 3
  });

  useEffect(() => {
    regl.frame(({ time }) => {
      regl.clear({
        color: [0, 0, 0, 0],
        depth: 1
      });
      drawTriangle({
        color: [
          Math.cos(time * 1.0),
          Math.sin(time * 0.8),
          Math.cos(time * 3.0),
          1
        ]
      });
    });

    return () => { regl.destroy() }; // Clean up when unmounted
  }, []);

  return <></>;
};


export default Sample;

ポイント

初期化
const regl = createRegl()のところで引数をしていないため、全画面のcanvasが新たに作成される(reglの仕様)。
既存のcanvasを使用したい場合等は引数で指定できる(公式ドキュメント参照)

描画
drawTriangle()は、frag, vertに文字列として記載されたGLSLに基づいて三角形を描画する関数。ここで、

color: regl.prop("color")

という部分に注目。drawTriangle()に引数colorを渡すことで動的に描画内容を変えられるようになっている。

副作用フック
useEffectによって、Reactコンポーネントの副作用として描画を実行している。
useEffectの第二引数が[]なので副作用は一度だけ実行されるが、その中でregl.frame()が呼ばれることによりアニメーションが開始する。

副作用のclean up

return () => { regl.destroy() };

useEffectのなかで上記のようなreturn文がある。今回はcomponentと無関係に全画面のcanvasが作成されているので、このように副作用のclean upを行わないと、別コンポーネントに画面表示を切り替えた後にもcanvasが残ってしまう。

※ そもそもコンポーネント外にcanvasを作成するのは良くないので、component内に予め用意したcanvasをcreateReglに渡すのが良い気がする

  1. three.jsでシェーダを扱う方法もあります

3
4
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
3
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?