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

雑に書きます。

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

そう！ただ６面体に画像を貼り付けただけのものですね。

でも、これをreact-three-fiberを使ってやるにはどうすれば...

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

ディレクトリ構成を関係ありそうなところだけ書いておきます。
>
root/
　├ build/
　├ public/
　└ src/
　　　├ components/
　　　│　　　└ TexturedBox.js
　　　├ resources/
　　　│　　　└ images/
　　　│　　　    └ crate.gif
　　　├ 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/TexturedBox.js
import * as THREE from 'three'
import React, { useRef, Suspense } from 'react'
import { Canvas, Dom, useFrame, useLoader } from 'react-three-fiber'
import textureUrl from '../resources/images/crate.gif'

function Cube() {
  const mesh = useRef()
  const texture = useLoader(THREE.TextureLoader, textureUrl)
  useFrame(() => {
    mesh.current.rotation.x += 0.005;
    mesh.current.rotation.y += 0.01;
  })
  return (
    <mesh ref={mesh}>
      <boxBufferGeometry attach="geometry" args={[200, 200, 200]} />
      <meshBasicMaterial attach="material" map={texture} depthTest={false} />
    </mesh>
  )
}

const TexturedBox = () => {
  return (
    <Canvas camera={{ position: [0, 0, 400] }}>
      <Suspense fallback={<Dom>...Loading</Dom>}>
        <Cube />
      </Suspense>
    </Canvas>
  )
}

export { TexturedBox };

```
```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 { TexturedBox } from './components/TexturedBox'

const App = () => {
  return (
    <BrowserRouter>
      <div>{document.title}</div>
      <Switch>
        <Route exact path='/'><Home /></Route>
        <Route path='/1'><TexturedBox /></Route>
      </Switch>
      <Link to='/'>ホーム画面へ</Link>
      <Link to='/1'>画像貼り付けた箱へ</Link>
    </BrowserRouter>
  )
}

export default App;
```

# 3.参考にしたもの
まず、画像を読み込むのにTextureLoaderを使うはずですよね。
「react-three-fiber TextureLoader」で検索すると...
あんま参考になりそうなやつ出てこないんですよねーｗ

公式のrecipes.mdには
https://github.com/react-spring/react-three-fiber/blob/master/recipes.md#handling-loaders

>const texture = useMemo(() => new THREE.TextureLoader().load(url), [url]
> meshLambertMaterial attach="material" map={texture}>

みたいな感じで書かれてますけど、いやそんだけじゃ分からんわと思いつつ他を探してもちゃんと書いてるやつ見つかりませんでした。

ただ、

> You can use React's built-in memoizing-features (as well as suspense) to build async dependency graphs.

と書かれているので、上記のようにuseMemoを使うか、Suspeneを使わなければ出来ないってことだけは分かりました...たぶんそう...
他のコードをちらほら見てる感じ、Suspenseを使ってるやつが多かったので、僕はSuspenseを使いました。

--------

次に、こちら。
https://codesandbox.io/s/r3f-basic-demo-x2nk1?file=/src/index.js:952-992

６面体のそれぞれの面に違う色を塗っていますね。
コレを見て、geometryにmaterialを貼り付けたいときはこんなふうに書くんだーと思ったので真似してやってみたらなんか出来ました。
それぞれ違う色のmaterialを貼り付けたい場合は、このURLのコードのようにmaterialを複数書かなければいけないんですが、貼り付けるものが１種類なら１つだけmaterialを書いとけばいいです。



# 4.感想
触り始めてまだ二日目なので、全然良くわかってないですけど参考になれば嬉しいです！
こっからどんどんThree.jsをReactで実装していきます！待っててください！誰か！

# 5.僕の関連記事(react-three-fiber関連)
ShaderMaterial
・https://qiita.com/kageyama0/items/1e50f9966d1afad57329
FontLoader + textGeometry(3Dの文字)
・https://qiita.com/kageyama0/items/a08cff01b23654f9ab15