引擎底层存在无效循环的数据结构设计,建议修改

最近阅读3.2.1 的引擎源码
看了渲染流程的发现 3d model 和 2d batch 的渲染过程都是通过每个camera 去遍历所有的 对象去过滤所需渲染object。这种方式有点简单粗暴了,如果场景对象多 camera 多的情况下存在很多无效循环的开销。
建议
public addModel (m: Model) {
m.attachToScene(this);
this._models.push(m);
ModelArrayPool.push(this._modelArrayHandle, m.handle);
}
应该按model 所属 layer 去存储model
_models : Map<number, Array>
public addModel (m: Model) {
m.attachToScene(this);

let layer = m.node.layer;
let arr = this._models.get(layer);
if( arr == null){
	arr = new Array();
	this._models.set(layer, arr);
}
arr.push(m);
ModelArrayPool.push(this._modelArrayHandle, m.handle);

}

camera 寻找自己关心的 model 只需要根据visible 获取自己关心layer

const modelsmap = scene.models;
const visibility = camera.visibility;
const layer = 1;

while(layer <= visibility){
if(layer & visibility != 0){
let models = modelsmap.get(layer);
for (let i = 0; i < models.length; i++) {
const model = models[i];

        // filter model by view visibility
        if (model.enabled) {
            if (model.node && ((visibility & model.node.layer) === model.node.layer)
                || (visibility & model.visFlags)) {
                // shadow render Object
                if (shadowObjects != null && model.castShadow && model.worldBounds) {
                    if (!_castBoundsInited) {
                        _castWorldBounds.copy(model.worldBounds);
                        _castBoundsInited = true;
                    }
                    AABB.merge(_castWorldBounds, _castWorldBounds, model.worldBounds);
                    shadowObjects.push(getCastShadowRenderObject(model, camera));
                }
                // frustum culling
                if (model.worldBounds && !intersect.aabbFrustum(model.worldBounds, camera.frustum)) {
                    continue;
                }

                renderObjects.push(getRenderObject(model, camera));
            }
        }
    }
}
layer <= 1;

}

这样能在 model 过多的场景情况下能节省大量的无效循环操作,另外2d 渲染的batch 也是同样的情况。
一般我们ui 摄像头和 3d 模型摄像头使用时都是独立的layer来的。目前底层的设计其实是会导致无效的循环。如果摄像头增加 模型数量增加的情况下这回导致我们渲染耗时浪费很大部分在这种无效的空循环过程。

4赞

我相信我发这玩意,肯定有人会说我不知天高地厚了,觉得这两者差别不大。但是js 本身性能低下的情况下这种无畏的开销我觉得能够避免还是应该规避,而且在大量模型和camera多的情况下这种开销算下来还是比较客观的。

目测回不了本。
每个节点原先被每个摄像机遍历一次,改为用Map查询一次,但是Map的hashkey计算是要时间的,这个结构的时间复杂度常数就比较高。

每帧用Array重新组织所有节点,加重GC。
只适用于特定场合,比如所有节点layer都永远不变化的情况下做特殊优化。

把性能分析测试结果发出来,有理有据让人信服,你就比天高比地厚就是神。

思路我觉得没问题,目前的无效遍历损耗确实存在

兄弟这还需要性能分享报告么。看代码就知道是无效循环。不要无脑喷呀

既然panda都说了那是在下错了:innocent:

你说的问题也存在的,需要维护 model 的 layer 更新逻辑,这块少不了额外的事件监听和处理。map 的检索性能和节省的遍历比起来应该是有收益的。

题主的实现不一定是最合理的实现,但是在 TS 中减少 scene culling 的遍历肯定是有必要的

culling 能给个开关吗?
实际有些游戏,本来就一个范围全可见,
用户自己控制就好,减少损耗。

大佬可以提交一个pr,帮助引擎引改进一下性能。

你的帖子已经被社区标记并被临时隐藏。

我这个实现主要是想表示这个可以提前分组减少不必要的循环。如果不怕麻烦不用map其实一个32的数组就够了。毕竟只要32位layer就够了。之所以我回去深究这些点主要是最近在优化游戏性能。再优化完游戏逻辑后看到引擎底层还有这方面的浪费感觉挺可惜的。本身目前引擎性能还存在一定问题的情况下这种浪费我觉得是值得去细究的。毕竟这种改动不大但是收益是明显的。我也是被逼疯了。目前游戏render time iOS能有20ms感觉任何浪费我都想节省下来。也是希望引擎越来越好!

嗯嗯,理解,这个思路对于普通模型 model 问题不大,对于 2d draw batch 可能会有排序问题,还需要仔细推敲一下。这块是肯定需要优化的,不仅是场景的模型收集和剔除,更重要的还有光源和阴影的收集剔除。

也欢迎提交你的解决方案到仓库,我们也会给你审核和完整的反馈

谢谢楼主的建议,所有无关且无意义的争论已被删除

1赞

人家LZ发现了问题,发帖出来,不管怎么说,官方或开源贡献者首先应该与LZ沟通了解情况,而不是两句话一说就开嘴炮,就算是LZ最后的建议不被官方采纳,LZ也是一片好心,楼主一开始说话有点责怪的意思,但是事实就是这样啊,CC本来就在成长中,还有很多问题需要改进。人家抱怨一下也是正常的,像这样的BUG贴我感觉才是社区中对CC最有益的帖子,人家帮你找到了BUG你还喷了人家一脸,开源贡献者有点飘了,大神确实是大神,我也拜读过不少的帖子,但是大神+平易近人才是真正的大神

还好吧?这个帖子不是都在正常讨论问题吗,哪有开嘴炮的。。

被隐藏被删除

被删帖的就一个人,而且那个人是针对官方的,不是针对发帖人的

na,na,na,好一个“所有”,是怕别人觉得你们不够光明是吧?

有点意思,我可没对官方引擎有看法,官方论坛管理人员滥用职权倒是一如既往