LoginSignup
10
8

More than 3 years have passed since last update.

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

Last updated at Posted at 2020-04-15

雑に書きます。

1.実装したいもの

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

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

でも、これを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"
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 };

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」で検索すると...
あんま参考になりそうなやつ出てこないんですよねーw

公式の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

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

10
8
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
10
8