? ? ? ? 模糊效果在游戲中經(jīng)常會(huì)用到,有的為了突出前景會(huì)把背景給模糊化览露,有的是因?yàn)橐恍┘寄苄枰:Ч怼D:莝hader中較為簡(jiǎn)單的一種應(yīng)用。
原理
? ? ?? 把一個(gè)點(diǎn)的像素值用它周?chē)狞c(diǎn)的像素值的加權(quán)平均代替差牛。
? ? ? ?先說(shuō)下這個(gè)模糊算法的大致思路命锄,我們?cè)谄沃髦锌梢缘玫疆?dāng)前像素點(diǎn)的顏色值,要想讓這個(gè)顏色變得模糊偏化,就要讓它與它周?chē)南袼攸c(diǎn)的顏色稍微接近一點(diǎn)脐恩,那么我們就需要拿到這個(gè)像素點(diǎn)周?chē)南袼攸c(diǎn)的顏色值,我們把這些個(gè)像素點(diǎn)的值加起來(lái)取平均值侦讨,就得到了一個(gè)區(qū)域內(nèi)的平均顏色驶冒。
? ? ? ? 如果直接使用這個(gè)顏色的話,最終的效果會(huì)變得很模糊韵卤,如果我們只是想稍微模糊一點(diǎn)的話骗污,就要讓這個(gè)平均值更接近于當(dāng)前像素點(diǎn)原本的顏色,為此怜俐,我們?nèi)【档臅r(shí)候?qū)γ總€(gè)像素點(diǎn)增加了一個(gè)權(quán)重的定義身堡,當(dāng)前像素點(diǎn)的權(quán)重最高,依次向周?chē)鷾p弱拍鲤,使得最后得到的均值的顏色更接近于當(dāng)前像素點(diǎn)原始的顏色贴谎。
直接上代碼
建一個(gè)頂點(diǎn)著色器命名為Blur.vert
//頂點(diǎn)著色器
//v_fragmentColor是從頂點(diǎn)著色器設(shè)置的顏色經(jīng)過(guò)光柵化階段的線性插值后傳給片段著色器的顏色。
//v_texCoord同樣是經(jīng)過(guò)線性插值而來(lái)的紋理坐標(biāo)季稳。
attribute vec4 a_position;
attribute vec2 a_texCoord;
attribute vec4 a_color;
//varying 頂點(diǎn)shader和片段shader之間相互傳遞的參數(shù)擅这。
varying vec4 v_fragmentColor;
varying vec2 v_texCoord;
void main()
{
? ? ? ? gl_Position = CC_PMatrix * a_position;
? ? ? ? v_fragmentColor = a_color;
? ? ? ? v_texCoord = a_texCoord;
}
precision mediump float是open es特有的精度限定符,原本的浮點(diǎn)數(shù)精度是double景鼠,opengl es為了提高渲染效率仲翎,限定精度為float類(lèi)型痹扇。
v_fragmentColor是從頂點(diǎn)著色器設(shè)置的顏色經(jīng)過(guò)光柵化階段的線性插值后傳給片段著色器的顏色。
v_texCoord同樣是經(jīng)過(guò)線性插值而來(lái)的紋理坐標(biāo)溯香。
CC_Texture0是一個(gè)采樣器鲫构,在加載Shader的時(shí)候,引擎會(huì)預(yù)先把這些uniform變量給加載進(jìn)來(lái)玫坛。
下面這部分代碼就是引擎預(yù)先加載進(jìn)來(lái)的uniform變量:
static const char * COCOS2D_SHADER_UNIFORMS =
? ? ? "uniform mat4 CC_PMatrix;\n"
? ? ? "uniform mat4 CC_MVMatrix;\n"
? ? ? "uniform mat4 CC_MVPMatrix;\n"
? ? ? "uniform mat3 CC_NormalMatrix;\n"
? ? ?"uniform vec4 CC_Time;\n"
? ? ? "uniform vec4 CC_SinTime;\n"
? ? ? "uniform vec4 CC_CosTime;\n"
? ? ? "uniform vec4 CC_Random01;\n"
? ? ? "uniform sampler2D CC_Texture0;\n"
? ? ? "uniform sampler2D CC_Texture1;\n"
? ? ? "uniform sampler2D CC_Texture2;\n"
? ? ? "uniform sampler2D CC_Texture3;\n"
? ? ? "http://CC INCLUDES END\n\n";
這些變量在shader里面如果沒(méi)有用到的話结笨,會(huì)被引擎給優(yōu)化掉。
texture2D()是shader的內(nèi)建方法湿镀,作用是從CC_Texture0采樣器中進(jìn)行紋理采樣炕吸,得到當(dāng)前片段的顏色值。
gl_FragColor是shader的內(nèi)建變量勉痴,表示當(dāng)前片段的顏色赫模,代碼中是把從采樣器中拿到的顏色值進(jìn)行一個(gè)變灰處理后,最后得到的顏色值再賦值給gl_FragColor蒸矛。gl_FragColor就是最終的顏色瀑罗。
建一個(gè)FragmentShader命名為Blur.frag
varying vec4 v_fragmentColor;
varying vec2 v_texCoord;
uniform vec2 resolution;//模糊對(duì)象的實(shí)際分辨率
uniform float blurRadius;//半徑
uniform float sampleNum;//間隔的段數(shù)
vec4 blur(vec2);
void main(void)
{
? ? ? ? vec4 col = blur(v_texCoord);
? ? ? ? gl_FragColor = vec4(col) * v_fragmentColor;
}
vec4 blur(vec2 p)
{
? ? ? if (blurRadius > 0.0 && sampleNum > 1.0)
? ? ?{
? ? ? ? ? ? ? ? vec4 col = vec4(0);
? ? ? ? ? ? ? ? vec2 unit = 1.0 / resolution.xy;//單位坐標(biāo)
? ? ? ? ? ? ? ? float r = blurRadius;
? ? ? ? ? ? ? ? float sampleStep = r / sampleNum;
? ? ? ? ? ? ? ? float count = 0.0;
? ? ? ? ? ? ? ? //遍歷一個(gè)矩形,當(dāng)前的坐標(biāo)為中心點(diǎn)莉钙,遍歷矩形中每個(gè)像素點(diǎn)的顏色
? ? ? ? ? ? ? ?for(float x = -r; x < r; x += sampleStep)
? ? ? ? ? ? ? ? {
? ? ? ? ? ? ? ? ? ? ? ? ? ? for(float y = -r; y < r; y += sampleStep)
? ? ? ? ? ? ? ? ? ? ? ? ? ?{
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? float weight = (r - abs(x)) * (r - abs(y));//權(quán)重廓脆,p點(diǎn)的權(quán)重最高,向四周依次減少
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? col += texture2D(CC_Texture0, p + vec2(x * unit.x, y * unit.y)) * weight;
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? count += weight;
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?}
? ? ? ? ? ? ? ? ? ?}
? ? ? ? ? ? ? ? ? ? ?//得到實(shí)際模糊顏色的值
? ? ? ? ? ? ? ? ? ? return col / count;
? ? ? ? ? }
? ? ? ? ? return texture2D(CC_Texture0, p);
}
使用示例
//精靈
auto splash = Sprite::create("HelloWorld.png");
splash->setPosition(100, 100);
this->addChild(splash, 1);
//vert:頂點(diǎn)著色器 ?frag:片段著色器
auto glprogram = GLProgram::createWithFilenames("Shaders/test/Blur.vert", "Shaders/test/Blur.frag");
auto glprogramstate = GLProgramState::getOrCreateWithGLProgram(glprogram);
splash->setGLProgramState(glprogramstate);
//設(shè)置屬性
Size size = sprite->getTexture()->getContentSizeInPixels();
glprogramstate->setUniformVec2("resolution", size); ?//設(shè)置圖片分辨率值
glprogramstate->setUniformFloat("blurRadius", 5);//像素點(diǎn)模糊處理的參考矩形的半徑
glprogramstate->setUniformFloat("sampleNum", 5);//選擇像素點(diǎn)的間隔的數(shù)量
效果
參考資料:https://www.cnblogs.com/cxiaojia/p/5195858.html