周末闲来无事,想玩玩OpenGL Shader,想想就实现一个放大镜效果的Shader吧。
着色器可以指定放大镜位置、半径、及放大部数,我实现是在片段着色中使用向后映射的双线性插值的方式对当前片段颜色进行插值,而顶点着色器什么都不做。
先来看一下顶点着色器。
1 | uniform float texture_id; |
5 | gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; |
6 | gl_FrontColor = gl_Color; |
7 | gl_TexCoord[texture_id] = gl_TextureMatrix[texture_id] * gl_MultiTexCoord0; |
再来看一下片段着色器。
01 | uniform vec2 in_circle_pos; |
02 | uniform float in_circle_radius; |
03 | uniform float in_zoom_times; |
05 | uniform float imageWidth; |
06 | uniform float imageHeight; |
08 | uniform float texture_id; |
10 | uniform sampler2D textureSampler; |
12 | vec2 transForTexPosition(vec2 pos) |
14 | return vec2(( float )pos.x/imageWidth, ( float )pos.y/imageHeight); |
17 | float getDistance(vec2 pos_src, vec2 pos_dist) |
19 | float quadratic_sum = pow ((pos_src.x - pos_dist.x), 2) + pow ((pos_src.y - pos_dist.y), 2); |
20 | return sqrt (quadratic_sum); |
23 | vec2 getZoomPosition() |
25 | float zoom_x = ( float )(gl_FragCoord.x - in_circle_pos.x) / in_zoom_times; |
26 | float zoom_y = ( float )(gl_FragCoord.y - in_circle_pos.y) / in_zoom_times; |
27 | return vec2(( float )in_circle_pos.x + zoom_x, ( float )in_circle_pos.y - zoom_y); |
32 | vec2 pos = getZoomPosition(); |
34 | float _x = floor (pos.x); |
35 | float _y = floor (pos.y); |
40 | vec4 data_00 = texture2D(textureSampler, transForTexPosition(vec2(_x, _y))); |
41 | vec4 data_01 = texture2D(textureSampler, transForTexPosition(vec2(_x, _y + 1))); |
42 | vec4 data_10 = texture2D(textureSampler, transForTexPosition(vec2(_x + 1, _y))); |
43 | vec4 data_11 = texture2D(textureSampler, transForTexPosition(vec2(_x + 1, _y + 1))); |
45 | return (1 - u) * (1 - v) * data_00 + (1 - u) * v * data_01 + u * (1 - v) * data_10 + u * v * data_11; |
50 | vec2 frag_pos = vec2(gl_FragCoord.x, gl_FragCoord.y); |
52 | if (getDistance(in_circle_pos, frag_pos) > in_circle_radius) |
53 | gl_FragColor = texture2D(textureSampler, gl_TexCoord[texture_id].st); |
55 | gl_FragColor = getColor(); |
再来看看一看客户端主要操作。
从编译的Shader程序中获取变量,用于后续操作。
1 | m_circle_pos = glGetUniformLocation(m_program, "in_circle_pos" ); |
2 | m_circle_radius = glGetUniformLocation(m_program, "in_circle_radius" ); |
3 | m_zoom_times = glGetUniformLocation(m_program, "in_zoom_times" ); |
5 | m_image_width = glGetUniformLocation(m_program, "imageWidth" ); |
6 | m_image_height = glGetUniformLocation(m_program, "imageHeight" ); |
7 | m_texture_sampler = glGetUniformLocation(m_program, "textureSampler" ); |
8 | m_texture_id = glGetUniformLocation(m_program, "texture_id" ); |
对上面获取的变量赋值。
1 | glUniform2f(m_circle_pos, circle_pos.x(), circle_pos.y()); |
2 | glUniform1f(m_circle_radius, ( float )100.0); |
3 | glUniform1f(m_zoom_times, ( float )2.0); |
5 | glUniform1f(m_image_width, ( float ) this ->width); |
6 | glUniform1f(m_image_height, ( float ) this ->height); |
8 | glUniform1i(m_texture_sampler, kTexture); |
9 | glUniform1i(m_texture_id, kTexture); |
画图。
1 | glBindTexture(GL_TEXTURE_2D, m_textures[kTexture]); |
4 | glTexCoord2f(0.0, 0.0);glVertex3f(- this ->width/2, this ->height/2, 0.0); |
5 | glTexCoord2f(0.0, 1.0);glVertex3f(- this ->width/2, - this ->height/2, 0.0); |
6 | glTexCoord2f(1.0, 1.0);glVertex3f( this ->width/2, - this ->height/2, 0.0); |
7 | glTexCoord2f(1.0, 0.0);glVertex3f( this ->width/2, this ->height/2, 0.0); |
最终效果如下: