Next.js(React)にPixiJSを導入して画像にフィルターを掛けるまでの手順

Next.js（Reactのフレームワーク）に[PixiJS](https://pixijs.com/)を導入して、画像にフィルターを掛けるまでの手順を解説していきます。（※TypeScriptを使用）

## Next.jsのプロジェクトを作成する
まずはNext.jsのプロジェクトを作成します。

```terminal
npx create-next-app@latest --ts
# OR
yarn create next-app --typescript
```
https://nextjs.org/docs/basic-features/typescript

`yarn dev`等でサーバーを起動するとWelcome Pageが立ち上がります。

![next.js.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/559347/70aa3bbd-4742-6e67-7176-9e669785096c.png)

## PixiJSをインストールする
続いてPixiJSをインストールします。
```
npm install pixi.js
# または
yarn add pixi.js
```
## PixiJSを使用する
PixiJSを読み込んで使用していきます。

```tsx:index.tsx
import type { NextPage } from 'next'
import * as PIXI from 'pixi.js'

const Home: NextPage = () => {
  console.log(PIXI)
  return (
    <></>
  )
}

export default Home
```
`console.log`でPixiJSが読み込まれているか確認します。
コンソール上にPixiJSのModuleが表示出来ていれば、読み込みは完了です。
![PixiJS.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/559347/21cfed08-2839-c162-ef87-12986ae225d8.png)

## PixiJSで画像を表示する

```react
import type { NextPage } from 'next'
import { useEffect } from 'react'
import * as PIXI from 'pixi.js'

const Home: NextPage = () => {
  let app: PIXI.Application, container: PIXI.Container, sprite: PIXI.Sprite
  const sizes = {
    width: 0,
    height: 0
  }

  useEffect(() => {
    sizes.width = window.innerWidth
    sizes.height = window.innerHeight   
    init()
    window.addEventListener('resize', resize)
  }, [])

  const init = () => {
    if (app) return
    app = new PIXI.Application({
      width: sizes.width,
      height: sizes.height,
      resizeTo: window
    })
    const main = document.getElementById('main')!
    main.appendChild(app.view)

    // コンテナの作成
    container = new PIXI.Container()
    app.stage.addChild(container)
    app.loader.add('/photo.jpg').load(spriteSetUp)
  }

  // 画像を表示
  const spriteSetUp = () => {
    sprite = PIXI.Sprite.from('/photo.jpg')
    sprite.width = sizes.width - 20
    sprite.height = 300
    sprite.anchor.x = 0.5
    sprite.anchor.y = 0.5
    sprite.position.x = sizes.width / 2
    sprite.position.y = sizes.height / 2
    container.addChild(sprite)
  }

  // リサイズ処理
  const resize = () => {
    sizes.width = window.innerWidth
    sizes.height = window.innerHeight
    sprite.position.x = sizes.width / 2
    sprite.position.y = sizes.height / 2
    app.renderer.resize(sizes.width, sizes.height)
  }
  return (
    <>
      <div
        id="main"
        style={{
          height: '100%',
          width: '100%',
          position: 'fixed',
          top: 0,
          left: 0
        }}
      ></div>
    </>
  )
}

export default Home

```
上記のコードで画像を表示することができます。
![next_pixi.js.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/559347/7c1d5063-1e08-d244-a2b0-48fcf9f4dcfe.png)

## Noiseフィルターをかける
表示した画像にNoise(ノイズ)フィルターをかける例になります。
https://api.pixijs.io/@pixi/filter-noise/PIXI/filters/NoiseFilter.html

```react
const Home: NextPage = () => {

// 省略

  const spriteSetUp = () => {
    sprite = PIXI.Sprite.from('/photo.jpg')
    sprite.width = sizes.width - 20
    sprite.height = 300
    sprite.anchor.x = 0.5
    sprite.anchor.y = 0.5
    sprite.position.x = sizes.width / 2
    sprite.position.y = sizes.height / 2
    container.addChild(sprite)
    noiseFilter()
  }

  // NoiseFilter
  const noiseFilter = () => {
    const noiseFilter = new PIXI.filters.NoiseFilter()
    noiseFilter.noise = 0.7
    noiseFilter.seed = 0.8
    sprite.filters = [noiseFilter]
  }

// 省略
}

export default Home
```

![pixi.js_noise.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/559347/da39618d-4bee-2d01-77fa-62bfce60c1e3.png)

### Noiseフィルターをアニメーションさせる例
```js
const noiseFilter = () => {
  const noiseFilter = new PIXI.filters.NoiseFilter()
  noiseFilter.noise = 0.7
  noiseFilter.seed = 0.8
  sprite.filters = [noiseFilter]

  app.ticker.add(() => {
    noiseFilter.seed = Math.random()
  })
}
```
`ticker`を使ってアニメーションさせています。

## その他のフィルター
PixiJSには他にも数々のフィルターが用意されています。
https://filters.pixijs.download/main/docs/index.html
フィルターのライブラリをインストールすることで実装できます。
例として、GlitchFilterを実装してみます。

```
npx install pixi-filters
# OR
yarn add pixi-filters
```
### Glitchフィルター

```js
import { GlitchFilter } from 'pixi-filters'

// GlitchFilter
const glitchFilter = () => {
  const glitchFilter = new GlitchFilter()
  sprite.filters = [glitchFilter]
  app.ticker.add(() => {
    glitchFilter.fillMode = 0
    glitchFilter.slices = 10
    glitchFilter.offset = Math.random() * 10
  })
}
```
![GlitchFilter.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/559347/c248a6ec-b1e2-11a9-91c4-68221c5544af.png)

```js
sprite.filters = [noiseFilter, glitchFilter]
```

`sprite.filters`に複数のフィルターを指定することで、フィルターの重ね掛けも可能です。

## 参考
https://pixijs.com/