three.jsでメモリのクリーンアップを続けます

前書き



最近、three.jsを使用してアプリケーションのメモリをクリーンアップした経験について書きました目標は、gltfモデルをロードしていくつかのシーンを再描画することであったことを思い出させてください。



それ以来、私は多くの実験を行ってきましたが、この小さな記事で前に言ったことを補足する必要があると思います。アプリケーションのパフォーマンスを向上させるのに役立ったいくつかのポイントがあります。



主要部分



three.jsでのゴミ収集のさまざまな例を研究して、threejsfundamentals.orgで提案されたアプローチに興味がありましたただし、提案された構成を実装し、this.track()ですべてのマテリアルとジオメトリをラップした後、新しいシーンをロードするときにGPUの負荷が増大し続けることが判明しました。さらに、提案された例は、EffectComposerおよび後処理用の他のクラスでは正しく機能しません。これらのクラスではtrack()を使用できないためです。



使用されるすべてのクラスにResourceTrackerを追加したソリューションは、明らかな理由で魅力的ではないため、前述のクラスをクリーニングする方法を補足することにしました。使用されているテクニックのいくつかを次に示します。



レセプション1。ラフ



クリーンアップメソッドの後にrenderer.infoを追加します。どのリソースが負荷を構成し、テクスチャまたはマテリアルに隠されているかを理解するために、アプリケーションからリソースを1つずつ削除します。これは問題を解決する方法ではなく、誰かが知らないかもしれないデバッグの方法にすぎません。



レセプション2。ロング



使用するクラスのコード(たとえば、three.js githubにあるAfterimagePass)を開いたら、必要なフレームワーク内でジオメトリとマテリアルの数を維持するためにクリーンアップする必要があるリソースが作成される場所を確認します。



this.textureComp = new WebGLRenderTarget( window.innerWidth, window.innerHeight, { ... }


それがあなたが必要なものです。ドキュメントによると、WebGLRenderTargetにはメモリをクリーンアップするためのdispose関数があります。次のようなものが得られます。



class Scene {
//...
    postprocessing_init(){ //   
        this.afterimagePass = new AfterimagePass(0);
        this.composer.addPass(this.afterimagePass);
    }
//...
}
//...

class ResourceTracker {
//...
    dispose() {
    //...
    sceneObject.afterimagePass.WebGLRenderTarget.dispose();
    //...
    }
}


レセプション3



動作しますが、この場合、クリーンアップコードが肥大化します。前回の記事でおなじみのアプローチを使ってみましょう。その中で、disposeNode(ノード)メソッドを実装したことを思い出してください。このメソッドでは、クリーンアップできるものを見つけるためにリソースが繰り返されました。disposeNode()は次のようになります。



disposeNode(node) {
            node.parent = undefined;
            if (node.geometry) {
                node.geometry.dispose();
            }
            let material = node.material;
            if (material) {
                if (material.map) {
                    material.map.dispose();
                }
                if (material.lightMap) {
                    material.lightMap.dispose();
                }
                if (material.bumpMap) {
                    material.bumpMap.dispose();
                }
                if (material.normalMap) {
                    material.normalMap.dispose();
                }
                if (material.specularMap) {
                    material.specularMap.dispose();
                }
                if (material.envMap) {
                    material.envMap.dispose();
                }
                material.dispose();
            }
        } else if (node.constructor.name === "Object3D") {
            node.parent.remove(node);
            node.parent = undefined;
        }
    }


では、使用したすべての追加クラスを取得して、ResourceTrackerに追加しましょう。



dispose() {
    for (let key in sceneObject.afterimagePass) {
        this.disposeNode(sceneObject.afterimagePass[key]);
    }
    for (let key in sceneObject.bloomPass) {
        this.disposeNode(sceneObject.bloomPass[key]);
    }
    for (let key in sceneObject.composer) {
        this.disposeNode(sceneObject.composer[key]);
    }
}


結果



これらすべてのアクションの結果として、FPSを大幅に増やし、アプリケーションのGPU負荷を減らしました。ResourceTrackerを誤って使用した可能性がありますが、とにかく追加のクラスには役立ちません。disposeNode(ノード)を介してEffectComposerを繰り返すことが、メモリ内のテクスチャの数に影響を与えることはどこにも見たことがありません(ただし、これがその方法です)。この問題は個別に検討する必要があります。



比較のために、以前のバージョンは古いアドレスのままですが、新しいバージョンは個別表示できます



プロジェクトは、何らかの形でgithubにあります。



同様のプロジェクトでの経験を聞いて、詳細について話し合っていただければ幸いです。



All Articles