【個人開発】Next.jsでのWebサイト制作 #3　トップページ紹介とThree.jsによる3Dモデルの実装紹介

Next.jsでのWebサイト制作 #3　では、トップページ紹介とThree.jsによる3Dモデルの実装紹介をしたいと思います。

## トップページ紹介
トップページは以下のようになっています。（ぜひアクセスしてご覧ください。）

https://ty-official-hp-14.vercel.app/


* メイン画像＋メインメッセージ　部分
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3817219/61f240ca-8e41-8f9f-845b-8859b5e91f3b.png)


* メッセージ部分
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3817219/dec4b0cc-b4cf-1902-dd61-7f7f217941f6.png)

* ブログ最新記事部分
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3817219/35d509a3-0183-f0d1-e45a-34e8e222ad77.png)


### メイン画像＋メインメッセージ　部分
この部分では、画像スライドショーとアニメーションによるメッセージの出現を実装しています。
ここで使用している技術は、以下過去記事にて紹介させていただいておりますので、ここでの説明は割愛させていただきます。

https://qiita.com/Naoto_eng_7010/items/3c9ff4548a05d9b8d798

https://qiita.com/Naoto_eng_7010/items/058498fd6442a2900ff3

### ブログ最新記事部分
ブログ最新記事部分では、Blogページ（microCMSからデータを取得）にて掲載している記事のうち、最新のものを表示する仕様となっています。

ここで使用している技術は、Blogページの回で紹介予定ですので、今回は割愛させていただきます。

### メッセージ部分
今回の記事は、このメッセージ部分における、3Dモデル「動く地球」の実装方法をメインに紹介します。
3Dモデルは、Three.jsという Javascriptライブラリを用いて実装しています。

![タイトルなし.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3817219/9570c01f-1caf-457b-7bb5-7dbb40c2e00c.gif)


## Three.jsとは？

Three.jsは、Webブラウザ上で3Dモデルを簡単に表示できるJavaScriptライブラリです。

JavaScriptの基本的な知識があれば、Three.jsを用いてWebブラウザ上に3Dモデルや3Dアニメーションを簡単に表示できるようになります。

もともと、WebGLという3Dモデルを扱う技術があったそうですが、かなり難易度が高いようです。（私は全く学んだことありません。。）

Three.jsを使うことでWebGLを使うよりも圧倒的に簡単に実装できます。

## 実装方法

### 3Dモデルのダウンロード
今回は以下サイトから3Dモデルを「GLTF」フォーマットでダウンロードし、public/modelsに格納しました。

https://sketchfab.com/3d-models/earth-0caafb7e837047a688a3e504c0ea74af

### インストール
```bash
npm install three
```

TypeScript使用時は型ファイルのインストールも必要
```bash
npm install @type/three
```

### 実装
以下が実際のコードです。
処理ごとの意味、説明は、コメントに記載してあります。

私自身、初めてThree.jsを扱ったため、わからないことが多く、「ググって。。。うまく動かないところを修正して。。。」の繰り返しでした。
そのため、あまり詳しい説明ができていませんが、ご了承ください。。。。

 ```tsx
import { useEffect, useRef } from "react";
import * as THREE from "three";
import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";

// ３Dモデル

function Earth() {
  // ３Dモデルを表示したい部分のDOM要素をuseRefでもってくる
  const canvasRef = useRef<HTMLCanvasElement | null>(null);

  // useEffect内に３Dモデルの設定を書くことで、レンダリング時に３Dモデルが生成されるようになる。
  // Three.jsで３Dモデルを出力するには、以下に定義する、scene, camera, rendererの３つのオブジェクトが最低限必要となる。
  useEffect(() => {
    const canvas = canvasRef.current as HTMLCanvasElement;

    const sizes = {
      width: 350,
      height: 370,
    };

    // scene（3D空間全体の情報をもつオブジェクト）
    const scene = new THREE.Scene();

    // camera（３Dモデルをどのように画面に映すかを、カメラをのぞいた時のようなイメージで定義できるオブジェクト）
    const camera = new THREE.PerspectiveCamera(
      85, //垂直視野
      sizes.width / sizes.height, //アスペクト比
      0.1, //Near（奥行きの手前側）
      1000 //Far（奥行きの最奥）→NearとFarの間にあるものが画面に映し出される。
    );
    camera.position.set(0, 0, 2); //カメラ自体の位置（x軸, y軸, z軸）

    // renderer（レンダリング設定）
    const renderer: THREE.WebGLRenderer = new THREE.WebGLRenderer({
      canvas: canvas, //useRefでとってきた要素。ここに３Dモデルがレンダリングされる。
      antialias: true, //3Dモデルの端を滑らかにする。
      alpha: true, //背景の設定（透明にしたい場合はtrue）
    });
    renderer.setSize(sizes.width, sizes.height); //ここの記述はお決まり。
    renderer.setPixelRatio(window.devicePixelRatio); //ここの記述はお決まり。

    // ライトの設定（この設定がないと映らない３Dモデルがある）
    const light = new THREE.PointLight(0xffffff, 1); //特定の方向からのライト（第１引数：光の色、第２引数：光の強さ）
    light.position.set(0, 1, 1); //sceneから見たライトの位置　（第１引数：x軸、第２引数：y軸、第３引数：z軸）
    scene.add(light); //sceneにライトを紐付け
    const ambientLight = new THREE.AmbientLight(0xffffff, 0.5); //全方向からのライト≒モデルそのものの光度（第１引数：光の色、第２引数：光の強さ）
    scene.add(ambientLight); //sceneにライトを紐付け

    // GLTFモデルのインポート
    let model: THREE.Object3D<THREE.Object3DEventMap>; // モデルを格納する変数
    const gltfLoader = new GLTFLoader();
    gltfLoader.load("/models/earth.gltf", (gltf) => {
      model = gltf.scene;
      model.scale.set(0.14, 0.14, 0.14); //modelの大きさ（スケール）を設定
      scene.add(model); //sceneにmodelを紐付け
    });

    // アニメーション
    const tick = () => {
      if (model) {
        // modelを回転させる
        model.rotation.y += 0.0025; // Y軸周りに毎フレーム回転（数字はスピード）
      }
      renderer.render(scene, camera); // 現在のシーンをカメラの視点からレンダリング（描画）（ここの記述はお決まり。）
      requestAnimationFrame(tick); // ブラウザに次の再描画のフレームでtick関数を呼び出すように要求（ここの記述はお決まり。）
    };
    tick(); //初回のアニメーションフレームを開始するためにtick関数を一度呼び出す（ここの記述はお決まり。）
  }, []);

  return (
    <canvas
      id="canvas"
      ref={canvasRef}
      className="  mx-auto  xl:ml-[67%]"
    ></canvas>
  );
}

export default Earth;

 ```

 上記実装により、３DモデルをWebブラウザに表示することができます。


## 最後に
今回は、トップページ（特に３Dモデル部分）について紹介させていただきました。
Three.jsはWebGLに比べると簡単にかけるものとは言われていますが、私としては十分難しかったです。。笑

次回は、Garalleyページ、Blogページについて、紹介させていただきたいと思います。

最後までお読みいただきありがとうございました！！

p.s.
Qiitaの記事をより多くの人に読んでもらう方法を教えてください！
タイトルを検索されやすいようなタイトルにする、くらいはやってみようと思っていますが、その他何かありましたらご教授いただければ幸いです！！！