WebGLを使ったグリグリ動くWebコンテンツをチームで作ってみた：解説【デザインエンジニア編】

# 初めに
WebGLで3Dを活用したWebサイト、「 [3DWebSite](https://playcanvas-demo.jp/examples/web/3dwebsite/) 」をPlayCanvasを利用して開発しました。
![Imgur](https://imgur.com/bj1IEIF.png)

- PlayCanvas : https://playcanvas.jp
- 3DWebsite : https://playcanvas-demo.jp/examples/web/3dwebsite/

ここでは、3DWebSiteを開発した際に得られた、__ゲームエンジンを利用してWebサイトを作る__知見を残すためそれぞれの担当メンバーが解説記事を執筆しています。

**解説記事一覧**

- [【3Dエンジニア編】](https://qiita.com/utautattaro/items/23f6bc6d3f50b21bf52f)
- [【3Dモデラー編】](https://qiita.com/shujimuna1102/items/89947ffd6a4a79ff1db5)
- [【フロントエンドエンジニア編】](https://qiita.com/yushimatenjin/items/de1aa22ab05fa45d79cc)
- [【デザインエンジニア編】](https://qiita.com/sutobu000/items/827df2d1cd77b5c4b025) ←**今ここ！！！**


3DWebSite解説【デザインエンジニア編】
---
[3DWebsite](https://playcanvas-demo.jp/examples/web/3dwebsite/)の**【DOM要素】**を担当したキドユウタ([@sutobu000](https://twitter.com/sutobu000))が、DOMの追加などをざっくばらんに解説していきます。

ちなみに、デザインエンジニアってなんぞやと思いますが単なる肩書であって、ここではマークアップなどのコーディングのことを話してます。
大してデザインの話はしていません。

\---

# Web(DOM)でPlayCanvasに何をしたのか
PlayCanvas内部のjsはWebと言うよりもゲーム寄りでWebに浸しみのある人には抵抗があるかもしれません…
そこで、PlayCanvasとwebのDOM要素を組み合わせるために以下のことを行いました。

- DOMの作成
- DOMをPlayCanvas内に追加
- DOMとPlayCanvasの連携

順を追って説明します。

## DOMの作成
あらかじめPlayCanvas内で使用するDOMを作成します。
PlayCanvas独自のコードエディターではJS以外のコーディングはしづらいので、自分の使い慣れたコードエディターで用意します。
今回PlayCanvasで作成するのは3Dwebsiteです。
その中でカルーセルを用意しDOMは各場面ごとに切り替わるように設計します。
カルーセルの設計はclass名を参照して今何ページ目が表示されているかを制御するようにしています。
そのため以下のようにhtmlを用意します。

- Top (index.html)
- Page01 (content01.html)
- Page02 (content02.html)
- Page03 (content03.html)
- Page04 (content04.html)

中のコードは以下のようなテンプレートパーツのようにしています。

```html
<div class="content__wrapper">
  <div class="content__inner">
    <h1 class="content__logo">LOGO</h1>
    <div class="content__btn">
      <div class="content__btn__item content__btn__item-left"></div>
      <div class="content__btn__item content__btn__item-right"></div>
    </div>
  </div>
</div>
```

上記の5ページをカルーセルでページ切り替えを行います。
htmlだけではなく、cssも合わせて用意します。

## DOMの追加
PlayCanvasに作成したDOMなどを追加します。
アセットに追加していくのですが、DOMの修正を行う場合にはPlayCanvasのコードエディターを使うことになります。
あらかじめローカルで作成していたコードと差異が危惧されますが、PlayCanvasのアセットに自動uploadしてくれるnpmパッケージ(playcanvas-node、playcanvas-gulp)が用意されています。
これを使うことで、ローカルでコード編集しつつオンライン上のPlayCanvasのアセットにも反映されるようになり、編集の手間が少なくなります。

PlayCanvas内にDOMを追加する方法はGUIなどで用意されているわけではなく、jsから追加することになります。
HTMLのheadタグやbodyタグに対し、appendChild()やinnerHTML、insertAdjacentHTML()などでhtmlを追加します。
以下のようにDOMの追加が行われます。cssも同様にhead内に追加します。

![image (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109168/18191862-af69-4e42-aea8-55fc11fa0fad.png)

##DOMとPlayCanvasの連携
カルーセルでDOMのページが切り替わるようになっていますが、このページごとにカメラのPositionも変更されるようにします。

DOMのページ数に合わせて、カメラのPositionも同じ数を設定します。
entityにenabledのcheckをfalseにしたカメラのPositionを設定しておきます。

![3DA080D77DE68A06CB9AC7448A16E248.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109168/9f12bf2d-4aa1-a2bf-1380-107ab14427f8.png)


これを使ってこのページではこのカメラのPosition、というようにします。

- Top [cameraPosition00(x,y,z)]
- Page01 [cameraPosition01(x,y,z)]
- Page02 [cameraPosition02(x,y,z)]
- Page03 [cameraPosition03(x,y,z)]
- Page04 [cameraPosition04(x,y,z)]

そのために、何ページ目が開かれた時の処理を作成します。
canvasの開発側で用意された setCameraSequence() というカメラのPositionを何ページ目の数値を引数で渡すことでカメラのPositionをTweenさせる関数を使います。

これを使って、今何ページが開いているのかを参照するためにページ数の変数を作成します。
これを使ってDOMとカメラのPositionを合わせて変更できるようにしました。

ちなみに、ページ数はグローバル変数で登録しています。
Canvas側の開発者との連携の際にお互いに使用するため、グローバル変数で現在のページ数を登録しています。

## 簡単にまとめるとDOMの構造はこんな感じ
今回はカルーセルのような構造ということで、特定のclass名が指定されたDOMを表示するといったものにしています。
先の説明で以下の画像のようにDOMはappendChild()などでbodyタグに追加しています。
この時、cssでは.is-showのclass名が指定されていれば表示されるように設定しておきます。
![img01.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109168/75fea35a-43f9-c3f2-f32f-0bb7384eb62c.jpeg)

グローバル変数に現在のページ数を保持していることを、先で説明しています。
これを使い、今はどのページを開いているのかを参照します。
開いているページには、.is-showのclass名を付与して表示させています。
以下の画像ではopacityを使って表示を切り替えているように説明していますが、実際にはz-indexも変更するようにしています。
アニメーションもCSS3のtransitionを使っていたり…この辺りはいろんなやり方がありますので色々試していい感じのものを使うのが良いです。
![img02.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109168/1b20914f-be62-7002-9fae-4349fbda4bbd.jpeg)

---

DOM開発は、あらかじめDOMのパーツを作成してそれをCanvasと連携できるように追加するのが基本になりそうです。

このようにCanvas開発側とDOM開発側はどこかしらで作業が共通し、同じデータを使用することがあります。
その場合にはグローバル変数などでお互いに触れるデータを作成し、どのように使用するのかを事前にplayCanvas内のチャットなどでやり取りする必要があるかもしれません。