OpenGLES(十)-GLSL案例:矩形、六边形、三角形马赛克OpenGLES(十)-GLSL案例:矩形、六边形、三角形马赛克

2021-08-09 11:19:23 浏览数 (2)

OpenGLES(十)-GLSL案例:矩形、六边形、三角形马赛克

矩形马赛克

效果图

这就是我们平时最常见、最无奈(都懂吧?)的矩形马赛克。

基本思路:

通过一个给定的矩形把原纹理分割成若干块。

在某个矩形中选取一个纹素(一般选取矩形左上角的纹素),然后用这个纹素填充整个矩形,就得到我们看到的迈赛克了。

  1. x轴Index = Int(当前点的X / 矩形的宽) y轴Index = Int(当前点的Y / 矩形的高)
  2. textureX = x轴Index * 矩形的宽 textureY = y轴Index * 矩形的高
片元着色器代码:
代码语言:javascript复制
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.先得到当前的X、y轴真实坐标
    vec2 intXY = vec2(size.x * varyTexCoord.x, size.y * varyTexCoord.y);
    //2.得到真实坐标隶属的矩形左上角的坐标
    vec2 XYMosaic = vec2(floor(intXY.x / mosaicSize.x) * mosaicSize.x, floor(intXY.y / mosaicSize.y) * mosaicSize.y);
    //将真实坐标转换为纹理坐标,并得到纹素
    vec4 realColor = texture2D(colorMap, vec2(XYMosaic.x / size.x, XYMosaic.y / size.y));
    gl_FragColor = realColor;
}

六边形马赛克

效果图

通过一个给定的六边形把原纹理分割成若干块(一般选择六边形的中心点的纹素)。原理和矩形马赛克是一样的,只是当前像素点隶属的六边形计算会有一些难度。

基本思路
  1. 如上图所示,我们将六边形使用矩形来分割。我们设定的矩阵宽高比例为: 3LEN : √3LEN(LEN是给定的六边形边长) x轴Index = int(当前点的x / (3 * LEN)) y轴Index = int(当前点的y / (√3 * LEN))
  1. 步骤1中的到了当前点隶属的矩形,每个矩形中只有两个顶点是六边形的中心点,所以比较的顶点选取分为四类: (1) IndexX偶数 indexY偶数:选择 左上、右下 (2) IndexX偶数 indexY奇数:选择 左下、右上 (3) IndexX奇数 indexY偶数:选择 左下、右上 (4) IndexX奇数 indexY奇数:选择 左上、右下
  1. 步骤2中的到了当前点隶属矩形的顶点,现在要找到当前点隶属于那个六边形,通过图中可以看到红点距离那个六边形的中心点近就隶属于那个六边形。
片元着色器代码:
代码语言:javascript复制
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;
    //第一步找到矩形顶点
    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;
    }
    gl_FragColor = texture2D(colorMap, result);
}
  • TR其实是: √3/2
  • TB其实是: 3/2

三角形马赛克

效果图

实现思路是在六边形马赛克的基础上,把六边形等分为6个三角形。

基本思路
  1. 与六边形马赛克一致,找到当前点隶属的六边形中心点。
  1. 通过看图发现只要知道当前点和中心点的夹角就可以知道对应的是哪个三角形 float θ = atan((当前点x - 六边形顶点 x)/(当前点y - 六边形顶点 y))
  2. 计算出每一个三角形大致中心点的纹理坐标
  3. 通过夹角判断隶属于哪个三角形
片元着色器代码:
代码语言:javascript复制
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 计算出夹角
        float a = atan(varyTexCoord.x - result.x , varyTexCoord.y - result.y);
    //3 计算出每一个三角形中心点的纹理坐标
        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 通过判断得到当前点隶属的三角形中心点
        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

0 人点赞