在天朝河蟹社会,许多影视作品中经常出现少儿不宜的片段,这时候有一个东西就少不了。没错,它就是马赛克!
以前弄过方块马赛克,圆形马赛克等,没有什么难度,最近看到苍蝇的研究,突然想能不能搞个六边形马赛克呢。
说着就动手!
首先看看六边形马赛克的结构,如下图:
而我们要做的效果就是:让一张图片,分割成由六边形组成,让每个六边形中的颜色相同(直接取六边形中心点像素RGB较方便,我们这里采用的就是这种方法)。
将它进行分割,取每个六边形的中心点画出一个矩阵,如下:
如上图,画出很多长和宽比例为2:√3的的矩形阵。然后我们可以对每个点进行编号,如上图中,采用坐标系标记。
假如我们的屏幕的左上点为上图的(0,0)点,则屏幕上的任一点我们找到它所对应的那个矩形了。
假定我们设定的矩阵比例为2*LEN : √3*LEN,那么屏幕上的任意点(x, y)所对应的矩阵坐标为(int(x/(2*LEN)), int(y/(√3*LEN)))。
这些应该不难理解。
看图我们可以发现,每个矩阵中的点其实分为两半。如矩阵(0, 0)和矩阵(1, 1),分为左上和右下,而矩阵(1,0)和矩阵(0,1)则分为左下和右上两部分。
任一一个矩阵都由这两种布局组成。
如此,我们可以发现,只要知道是在哪个矩阵,然后计算它离矩阵两个对角点的距离那个较短,我们就能判断它是属于哪一个六边形的了。
这里需要注意的是:矩阵的横坐标和纵坐标都为奇数或者都为偶数时,要比较的点,即六边形中点分别为矩形左上点和右下点,否则为左下点和右上点。
我们只需要判断横纵坐标即可。
根据这些信息,我们写出碎片着色脚本如下:
#version 400
#extension GL_ARB_texture_rectangle : enable
uniform float len;
uniform sampler2DRect colorTex0;
void main (void){
float TR = 0.866025f;
float x = gl_TexCoord[0].x;
float y = gl_TexCoord[0].y;
int wx = int(x/1.5f/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.5f*wx, len*TR*wy);
v2 = vec2(len*1.5f*(wx+1), len*TR*(wy+1));
} else {
v1 = vec2(len*1.5f*wx, len*TR*(wy+1));
v2 = vec2(len*1.5f*(wx+1), len*TR*wy);
}
} else {
if(wy/2 * 2 == wy) {
v1 = vec2(len*1.5f*wx, len*TR*(wy+1));
v2 = vec2(len*1.5f*(wx+1), len*TR*wy);
} else {
v1 = vec2(len*1.5f*wx, len*TR*wy);
v2 = vec2(len*1.5f*(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 = texture2DRect(colorTex0, vn);
gl_FragColor = color;
}
里面的判断就是关于属于哪一个六边形的判断。
我们可以让len为固定值,以我的照片为例,效果如下:
当然,我们也可以实时改变len值,让六边形的变大变小:
是不是很炫,^_^.
下面为openframeworks中的主要代码:
#include "testApp.h"
//--------------------------------------------------------------
void testApp::setup(){
img.loadImage("bg.jpg");
fbo.allocate(640, 480);
shader.load("hexagon.vert", "hexagon.frag");
len = 20.0f;
bAdd = false;
}
//--------------------------------------------------------------
void testApp::update(){
if(len < 10.0f)
bAdd = true;
if(len > 20.0f)
bAdd = false;
len += bAdd ? (0.005f):(-0.005f);
}
//--------------------------------------------------------------
void testApp::draw(){
ofEnableAlphaBlending();
img.draw(0, 0, 640, 480);
fbo.begin();
img.draw(0, 0, 640, 480);
fbo.end();
shader.begin();
shader.setUniform1f("len", len);
shader.setUniformTexture("colorTex0", fbo.getTextureReference(), 0);
fbo.draw(0, 0, 640, 480);
shader.end();
ofDisableAlphaBlending();
}
另外还有三角形马赛克效果。
源码地址