【React】React Three Fiber基礎

React

ReactでThreeが使えると知りやってみたときのメモ。Three.jsよりコンポーネント単位で書けて書きやすいと思うときもあります。簡単に書けるようなライブラリもたくさんあるし。

インストール

npm install three @types/three @react-three/fiber

three・・・Web上で3Dグラフィックスを扱うための基本ライブラリ
@types/three・・・TypeScript環境でthree.jsを安全に使うための型定義
@react-three/fiber・・・Reactとthree.jsを統合して使うためのReact用のラッパーライブラリ

簡単なセットアップ

import { Canvas } from "@react-three/fiber";

function App() {
  return (
    <Canvas>
      <mesh>
        <boxGeometry args={[2, 2, 4]} />
        <meshStandardMaterial />
      </mesh>
    </Canvas>
  );
}

r3f(react three fiber)のCanvasコンポーネントを使うと、カメラやシーンの設定などなくても、レンダリングできるセットができて便利です。

meshを作るときはThree.jsと同様ジオメトリとマテリアルを作成します。

ライトの種類とプロパティ

Canvasの中に設置します。

<Canvas>
      <directionalLight position={[0, 0, 2]} />
      <mesh>
        <boxGeometry />
        <meshStandardMaterial color={"orange"} />
      </mesh>
    </Canvas> position={[0, 0, 2]} />

AmbientLight(環境光)

  • 全体的な照明を提供し、シーン全体を均等に照らします。影はできません。
  • プロパティ:
    • color: 光の色(デフォルトは白)。
    • intensity: 光の強さ。デフォルトは 10 で光なし)。
  • 例: <ambientLight color={"white"} intensity={0.5} />
<ambientLight intensity={0.5} />

DirectionalLight(平行光源)

  • ある方向からの光を照射します。太陽光のような効果を生み出し、影を生成できます。
  • プロパティ:
    • color: 光の色。
    • intensity: 光の強さ。
    • position: 光の発生場所の位置 [x, y, z]
    • castShadow: 影を生成するかどうかの設定。
  • 例: <directionalLight color={"white"} intensity={0.8} position={[5, 10, 5]} castShadow={true} />
<directionalLight position={[0, 0, 2]} intensity={0.5} />

PointLight(点光源)

  • 全方向に向けて光を放射します。街灯やランプのような効果を生み出します。影も生成可能です。
  • プロパティ:
    • color: 光の色。
    • intensity: 光の強さ。
    • distance: 光が届く最大距離(これを超えると光が消えます)。
    • decay: 距離による光の減衰を制御します。
    • position: 光の発生場所の位置。
    • castShadow: 影を生成するかどうか。
  • 例: <pointLight color={"yellow"} intensity={1} distance={50} decay={2} position={[0, 10, 0]} />

SpotLight(スポットライト)

  • 円錐状に絞り込まれた光を放射し、特定の対象に焦点を当てます。舞台のスポットライトに似ています。
  • プロパティ:
    • color: 光の色。
    • intensity: 光の強さ。
    • distance: 光が届く最大距離。
    • angle: 光の広がる角度(円錐の広がり)。
    • penumbra: 光のソフトエッジ(0~1)。
    • decay: 距離による光の減衰。
    • position: 光の発生場所の位置。
    • target: 光を向ける対象。
    • castShadow: 影を生成するかどうか。
  • 例: <spotLight position={[5, 10, 5]} angle={0.3} penumbra={0.1} castShadow={true} />

HemisphereLight(半球光源)

  • 天空と地面から異なる色の光を発生させます。環境全体に柔らかい光を提供します。
  • プロパティ:
    • skyColor: 天空の色。
    • groundColor: 地面の色。
    • intensity: 光の強さ。
  • 例: <hemisphereLight skyColor={"lightblue"} groundColor={"brown"} intensity={0.6} />

RectAreaLight(矩形エリアライト)

  • 矩形の面から光を発します。物理的な光源を再現する際に使います。通常のライトとは異なり、よりリアルな効果を生み出します。
  • プロパティ:
    • color: 光の色。
    • intensity: 光の強さ。
    • width: 照明の幅。
    • height: 照明の高さ。
  • 例: <rectAreaLight color={"white"} intensity={1} width={5} height={2} position={[0, 5, 0]} />

ジオメトリとプロパティ

boxGeometry

立方体や長方体を作成します。
プロパティ: [width, height, depth, widthSegments, heightSegments, depthSegments]
※プロパティは省略してもデフォルトの数値があります

<boxGeometry args={[1, 1, 1, 3, 3, 3]} />

sphereGeometry

球形のジオメトリを作成します。
プロパティ: [radius, widthSegments, heightSegments]

<sphereGeometry args={[1, 10, 10]} />

planeGeometry

平面(2Dの四角形)を作成します。
プロパティ: [width, height, widthSegments, heightSegments]

<planeGeometry args={[1, 1, 10, 10]} />

circleGeometry

  • 円形のジオメトリを作成します。
  • プロパティ: [radius, segments]
<circleGeometry args={[1, 10]} />

TorusGeometry(トーラス/ドーナツ形)

  • ドーナツ形状を作成します。
  • プロパティ: [radius, tube, radialSegments, tubularSegments]
  • 例: <torusGeometry args={[1, 0.4, 16, 100]} />

