Souzen Yurama Notes

It's huge notepad for memo.


Vue3 + Babylon.jsで Engine や Scene 初期化失敗(this._engine._features is undefined)

結論

  • <canvas>以外に対して Engine や Scene を割り当てようとしている。
    • これはengineの canvasContenxt の判定で失敗する。<div>とかに割り当てようとしていると失敗する。
  • Vue2, Vue3の created() 下でEngineやSceneを割り当てようとしている
    • ちゃんと調べていないが、Vue側でテンプレートが読み込まれて、canvasContextとして割り当てられる前に処理が行われるので失敗する。
      created() 内で console.log(this.$refs.myCanvas); すると、undefined が返っているが、これでも engine は初期化できてしまう。
    • mount() 内で初期化するとOK。

調査

sceneで _engine._feature が undefined になっているところから調査。

まず、Sceneの実装は次の箇所。

https://github.com/s-yurama/Babylon.js/blob/master/packages/dev/core/src/scene.ts

そうすると、まず Scene内のEngine初期化は次にあった。

    // Private
    private _engine: Engine;

そして、Engineは次のimportから、場所がわかる。

import type { Engine } from "./Engines/engine";

なので、

https://github.com/s-yurama/Babylon.js/blob/master/packages/dev/core/src/Engines/engine.ts

で、 _feature が初期化されている場所を調べていく。

その前に、

    constructor(
        canvasOrContext: Nullable<HTMLCanvasElement | OffscreenCanvas | WebGLRenderingContext | WebGL2RenderingContext>,
        antialias?: boolean,
        options?: EngineOptions,
        adaptToDeviceRatio: boolean = false
    ) {
        super(canvasOrContext, antialias, options, adaptToDeviceRatio);

        Engine.Instances.push(this);

        if (!canvasOrContext) {
            return;
        }

        this._features.supportRenderPasses = true;

で、ThinEngineextendsしているので、次に見るのは

https://github.com/s-yurama/Babylon.js/blob/master/packages/dev/core/src/Engines/thinEngine.ts


そうすると、次の行があり、 _features を保持していることがわかった。

    /** @internal */
    public _features: EngineFeatures;

これが初期化されていない原因を追う。


まず、初期化しているのは次の箇所。

    protected _initFeatures(): void {
        this._features = {
//

次に、このメソッドが呼ばれているかを追いかける。


呼んでいるのはコンストラクタだけだった。

    constructor(
        canvasOrContext: Nullable<HTMLCanvasElement | OffscreenCanvas | WebGLRenderingContext | WebGL2RenderingContext>,
        antialias?: boolean,
        options?: EngineOptions,
        adaptToDeviceRatio?: boolean
    ) {

(中略)

    this.resize();

    this._initGLContext();
    this._initFeatures();

そうすると、次の行でreturnしていたことがわかった。
( divに対してengineを割り当てようとすると、中身が無いのでここでreturnしてしまう。 )

        if (!canvasOrContext) {
            return;
        }

そうすると、初期化用のメソッドを呼んでいる次に至るまでには、
上記のreturnしかない。

このため、canvasではない場合、_feature を作れていないと判断。