[LayaAir 1.0]1.0 骨骼drawcall优化猥琐方法

适合那些这辈子都不可能把项目迁移到2.0的童鞋
 
先说下1.0里骨骼渲染大致流程:
大概是从BoneSlot开始,draw方法中大体上会把部件分为两种,
一种是简单贴图,没有作蒙皮的,这个最终blablabla是通过SubmitTexture提交渲染的,SubmitTexture对drawcall是有优化的,它会通过WebGLContext2D里的字段_renderKey(一个私有字段到处全局赋值也是醉了),去检查当前待渲染贴图和上一张贴图是否符合优化条件,去决定是否在一个Submit里塞上多份绘制数据 ;
所以如果动画部件是连续的简单贴图,那dawcall是可以合并的;
然后就是蒙皮的部件了,1.0里面每个BoneSlot的draw里如果发现需要绘制的是带蒙皮的部件,就会创建一个Submit,这里没有诸如SubmitTexture一样的猥琐合批操作,
 
 
 
所以我们可以自己魔改啊ヾ(=゚・゚=)ノ喵♪
 
 
思路大致上是这样的,先贴一下SkinMesh里相关方法:
        public function render(context:*, x:Number, y:Number):void {
            if (Render.isWebGL && mTexture) {
                context._renderKey = 0;
                context._shader2D.glTexture = null;
                SkinMeshBuffer.getInstance().addSkinMesh(this);
// todo : 这是是不是可以合并下同一贴图的submit?
                var tempSubmit:Submit = Submit.createShape(context, mIBBuffer, mVBBuffer, mEleNum, _indexStart, Value2D.create(ShaderDefines2D.SKINMESH, 0));
                transform || (transform = Matrix.EMPTY);
                transform.translate(x, y);
                Matrix.mul(transform, context._curMat, _tempMatrix);
                transform.translate( -x, -y);
                //此处每次都创建新的数组,应该可以改成使用对象池
                
                var tShaderValue:SkinSV = tempSubmit.shaderValue as SkinSV;
                var tArray:Array = tShaderValue.u_mmat2||RenderState2D.getMatrArray();
                RenderState2D.mat2MatArray(_tempMatrix, tArray); 
                tShaderValue.textureHost = mTexture;
                tShaderValue.offsetX = 0;
                tShaderValue.offsetY = 0;
                tShaderValue.u_mmat2 = tArray;
                tShaderValue.ALPHA = context._shader2D.ALPHA;
                context._submits[context._submits._length++] = tempSubmit;
            }
            else if (Render.isConchApp&&mTexture)
            {               
                transform || (transform=Matrix.EMPTY);
                context.setSkinMesh&&context.setSkinMesh(x, y, _ps, mVBData, mEleNum, 0, mTexture,this.transform );
            }
            
        }
 
要做的就是当发现当前绘制的贴图符合合批条件时,不要新建Submit了,而是直接把绘制数据塞上一个Submit里去,
这里主要是要处理一下u_mmat2,把变换这步从shader里挪出来,在这里
        private function _initMyData():void
        {
            var vsI:int=0;
            var vI:int=0;
            var vLen:int= _verticles.length;
            var tempVLen:int = vLen * 4;
            _vs = _tempVS;
            var insertNew:Boolean=false;
            if (Render.isConchNode || Render.isConchApp)
            {
                _vs.length = tempVLen;
                insertNew = true;
            }else
            {
                if (_vs.length < tempVLen)
                {
                    _vs.length = tempVLen;
                    insertNew = true;
                }
            }
            _tVSLen = tempVLen;
            if (insertNew)
            {
                while (vsI < tempVLen)
                {
                    _vs[vsI] = _verticles[vI];
                    _vs[vsI + 1] = _verticles[vI + 1];
                    _vs[vsI + 2] = _uvs[vI];
                    _vs[vsI + 3] = _uvs[vI + 1];
                    _vs[vsI + 4] = 1;
                    _vs[vsI + 5] = 1;
                    _vs[vsI + 6] = 1;
                    _vs[vsI + 7] = 1;
                    vsI += 8;
                    vI += 2;
                }
            }else
            {
                while (vsI < tempVLen)
                {
                    _vs[vsI] = _verticles[vI];
                    _vs[vsI + 1] = _verticles[vI + 1];
                    _vs[vsI + 2] = _uvs[vI];
                    _vs[vsI + 3] = _uvs[vI + 1];
                    vsI += 8;
                    vI += 2;
                }
            }
            
        }
 
处理掉,具体怎么处理Matrix类里有现成的,就懒得说啦XD
 
再然后,贴一下Submit里的相关方法
/*
         create方法只传对submit设置的值
         */
        public static function createSubmit(context:WebGLContext2D, ib:IndexBuffer2D, vb:VertexBuffer2D, pos:int, sv:Value2D):Submit {
            var o:Submit = _cache._length ? _cache[--_cache._length] : new Submit();
            
            if (vb == null) {
                vb = o._selfVb || (o._selfVb = VertexBuffer2D.create(-1));
                vb.clear();
                pos = 0;
            }
            o._ib = ib;
            o._vb = vb;
            
            o._startIdx = pos * CONST3D2D.BYTES_PIDX;
            o._numEle = 0;
            var blendType:int = context._nBlendType;
            o._blendFn = context._targets ? BlendMode.targetFns[blendType] : BlendMode.fns[blendType];
            o.shaderValue = sv;
            o.shaderValue.setValue(context._shader2D);
            var filters:Array = context._shader2D.filters;
            filters && o.shaderValue.setFilters(filters);
            return o;
        }
 
在创建的时候,如果发现本帧中,上一个ISubmit是Submit,并且使用的 贴图是一样的,那么就不创建新的Submit了,直接把上一个Submit的_numEle加一下这次要创建的顶点数就好了;
 
再再然后怎么判断上一个ISubmit,就自己各显神通啦,我自己是在每个submit类里创建时候赋值一下全局变量lastSubmit来辅助判断的
 
已邀请:

yc999999

赞同来自:

可以请教一下这个问题吗
 

yc999999

赞同来自:

多谢

182*****089

赞同来自:

大神,能把你具体处理的几个引擎库分享下我吗?

victor3345

赞同来自:

希望能把具体处理的几个引擎文件代码分享一下。没相关知识真的很难自己魔改啊

要回复问题请先

商务合作
商务合作