疑难杂症小记

69 篇文章 5 订阅
63 篇文章 1 订阅

  

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

 

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


// generate original vertex data
NGUIText.Print(text, verts, uvs, cols);

// apply an effect if one was requested
if (effectStyle != Effect.None)
{
	// apply shadow vertex data
	ApplyShadow(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 header

SubShader
{
	Tags
	{
		"Queue" = "Transparent"
		"IgnoreProjector" = "True"
		"RenderType" = "Transparent"
	}

	Cull Off
	Lighting Off
	ZWrite Off
	Offset -1, -1
	Fog { Mode Off }
	Blend SrcAlpha OneMinusSrcAlpha

	Pass
	{
		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 data
		verts.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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值