FragmentShaderを表示するreactコンポーネントの作り方

![fragmentshader.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24723/d4b18d2a-5c8d-f2ef-153d-49a275be3abf.jpeg)


# 概要
CRAでプロジェクトを作成、プロジェクトにPackageを入れて、↑を表示するシンプルなReactコンポーネントの作成を行います。

# 環境
* Mac
* yarn/npx (CRAのグローバルインストールは非推奨のため)
* TypeScript 3.5+ （オプション）

# CRAでベースアプリを作成
```zsh
# npxの場合
$ npx create-react-app myshader

# yarnの場合
$ yarn create react-app myshader


# npx & typescriptを利用する場合
$ npx create-react-app myshader --template typescript

# yarn & typescriptを利用する場合
$ yarn create react-app myshader --template typescript
```

大抵の場合は必要ないですが、一応CRAがちゃんとコードを生成している事を確認しておきます。

```zsh
$ cd myshader

# yarn
$ yarn start

# npm
$ npm start
```

[TypeScriptの場合]
![cra.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24723/e97367b0-91af-11e8-3d13-6ee08a6d7dc2.png)


# react-vfxをインストール
[react-vfx](https://github.com/fand/react-vfx)をインストールします。
併せて、`styled-components`も入れておきます。CSSやSCSSまたはSASSが好きな方はインストールしなくても全く問題ないです。
ちなみ、react-vfxはtsで書かれているので、＠typesファイルのインストールは不要です。

```zsh
# yarn
$ yarn add react-vfx styled-components
$ yarn add -D @types/styled-components <-- if you use typescript

# npm
$ npm install react-vfx styled-components
$ npm install -D @types/styled-components <-- if you use typescript
```

# コンポーネントを作成
一番最初の画像を表示するためのシンプルなコンポーネントを作成していきます。
名前はなんでも良いのですが、今回は分かりやすく`MyShader.tsx`としました。
本当はフォルダを作るべきなんですが、目的はreact-vfxを試す事なので、`src`直下に作りました。

```ts
import React from "react";
import * as VFX from "react-vfx";
import styled from "styled-components";

const Content = styled.div`
  width: 100vw;
  height: 100vh;
`;

const metal = `
uniform vec2 resolution;
uniform float time;
void main()
{
    vec2 coord = gl_FragCoord.xy / resolution.xy;
    vec2 st = coord;
    vec3 line = vec3(0.0);

    coord *= 4.;

    float len;

    for (int i = 0; i < 15; i++) {
        len = length(vec2(coord.x, coord.y));
        coord.x += cos(coord.y + sin(len)) + cos(time * .07) * 0.2;
        coord.y += sin(coord.x + cos(len)) + sin(time * 0.1);
    }

    len *= cos(len * 0.4);

    len -= 10.;

    for (float i = 0.0; i < 5.0; i++) {
        len += 0.11 / abs(mod(st.x, 1.09 * i) * 200.) * 1.;
    }

    vec3 color = vec3(cos(len + 0.2) * 1.15, cos(len + 0.1), cos(len - 0.05));

    gl_FragColor = vec4(color, 1.0);
}
`;

const MyShader: React.FC = () => {
  return (
    <>
      <VFX.VFXProvider>
        <VFX.VFXSpan shader={metal}>
          <Content></Content>
        </VFX.VFXSpan>
      </VFX.VFXProvider>
    </>
  );
}

export default MyShader;
```

コード自体は非常にシンプルで、react-vfxをインポート
`import * as VFX from "react-vfx";`
FragmentShaderをリテラル内に記述して、metalという変数を定義
インポートしたvfxのコンポーネントを使って、metal（FragmentShader）をロード

`Content`は表示するためだけのものなので、普通にCSSを書いて、インポートする方がstyled-componentsを使うより簡単かつ楽だと思います。


あとはこれをApp.tsxもしくはApp.jsにインポートして、<MyShader />を記述したのちに、アプリを起動すれば、FragmentShaderで記述されたアニメーションが表示されます。

ちなみに、`metal`の部分に[ShaderToy](https://www.shadertoy.com/)のコードを移植して、変数名等を修正すれば、簡単に色々なモノを試せます。ただし、公開する場合はライセンスに気をつける必要があります。


# react-vfxサンプルページ
react-vfx自体もエフェクトを持っているので、Shaderを書かなくても面白いエフェクトをページに簡単に加える事ができます。
https://amagi.dev/react-vfx/


[text]
![Screen Shot 2020-07-30 at 2.06.53 AM.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/24723/2df284e9-16fa-e71e-b46f-fe772316b695.png)



repo：https://github.com/koji/typescript/tree/master/shadereact
レポジトリを試す場合は下記を実行すれば、動きます。

```zsh
$ cd shaderreact
$ yarn
$ yarn start
```


Dev.toに投稿したポストを日本語にして投稿してみました。
元の記事
https://dev.to/kojikanao/use-fragmentshader-with-reactjs-easily-react-vfx-52lm