-->

分類

2016年4月26日 星期二

Mosaic Shader for Unity

one of my friends wanted to make 3D h-game and he wondered how to make mosaic effect in 3D, so I did some research and made this



references:
风宇冲Unity3D教程学院 第二十三讲GrabPass
Dr.Dobb's Understanding Photomosaics
Shader "Custom/MosaicShader" {
 Properties{
  _MainTex("Base (RGB)", 2D) = "white" {}
 }

 SubShader
 {
  Tags{ "Queue" = "Transparent" }

  GrabPass
  {
   "_MyGrabTexture"
  }

  pass
  {
   Name "pass2"
   CGPROGRAM
   #pragma vertex vert
   #pragma fragment frag

   #include "UnityCG.cginc"
   sampler2D _MyGrabTexture;
   float4 _MyGrabTexture_ST;

   struct VertexIn
   {
    float4 vertex : POSITION;
    float2 texcoord : TEXCOORD0;
    float4 screenPos : TEXCOORD1;
   };
   struct VtoF 
   {
    float4  pos : SV_POSITION;
    float2  uv : TEXCOORD0;
    float4 screenPos : TEXCOORD1;
   };

   VtoF vert(VertexIn v)
   {
    VtoF o;
    o.pos = mul(UNITY_MATRIX_MVP,v.vertex);
    o.uv = TRANSFORM_TEX(v.texcoord,_MyGrabTexture);
    /*
    //source code in UnityCG.cginc
    inline float4 ComputeScreenPos(float4 pos) {
     //if we do perspective divide here(pos/pos.w), we got pos.x in range (-1, 1)(NDC)
     float4 o = pos * 0.5f;
     //if we do perspective divide here(o/pos.w), we got o.x in range (-0.5,0.5)
     #if defined(UNITY_HALF_TEXEL_OFFSET)
     o.xy = float2(o.x, o.y*_ProjectionParams.x) + o.w * _ScreenParams.zw;
     #else
     o.xy = float2(o.x, o.y*_ProjectionParams.x) + o.w;
     #endif

     o.zw = pos.zw;
     //if we do perspective divide here(o/pos.w), we got o.x in range (0,1)
     //o.x / pos.w in range(-0.5, 0.5), o.w / pos.w = 0.5
     //(o.x + o.w) / pos.w in range (-0.5 + 0.5, 0.5 + 0.5) = (0,1)
     return o;
    }
    */
    o.screenPos = ComputeScreenPos(o.pos);
    return o;
   }
   float4 frag(VtoF i) : COLOR
   {
    //perspective divide for screen pos to normalize p to be in the range of (0,1)
    fixed4 p = i.screenPos / i.screenPos.w;
    float4 tmp = float4(0, 0, 0, 0);

    //http://docs.unity3d.com/462/Documentation/Manual/SL-BuiltinValues.html
    //_ScreenParams: screen dimension in pixel
    //p.x*_ScreenParams.x: get x coordinate on screen, unit: pixel
    //floor(p.x*_ScreenParams.x / 10) * 10: 100 -> 100, 101 -> 100, 102 -> 100 ..., 109 -> 100, 110 -> 110
    [unroll(10)]
    for (float ii = floor(p.x*_ScreenParams.x / 10) * 10; ii < floor(p.x*_ScreenParams.x / 10) * 10 + 10; ii += 1)
    {
     [unroll(10)]
     for (float jj = floor(p.y *_ScreenParams.y / 10) * 10; jj < floor(p.y *_ScreenParams.x / 10) * 10 + 10; jj += 1)
     {
      //sample pixel color on screen
      tmp += tex2D(_MyGrabTexture, float2(ii / _ScreenParams.x, 1 - jj / _ScreenParams.y));
     }
    }
    return tmp / 100;//average samples
   }
   ENDCG
  }
 }
}

1 則留言: