自动合批(USE INSTANCING)层级乱了

Cocos creator 1.1.2 版本
使用USE INSTANCING合批之后,层级显示全乱了。

请仔细看下图,红色一会在下,一会在上,一会又在下。(每一个红色圆圈,都是一个quad)



1赞

不同颜色之间不要合批试试(使用不同的材质)

熊猫大神你好。
不同颜色现在就是不同材质,每个材质我勾选了USE INSTANCEING。
不同颜色的quad我都是放在同一节点下面,合批的时候确实是同材质之间才会合批。但是层级显示会乱掉。
比如红色,有时候上层,下一帧又在下层了。。

材质的 Pass 有一个 priority 属性,调整一下

https://docs.cocos.com/creator3d/manual/zh/material-system/pass-parameter-list.html

P大,刚刚测试了一下,也是同样的问题。

补充一下:
我们是一个涂色游戏,每一个色块都是一个quad。
如果不开启USE INSTACEING,Draw call能到1000+,非常卡。(浏览器不卡,微信小游戏卡的要死,不知道为什么)

p大,这个是不是引擎的BUG啊?如果是的话,我暂时不处理了,我们这边真是查了4,5天没找到解决方案。

quad 是否是开启透明的呢?透明物体本身其实是不适合合批的,因为绘制顺序没法保证,现在引擎虽然没有限制,但理论上透明和合批只能二选一噢。

哦对另外引擎的 instance queue 里好像的确没有根据 priority 排序,这可能是你遇到的问题,我明天看下

每个颜色设置一个z

我把quad的透明关了。
甚至把quad换成不透明的圆柱体也是一样的。渲染层级乱了

那听起来有问题,不透明的圆柱体之间应该有正常的深度检测的呀,不可能再乱了,是不是把深度检测或写入关了?

原先的Y坐标我都设置为0,现在每一个我都给一个数值(逐渐增大)之后就正常显示。
Cocos creator 版本1.1.2
测试,正常batching…并且显示正常

嗯嗯,针对你的需求,可能最好的办法是保持深度写入和检测开启,然后不同颜色给不同的 z 值来解决。blending 可以根据需求开启,看起来你也没有需要半透明,z 值赋个偏移绕开 z-fighting 就好

3.6.2 instancing 的优先度依旧不能调整
我这里有个需求是, 有多个相同模型的物件需要关闭深度测试盖在所有模型的前面
有试过使用摄像机分层, 但该物件的阴影绘制有困难

instancing 的物件也需要有优先度的排序功能
时隔两年这功能该补上了
@panda @jare

需要修改instancing queue 来实现材质排序

/*

Copyright © 2020-2023 Xiamen Yaji Software Co., Ltd.

https://www.cocos.com/

Permission is hereby granted, free of charge, to any person obtaining a copy

of this software and associated documentation files (the “Software”), to deal

in the Software without restriction, including without limitation the rights to

use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies

of the Software, and to permit persons to whom the Software is furnished to do so,

subject to the following conditions:

The above copyright notice and this permission notice shall be included in

all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

THE SOFTWARE.

*/

import { InstancedBuffer } from ‘./instanced-buffer’;

import { Device, RenderPass, PipelineState, CommandBuffer, DescriptorSet } from ‘…/gfx’;

import { PipelineStateManager } from ‘./pipeline-state-manager’;

import { SetIndex } from ‘./define’;

/**

  • @en Render queue for instanced batching

  • @zh 渲染合批队列。

*/

export class RenderInstancedQueue {

/**

 * @en A set of instanced buffer

 * @zh Instance 合批缓存集合。

 */

public queue = new Set<InstancedBuffer>();

private _renderQueue: InstancedBuffer[] = [];

private _renderNoBlendQueue: InstancedBuffer[] = [];

private _renderBlendQueue: InstancedBuffer[] = [];

/**

 * @en Clear the render queue

 * @zh 清空渲染队列。

 */

public clear (): void {

    const it = this.queue.values(); let res = it.next();

    while (!res.done) {

        res.value.clear();

        res = it.next();

    }

    this._renderQueue.length = 0;

    this._renderNoBlendQueue.length = 0;

    this._renderBlendQueue.length = 0;

    this.queue.clear();

}

public sort (): void {

    let it = this.queue.values();

    let res = it.next();

    while (!res.done) {

        if (!(res.value.pass.blendState.targets[0].blend)) {

            // this._renderQueue.push(res.value);

            this._renderNoBlendQueue.push(res.value);

        }

        res = it.next();

    }

    it = this.queue.values();

    res = it.next();

    while (!res.done) {

        if (res.value.pass.blendState.targets[0].blend) {

            // this._renderQueue.push(res.value);

            this._renderBlendQueue.push(res.value);

        }

        res = it.next();

    }

    this._renderNoBlendQueue.sort((a:InstancedBuffer,b:InstancedBuffer)=>{return a.pass.priority - b.pass.priority;});

    this._renderBlendQueue.sort((a:InstancedBuffer,b:InstancedBuffer)=>{return a.pass.priority - b.pass.priority;});

    this._renderQueue.push(...this._renderNoBlendQueue);

    this._renderQueue.push(...this._renderBlendQueue);

}

public uploadBuffers (cmdBuff: CommandBuffer): void {

    const it = this.queue.values(); let res = it.next();

    while (!res.done) {

        if (res.value.hasPendingModels) res.value.uploadBuffers(cmdBuff);

        res = it.next();

    }

}

/**

 * @en Record command buffer for the current queue

 * @zh 记录命令缓冲。

 * @param cmdBuff The command buffer to store the result

 */

public recordCommandBuffer (

    device: Device,

    renderPass: RenderPass,

    cmdBuff: CommandBuffer,

    descriptorSet: DescriptorSet | null = null,

    dynamicOffsets?: Readonly<number[]>,

): void {

    const it = this._renderQueue.length === 0 ? this.queue.values() : this._renderQueue[Symbol.iterator]();

    let res = it.next();

    while (!res.done) {

        const { instances, pass, hasPendingModels } = res.value;

        if (hasPendingModels) {

            cmdBuff.bindDescriptorSet(SetIndex.MATERIAL, pass.descriptorSet);

            let lastPSO: PipelineState | null = null;

            for (let b = 0; b < instances.length; ++b) {

                const instance = instances[b];

                if (!instance.count) { continue; }

                const shader = instance.shader;

                const pso = PipelineStateManager.getOrCreatePipelineState(device, pass, shader!, renderPass, instance.ia);

                if (lastPSO !== pso) {

                    cmdBuff.bindPipelineState(pso);

                    lastPSO = pso;

                }

                if (descriptorSet) cmdBuff.bindDescriptorSet(SetIndex.GLOBAL, descriptorSet);

                if (dynamicOffsets) {

                    cmdBuff.bindDescriptorSet(SetIndex.LOCAL, instance.descriptorSet, dynamicOffsets);

                } else {

                    cmdBuff.bindDescriptorSet(SetIndex.LOCAL, instance.descriptorSet, res.value.dynamicOffsets);

                }

                cmdBuff.bindInputAssembler(instance.ia);

                cmdBuff.draw(instance.ia);

            }

        }

        res = it.next();

    }

}

}

这是3.8.1的修改后的代码,可以使用材质pass的priority调整instancing顺序。如果不改这里,那么现在的官方实现里只能是一个instancing对象首次被使用时,被插入队列,后插后画。