疑难杂症小记

来源:互联网 发布:java下载源码 编辑:程序博客网 时间:2024/06/03 12:54

  

  说来其实也不算什么疑难杂症,原因后面再叙,只是最近遇到个代码问题确实令我犯了好一阵疑难,在此简单一记,算作总结吧~

 

  起因颇为简单,平时工作时无意瞟了一眼NGUIUILabel实现,其中有段实现字体阴影的代码,原理来说其实挺清晰的,就是将原先用以渲染文本的顶点数据原样拷贝一份,然后做些位置偏移和颜色改变即可,代码大概是这副样子~


// generate original vertex dataNGUIText.Print(text, verts, uvs, cols);// apply an effect if one was requestedif (effectStyle != Effect.None){// apply shadow vertex dataApplyShadow(verts, uvs, cols, offset, end, pos.x, -pos.y);}

  浮光掠影的看了一下,突然想到一个问题:既然ApplyShadow整体复制了一份文本顶点数据,那么最终生成的顶点数据大概就是:

 

  v1, v2, v3, ... , c1, c2, c3, ... 

  (其中v1, v2, v3, ... 为原始顶点数据、c1, c2, c3, ... 为复制后的顶点数据)

 

  那么问题来了,既然这些顶点是在同一个drawcall中进行绘制的,那么为何c1, c2, c3, ...的绘制结果总是在v1, v2, v3, ... 之后呢?如果不能保证这个绘制顺序,那么自然也不能正确的实现文本阴影的渲染~

 

  依着这个疑问,首先瞅了下相关的NGUI Shader实现,大概来看还是相对简单的,代码大抵是这样:


// shader headerSubShader{Tags{"Queue" = "Transparent""IgnoreProjector" = "True""RenderType" = "Transparent"}Cull OffLighting OffZWrite OffOffset -1, -1Fog { Mode Off }Blend SrcAlpha OneMinusSrcAlphaPass{CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"struct appdata_t{float4 vertex : POSITION;half4 color : COLOR;float2 texcoord : TEXCOORD0;};struct v2f{float4 vertex : POSITION;half4 color : COLOR;float2 texcoord : TEXCOORD0;};sampler2D _MainTex;v2f vert (appdata_t v){v2f o;o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);o.texcoord = v.texcoord;o.color = v.color;return o;}half4 frag (v2f i) : COLOR{half4 col = i.color;col.a *= tex2D(_MainTex, i.texcoord).a;return col;}ENDCG}}// other SubShaders

  简单上张图~


  值得注意的就是Shader关闭了ZWrite,这将导致所有的顶点都会被渲染至framebuffer,如果我们尝试打开下ZWriteZ-fighting便如期而至了~


  但是目前虽然确定了所有顶点都会被渲染,但是各个顶点间的渲染顺序还不能确定,普通渲染一般都会打开ZWrite,那么这时的渲染顺序其实并不重要,因为最终的绘制顺序会由ZBuffer来保证,可惜这里的ZWrite被关闭了~

 

  继续Google了一阵,觉得还是请教下熟悉这块的同事效率更高,于是问了下引擎组的同事,几次询问讨论下来,确定了渲染顺序的问题:

 

  即顶点的渲染顺序与其提交至GPU的顺序是一致的(至少“看上去”是的,GPU可以在保证渲染结果正确性的基础上进行优化),所以如果那上面的例子来说的话:

 

   v1, v2, v3, ... , 会首先绘制,然后绘制c1, c2, c3, ... 

 

  WTF,如果是这样的话,文本的阴影就会一直显示在文本之上!但是同事的一个简单示例又确实说明了这种渲染顺序的正确性,没办法,事实证明还有猫腻的地方,得再细查一下~

 

  重新回头深入看了一下之前那个想当然的ApplyShadow,终于发现了蹊跷:

/// <summary>/// Apply a shadow effect to the buffer./// </summary>public void ApplyShadow (BetterList<Vector3> verts, BetterList<Vector2> uvs, BetterList<Color32> cols, int start, int end, float x, float y){// implementation details ...for (int i = start; i < end; ++i){    // add copy buffer dataverts.Add(verts.buffer[i]);uvs.Add(uvs.buffer[i]);cols.Add(cols.buffer[i]);// update verts.buffer[i]Vector3 v = verts.buffer[i];v.x += x;v.y += y;verts.buffer[i] = v;// implementation details ...// update cols.buffer[i]}}

  原来该方法是将阴影顶点数据加到了原顶点数据之前!还是按照之前的示例来说,正确的顶点数据应该是:

 

  c1, c2, c3, ..., v1, v2, v3, ...

  (其中v1, v2, v3, ... 为原始顶点数据、c1, c2, c3, ... 为复制后的顶点数据)

 

  看到此,终算是全身通畅了,SO上也有相关的解答(好像还提到了例外的情况,不是十分熟悉),Spec也大概了浏览了一下,不过暂时没有定位到十分相关的说明,有 了解的童鞋可以告之一下~

 

  就这样吧~



0 0
原创粉丝点击