React.js + react-three-fiberでThree.jsの公式exampleと同じものを実装してみた！#2

雑に書きます。

# 1.実装したいもの
こちらが今回react-three-fiberを使って実装するものです...
https://threejs.org/examples/?q=shader#webgl_shader

shaderを読み込むだけですねー

# 2.ディレクトリ構成＆コード

ディレクトリ構成を関係ありそうなところだけ書いておきます。
>
root/
　├ build/
　├ public/
　└ src/
　　　├ components/
　　　│　　　└ Shader.js
　　　│　　　└ PurpleShader.js
　　　├ App.js
　　　└ index.js

```package.json(一部)
    "react": "^16.13.1",
    "react-dom": "^16.13.1",
    "react-router-dom": "^5.1.2",
    "react-scripts": "3.4.1",
    "react-three-fiber": "4.0.7",
    "three": "^0.115.0"
```

```react:src/components/Shader.js
import React, { Suspense, useRef } from "react"
import { Canvas, useFrame } from "react-three-fiber"
import { PurpleShader } from "./PurpleShader"

function Plane() {
  const ref = useRef()
  useFrame(({ clock }) => {
    const time = clock.getElapsedTime()
    ref.current.material.uniforms.time.value = time;
  })

  return (
    <mesh ref={ref}>
      <planeBufferGeometry attach="geometry" args={[2,2,2]} />
      <shaderMaterial
        attach="material"
        args={[PurpleShader]}
      />
    </mesh>
  )
}

const Shader = () => {
  return (
    <Canvas camera={{ position: [- 1, 1, 1], near: 0.01, far: 10000, fov: 60 }}>
      <ambientLight intensity={0.85} />
      <Suspense fallback={null}>
        <Plane />
      </Suspense>
    </Canvas>
  )
}

export { Shader };
```

```react:src/components/PurpleShader.js
const PurpleShader = {
  uniforms: {
    time: { type: "f", value: 1.0 }
  },
  vertexShader: `
    varying vec2 vUv;
    void main()	{
      vUv = uv;
      gl_Position = vec4( position, 1.0 );
    }
  `,
  fragmentShader: `
    varying vec2 vUv;
    uniform float time;
    void main()	{
      vec2 p = - 1.0 + 2.0 * vUv;
      float a = time * 40.0;
      float d, e, f, g = 1.0 / 40.0 ,h ,i ,r ,q;

      e = 400.0 * ( p.x * 0.5 + 0.5 );
      f = 400.0 * ( p.y * 0.5 + 0.5 );
      i = 200.0 + sin( e * g + a / 150.0 ) * 20.0;
      d = 200.0 + cos( f * g / 2.0 ) * 18.0 + cos( e * g ) * 7.0;
      r = sqrt( pow( abs( i - e ), 2.0 ) + pow( abs( d - f ), 2.0 ) );
      q = f / r;
      e = ( r * cos( q ) ) - a / 2.0;
      f = ( r * sin( q ) ) - a / 2.0;
      d = sin( e * g ) * 176.0 + sin( e * g ) * 164.0 + r;
      h = ( ( f + d ) + a / 2.0 ) * g;
      i = cos( h + r * p.x / 1.3 ) * ( e + e + a ) + cos( q * g * 6.0 ) * ( r + h / 3.0 );
      h = sin( f * g ) * 144.0 - sin( e * g ) * 212.0 * p.x;
      h = ( h + ( f - e ) * q + sin( r - ( a + h ) / 7.0 ) * 10.0 + i / 4.0 ) * g;
      i += cos( h * 2.3 * sin( a / 350.0 - q ) ) * 184.0 * sin( q - ( r * 4.3 + a / 12.0 ) * g ) + tan( r * g + h ) * 184.0 * cos( r * g + h );
      i = mod( i / 5.6, 256.0 ) / 64.0;
      if ( i < 0.0 ) i += 4.0;
      if ( i >= 2.0 ) i = 4.0 - i;
      d = r / 350.0;
      d += sin( d * d * 8.0 ) * 0.52;
      f = ( sin( a * g ) + 1.0 ) / 2.0;
      gl_FragColor = vec4( vec3( f * i / 1.6, i / 2.0 + d / 13.0, i ) * d * p.x + vec3( i / 1.3 + d / 8.0, i / 2.0 + d / 18.0, i ) * d * ( 1.0 - p.x ), 1.0 );
    }
  `
}

export { PurpleShader }
```
```react:src/components/App.js
import React from 'react'
import { BrowserRouter, Route, Switch, Link } from 'react-router-dom'
//import './css/index.css'
import { Home } from './components/Home'
import { Shader } from './components/Shader'

const App = () => {
  return (
    <BrowserRouter>
      <div>{document.title}</div>
      <Switch>
        <Route exact path='/'><Home /></Route>
        <Route path='/1'><Shader /></Route>
      </Switch>
      <Link to='/'>ホーム画面へ</Link>
      <Link to='/1'>　シェーダー</Link>
    </BrowserRouter>
  )
}

export default App;
```

# 3.参考にしたもの
https://codesandbox.io/s/t9-react-three-fiber-shadermaterial-1g4qq?file=/src/index.js
https://threejs.org/examples/?q=shader#webgl_shader


# 4.感想
shaderMaterilaはどう使うのかなーと思って、やってみました。

# 5.Three.jsサンプル実装シリーズ
TextureLoader
・https://qiita.com/drafts/56d211a47d139e424e5b/