Shader笔记3 - 模糊(Blur)

        模糊效果在游戏中经常会用到,有的为了突出前景会把背景给模糊化,有的是因为一些技能需要模糊效果。模糊是shader中较为简单的一种应用。

原理

       把一个点的像素值用它周围的点的像素值的加权平均代替。

       先说下这个模糊算法的大致思路,我们在片段着色器中可以得到当前像素点的颜色值,要想让这个颜色变得模糊,就要让它与它周围的像素点的颜色稍微接近一点,那么我们就需要拿到这个像素点周围的像素点的颜色值,我们把这些个像素点的值加起来取平均值,就得到了一个区域内的平均颜色。

        如果直接使用这个颜色的话,最终的效果会变得很模糊,如果我们只是想稍微模糊一点的话,就要让这个平均值更接近于当前像素点原本的颜色,为此,我们取均值的时候对每个像素点增加了一个权重的定义,当前像素点的权重最高,依次向周围减弱,使得最后得到的均值的颜色更接近于当前像素点原始的颜色。

直接上代码

建一个顶点着色器命名为Blur.vert

//顶点着色器

//v_fragmentColor是从顶点着色器设置的颜色经过光栅化阶段的线性插值后传给片段着色器的颜色。

//v_texCoord同样是经过线性插值而来的纹理坐标。

attribute vec4 a_position;

attribute vec2 a_texCoord;

attribute vec4 a_color;

//varying 顶点shader和片段shader之间相互传递的参数。

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特有的精度限定符,原本的浮点数精度是double,opengl es为了提高渲染效率,限定精度为float类型。

v_fragmentColor是从顶点着色器设置的颜色经过光栅化阶段的线性插值后传给片段着色器的颜色。

v_texCoord同样是经过线性插值而来的纹理坐标。

CC_Texture0是一个采样器,在加载Shader的时候,引擎会预先把这些uniform变量给加载进来。

下面这部分代码就是引擎预先加载进来的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"

      "//CC INCLUDES END\n\n";

这些变量在shader里面如果没有用到的话,会被引擎给优化掉。

texture2D()是shader的内建方法,作用是从CC_Texture0采样器中进行纹理采样,得到当前片段的颜色值。

gl_FragColor是shader的内建变量,表示当前片段的颜色,代码中是把从采样器中拿到的颜色值进行一个变灰处理后,最后得到的颜色值再赋值给gl_FragColor。gl_FragColor就是最终的颜色。

建一个FragmentShader命名为Blur.frag

varying vec4 v_fragmentColor;

varying vec2 v_texCoord;

uniform vec2 resolution;//模糊对象的实际分辨率

uniform float blurRadius;//半径

uniform float sampleNum;//间隔的段数

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;//单位坐标

                float r = blurRadius;

                float sampleStep = r / sampleNum;

                float count = 0.0;

                //遍历一个矩形,当前的坐标为中心点,遍历矩形中每个像素点的颜色

               for(float x = -r; x < r; x += sampleStep)

                {

                            for(float y = -r; y < r; y += sampleStep)

                           {

                                          float weight = (r - abs(x)) * (r - abs(y));//权重,p点的权重最高,向四周依次减少

                                          col += texture2D(CC_Texture0, p + vec2(x * unit.x, y * unit.y)) * weight;

                                          count += weight;

                             }

                   }

                     //得到实际模糊颜色的值

                    return col / count;

          }

          return texture2D(CC_Texture0, p);

}

使用示例

//精灵

auto splash = Sprite::create("HelloWorld.png");

splash->setPosition(100, 100);

this->addChild(splash, 1);

//vert:顶点着色器  frag:片段着色器

auto glprogram = GLProgram::createWithFilenames("Shaders/test/Blur.vert", "Shaders/test/Blur.frag");

auto glprogramstate = GLProgramState::getOrCreateWithGLProgram(glprogram);

splash->setGLProgramState(glprogramstate);

//设置属性

Size size = sprite->getTexture()->getContentSizeInPixels();

glprogramstate->setUniformVec2("resolution", size);  //设置图片分辨率值

glprogramstate->setUniformFloat("blurRadius", 5);//像素点模糊处理的参考矩形的半径

glprogramstate->setUniformFloat("sampleNum", 5);//选择像素点的间隔的数量

效果



参考资料:https://www.cnblogs.com/cxiaojia/p/5195858.html

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容

  • 描边原理:在片段着色器里面,对于每个像素:1. 如果它是不透明的像素,则不管,维持原本颜色;2. 如果透明,是...
    work_xiao阅读 2,935评论 1 1
  • 本文主要介绍cocos2d-x如何使用OpenGL实现着色器程序,介绍可以通过GLSL语言实现的两类着色器...
    work_xiao阅读 4,488评论 0 5
  • 转载注明出处:点击打开链接 Shader(着色器)是一段能够针对3D对象进行操作、并被GPU所执行的程序。Shad...
    游戏开发小Y阅读 3,323评论 0 4
  • 一:着色的原理 OpenGL着色语言(OpenGL Shading Language)是用来在OpenGL中着色编...
    wo不懂阅读 986评论 0 2
  • 先贴一个案例,我们做类似的图片展示的时候,都会需要对相应的图片进行裁剪以适应我们现实的大小,不然图片就会被拉伸或者...
    Haer不变阅读 2,439评论 0 2