2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

LiveView on Babylon.js でチュートリアルの1章やってみた

Posted at

はじめに

この記事はElixirアドベントカレンダー2025のシリーズ2、10日目の記事です

今回はBabylon.jsのチュートリアルの1章をLiveView+Babylon.jsでやっていく記事になります

Hooksの作成

前回はちょろっとだけだったのでColocatedHookで操作しましたが、しっかりと書く場合はちゃんとJS Hookとして書いた方が良いのでhooksを設定してきます

チャプターごとにHabylonxxx.jsを作成してHooksで読み込んでまとめます
それをapp.jsで展開するという感じです

assets/js/BabylonHookxxx.js
const BabylonHookxxx = {
  mounted() {
    const canvas = document.getElementById("renderCanvas");
    const engine = new BABYLON.Engine(canvas, true);
  },
};

export default BabylonHook;
assets/js/hooks.js
const Hooks = {
};

export default Hooks;
assets/js/app.js
import { Socket } from "phoenix";
import { LiveSocket } from "phoenix_live_view";
import { hooks as colocatedHooks } from "phoenix-colocated/babylon";
import topbar from "../vendor/topbar";
+ import Hooks from "./hooks";

const csrfToken = document
  .querySelector("meta[name='csrf-token']")
  .getAttribute("content");
const liveSocket = new LiveSocket("/live", Socket, {
  longPollFallbackMs: 2500,
  params: { _csrf_token: csrfToken },
-  hooks: { ...colocatedHooks},  
+  hooks: { ...colocatedHooks, ...Hooks },
});

1-01 HelloWorld

チュートリアル1-01のHelloWorldをやります、豆腐の出現ですね

チュートリアルのシーン一覧みたいにしたいので色々手を加えていきます

home
-> チュートリアル1-01
-> チュートリアル1-03
のような感じですね

lib/babylon_web/live/home_live.ex
defmodule BabylonWeb.HomeLive do
  use BabylonWeb, :live_view

  def render(assigns) do
    ~H"""
    <Layouts.app flash={@flash}>
      <div class="flex flex-col w-1/2 gap-4">
        <.button navigate={~p"/ch101"}>Chapter1-01</.button>
      </div>
    </Layouts.app>
    """
  end
end

一覧に追加したら、ルーティングにも追加します

lib/babylon_web/router.ex
  scope "/", BabylonWeb do
    pipe_through :browser

    live "/", HomeLive
+   live "/ch101", Ch101Live
  end

追加したら画面を作っていきます、戻るボタンをつけたヘッダーとCanvasを表示します
hookの指定は先程作成した BablyonHook101を指定します

lib/babylon_web/live/ch101_live.ex
defmodule BabylonWeb.Ch101Live do
  use BabylonWeb, :live_view

  def render(assigns) do
    ~H"""
    <div class="p-4">
      <.header>
        Chapter 1-01
        <:actions><.button navigate={~p"/"}>Back</.button></:actions>
      </.header>
    </div>
    <canvas class="w-screen h-[88vh]" id="renderCanvas" phx-hook="BabylonHook101" phx-update="ignore">
    </canvas>
    """
  end
end

hooksはこのように貼り付けます

チュートリアルにはありませんがengine.runRenderLoopしないとレンダリングされないので注意してください

assets/js/BabylonHook101.js
const BabylonHook101 = {
  mounted() {
    const canvas = document.getElementById("renderCanvas");
    const engine = new BABYLON.Engine(canvas, true);
        // シーンを作成
    const scene = new BABYLON.Scene(engine);
    // カメラを作成
    const camera = new BABYLON.ArcRotateCamera(
      "camera",
      -Math.PI / 2,
      Math.PI / 2.5,
      3,
      new BABYLON.Vector3(0, 0, 0),
      scene
    );
    // ユーザからの入力でカメラをコントロールするため、カメラをキャンバスにアタッチ
    camera.attachControl(canvas, true);
    // ライトを作成
    const light = new BABYLON.HemisphericLight(
      "light",
      new BABYLON.Vector3(0, 1, 0),
      scene
    );
    // 箱 (豆腐) を作成
    const box = BABYLON.MeshBuilder.CreateBox("box", {}, scene);

    engine.runRenderLoop(() => {
      scene.render();
    });

  },
};

