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

效果圖
這就是我們平時(shí)最常見、最無奈(都懂吧?)的矩形馬賽克。
基本思路:

通過一個(gè)給定的矩形把原紋理分割成若干塊。
在某個(gè)矩形中選取一個(gè)紋素(一般選取矩形左上角的紋素),然后用這個(gè)紋素填充整個(gè)矩形,就得到我們看到的邁賽克了。
- x軸Index = Int(當(dāng)前點(diǎn)的X / 矩形的寬)
y軸Index = Int(當(dāng)前點(diǎn)的Y / 矩形的高) - 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ì)有一些難度。
基本思路

- 如上圖所示,我們將六邊形使用矩形來分割。我們?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中的到了當(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ù):選擇 左上、右下

- 步驟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è)三角形。
基本思路
- 與六邊形馬賽克一致,找到當(dāng)前點(diǎn)隸屬的六邊形中心點(diǎn)。

通過看圖發(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))計(jì)算出每一個(gè)三角形大致中心點(diǎn)的紋理坐標(biāo)
通過夾角判斷隸屬于哪個(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);
}
}