OpenGLES(十)-GLSL案例:矩形、六邊形、三角形馬賽克

OpenGLES(十)-GLSL案例:矩形、六邊形、三角形馬賽克

矩形馬賽克

效果圖

這就是我們平時(shí)最常見、最無奈(都懂吧?)的矩形馬賽克。

基本思路:

通過一個(gè)給定的矩形把原紋理分割成若干塊。

在某個(gè)矩形中選取一個(gè)紋素(一般選取矩形左上角的紋素),然后用這個(gè)紋素填充整個(gè)矩形,就得到我們看到的邁賽克了。

  1. x軸Index = Int(當(dāng)前點(diǎn)的X / 矩形的寬)
    y軸Index = Int(當(dāng)前點(diǎn)的Y / 矩形的高)
  2. textureX = x軸Index * 矩形的寬
    textureY = y軸Index * 矩形的高
片元著色器代碼:
precision highp float;
varying lowp vec2 varyTexCoord;
uniform sampler2D colorMap;
uniform vec2 size;
const vec2 mosaicSize = vec2(32.0, 32.0);

void main(void) {
    //1.先得到當(dāng)前的X、y軸真實(shí)坐標(biāo)
    vec2 intXY = vec2(size.x * varyTexCoord.x, size.y * varyTexCoord.y);
    //2.得到真實(shí)坐標(biāo)隸屬的矩形左上角的坐標(biāo)
    vec2 XYMosaic = vec2(floor(intXY.x / mosaicSize.x) * mosaicSize.x, floor(intXY.y / mosaicSize.y) * mosaicSize.y);
    //將真實(shí)坐標(biāo)轉(zhuǎn)換為紋理坐標(biāo),并得到紋素
    vec4 realColor = texture2D(colorMap, vec2(XYMosaic.x / size.x, XYMosaic.y / size.y));
    gl_FragColor = realColor;
}

六邊形馬賽克

效果圖

通過一個(gè)給定的六邊形把原紋理分割成若干塊(一般選擇六邊形的中心點(diǎn)的紋素)。原理和矩形馬賽克是一樣的,只是當(dāng)前像素點(diǎn)隸屬的六邊形計(jì)算會(huì)有一些難度。

基本思路
  1. 如上圖所示,我們將六邊形使用矩形來分割。我們?cè)O(shè)定的矩陣寬高比例為: 3LEN : √3LEN(LEN是給定的六邊形邊長)
    x軸Index = int(當(dāng)前點(diǎn)的x / (3 * LEN))
    y軸Index = int(當(dāng)前點(diǎn)的y / (√3 * LEN))
  1. 步驟1中的到了當(dāng)前點(diǎn)隸屬的矩形,每個(gè)矩形中只有兩個(gè)頂點(diǎn)是六邊形的中心點(diǎn),所以比較的頂點(diǎn)選取分為四類:
    (1) IndexX偶數(shù) indexY偶數(shù):選擇 左上、右下
    (2) IndexX偶數(shù) indexY奇數(shù):選擇 左下、右上
    (3) IndexX奇數(shù) indexY偶數(shù):選擇 左下、右上
    (4) IndexX奇數(shù) indexY奇數(shù):選擇 左上、右下
  1. 步驟2中的到了當(dāng)前點(diǎn)隸屬矩形的頂點(diǎn),現(xiàn)在要找到當(dāng)前點(diǎn)隸屬于那個(gè)六邊形,通過圖中可以看到紅點(diǎn)距離那個(gè)六邊形的中心點(diǎn)近就隸屬于那個(gè)六邊形。
片元著色器代碼:
precision highp float;
varying lowp vec2 varyTexCoord;
uniform sampler2D colorMap;

const float mosaicSize = 0.03;

void main(void) {
    
    float TR = 1.73205;
    float TB = 3.0;
    //第一步找到矩形頂點(diǎn)
    int indexX = int(varyTexCoord.x / TB / mosaicSize);
    int indexY = int(varyTexCoord.y / TR / mosaicSize);
    vec2 v1, v2, result;
    //第二步找到矩形中可用于取色的頂點(diǎn)
    if(indexX / 2 * 2 == indexX) {
        if(indexY / 2 * 2 == indexY) {
            v1 = vec2(float(indexX) * mosaicSize * TB, float(indexY) * mosaicSize * TR);
            v2 = vec2(float(indexX + 1) * mosaicSize * TB, float(indexY + 1) * mosaicSize * TR);
        }else{
            v1 = vec2(float(indexX) * mosaicSize * TB, float(indexY + 1) * mosaicSize * TR);
            v2 = vec2(float(indexX + 1) * mosaicSize * TB, float(indexY) * mosaicSize * TR);
        }
    }else{
        if(indexY / 2 * 2 == indexY) {
            v1 = vec2(float(indexX) * mosaicSize * TB, float(indexY + 1) * mosaicSize * TR);
            v2 = vec2(float(indexX + 1) * mosaicSize * TB, float(indexY) * mosaicSize * TR);
        }else{
            v1 = vec2(float(indexX) * mosaicSize * TB, float(indexY) * mosaicSize * TR);
            v2 = vec2(float(indexX + 1) * mosaicSize * TB, float(indexY + 1) * mosaicSize * TR);
        }
    }
    //第三步通過比較遠(yuǎn)近來確定紋素的坐標(biāo)
    float s1 = sqrt(pow(varyTexCoord.x - v1.x, 2.0) + pow(varyTexCoord.y - v1.y, 2.0));
    float s2 = sqrt(pow(varyTexCoord.x - v2.x, 2.0) + pow(varyTexCoord.y - v2.y, 2.0));
    if(s1 < s2){
        result = v1;
    }else{
        result = v2;
    }
    gl_FragColor = texture2D(colorMap, result);
}
  • TR其實(shí)是: √3/2
  • TB其實(shí)是: 3/2

