⌨️

[Webブラウザで完結]3D DesignをSplineで。~そして、Reactで使う~

2023/02/01に公開

はじめに

こんにちは、Makottyです。
今回も、面白そうなものをTwitterで見つけたので紹介して行きたいと思います。
実際触ってて、めっちゃ面白かったです。というか面白すぎました。
「17300文字もあるの!?」って思うかもしれませんが、ほとんど画像のURLなので、さらっと流し見してみてください。
文章を読まなくても、画像を見るだけで大体何をやっているか分かると思います。

Splineとは

SplineはWebブラウザだけでも、利用できる3D Design Toolです。
誰でも簡単に3Dのデザインを作成することができ、画像や動画、3Dオブジェクトやコンポーネントとして、自身のプロジェクトに落とし込むことができます。
チームメンバーとリアルタイムで共同作業ができ、共有することもできます。

特徴

  • リアルタイムコラボレーション
  • 3Dモデリング
  • アニメーション
  • インタラクティブな体験
  • 素材の状態変更
  • 3Dスカルプティング

対応する出力形式

  • 公開URL
  • コード(Vanilla JS, Three.js, React, react-three-fiber)
  • 画像(JPG, PNG)
  • 動画(MP4, GIF, WEBM, image sequence)
  • 3D Formats(GLTF, STL, USDZ)

etc...

シーンの最適化

3Dといえば、読み込み時間やオブジェクトの数などパフォーマンスに関わる事がたくさんあると思います。
その最適化について、公式の記事があるので是非合わせて読んでみてください。
https://docs.spline.design/f6351697797e4e41bbf57d62ab905a06

公式サイト

詳しくは公式サイトを見てみて下さい。
見ているだけでワクワクするはずです。
https://spline.design/

公式チュートリアルをやってみる(ちょいアレンジ)

今回は公式のチュートリアル「How to create an interactive 3D keyboard with Spline」をやってみます。

新規プロジェクトの作成

右上のNew Fileから新しいプロジェクトを開始してください。
New File

キーキャップをモデリングする

上部メニューからCubeを選択して下さい。

適当にプロジェクトに配置したら、右クリックし、「Reset Position」を選択し、プロジェクトの中心に移動させてください。

Alt+左クリックなどで見る角度を変えます

グリッドは必要ないので今回はOFFにしておきます。
右のメニューの「Grid Plane」から変更することができます。

右メニューから「Smooth & Edit」を選択し、滑らかにします。

この時、「Subdivision Modifer」の「Level」を0にします。

上部の面を選択し、キーキャップの形に寄せていきます。

「Subdivision Modifer」の「Level」を3にします。

これでは、キーキャップの形には程遠いので、上部メニューから「Loop Cut」を選択、Cubeの横軸の中心を選択し、さらにサブディビジョンを追加します。


すると、「Edge Slide」が使用できるようになったので先ほど追加したサブディビジョンを下に移動します。

同じようにして横軸にサブディビジョンを追加して、次は上に移動したものを作成します。

次は、「Loop Cut」を縦軸で縦横一回ずつ行います。

するとだんだんキーキャップの形になってきているのがわかると思います。

さらに近づけるためサブディビジョンを追加します。

細分化を重ねることでより形状を近づけることができます。


次に上部メニューから「Vertex」を選択し、四つの角、それぞれ二つの頂点をShiftキーを押しながら選択します。

キーキャップ上部に少し丸みをつけます。

次は中心部分を選択し、下に少し下げ、キャップの中心を少しへこまします。(3つを下げた後に、真ん中の部分だけを選択し、さらに少し下げています。)

少しへこんでいるのがわかると思います。

これでキーキャップの完成です。

シーンの背景色を変更する

右のメニューから「Flame」の「BG Color」でお好みの背景色に変更します。
今回は明るめの色を設定していきます。

パレットを使って変更することができるので、自由に変更してください。

ライトの位置を変えてみる

ライトを選択し、右手前から左上に移動します。

キーキャップのマテリアルを作成する

右メニューの「Material」の横の四つの点をクリックします。

マテリアルのウィンドウが出てくるので、「+」で新しいマテリアルを作成します。

マテリアルの名前は「Key Cap」にしておきます。

「Edit Material Asset」ウィンドウで「+」を押して、「Depth」を追加します。

