2010-12-02

Unity 3D 字串只顯示在指定區域內

3D Text 字串顯示可用在很多地方例如文字編輯器,跑馬燈等...。以跑馬燈為例,字體因為只能顯示在特定範圍內,因此當字體從邊框跑進來時需要對字體進行裁切。這邊對字體裁切的概念是在字串 Mesh 前方建立一個隱形的 Clipper,當後方字串進行貼圖時,將圖片像素的座標空間轉換至 Clipper 的座標空間,然後檢查像素的範圖是否在 Clipper 內,否則將像素設定成透明。


欲達成上述效果需要自己寫相對應的 Shader 並套用在 3D Text 上,這裡提供 Shader 如下:
Shader "ModifiedTextShader"
{ 
 Properties
 {
  _MainTex ("Font Texture", 2D) = "white" {}
  _Color ("Text Color", Color) = (1,1,1,1) 
 }
 
 SubShader
 {
  Tags
  {
   "Queue"="Transparent"
   "IgnoreProjector"="True" 
   "RenderType"="Transparent"
  }
 
  Pass
  {
   CGPROGRAM
   // Upgrade NOTE: excluded shader from OpenGL ES 2.0 because it does not contain a surface program or both vertex and fragment programs.
   #pragma exclude_renderers gles
   #pragma vertex vert
   #pragma fragment frag
   #include "UnityCG.cginc"
 
   struct v2f
   {
    float4 pos : SV_POSITION;
    float4 uv[2] : TEXCOORD0;
    float4 color : COLOR0;
   };
 
   uniform float4x4 _ClipMatrix;
   uniform float4 _Color;
   sampler2D _MainTex;
   uniform float _ClipWidth;
   uniform float _ClipHeight;
 
   v2f vert( appdata_base v )
   {
    v2f o;
    o.pos = mul (UNITY_MATRIX_MVP, v.vertex);
 
    o.uv[0] = v.texcoord;
 
    float4 c = mul( _Object2World, v.vertex ); 
    c = mul( _ClipMatrix, c ); 
    o.uv[1] = c;
 
    o.color = _Color;
 
    return o;
   }
 
   half4 frag(v2f i) : COLOR
   {
    half4 texcol =tex2D(_MainTex, i.uv[0].xy);
    texcol =float4(i.color.r, i.color.g, i.color.b ,texcol.a);
 
    float halfWidth =_ClipWidth*0.5f;
    float halfHeight =_ClipHeight*0.5f;
    if (
     i.uv[1].x >halfWidth || 
     i.uv[1].x <-halfWidth|| 
     i.uv[1].y >halfHeight || 
     i.uv[1].y <-halfHeight)
     texcol.a =0;
 
    return texcol;
   }
 
   ENDCG
 
   Cull Off
   ZWrite On 
   Fog { Mode Off } 
   Blend SrcAlpha OneMinusSrcAlpha 
  }
 } 
}

其中 _ClipMatrix,_ClipWidth與_ClipHeight分別代表Clipper的座標轉換矩陣,Clipper的寬度和Clipper的高度,使用此Shader時:

1) 將此Shader設定給3DText的Mesh Renderer
2) 設定 font Texture 給此 Shader 的 Font Texture
3) 建立 clipper 物件並在物件內加入下列指令:
Shader.SetGlobalMatrix("_ClipMatrix", transform.worldToLocalMatrix);
Shader.SetGlobalFloat("_ClipWidth", 20.0f);
Shader.SetGlobalFloat("_ClipHeight", 20.0f);
分別代表設定 Clipper 轉換矩陣、Clipper的寬度為 20, Clipper的高度為 20。

4 則留言 :

  1. 請問, 可以解釋一下步驟嗎? 我把 Shader 做成 Material, 掛到 3DText 的 Mesh Renderer, 字就不能顯示了 &*.*

    回覆刪除
    回覆
    1. 您好, 我自己按照文章寫的方法也弄不出來,... 當初的設定順序有忘了,後來干脆另外弄了一個相同功能的範例放在 https://github.com/phardera/unity3d_3dtext_clipper.git ,大概敘述一下這個範例建立的順序就是把 clipperScript 拖曳到 New Text (3D Text) 物件上,然後另外建立一個物件 (GameObject) 並命名為 clipper 就設定完成,按下 Play 之後就可以看到效果,在 Play 的狀態下試著移動 clipper 物件可以發現摭罩範圍隨著 clipper 物件移動而變化,...

      刪除
  2. 請問這在android 和 ios能動作嗎?
    我試了你的方式在device上就變一個個方塊了

    回覆刪除
    回覆
    1. 您好, 答案是不能, 文章裡的 shader 寫法不能用在 OpenGL ES。針對這個問題我剛修改 shader 並更新到 git 上了,現在應該可以同時在 pc, ios, android 裝置上正常執行,您再試試。

      刪除