1. 程式人生 > >Shader之旅2:四宮格畫面實現

Shader之旅2:四宮格畫面實現

書寫本文的初衷是為了自我反省記錄。如有表達不當,請批評指正

首先貼出shader程式碼。這段程式碼是實現相機拍攝畫面四宮格的實現。分別傳入不同的channel 0 1 2 3。然後將UV進行切割分為四塊填入四個channel

uniform float selected_ratio;
uniform float selected;


#include "res/shaders/BlendMode.frag"
//建立新uv
vec2 newImage(vec2 uv, float ratio, vec2 padding){
    uv -= padding;
    uv /= ratio;
    return uv;
}
//------------------------------------------
//void mainImage(out vec4 fragColor, in vec2 fragCoord)是一個二次封裝的著色器入口函式用過shadertoy都知道此函式
//------------------------------------------
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    vec2 uv = (fragCoord.xy / iResolution.xy);//iResolution是一個螢幕適應的變數將coord延展到當前螢幕
    vec4 color;
    vec4 channelColor;
    vec2 selectedUv = uv;
    bool flag_u = false;
    bool flag_v = false;
//--------------------------------------
//切割UV
//--------------------------------------
    if(uv.x>0.5){
        flag_u = true;
        uv.x -= 0.5;
    }
    
    if(uv.y>0.5){
        flag_v = true;
        uv.y -= 0.5;
    }

    uv = (uv * vec2(2.0,2.0));
    
    if (flag_u && flag_v) // 右上角
    {
        color = texture(iChannel1, uv);
        fragColor = color;
    } 
    else if (flag_u && !flag_v) // 右下角
    {
        color = texture(iChannel3, uv);
        fragColor = color;      
    } 
    else if (!flag_u && flag_v) // 左上角
    {
        color = texture(iChannel0, uv);
        fragColor = color;
    } 
    else if (!flag_u && !flag_v) // 左下角
    {
        color = texture(iChannel2, uv);
        fragColor = color;        
    }

//--------------------------------------
//此段程式碼是實現點選四個宮格,對應的宮格放大佔滿螢幕
//--------------------------------------

    if (selected == 1.0){
        if (selectedUv.x < selected_ratio && selectedUv.y > (1.0 - selected_ratio)){
            selectedUv = newImage(selectedUv, selected_ratio, vec2(0.0, 1.0 - selected_ratio));
            fragColor = texture(iChannel0, selectedUv);
        }

    }else if(selected == 2.0){
        if (selectedUv.x > (1.0 - selected_ratio) && selectedUv.y > (1.0 - selected_ratio)){
            selectedUv = newImage(selectedUv, selected_ratio, vec2(1.0 - selected_ratio, 1.0 - selected_ratio));
            fragColor = texture(iChannel1, selectedUv);
        }

    }else if(selected == 3.0){
        if (selectedUv.x < selected_ratio && selectedUv.y < selected_ratio){
            selectedUv = newImage(selectedUv, selected_ratio, vec2(0.0));
            fragColor = texture(iChannel2, selectedUv);
        }
    }else if(selected == 4.0){
        if (selectedUv.x > (1.0 - selected_ratio) && selectedUv.y < selected_ratio){
            selectedUv = newImage(selectedUv, selected_ratio, vec2(1.0 - selected_ratio, 0.0));
            fragColor = texture(iChannel3, selectedUv);
        }
    }
    
}

這裡關於入口函式在多說一下。我們都知道shader的入口函式為main函式而上述程式碼中為一個二次封裝的入口函式,與shadertoy中一樣。下面進行一下說明。

上述shader可以寫成如下形式,以下程式碼是在OpenGL es3.0下書寫的shader

  • 首先宣告版本
  • 說明精度
  • 將mainImage()中的fragcoord替換為gl_FragCoord內建函式
  • fragColor作為輸出宣告在開頭
#version 300 es
precision mediump float;

uniform float selected_ratio;
uniform float selected;
out vec4 fragColor;

#include "res/shaders/BlendMode.frag"
//建立新uv
vec2 newImage(vec2 uv, float ratio, vec2 padding){
   ............
}

void main()
{
    vec2 uv = (gl_FragCoord.xy / iResolution.xy);//iResolution是一個螢幕適應的變數將coord延展到當前螢幕
  
    .............
}

下面是將程式碼放置到shadertoy上的效果