1. 程式人生 > >Shader特效——“馬賽克”的實現【GLSL】

Shader特效——“馬賽克”的實現【GLSL】

參考自:http://tech.it168.com/n/2007-03-29/200703291522292_3.shtml 和 http://blog.csdn.net/simpledrunk/article/details/17170965


原圖:



”圓形” 效果圖1 :


“圓形”效果2:



片元著色器程式碼:

uniform sampler2D Texture0;

const vec2 texSize = vec2(640., 640.);
const vec2 mosaicSize = vec2(8., 8.);

varying vec2 vUV;

void main(void)
{
   vec2 xy = vec2(vUV.x * texSize.x, vUV.y * texSize.y);// 取值範圍換算到影象尺寸大小
   // 計算某一個小mosaic的中心座標
   vec2 xyMosaic = vec2(floor(xy.x / mosaicSize.x) * mosaicSize.x, 
         floor(xy.y / mosaicSize.y) * mosaicSize.y )
         + .5*mosaicSize;
   // 計算距離中心的長度      
   vec2 delXY = xyMosaic - xy;
   float delL = length(delXY);
   // 換算回紋理座標系
   vec2 uvMosaic = vec2(xyMosaic.x / texSize.x, xyMosaic.y / texSize.y);
   
   vec4 finalColor;
   if(delL<0.5*mosaicSize.x)
   {
      finalColor = texture2D(Texture0, uvMosaic);
   }
   else
   {
      //finalColor = texture2D(Texture0, vUV);
      finalColor = vec4(0., 0., 0., 1.);
   }
   
   gl_FragColor = finalColor;
}


“方形” 效果圖:



片元著色器程式碼:

uniform sampler2D Texture0;

const vec2 texSize = vec2(640., 640.);
const vec2 mosaicSize = vec2(8., 8.);

varying vec2 vUV;

void main(void)
{
   vec4 color;
   //float ratio = texSize.y/texSize.x;
   
   vec2 xy = vec2(vUV.x * texSize.x /** ratio */, vUV.y * texSize.y);
   
   vec2 xyMosaic = vec2(floor(xy.x / mosaicSize.x) * mosaicSize.x, 
         floor(xy.y / mosaicSize.y) * mosaicSize.y );
   
   //第幾塊mosaic
   vec2 xyFloor = vec2(floor(mod(xy.x, mosaicSize.x)), 
                  floor(mod(xy.y, mosaicSize.y)));
   #if 0
   if((xyFloor.x == 0 || xyFloor.y == 0))
   {
      color = vec4(1., 1., 1., 1.);
   }
   else
   #endif
   {
      vec2 uvMosaic = vec2(xyMosaic.x / texSize.x, xyMosaic.y / texSize.y);
      color = texture2D( Texture0, uvMosaic );
   }
   
   gl_FragColor = color;
}


“六邊形” 效果圖:



片元著色器程式碼:

uniform float Time_x;
uniform sampler2D Texture0;
varying vec2 vUV;

uniform float len;

void main (void){
   float TR = 0.866025;
   float x = vUV.x;
   float y = vUV.y;
   int wx = int(x/1.5/len);
   int wy = int(y/TR/len);
   vec2 v1, v2, vn;
   if(wx/2 * 2 == wx) {
      if(wy/2 * 2 == wy) {
            v1 = vec2(len*1.5*wx, len*TR*wy);
            v2 = vec2(len*1.5*(wx+1), len*TR*(wy+1));
         } else {
            v1 = vec2(len*1.5*wx, len*TR*(wy+1));
            v2 = vec2(len*1.5*(wx+1), len*TR*wy);
         }
      } else {
      if(wy/2 * 2 == wy) {
         v1 = vec2(len*1.5*wx, len*TR*(wy+1));
         v2 = vec2(len*1.5*(wx+1), len*TR*wy);
         } else {
            v1 = vec2(len*1.5*wx, len*TR*wy);
            v2 = vec2(len*1.5*(wx+1), len*TR*(wy+1));
         }
   }
   float s1 = sqrt( pow(v1.x-x, 2) + pow(v1.y-y, 2) );
   float s2 = sqrt( pow(v2.x-x, 2) + pow(v2.y-y, 2) );
   if(s1 < s2)
      vn = v1;
   else
      vn = v2;
   vec4  color = texture2D(Texture0, vn);
   gl_FragColor = color;
}