三角形馬賽克

效果圖

實(shí)現(xiàn)思路是在六邊形馬賽克的基礎(chǔ)上,把六邊形等分為6個(gè)三角形。

基本思路
  1. 與六邊形馬賽克一致,找到當(dāng)前點(diǎn)隸屬的六邊形中心點(diǎn)。
  1. 通過看圖發(fā)現(xiàn)只要知道當(dāng)前點(diǎn)和中心點(diǎn)的夾角就可以知道對(duì)應(yīng)的是哪個(gè)三角形
    float θ = atan((當(dāng)前點(diǎn)x - 六邊形頂點(diǎn) x)/(當(dāng)前點(diǎn)y - 六邊形頂點(diǎn) y))

  2. 計(jì)算出每一個(gè)三角形大致中心點(diǎn)的紋理坐標(biāo)

  3. 通過夾角判斷隸屬于哪個(gè)三角形

片元著色器代碼:
precision highp float;
varying lowp vec2 varyTexCoord;
uniform sampler2D colorMap;

const float mosaicSize = 0.03;

void main(void) {
    //局部馬賽克判斷思路
    if(varyTexCoord.x >= 0.25 && varyTexCoord.x <= 0.75 && varyTexCoord.y >= 0.25 && varyTexCoord.y <= 0.75){
        float TR = 0.866025;
        float TB = 1.5;
        const float PI6 = 0.523599;
        
        int indexX = int(varyTexCoord.x / TB / mosaicSize);
        int indexY = int(varyTexCoord.y / TR / mosaicSize);
        vec2 v1, v2, result;
        
        if(indexX / 2 * 2 == indexX) {
            if(indexY / 2 * 2 == indexY) {
                v1 = vec2(float(indexX) * mosaicSize * TB, float(indexY) * mosaicSize * TR);
                v2 = vec2(float(indexX + 1) * mosaicSize * TB, float(indexY + 1) * mosaicSize * TR);
            }else{
                v1 = vec2(float(indexX) * mosaicSize * TB, float(indexY + 1) * mosaicSize * TR);
                v2 = vec2(float(indexX + 1) * mosaicSize * TB, float(indexY) * mosaicSize * TR);
            }
        }else{
            if(indexY / 2 * 2 == indexY) {
                v1 = vec2(float(indexX) * mosaicSize * TB, float(indexY + 1) * mosaicSize * TR);
                v2 = vec2(float(indexX + 1) * mosaicSize * TB, float(indexY) * mosaicSize * TR);
            }else{
                v1 = vec2(float(indexX) * mosaicSize * TB, float(indexY) * mosaicSize * TR);
                v2 = vec2(float(indexX + 1) * mosaicSize * TB, float(indexY + 1) * mosaicSize * TR);
            }
        }
        float s1 = sqrt(pow(varyTexCoord.x - v1.x, 2.0) + pow(varyTexCoord.y - v1.y, 2.0));
        float s2 = sqrt(pow(varyTexCoord.x - v2.x, 2.0) + pow(varyTexCoord.y - v2.y, 2.0));
        if(s1 < s2){
            result = v1;
        }else{
            result = v2;
        }
        
    //2 計(jì)算出夾角
        float a = atan(varyTexCoord.x - result.x , varyTexCoord.y - result.y);
    //3 計(jì)算出每一個(gè)三角形中心點(diǎn)的紋理坐標(biāo)
        vec2 area1 = vec2(result.x, result.y - mosaicSize * TR / 2.0);
        vec2 area2 = vec2(result.x + mosaicSize / 2.0, result.y - mosaicSize * TR / 2.0);
        vec2 area3 = vec2(result.x + mosaicSize / 2.0, result.y + mosaicSize * TR / 2.0);
        vec2 area4 = vec2(result.x, result.y + mosaicSize * TR / 2.0);
        vec2 area5 = vec2(result.x - mosaicSize / 2.0, result.y + mosaicSize * TR / 2.0);
        vec2 area6 = vec2(result.x - mosaicSize / 2.0, result.y - mosaicSize * TR / 2.0);
    //4 通過判斷得到當(dāng)前點(diǎn)隸屬的三角形中心點(diǎn)
        vec2 vn;
        if (a >= -PI6 && a < PI6){
            vn = area1;
        }else if(a >= PI6 && a < 3.0 * PI6){
            vn = area2;
        }else if(a >= 3.0 * PI6 && a < 5.0 * PI6){
            vn = area3;
        }else if((a >= PI6 * 5.0 && a <= PI6 * 6.0) || (a<-PI6 * 5.0 && a>-PI6 * 6.0)){
            vn = area4;
        }else if(a < -PI6 * 3.0 && a >= -PI6 * 5.0){
            vn = area5;
        }else if(a <= -PI6 && a> -PI6 * 3.0){
            vn = area6;
        }
        gl_FragColor = texture2D(colorMap, vn);
    }else{
        gl_FragColor = texture2D(colorMap, varyTexCoord);
    }
}
完整DEMO地址: Github
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容