NGUI将使用相同atlas的组件,归类到一个drawcall中,也就是这些组件的绘制,只消耗一次gl调用。这样来提高gup的绘制效率。
其原理如下:
UPPanel作为drawcall的组织归类结构,以下UIPanel简称panel。panel会根据自己child的层次,将不同的UIWidget归结到不同的drawcall中。
理论归结过程如下:
将所有的panel的child按照deep排序,如果deep相同,则按照metrial,否则按照metrial的instanceid。
[System.Diagnostics.DebuggerHidden]
[System.Diagnostics.DebuggerStepThrough]static public int PanelCompareFunc (UIWidget left, UIWidget right){if (left.mDepth < right.mDepth) return -1;if (left.mDepth > right.mDepth) return 1;Material leftMat = left.material;Material rightMat = right.material;if (leftMat == rightMat) return 0;if (leftMat != null) return -1;if (rightMat != null) return 1;return (leftMat.GetInstanceID() < rightMat.GetInstanceID()) ? -1 : 1;}从最小的开始查起,标记最小的使用的atlas。进入下一个,如果和上一个使用同一个atlas,则将这两个uiwidget归纳在同一个drawcall里。如果是不同的atlas,则创建不同的drawcall。
注意:
1、即使使用同一个atals,如果deep不同,并且位于deep1和deep2之间有使用其他atals的widget,则也会产生两个drawcall。
(原因:不同的深度间,不可能同一个drawcall绘制,会出现遮挡倒序的问题。
注意事项:如果两个widget使用同一个atlas,则尽量将其deep设置的相同或者相邻,最好是在设计之初,就给不同的atlas设计好其所应该属于的deep。)
2、尽量将ui上的元素归结到atlas中,这样能增加绘制效率。如果不需要特别为其制定shader的话,尽量用sprite替代texture2d(因为texture2d需要单独一个drawcall)。
相关代码:
/// <summary>
/// Fill the geometry fully, processing all widgets and re-creating all draw calls.
/// </summary>
void FillAllDrawCalls ()
{
for (int i = 0; i < drawCalls.size; ++i)
UIDrawCall.Destroy(drawCalls.buffer[i]);
drawCalls.Clear();
Material mat = null;
Texture tex = null;
Shader sdr = null;
UIDrawCall dc = null;
if (mSortWidgets) SortWidgets();
for (int i = 0; i < widgets.size; ++i)
{
UIWidget w = widgets.buffer[i];
if (w.isVisible && w.hasVertices)
{
Material mt = w.material;
Texture tx = w.mainTexture;
Shader sd = w.shader;
if (mat != mt || tex != tx || sdr != sd)
{
if (mVerts.size != 0)
{
SubmitDrawCall(dc);
dc = null;
}
mat = mt;
tex = tx;
sdr = sd;
}
if (mat != null || sdr != null || tex != null)
{
if (dc == null)
{
dc = UIDrawCall.Create(this, mat, tex, sdr);
dc.depthStart = w.depth;
dc.depthEnd = dc.depthStart;
dc.panel = this;
}
else
{
int rd = w.depth;
if (rd < dc.depthStart) dc.depthStart = rd;
if (rd > dc.depthEnd) dc.depthEnd = rd;
}
w.drawCall = dc;
if (generateNormals) w.WriteToBuffers(mVerts, mUvs, mCols, mNorms, mTans);
else w.WriteToBuffers(mVerts, mUvs, mCols, null, null);
}
}
else w.drawCall = null;
}
if (mVerts.size != 0) SubmitDrawCall(dc);
}