CylinderGeometry(円柱)

  • 円柱または円錐形を作成します。
  • プロパティ: [radiusTop, radiusBottom, height, radialSegments]
  • 例: <cylinderGeometry args={[1, 1, 2, 32]} />

ConeGeometry(円錐)

  • 円錐形のジオメトリを作成します。
  • プロパティ: [radius, height, radialSegments]
  • 例: <coneGeometry args={[1, 2, 32]} />

TorusKnotGeometry(トーラスノット)

  • 結び目の形をしたトーラスの形状を作成します。
  • プロパティ: [radius, tube, tubularSegments, radialSegments, p, q]
  • 例: <torusKnotGeometry args={[1, 0.4, 100, 16]} />

DodecahedronGeometry(十二面体)

  • 十二面体のジオメトリを作成します。
  • プロパティ: [radius, detail]
  • 例: <dodecahedronGeometry args={[1, 0]} />

OctahedronGeometry(八面体)

  • 八面体のジオメトリを作成します。
  • プロパティ: [radius, detail]
  • 例: <octahedronGeometry args={[1, 0]} />

IcosahedronGeometry(二十面体)

  • 二十面体のジオメトリを作成します。
  • プロパティ: [radius, detail]
  • 例: <icosahedronGeometry args={[1, 0]} />

TetrahedronGeometry(四面体)

  • 四面体のジオメトリを作成します。
  • プロパティ: [radius, detail]
  • 例: <tetrahedronGeometry args={[1, 0]} />

RingGeometry(リング)

  • 円形のリング状ジオメトリを作成します。
  • プロパティ: [innerRadius, outerRadius, thetaSegments]
  • 例: <ringGeometry args={[1, 5, 32]} />

TextGeometry(テキスト)

  • 3Dのテキストを生成します(フォントをロードする必要があります)。
  • プロパティ: {text, size, height, curveSegments, font, bevelEnabled, bevelThickness, bevelSize}
  • 例: <textGeometry args={["Hello", { font, size: 80, height: 5 }]} />

メッシュのプロパティ

メッシュの見た目や動作、光の影響などを調整します

<mesh
        position={[1, 0, 1]}
        rotation={[Math.PI / 6, 0, 0]}
        scale={[2, 2, 1]}
        castShadow={true} //オブジェクトが影を落とすようになります。
        receiveShadow={true} //オブジェクトが影を受け取る
        visible={true} //true で表示、false で非表示。
        frustumCulled={false}//カメラの視野に入っている場合のみ描画されるようにするかを指定します。false にすると、視界外でも描画されます。
        userData={{someData: 'example'}}//カスタムデータをメッシュに持たせるために使用します
        onClick={()=>console.log("clicked")}
      >
        <boxGeometry />
        <meshStandardMaterial color={"orange"} />
      </mesh>

他にもonPointerOverなどReactのイベントハンドラを利用できます

マテリアルのプロパティ

素材、材質、テクスチャ、色、透明度などを調整できます

meshStandardMaterial

<meshStandardMaterial
          color={"orange"}
          roughness={0.5}
          metalness={5}
          emissive={"red"} //発光の色
          emissiveIntensity={20}
          wireframe={true}
          map={texture} //UVマッピングでオブジェクトに画像を適用する
          normalMap={normalMapTexture}//凹凸感を表現するためのマップ
          opacity={0.5}//1は完全に不透明、0は完全に透明。
          transparent={true}//opacityで透明度を制御できます。
          envMap={cubemap}//物体が反射する環境をシミュレート
        />

他にもroughnessMapやaoMapなど設定できます

メッシュのコンポーネント化

同種のメッシュを複数作る場合、メッシュコンポーネントを作る関数を作って、コンポーネントとして記述することができます。propsでプロパティを渡し、いろいろなメッシュをコード量少なく作れます

const Cube = ({ position, size, color }) => {
  return (
    <mesh position={position}>
      <boxGeometry args={size} />
      <meshStandardMaterial color={color} />
    </mesh>
  );
};

function App() {
  return (
    <Canvas>
        <Cube position={[1, 0, 1]} color={"green"} size={[1, 1, 1]} />
        <Cube position={[-1, 0, 1]} color={"red"} size={[1, 1, 1]} />
        <Cube position={[1, 2, 1]} color={"pink"} size={[1, 1, 1]} />
        <Cube position={[-1, 2, 1]} color={"blue"} size={[1, 1, 1]} />
    </Canvas>
  );
}

グループ

複数のメッシュをまとめてトランスフォームできます。

<group position={[0, 1, 0]}>
        <Cube position={[1, 0, 1]} color={"green"} size={[1, 1, 1]} />
        <Cube position={[-1, 0, 1]} color={"red"} size={[1, 1, 1]} />
        <Cube position={[1, 2, 1]} color={"pink"} size={[1, 1, 1]} />
        <Cube position={[-1, 2, 1]} color={"blue"} size={[1, 1, 1]} />
      </group>

まとめ

一見難しそうなThree.jsが、Reactだとコンポーネントのように扱えて、なんとなく簡単に使えるような気がしてきますね。ぽんぽんとコンポーネントを追加してオブジェクトやライトなどをシーンに増やせるので書いてても気持ちがいいです。

あとアニメーションに関してはこちらで記事を書いてますのでよろしければどうぞ。