「Lighting」の下に「Depth」を移動し、「Color」を削除します。

「Depth」をクリックして、グラデーションを調整します。
(右の三角形を広げるだけです。)

グラデーションの右の「Color」を変更します。
ここでは#77777を設定します。

「Lighting」の横にあるものを選択し、「Overlay」を選択します。

これでマテリアルの完成です。

キーキャップに刻印する

上部のメニューから「Text」を選択します。

テキストを配置し、上下左右中央揃えにしてキーキャップに刻印します。
「FontSize」は72に設定、X軸の「Position」を0にしてすきな位置に刻印します。

とてもいい感じですね。

キーキャップをグループ化し、複製する

キーキャップと刻印を選択した状態で、Ctrl+Gをしてグループ化します。

グループ名は「W Key」にしておきます。

W Keyを選択した状態でCtrl+Cで複製し、Ctrl+Vでペーストします。
同じ位置に複製されるので、Y軸の矢印(青い矢印)を使用して下に移動します。

刻印を「S」に変更して、グループ名を「S Key」にします。

同じようにして、「A Key」「D Key」を作成します。

これでW,A,S,D Keyを作成することができました。

キーボードの基盤を作る

上部メニューからRectangleを選択します。

基盤をキーキャップの中心に来るように配置します。
WASDをグループ化しておくとそろえやすいです。

この時、RectangleのCorner(角の丸み)は24に指定しておきます。

基盤をY軸方向に下へ移動し、基盤に厚みを持たせます。

右のメニューから「Extrision」を100にしていい感じに配置してください。

「Bevel」と「Bevel Sides」をそれぞれ10,3に設定します。
こうすることで基盤に丸みを持たせることができます。

微調整はお好みで各々行ってください。
最終的に私はこんな感じになりました!

Stateを追加しよう

右のメニューから「States」の「+」を選択し、新しくStateを作成してください。

右の「States」の中に、「BaseState」と「State」が追加されていると思います。

「Base State」は元の状態です。
「State」が青色になっている状態で「W Key」のPositionのY軸を-70に設定します。
これで「W Key」が「押されて沈んでいる状態」を作成することができました。

Eventを追加しよう

右のメニューから「Events」の「+」を選択し、新しくEventを作成してください。

すると作成する「Edit Event」ウィンドウが現れます。

「Start」となっているドロップダウンをクリックすると様々なイベントの種類が出てくると思います。色んなことが出来そうで、わくわくしますね。

今回はまず、「Key Down」(○キーを押したときに発火させるイベント)を選択します。

選択したら、どのキーを押したときに発火させるかを設定できるので、「w」を指定します。

次に「Actions」を指定します。
今回は動きをつけるので、「Transition」を選択します。

実はとりあえずはこれだけで「W Key」が沈むというアニメーションは完成します。
上部メニューから「Play」を選択し、Wキーを押してみてください。

実際の画面です。
「W Key」が沈んでいるのがわかりますね。

沈むアニメーションがぬるっとしていてなんか変なので、
「Duration」を0.07に設定して、遅延を短くします。
(お好みの長さにしてください。)

このまま、元に戻るイベントも追加していきます。
先ほど同様、「Events」の「+」から新たなEventを追加します。

次は、キーを離したときに発火させたいので、「Key Up」を選択します。

先ほど同様、「Key」には「w」を、そして、「Transition」を選択し、「Duration」は、「Key Down」で指定した0.07を指定します。

先ほどと違うのは「To」に指定されているStateです。
今回は発火したら元の位置に戻したいのです。

作成したStateはY軸に-70するものでした。

元に戻す、そう、「Down State」を作る際に一緒に作成された「Base State」を使用します。
「To」に「Base State」を指定します。
これでWキーを離したときに、元の位置に戻ります。

これで、「W Key」の動きは作成できました。

これを、A,S,D Keyでも行います。

完成形!!

めっちゃ面白くないですか?(笑)
これ、めっちゃ押したくなるんですよ...

Reactで使おう!

環境構築⚡

今回も、お馴染みのVite⚡を使用していきます。
Viteについて詳しく知りたい方はこちらをどうぞ。
https://ja.vitejs.dev/guide/

  • npm
npm create vite@latest spline-sample-app --template react-ts
  • yarn