“三角形” 效果圖:



片元著色器程式碼:

varying vec2 vUV;

uniform sampler2D Texture0;

// len 是六邊形的邊長
uniform float len;

void main (void){
   const float TR = 0.866025;  // .5*(3)^.5
   const float PI6 = 0.523599; // PI/6
   
   float x = vUV.x;
   float y = vUV.y;
   
   // 1.5*len 是矩形矩陣的長,TR*len 是寬
   // ::計算矩形矩陣的頂點座標 (0,0)(0,1)(1,0)(1,1)
   int wx = int(x/(1.5*len));
   int wy = int(y/(TR*len));
   
   vec2 v1, v2, vn;
   
   // 判斷是矩形的哪個頂點,上半部還是下半部
   if(wx/2 * 2. == wx) 
   {
      if(wy/2 * 2. == wy) 
      {     // left top
            // 選擇位於六邊形中心的紋素作為顏色參考:左上右下
            v1 = vec2(len*1.5*wx, len*TR*wy);
            v2 = vec2(len*1.5*(wx+1), len*TR*(wy+1));
      } 
      else 
      {  // left bottom
         // 左下右上
         v1 = vec2(len*1.5*wx, len*TR*(wy+1));
         v2 = vec2(len*1.5*(wx+1), len*TR*wy);
      }
   } 
   else 
   {
      if(wy/2 * 2. == wy) 
      {  // right top
         // 左下右上
         v1 = vec2(len*1.5*wx, len*TR*(wy+1));
         v2 = vec2(len*1.5*(wx+1), len*TR*wy);
      } 
      else 
      {  // right bottom
         // 左上右下
         v1 = vec2(len*1.5*wx, len*TR*wy);
         v2 = vec2(len*1.5*(wx+1), len*TR*(wy+1));
      }
   }
   // 計算參考點與當前紋素的距離
   float s1 = sqrt( pow(v1.x-x, 2.) + pow(v1.y-y, 2.) );
   float s2 = sqrt( pow(v2.x-x, 2.) + pow(v2.y-y, 2.) );
   // 選擇距離小的參考點
   if(s1 < s2)
      vn = v1;
   else
      vn = v2;
      
   vec4 mid = texture2D(Texture0, vn);
   float a = atan((x-vn.x)/(y-vn.y));// 計算夾角
   // 分別計算六個三角形的中心點座標,之後將作為參考點
   vec2 area1 = vec2(vn.x, vn.y-len*TR/2.);
   vec2 area2 = vec2(vn.x+len/2., vn.y-len*TR/2.);
   vec2 area3 = vec2(vn.x+len/2., vn.y+len*TR/2.);
   vec2 area4 = vec2(vn.x, vn.y+len*TR/2.);
   vec2 area5 = vec2(vn.x-len/2., vn.y+len*TR/2.);
   vec2 area6 = vec2(vn.x-len/2., vn.y-len*TR/2.);
   
   // 根據夾角判斷是哪個三角形
   if(a >= PI6 && a < PI6*3.)
      vn = area1;
   else if(a>=PI6*3. && a<PI6*5.)
      vn = area2;
   else if((a>=PI6*5. && a<=PI6*6.) || (a<-PI6*5. && a>-PI6*6.))
      vn = area3;
   else if(a<-PI6*3. && a>=-PI6*5.)
      vn = area4;
   else if(a<=-PI6 && a>-PI6*3.)
      vn = area5;
   else if(a>-PI6 && a<PI6)
      vn = area6;
      
   vec4  color = texture2D(Texture0, vn);
   gl_FragColor = color;

}


另附其他效果: