3.6以下引擎切场景时阴影内存泄漏的非官方补丁

一 现象

如这个帖子所说https://forum.cocos.org/t/topic/113191,Creator3.x场景中开启阴影后,例如阴影贴图使用的是2048*2048,则每一次切换场景都会引起36M(贴图16M+深度20M)的内存泄漏,而且是必现。

这个BUG在3.x引擎一直存在,从3.6开始才没有这个问题,但是我没有找到专门针对这个BUG的fix说明。我们项目用的是3.4.2引擎,上线在即,升级引擎肯定不行,只能自己动手修改引擎源码来解决了。

二 原因分析

在ShadowFlow中有个名为shadowFrameBufferMap的Map对象,Map对象存放着以light为key,值为frameBuffer的对象,frameBuffer创建了阴影和深度共两张纹理。每次切换场景会从 shadowFrameBufferMap 中检索light是否已存在,如果不存在则新创建一个frameBuffer。

现在不知问题在哪,切换场景后light对象属性被修改,导致检索不到,则每次都创建一个新的frameBuffer,也即创建两张新纹理,所以shadowFrameBufferMap越来越大,并且原来的纹理没有释放。

三 临时修复方案

因为每次切换场景时,都会调用 _detachFromScene 来移除light,所以就在这里根据旧light,从 shadowFrameBufferMap 中找到 frameBuffer 来释放,反复测试后没出现问题。

修改Creator3.4.2版本的引擎源码如下。

在 core/pipeline/shadow/shadow-flow.ts 中增加一个方法:

public destroyFrameBufferByLight(light: Light) {
    if (!light || !this._pipeline || !this._pipeline.pipelineSceneData) {
        return;
    }

    const shadowFrameBufferMap = this._pipeline.pipelineSceneData.shadowFrameBufferMap;
    const frameBuffer = shadowFrameBufferMap.get(light);
    if (!frameBuffer) { 
        return; 
    }

    const renderTargets = frameBuffer.colorTextures;
    for (let i = 0; i < renderTargets.length; i++) {
        const renderTarget = renderTargets[i];
        if (renderTarget) {
            renderTarget.destroy();
        }
    }
    renderTargets.length = 0;

    const depth = frameBuffer.depthStencilTexture;
    if (depth) {
        depth.destroy();
    }

    frameBuffer.destroy();
    shadowFrameBufferMap.delete(light);
}

在 render-scene.ts 文件开头,增加:

import { ShadowFlow } from '../../pipeline/shadow/shadow-flow';

在 removeDirectionalLight 函数开头处,增加:

public removeDirectionalLight (dl: DirectionalLight) {
    if (this._root && this._root.pipeline && this._root.pipeline.flows) {
        let shadowFlow = this._root.pipeline.flows[0];
        if (shadowFlow && shadowFlow instanceof ShadowFlow) {
            shadowFlow.destroyFrameBufferByLight(dl);
        }
    }
    // ...
}

说明:
1、因为我的场景只用到了 DirectionalLight ,如果是其它类型的灯光,请自行测试。
2、项目上线在即,不知道这种修改是否有其它问题,请各大佬指示;

1赞

6a5dbcc9502a41af020fef3e301dd9dd