yarn create vite spline-sample-app --template react-ts
成功 ※yarnの場合
yarn create v1.22.17
[1/4] Resolving packages...
[2/4] Fetching packages...
[3/4] Linking dependencies...
[4/4] Building fresh packages...
success Installed "create-vite@4.0.0" with binaries:
      - create-vite
      - cva

Scaffolding project in /home/makotty/MyProject/spline-sample-app...

Done. Now run:

  cd spline-sample-app
  yarn
  yarn dev

Done in 1.83s.

と出ていたら、成功です。
相変わらず速い。

最後に

yarn

を実行するのを忘れないでください。パッケージをインストールします。

フォルダ、ファイルの整理

とりあえず、こんな感じにしておきます。

react-splineの導入

  • npm
npm install @splinetool/react-spline @splinetool/runtime
  • yarn
yarn add @splinetool/react-spline @splinetool/runtime
成功 ※yarnの場合
yarn add v1.22.17
[1/4] Resolving packages...
[2/4] Fetching packages...
[3/4] Linking dependencies...
[4/4] Building fresh packages...
success Saved lockfile.
success Saved 4 new dependencies.
info Direct dependencies
├─ @splinetool/react-spline@2.2.5
└─ @splinetool/runtime@0.9.202
info All dependencies
├─ @splinetool/react-spline@2.2.5
├─ @splinetool/runtime@0.9.202
├─ on-change@4.0.2
└─ react-merge-refs@1.1.0
Done in 5.03s.

SplineからExport

上部メニューから「Export」を選択してください。

「Code Export(Beta)」を選択し、「Export」を選択して出てきたウィンドウの上部のドロップダウンから「React」を選択してください。
いったん真ん中のコードを使用することとします。
(クリップボードでコピーして、App.tsxに貼り付けてください)

App.tsx
import Spline from "@splinetool/react-spline";

const App = () => {
  return (
    <Spline scene="https://prod.spline.design/Ec6djAuEt5dsHz4v/scene.splinecode" />
  );
};

export default App;

これでは、しっかり見れないので、全画面で表示するようにスタイルを適応します。
(index.cssでbodyのmarginを0にしておきます。)

App.tsx
import Spline from "@splinetool/react-spline";

import "./App.css";

const App = () => {
  return (
    <div className="FpsKeyboard">
      <Spline scene="https://prod.spline.design/Ec6djAuEt5dsHz4v/scene.splinecode" />
    </div>
  );
};

export default App;
App.css
.FpsKeyboard {
  width: 100%;
  height: 100vh;
}
index.css
body {
  margin: 0;
}

こちらを実行して、

yarn dev
実行例
  VITE v4.0.4  ready in 266 ms

  ➜  Local:   http://localhost:5173/
  ➜  Network: use --host to expose
  ➜  press h to show help

http://localhost:5173/にアクセスしてみてください。

いい感じですね!
この時点でも、ちゃんと、W,A,S,Dキーを押すと3Dオブジェクトもそれに伴い、動きます。

Splineで作成したEventに連動するイベントをReactで作ってみよう

<Spline>コンポーネントにPropsを渡すことで、Splineで作成したEventに対応するイベントをReactで作ることができるようになります。

受け渡すべきPropsはこちらを参考にしてください。TypeScript用に、型も参考にします。
https://github.com/splinetool/react-spline#spline-component-props

今回は、Splineで「Key Up」と「Key Down」を使用したので、PropsにonKeyUponKeyDownを渡してあげます。

App.tsx
import Spline from "@splinetool/react-spline";
import type { SplineEvent } from "@splinetool/runtime";

import "./App.css";

const App = () => {
  return (
    <div className="FpsKeyboard">
      <Spline
        scene="https://prod.spline.design/Ec6djAuEt5dsHz4v/scene.splinecode"
        onKeyUp={onKeyUp}
        onKeyDown={onKeyDown}
      />
    </div>
  );
};

export default App;

「Key Up」と「Key Down」が実行されたときに実行するイベント、onKeyUponKeyDownを作成していきます。

App.tsx
import Spline from "@splinetool/react-spline";
import type { SplineEvent } from "@splinetool/runtime";

import "./App.css";

