👏

【React Three Fiber】Reactで作る3D【#18Examples Water】

2023/04/14に公開

【#18Examples Water】

YouTube:https://youtu.be/Xc-gGDpHTWs

https://youtu.be/Xc-gGDpHTWs

今回は「React-Three-Fiber」の「Examples」から

https://docs.pmnd.rs/react-three-fiber/getting-started/examples

「Water shader」を実装する方法について解説します。

https://codesandbox.io/s/1b40u

まずは、「src」->「components」フォルダに
「GeoOcean.tsx」というファイルを作成します。

そして、「codesandbox」の内容をすべてコピーします。

コピーができましたら、
「App」となっているコンポーネント名を「GeoOcean」に変更します。

「React-Three-Fiber」で「water」のタグを使用するためには、
「extend({ Water })」を使用します。

src/components/GeoOcean.tsx
import * as THREE from 'three'
import React, { Suspense, useRef, useMemo } from 'react'
import {
  Canvas,
  extend,
  useThree,
  useLoader,
  useFrame,
} from '@react-three/fiber'
import { OrbitControls, Sky } from '@react-three/drei'
import { Water } from 'three-stdlib'

extend({ Water })

function Ocean() {
  const ref = useRef()
  const gl = useThree((state) => state.gl)
  const waterNormals = useLoader(THREE.TextureLoader, '/waternormals.jpeg')
  waterNormals.wrapS = waterNormals.wrapT = THREE.RepeatWrapping
  const geom = useMemo(() => new THREE.PlaneGeometry(10000, 10000), [])
  const config = useMemo(
    () => ({
      textureWidth: 512,
      textureHeight: 512,
      waterNormals,
      sunDirection: new THREE.Vector3(),
      sunColor: 0xffffff,
      waterColor: 0x001e0f,
      distortionScale: 3.7,
      fog: false,
      format: gl.encoding,
    }),
    [waterNormals]
  )
  useFrame(
    (state, delta) => (ref.current.material.uniforms.time.value += delta)
  )
  return <water ref={ref} args={[geom, config]} rotation-x={-Math.PI / 2} />
}

function Box() {
  const ref = useRef()
  useFrame((state, delta) => {
    ref.current.position.y = 10 + Math.sin(state.clock.elapsedTime) * 20
    ref.current.rotation.x =
      ref.current.rotation.y =
      ref.current.rotation.z +=
        delta
  })
  return (
    <mesh ref={ref} scale={20}>
      <boxGeometry />
      <meshStandardMaterial />
    </mesh>
  )
}

export default function GeoOcean() {
  return (
    <Canvas camera={{ position: [0, 5, 100], fov: 55, near: 1, far: 20000 }}>
      <pointLight position={[100, 100, 100]} />
      <pointLight position={[-100, -100, -100]} />
      <Suspense fallback={null}>
        <Ocean />
        <Box />
      </Suspense>
      <Sky scale={1000} sunPosition={[500, 150, -1000]} turbidity={0.1} />
      <OrbitControls />
    </Canvas>
  )
}

ここまでできましたら、
App.tsxに上記のコンポーネントを設定します。

src/App.tsx
import { Canvas } from '@react-three/fiber'
import { OrbitControls } from '@react-three/drei'
import GeoBox from './components/GeoBox'
import GeoText from './components/GeoText'
import GeoText3d from './components/GeoText3d'
import GeoTexture from './components/GeoTexture'
import GeoEnv from './components/GeoEnv'
import GeoGltf from './components/GeoGltf'
import GeoStars from './components/GeoStars'
import GeoParticles from './components/GeoParticles'
import GeoMaath from './components/GeoMaath'
import GeoShader from './components/GeoShaders'
import GeoOcean from './components/GeoOcean'

function App() {
  return (
    // <div className="w-full h-screen">
    //   <Canvas shadows camera={{ position: [0, 0, 10] }}>
    //     <ambientLight intensity={0.1} />
    //     <directionalLight position={[0, 0, 5]} castShadow />
    //     {/* <GeoBox /> */}
    //     {/* <GeoText /> */}
    //     {/* <GeoText3d /> */}
    //     {/* <GeoTexture /> */}
    //     {/* <GeoEnv /> */}
    //     {/* <GeoGltf /> */}
    //     {/* <GeoStars /> */}
    //     {/* <GeoParticles /> */}
    //     {/* <GeoMaath /> */}
    //     <OrbitControls />
    //   </Canvas>
    // </div>
    <div className="w-full h-screen">
      <GeoOcean />
    </div>
  )
}

export default App

ここまでできましたら、
「codesandbox」の「public」フォルダ内にある
「waternormals.jpeg」をダウンロードして、
自分のアプリの「public」フォルダの直下に移動します。

Discussion