1. 程式人生 > >Shader特效——實現“放大鏡/縮小鏡”【GLSL】

Shader特效——實現“放大鏡/縮小鏡”【GLSL】

放大效果:


縮小效果:


片元著色器程式碼:

const float in_circle_radius = 96.;             //從客戶端傳入的放大鏡圓半徑
const float in_zoom_times = 2.;                 //從客戶端傳入的放大鏡放大倍數

const float imageWidth = 640.;                  //從客戶端傳入的圖片寬資料
const float imageHeight = 640.;                 //從客戶端傳入的圖片高資料

uniform sampler2D Texture0;

varying vec2 vUV;

vec2 in_circle_pos = vec2(320., imageHeight-320.);    //從客戶端傳入的放大鏡圓心位置


// 轉換為紋理範圍
vec2 transForTexPosition(vec2 pos)
{
    return vec2(float(pos.x/imageWidth), float(pos.y/imageHeight));
}

// Distance of Points
float getDistance(vec2 pos_src, vec2 pos_dist)
{
    float quadratic_sum = pow((pos_src.x - pos_dist.x), 2.) + pow((pos_src.y - pos_dist.y), 2.);
    return sqrt(quadratic_sum);
}
 
vec2 getZoomPosition()
{   // zoom_times>1. 是放大, 0.< zoom_times <1.是縮小
    float zoom_x = float(gl_FragCoord.x-in_circle_pos.x) / in_zoom_times;
    float zoom_y = float(gl_FragCoord.y-in_circle_pos.y) / in_zoom_times;
    
    return vec2(float(in_circle_pos.x + zoom_x), float(-in_circle_pos.y + zoom_y));
}

vec4 getColor()
{
    // ❤
    vec2 pos = getZoomPosition();

    float _x = floor(pos.x);
    float _y = floor(pos.y);

    float u = pos.x - _x;
    float v = pos.y - _y;
    //雙線性插值取樣
    vec4 data_00 = texture2D(Texture0, transForTexPosition(vec2(_x, _y))); 

    vec4 data_01 = texture2D(Texture0, transForTexPosition(vec2(_x, _y + 1.))); 

    vec4 data_10 = texture2D(Texture0, transForTexPosition(vec2(_x + 1., _y))); 

    vec4 data_11 = texture2D(Texture0, transForTexPosition(vec2(_x + 1., _y + 1.))); 

    return (1. - u) * (1. - v) * data_00 + (1. - u) * v * data_01 + u * (1. - v) * data_10 + u * v * data_11;

}

void main(void)
{ 
  vec2 frag_pos = vec2(gl_FragCoord.x, gl_FragCoord.y);
  //若當前片段位置距放大鏡圓心距離大於圓半徑時,直接從紋理中取樣輸出片段顏色 

  if (getDistance(in_circle_pos, frag_pos) > in_circle_radius) 
    gl_FragColor = texture2D(Texture0, vUV);
  else 
 //距離小於半徑的片段,二次線性插值獲得顔色。 
    gl_FragColor = getColor();
}