公開日 2019年6月25日

かわいい3Dエンジン「Zdog」の紹介

先日、CodePenを眺めていたところ、Zdogというものを見つけて、とてもよかったので一通りドキュメントをみていろいろ作ってみました。

いつもならそれで終わりなのですが、6 月 4 日にリリースされたばかり1で日が浅く、まだ日本語の情報が少なかったため、自分のための備忘録も兼ねて簡単にご紹介します。

Zdog とは

zzzdog.png

Round, flat, designer-friendly pseudo-3D engine for canvas & SVG

フラットで丸みを帯びたレンダリングがなされる擬似 3D エンジンです。

sushidesu2.gif こんなのや、

zdog.gif こんなのが簡単に作れます。 ロゴがこうやってぐりぐり動かせるのとてもいいと思います。

Zdog v1 is a beta-release, of sorts.

まだベータ版ということで、V2 が現在開発中2のようです。

Zdog 入門

せっかくなので、公式ドキュメントの Getting started を参考にしながら、Zdog で 3D モデルを表示して、ドラッグで動かすまでをやっていこうと思います。

インストール

公式ドキュメントには 3 通りの導入方法が紹介されていました。詳しくは公式サイトをご覧ください。

今回は、CDN を使います。

0. 準備

下記のサンプルコードは CDN を利用する場合の例です。この記事ではこのサンプルコードを使って説明していきます。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>Zdog Tutorial</title>
    <script src="https://unpkg.com/zdog@1/dist/zdog.dist.min.js"></script>
  </head>
  <body>
    <canvas width="240" height="240" class="zdog-canvas"></canvas>
    <script>
      // ここにコードを記述
    </script>
  </body>
</html>

1. Illustrationインスタンスを作成

まず初めに親となるIllustrationインスタンスを作成します。

// ここにコードを記述
const illo = new Zdog.Illustration({
  element: ".zdog-canvas",
})

element: '.zdog-canvas'とすることで表示する<canvas>要素を指定しています。

illust.jpg

<canvas>要素と結び付けたIllustrationに、この後登場するEllipseShapeなどの図形を追加していき、最後にIllustrationをレンダリングするという流れになります。

2. 図形を追加

今回は円を表示してみようと思います。

// ここにコードを記述
const illo = new Zdog.Illustration({
  element: ".zdog-canvas",
})

// 円を追加
new Zdog.Ellipse({
  addTo: illo,
  diameter: 80, // 直径
  stroke: 20, // 線の太さ
  color: "#E62", // 図形の色
})

addTo: illoとすることで先程作成したIllustrationに図形を追加しています。 ただ、まだ追加しただけでレンダリングを行っていないので図形は表示されません。

3. レンダリング

// ここにコードを記述
const illo = new Zdog.Illustration({
  element: ".zdog-canvas",
})

// 円を追加
new Zdog.Ellipse({
  addTo: illo,
  diameter: 80, // 直径
  stroke: 20, // 線の太さ
  color: "#E62", // 図形の色
})

// 図形を描画
illo.updateRenderGraph()

IllustrationクラスのupdateRenderGraphメソッドを呼び出すことで図形をレンダリングします。

start3.jpg

たった 3 ステップでフラットな 3D 図形を表示することができました!

しかし、このままだと動かないので 3D っぽくありません。ということで、次は図形をアニメーションさせてみようと思います。

4. アニメーション

アニメーション用の関数を作成して、requestAnimationFrame()に渡します。

// - 省略 -
const animate = () => {
  illo.rotate.x += 0.03
  illo.rotate.y += 0.03 // 図形を回転
  illo.updateRenderGraph() // 回転後の図形を描画

  requestAnimationFrame(animate) // 再度呼び出し
}
animate()

move2.gif

くるくる回ります!

5. ドラッグで回転

// ここにコードを記述
const illo = new Zdog.Illustration({
  element: ".zdog-canvas",
  dragRotate: true, // ←これを追加
})

dragRotate: trueと設定するだけです。簡単にぐりぐりできます!

drag.gif

完成

初心者の私でも特につまずくことなく 3D 図形を表示して、ドラッグでぐりぐりすることができました!

Zdog is friendly. Modeling is done with a straight-forward declarative API.

とあるようにとても直感的でわかりやすいですね。

