spine设置成3d节点后勾选 Enable Batch 导致 z 坐标无效

creator版本 2.4.3
在项目中发现,将spine设置为3d节点后,可以正常显示3d效果,但是当勾选了 Enable Batch ,开启合批功能后,会导致3d效果显示无效。于是翻看了一下源码,最终在 spine-assembler.js 中发现了问题。
在这个文件中可以找到这样一段代码:

let worldMat = undefined;

        if (_comp.enableBatch) {

            worldMat = _node._worldMatrix;

            _mustFlush = false;

            _handleVal |= FLAG_BATCH;

        }

        if (comp.isAnimationCached()) {

            // Traverse input assembler.

            this.cacheTraverse(worldMat);

        } else {

            if (_vertexEffect) _vertexEffect.begin(comp._skeleton);

            this.realTimeTraverse(worldMat);

            if (_vertexEffect) _vertexEffect.end();

        }

这里我们可以看到当spine开启合批功能( _comp.enableBatch )后,就将这个节点的世界矩阵传给 cacheTraverse 或 realTimeTraverse方法,来计算spine的渲染顶点,在这两个方法里面,我发现这样一段代码。

if (worldMat) {
                    worldMatm = worldMat.m;

                    _m00 = worldMatm[0];

                    _m04 = worldMatm[4];

                    _m12 = worldMatm[12];

                    _m01 = worldMatm[1];

                    _m05 = worldMatm[5];

                    _m13 = worldMatm[13];

                    for (let ii = _vertexFloatOffset, nn = _vertexFloatOffset + _vertexFloatCount; ii < nn; ii += _perVertexSize) {

                        _x = vbuf[ii];

                        _y = vbuf[ii + 1];

                        vbuf[ii] = _x * _m00 + _y * _m04 + _m12;

                        vbuf[ii + 1] = _x * _m01 + _y * _m05 + _m13;

                    }

                }

截取的 realTimeTraverse 里面的代码,在 cacheTraverse 里面也有类似的代码。
这段代码的意思很明确,只计算了 x 和 y 坐标,也就是没计算 z 坐标。
cocos合批的原理是什么?就是用世界矩阵计算出所有需要合批的渲染图元的世界坐标,这样,在shader里面就只有vp矩阵,没有m矩阵。而vp矩阵是所有节点共用的,于是,就不会因为mvp矩阵(shader里面的一个uniform)的不同而打断合批。sprite的合批也是一样的原理。
这样虽然减少了drawcall,但是增加了矩阵的计算量。cocos为了节省性能,只计算了x、y坐标,导致z坐标一直为0,于是3d显示无效。
没有开启合批的时候,矩阵是直接由shader来计算的,里面包含了z坐标的变换信息(需要将节点设置成3d节点,否则,矩阵里面也不会有z坐标的数据),所以可以显示3d效果。
怎么做可以既让3d起效,又可以合批呢?
这里有一个方法,把具有相同变换的spine节点放到同一个父节点下,然后将这个节点设置成3d节点,shader里面的m矩阵设置成这个父节点的世界矩阵,shader里面的顶点坐标设置成spine顶点相对父节点的坐标,这样,即有3d效果,又可以减少drawcall。

感谢反馈,这个问题,我们已经内部反馈并记录了。

现在有个新需求,多个spine共用一套纹理和altas,但是creator编辑器不支持绑定纹理和altas。于是想要自己加载json文件,这时会被creator识别成spine文件,由于没有对应的纹理,加载出来的是json对象,不是cc.Asset类型,会报 addRef 方法找不到的错误。加载的时候修改type也没有效果。

问题出在asset-manager文件夹下的load.js文件里面,assets.get(uuid)获取的不是资源类型,是对象。我看了下map,其他的都是正常的资源类型。

你的 API 是怎么调用的?