老规矩先看效果,下图中上部分图片是原图,下部分图片是修改过模糊度的图片。
上图通过滑块动态修改图片的模糊程度,滑块越靠右图片越模糊。
设置模糊图片主要是通过修改某一个像素点的颜色来实现的,就是将某一个像素点上下左右四个像素点的颜色算一下平均值作为当前像素的最终颜色。所有的颜色都这样处理就会出现模糊的效果了。
BlurViewController继承自BaseViewController
#import "BaseViewController.h"
NS_ASSUME_NONNULL_BEGIN
@interface BlurViewController : BaseViewController
@end
NS_ASSUME_NONNULL_END
#import "BlurViewController.h"
int esBlurMain ( ESContext *esContext, float width, float height );
void changeBlurValue(float value);
@interface BlurViewController ()
@end
@implementation BlurViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self setupGL];
CGFloat statusHeight = [[UIApplication sharedApplication] statusBarFrame].size.height;
CGFloat navheight = self.navigationController.navigationBar.frame.size.height;
UISlider *slider = [[UISlider alloc] initWithFrame:CGRectMake(100, statusHeight + navheight, 200, 50)];
slider.backgroundColor = [UIColor redColor];
[slider addTarget:self action:@selector(slider:) forControlEvents:UIControlEventValueChanged];
[self.view addSubview:slider];
}
- (void)slider:(UISlider *)slider {
changeBlurValue(slider.value);
}
- (void)setupGL
{
[super setupGL];
esBlurMain(&_esContext, ((GLKView *)self.view).drawableWidth, ((GLKView *)self.view).drawableWidth);
}
- (void)update
{
if ( _esContext.updateFunc )
{
_esContext.updateFunc( &_esContext, self.timeSinceLastUpdate );
}
}
- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
{
_esContext.width = view.drawableWidth;
_esContext.height = view.drawableHeight;
if ( _esContext.drawFunc )
{
_esContext.drawFunc( &_esContext );
}
}
@end
上面这些没什么好说的,都是OC代码,主要就是初始化数据。
下面开始渲染部分:
实现一个正方形顶点坐标以及纹理坐标
GLfloat blur_vertices[] = {
-0.5, -0.5, 0.0f,
0.5, -0.5, 0.0f,
0.5, 0.5, 0.0f,
-0.5, -0.5, 0.0f,
0.5, 0.5, 0.0f,
-0.5, 0.5, 0.0f
};
GLfloat blur_texture[] = {
0,0,
1,0,
1,1,
0,0,
1,1,
0,1
};
shader设置如下:
static int Init ( ESContext *esContext )
{
char vShaderStr[] =
"#version 300 es \n"
"layout(location=0) in vec4 a_position; \n"
"layout(location=1) in vec2 a_texCoord; \n"
"uniform mat4 u_mvpMatrix; \n"
"out vec2 v_texCoord; \n"
"void main() \n"
"{ \n"
" gl_Position = u_mvpMatrix * a_position; \n"
" v_texCoord = a_texCoord; \n"
"}";
char fShaderStr[] =
"#version 300 es \n"
"precision mediump float; \n"
"uniform sampler2D s_texture; \n"
"uniform float u_blurStep; \n"
"in vec2 v_texCoord; \n"
"layout(location = 0) out vec4 outColor; \n"
"void main(void) { \n"
" vec4 sample0, sample1, sample2, sample3; \n"
" float fStep = u_blurStep / 100.0; \n"
//通过计算每个像素周围四个像素的平均颜色,得到最终显示的颜色
" sample0 = texture(s_texture, vec2(v_texCoord.x - fStep, v_texCoord.y - fStep)); \n"
" sample1 = texture(s_texture, vec2(v_texCoord.x + fStep, v_texCoord.y + fStep)); \n"
" sample2 = texture(s_texture, vec2(v_texCoord.x + fStep, v_texCoord.y - fStep)); \n"
" sample3 = texture(s_texture, vec2(v_texCoord.x - fStep, v_texCoord.y + fStep)); \n"
" outColor = (sample0 + sample1 + sample2 + sample3) / 4.0; \n"
"} \n";
UserData *userData = esContext->userData;
userData->programObject = esLoadProgram ( vShaderStr, fShaderStr );
userData->mvpLoc = glGetUniformLocation(userData->programObject, "u_mvpMatrix");
userData->samplerLoc = glGetUniformLocation(userData->programObject, "u_texture");
userData->blurStep = glGetUniformLocation(userData->programObject, "u_blurStep");
userData->texture = LoadTexture ( esContext->platformData, "lightmap.tga" );
glClearColor ( 1.0f, 1.0f, 1.0f, 0.0f );
// Fill in particle data array
srand ( 0 );
if ( userData->texture <= 0)
{
return FALSE;
}
return TRUE;
}
设置投影矩阵以及模型矩阵
static void Update ( ESContext *esContext, float deltaTime )
{
UserData *userData = esContext->userData;
float aspect = (float)esContext->width / ((float)esContext->height / 2.0);
esMatrixLoadIdentity(&userData->projectionMatrix);
esPerspective(&userData->projectionMatrix, 60.0f, aspect, 1.0f, 20.0f);
esMatrixLoadIdentity(&userData->modelViewMatrix);
esTranslate(&userData->modelViewMatrix, 0, 0, -2);
esScale(&userData->modelViewMatrix, 2, 2, 2);
esMatrixMultiply(&userData->mvpMatrix, &userData->modelViewMatrix, &userData->projectionMatrix);
}
最后的渲染工作
static void Draw ( ESContext *esContext )
{
UserData *userData = esContext->userData;
//模糊画面
glViewport ( 0, 0, esContext->width, esContext->height / 2);
glClear ( GL_COLOR_BUFFER_BIT );
glUseProgram ( userData->programObject );
glUniformMatrix4fv(userData->mvpLoc, 1, GL_FALSE, (GLfloat *)&userData->mvpMatrix.m[0][0]);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, userData->texture);
glUniform1i(userData->samplerLoc, 0);
glUniform1f(userData->blurStep, blurValue);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, blur_vertices);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, blur_texture);
glDrawArrays(GL_TRIANGLES, 0, 6);
//原始画面
glViewport ( 0, esContext->height / 2, esContext->width , esContext->height / 2 );
glUniform1f(userData->blurStep, 0);
esTranslate(&userData->mvpMatrix, 0, -0.3, 0);
glUniformMatrix4fv(userData->mvpLoc, 1, GL_FALSE, (GLfloat *)&userData->mvpMatrix.m[0][0]);
glDrawArrays(GL_TRIANGLES, 0, 6);
}
当滑动滑块的时候修改blurValue数值,0-1
float blurValue = 0;
void changeBlurValue(float value) {
blurValue = value;
}
详细代码可以下载demo看一下
所有demo地址
本人原文博客地址