const App = () => {
  const onKeyUp = (e: SplineEvent) => {
    console.log("Key Up");
  };

  const onKeyDown = (e: SplineEvent) => {
    console.log("Key Down");
  };

  return (
    <div className="FpsKeyboard">
      <Spline
        scene="https://prod.spline.design/Ec6djAuEt5dsHz4v/scene.splinecode"
        onKeyUp={onKeyUp}
        onKeyDown={onKeyDown}
      />
    </div>
  );
};

export default App;

W,A,S,Dどれかのキーを押したり離したりすると、DevToolのコンソールに、Key Up, Key Downと表示されるはずです。

次はこれを、W,A,S,Dキーそれぞれに分けていきます。

if (e.target.name === "W Key") return console.log("w key up");

こうすることで、各Keyに対するイベントを実行することができます。
詳しくはこちらをどうぞ!
https://github.com/splinetool/react-spline#listen-to-events

条件式に書いている"W Key"はSpline側で決めたオブジェクトの名前です。
(Cube(キーキャップ)とText(刻印)が一緒になったグループの名前ですね。)

これをすべてのキーに適応した関数を書いていきます。

App.tsx
import Spline from "@splinetool/react-spline";
import type { SplineEvent } from "@splinetool/runtime";

import "./App.css";

const App = () => {
  const onKeyUp = (e: SplineEvent) => {
    if (e.target.name === "W Key") return console.log("w key up");
    if (e.target.name === "A Key") return console.log("a key up");
    if (e.target.name === "S Key") return console.log("s key up");
    if (e.target.name === "D Key") return console.log("d key up");
  };

  const onKeyDown = (e: SplineEvent) => {
    if (e.target.name === "W Key") return console.log("w key down");
    if (e.target.name === "A Key") return console.log("a key down");
    if (e.target.name === "S Key") return console.log("s key down");
    if (e.target.name === "D Key") return console.log("d key down");
  };

  return (
    <div className="FpsKeyboard">
      <Spline
        scene="https://prod.spline.design/Ec6djAuEt5dsHz4v/scene.splinecode"
        onKeyUp={onKeyUp}
        onKeyDown={onKeyDown}
      />
    </div>
  );
};

export default App;

もっといい書き方があるのは重々承知ですが、とりあえずでいいのでこれで行きます。

DevToolのコンソールを見てみると、押したり離したりしたキーに対する出力が行われているはずです。

これで、
Wキーを押している間(W KeyのKey Down発火)は前進をして、
Wキーを離すと(W KeyのKey Up発火)停止する、
Aキーを押している間(A KeyのKey Down発火)は左前進をして、
Aキーを離すと(A KeyのKey Up発火)停止する
Sキーを押している間(S KeyのKey Down発火)は後退をして、
Sキーを離すと(S KeyのKey Up発火)停止する、
Dキーを押している間(D KeyのKey Down発火)は右前進をして、
Dキーを離すと(D KeyのKey Up発火)停止するなどといったゲームみたいな動きを作ることができ、さらに、プレイヤーがどんな操作をしているのかが視覚的に分かるものを3Dモデルで簡単に作成できるなと感じました。

最後に今回作成した作品のGitHubを貼っておきます。
git cloneして、いろいろ触ってみてください。
https://github.com/Makotty/spline-sample-app

Splineで公開URLも作れるのでそれも載せておきます。
https://my.spline.design/3dfpskey-a1d459b0458da4002b8f01290d7bb0a8/

まとめ

今回は、Twitterで見つけた「Spline」を紹介しました。
記事制作を通し、僕自身、様々な可能性を感じ、プライベートでもいろいろ作ってみたいなと思いました。
また、以前紹介した「Rive」とも組み合わせると、インタラクティブで面白い作品が作れそうだなと感じました。
もし、何か作品を作り上げることができた時は、Twitterなどで公開したいと思います。

Splineにはありすぎるくらい様々なチュートリアルがあります。
これをちょっとやってみるだけでめちゃくちゃ楽しめると思います。
ぜひ、少しでも興味を持ってくださった方がいれば、お暇な時にやってみてほしいと心の底から思います。

今回はこちらの記事を最後まで見てくださりありがとうございました。
沢山の方にこの記事を見ていただけると嬉しいので、ぜひ拡散してくださると喜びます(⌒∇⌒)

JUNNI

Discussion