export default BabylonHook101;
assets/js/hooks.js
import BabylonHook101 from "./BabylonHook101";
const Hooks = {
  BabylonHook101: BabylonHook101,
};

export default Hooks;

動かすとこんな感じ

de996f5d87fe3c66b75b2328158bbc14.gif

1-03 モデル(シーン)の読み込み

02はviewの話なので飛ばして、モデルの読み込みですね

lib/babylon_web/live/home_live.ex
defmodule BabylonWeb.HomeLive do
  use BabylonWeb, :live_view

  def render(assigns) do
    ~H"""
    <Layouts.app flash={@flash}>
      <div class="flex flex-col w-1/2 gap-4">
        <.button navigate={~p"/ch101"}>Chapter1-01</.button>
+       <.button navigate={~p"/ch103"}>Chapter1-03</.button>        
      </div>
    </Layouts.app>
    """
  end
end

一覧に追加したら、ルーティングにも追加します

lib/babylon_web/router.ex
  scope "/", BabylonWeb do
    pipe_through :browser

    live "/", HomeLive
    live "/ch101", Ch101Live
+   live "/ch103", Ch103Live   
  end

公式のシーンを読み込むコードがあるのでそちらを以下の変更します
Elixirやってるとめっちゃ副作用発生して気持ち悪いっすね・・・

流れ的には

  1. scene読み込み完了
  2. sceneからメッシュ名で取得してy方向に2移動
  3. インデックスで取得してy方向に1移動
  4. sceneを返却
  5. レンダリング開始

となってますね

assets/js/BabylonHook103.js
const BabylonHook103 = {
  mounted() {
    const canvas = document.getElementById("renderCanvas");
    const engine = new BABYLON.Engine(canvas, true);
    const scene = new BABYLON.Scene(engine);
    createAttachment(scene, canvas);
    loadScene(scene);

    engine.runRenderLoop(() => {
      scene.render();
    });
  },
};

const createAttachment = ({ scene, canvas }) => {
  const camera = new BABYLON.ArcRotateCamera(
    "camera",
    -Math.PI / 2,
    Math.PI / 2.5,
    15,
    new BABYLON.Vector3(0, 0, 0),
    scene
  );
  camera.attachControl(canvas, true);
  new BABYLON.HemisphericLight("light", new BABYLON.Vector3(1, 1, 0), scene);
};

const loadScene = (scene) => {
  // モデル読み込み
  BABYLON.SceneLoader.ImportMeshAsync(
    "",
    "https://assets.babylonjs.com/meshes/",
    "both_houses_scene.babylon",
    scene
  ).then((result) => {
    // 読み込みが完了したら
    const house1 = scene.getMeshByName("detached_house");
    house1.position.y = 2; // y 軸方向(↑)に +2
    const house2 = result.meshes[2];
    house2.position.y = 1;
  });
};

export default BabylonHook103;
assets/js/hooks.js
import BabylonHook101 from "./BabylonHook101";
+ import BabylonHook103 from "./BabylonHook103";

const Hooks = {
  BabylonHook101: BabylonHook101,
+ BabylonHook103: BabylonHook103,
};

export default Hooks;

追加したら画面を作っていきます、戻るボタンをつけたヘッダーとCanvasを表示します
hookの指定は先程作成した BablyonHook103を指定します

lib/babylon_web/live/ch103_live.ex
defmodule BabylonWeb.Ch103Live do
  use BabylonWeb, :live_view

  def render(assigns) do
    ~H"""
    <div class="p-4">
      <.header>
        Chapter 1-03
        <:actions><.button navigate={~p"/"}>Back</.button></:actions>
      </.header>
    </div>
    <canvas class="w-screen h-[88vh]" id="renderCanvas" phx-hook="BabylonHook103" phx-update="ignore">
    </canvas>
    """
  end
end

こんな感じで表示されます

e8ef20e53e8320b50626b30977894889.gif

最後に

1-02、1-04はWebページで表示する方法なので今回はスキップしました
まだほぼ貼り付けるだけなので、LiveViewに乗せる利点のほうがでてくるとよいかな・・・

次回は2章を進めていきます本記事は以上になりますありがとうございました

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?