最後に、完成したコードを改めて記しておきます。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>Zdog Tutorial</title>
    <script src="https://unpkg.com/zdog@1/dist/zdog.dist.min.js"></script>
  </head>
  <body>
    <canvas width="240" height="240" class="zdog-canvas"></canvas>
    <script>
      // ここにコードを記述
      const illo = new Zdog.Illustration({
        element: ".zdog-canvas",
        dragRotate: true,
      })

      new Zdog.Ellipse({
        addTo: illo,
        diameter: 80, // 直径
        stroke: 20, // 線の太さ
        color: "#E62", // 図形の色
      })

      const animate = () => {
        illo.rotate.x -= 0.03
        illo.rotate.y += 0.03 // 図形を回転
        illo.updateRenderGraph() // 回転後の図形を描画

        requestAnimationFrame(animate) // 再度呼び出し
      }
      animate()
    </script>
  </body>
</html>

番外編:ネコをつくる 😹

これだけだとドキュメントまんまなので、番外編としてネコをつくってみます。少し長いので隠してあります。

クリックして開く

頭をつくる

neko_1.jpg

const head = new Zdog.Shape({
  addTo: illo,
  stroke: 200,
  color: "#9ED",
})

頭を作ります。Shapeクラスはパスで様々な形状の図形を作ることができますが、何も指定しない場合、ただの点が作られます。今回はその点の太さを調整して、球をつくっています。

右耳を作る

ネコといえば耳なので耳を作ります。Polygonクラスを使うと多角形を作ることができますが、今回は先ほど使ったShapeにパスを指定して三角形を作っています。

const ear_right = new Zdog.Shape({
  addTo: illo,
  stroke: 20,
  fill: true,
  path: [
    { x: 0, y: -10 },
    { x: 30, y: 30 },
    { x: -30, y: 30 },
  ],
  translate: { x: -90, y: -80, z: 10 },
  rotate: { z: -0.6 },
})

translaterotateを指定することで、図形の位置を調整することができます。

neko_2.jpg

まだネコではありません。

左耳を作る

目や耳など、同じものを何個も作るときには、copy()メソッドを使うと便利です。

// ear_left
ear_right.copy({
  addTo: illo,
  translate: { x: 90, y: -80, z: 10 },
  rotate: { z: 0.6 },
})

引数として、様々なオプションを渡すことで、位置や大きさなどを調整できます。

neko_3.jpg

まだネコではありません(目がないので)

目を作る

Ellipseで円を作る際にquartersを指定することで半円が作れます。

const eye_right = new Zdog.Ellipse({
  addTo: illo,
  diameter: 40,
  quarters: 2,
  stroke: 10,
  rotate: { z: -Zdog.TAU / 4 },
  translate: { x: -40, z: 90 },
})
// eye_left
eye_right.copy({
  translate: { x: 40, z: 90 },
})

図形を 1/4 や 1/2 などキリの良い単位で回転させたい場合はZdog.TAUを使います。

neko_4.jpg

これはネコです。(目があるので)

口があるとかわいいので

Shapeを使って線を引いていきます。頂点の x,y,z 軸を示すオブジェクトを渡すだけなのでとても簡単です。

const mouth = new Zdog.Shape({
  addTo: illo,
  stroke: 8,
  path: [{ x: -14 }, { x: 14 }],
  translate: { y: 20, z: 90 },
})

neko_5.jpg

よりネコらしくなりました。でもまだ何か足りない気もします。

ひげも必要でした

口と同じ要領でpathをひいて位置を調整します。

// ひげ
const hige_left = new Zdog.Group({
  addTo: illo,
  translate: { x: -90, y: 10, z: 60 },
})

// 1本目のひげ
const hige = new Zdog.Shape({
  addTo: hige_left,
  stroke: 9,
  path: [{ x: 15 }, { x: -15 }],
  rotate: { z: 0.4 },
})
// 2本目のひげ
hige.copy({
  translate: { y: 40 },
  rotate: { z: -0.2 },
})

// まとめて複製
hige_left.copyGraph({
  rotate: { z: Zdog.TAU / 2 },
  translate: { x: 90, y: 50, z: 60 },
})

ひげのように複数の図形をまとめるときに便利なのがGroupです。addToに作成したGroupを指定することでまとめることができます。

copy()メソッドは、子孫のアイテムまでコピーしてくれないので、まとめた図形を複製する際はcopyGraph()メソッドを使います。

完成

neko_6.jpg

かわいいネコができました!一応、こちらにコードも載せておきます。

おわりに

簡単な説明ということで物足りない部分もあるかと思いますが、参考になれば幸いです。

また、この Zdog をいたるところに使って3作成したホームページがあります。よろしければぜひご覧ください。

参考