本章为大家带来马赛克/像素化特效。
马赛克和像素化特效有点类似,只不过程度不同,视乎格子的数量多少,可以认为是马赛克,也可以认为是像素化
2d-sprite-mosaic.gif一、马赛克特效原理
马赛克的原理很简单,一句话形容就是 m x n 方块内取同一颜色 ,具体为两个步骤:
- 将纹理分成 m x n 个方块
- 方块内取同一个颜色
至此,本章完,你已经可以根据这个原理去实现效果了。
二、马赛克代码实现
将纹理分成 m x n 个方块 ,m 和 n 应该属于外部控制,因此我们将这两个属性设置为uniform变量,并定义如下:
uniform Mosaic {
// X轴方块数量
float xBlockCount;
// Y轴方块数量
float yBlockCount;
}
那么我们又如何实现方块内取同一个颜色呢?其中一种解决方案
- 计算顶点所在方块
- 取该方块内某一点,代表该方块的颜色
举个例子:
图中A点,B点,我们很明显知道它是落在方块 (1,0) 上,按照上面的操作,实际上,A,B两点采用的是方块(1,0) 的颜色,这里也可以变相理解为 A,B两点的坐标映射(或者叫投影)到格子(1,0) 的坐标 。
explain抽象一下,实际的问题就变为:
我们怎么计算某个点的映射格子呢?这里,我们尝试分步计算
2.1 计算点在X轴上坐落的格子
首先,X轴上,每个格子的宽度可以这样子求解
float blockWidth = 1.0 / xBlockCount;
为了避免 xBlockCount 为 0 的问题,导致出现除以 0 的问题,我们可以这样子优化一下:
// 计算x轴格子宽度
float xCount;
if (xBlockCount <= 0.0) {
xCount = 1.0;
} else {
xCount = xBlockCount;
}
float blockWidth = 1.0 / xCount;
然后,用点的X坐标除以格子的宽度,然后向下取整,就可以得出点在X轴上哪个格子了
float blockXIndex = floor(v_uv0.x / blockWidth);
2.2 计算点在Y轴上坐落的格子
同理,我们也可以求出点在Y轴上的哪个格子:
// 同理,求出当前 v_uv0 在y轴上的哪个格子
float yCount;
if (yBlockCount <= 0.0) {
yCount = 1.0;
} else {
yCount = yBlockCount;
}
float blockHeight = 1.0 / yCount;
float blockYIndex = floor(v_uv0.y / blockHeight);
2.3 计算格子颜色
现在我们知道点是坐落格子是 (blockXIndex, blockYIndex)
,那么这个格子取什么颜色呢?
一般而言,我们取格子中心点所在颜色作为格子的颜色,当然你也可以有不同的实现。
计算格子中心点其实也很好算
// X:格子宽度 * 格子索引 + 半个格子的宽度
// Y:格子高度 * 格子索引 + 半个格子的高度
vec2 pos = vec2(blockWidth * blockXIndex + blockWidth * 0.5, blockHeight * blockYIndex + blockHeight * 0.5);
// 即
vec2 pos = vec2(blockWidth * (blockXIndex + 0.5), blockHeight * (blockYIndex + 0.5));
OK,现在我们可以得出了完整的映射代码
code通过上面这份代码,我们就可以将顶点映射到不同格子,并且实现同一个格子显示同一个颜色(颜色为格子中心点的颜色)了。
2.4 应用映射
在 片段着色器 中应用一下映射刚刚的映射函数,更新每个 uv0 的实际映射坐标:
CCProgram fs加上一些我们在 Cocos Creator Shader Effect 系列 - 3 - Effect 文件调试 中说到的调试手段,你就能得到马赛克的效果了
2d-sprite-mosaic.gif三、总结
从上面的动图,你可以看到,视乎格子数量多少,一定程度上可以叫马赛克,在另外一个程度上,也可以叫像素化,重点在于 格子数量 这个变量,实际使用的时候,我们可以根据自己的需求去进行控制。
另外一个点就是,本张我们介绍了点映射或者叫 点投影 ,这是一个很好玩的操作,不同的投影方式能产生不同的效果,可以想点什么效果,去试试玩~
OK,本章完,完整代码在我的 Github 仓库 或 Gitee 仓库 中可以找到。
下一篇:
上一篇:
网友评论