Q: What can YOU do with OpenGL? A: Do whatever you want.
OpenGLES is not as scary as you might think, and it’s not as easy as you might think. For 202 years, this series uses OpenGLES3.0.
- [- multimedia -] OpenGLES3.0 access video implementation effects – introduction
- [-opengles3.0 -] Episode 1 Mainline – Open the door to a new world
- [-opengles3.0 -] Set 2 mainline – Draw surface and image map
- [-opengles3.0 -] Episode 3 Mainline – Shader shader and image effects
- [-Opengles3.0 -] Fourth set Branch 1 – Camera access OpenGLES3.0 to achieve special effects
- [-Opengles3.0 -] fifth set Sub 1 – Video access OpenGLES3.0 to achieve special effects
- [-Opengles3.0 -] sixth set mainline – OpenGL viewport details and matrix transformation (part I)
- [-Opengles3.0 -] seventh set mainline – OpenGL viewport details and matrix transformation (part 2)
- [-Opengles3.0 -] episode 8 – Branch 2 – Drawing complex surfaces
- [-Opengles3.0 -] 集 9 – Branch 2 – Drawing stereo graphics
- [-Opengles3.0 -] 10 集 集 2 – OpenGLES Display modeling software 3D models
This article mainly introduces the use of shader code, and based on the custom components of the special effects image by now you should be able to paste an image in the GLSerfaceView, if not, go out and turn left in episode 2
1. Texture shader code
Let’s start with this poster
1.1 Vertex shaders:texture.vsh
# version 300 es statement version of OpenGL es 3.00 specification in said input, Java — > GLSL vec3 said three dimensional vector, vec2 said 2 d vector, the out said output, Here VSH –> FSH gl_Position indicates the position of the vertex,
---->[texture.vsh]----
#version 300 es
layout (location = 0) in vec3 aPosition;
layout (location = 1) in vec2 aTexCoord;
out vec2 vTexCoord;
void main(){gl_Position = vec4(aposition.x, aposition.y, aposition.z, 1.0); vTexCoord = aTexCoord; }Copy the code
Layout (location = 0) indicates that the aPosition handle is 0. The following Java code assigns the aPosition value according to 0 when entering parameters. ATexCoord also notes that the simulator does not support layout well at present, so it needs to start from 0. It is recommended that the real machine test, optionally specified, corresponding to
---->[GLTextureDrawer.java]---- private int aPosition = 0; Private int aTexCoord = 1; // Map coordinate handleCopy the code
What the vertex shader code says is that you need to pass in two variables, aPosition and aTexCoord where gl_Position is a four-dimensional vector that determines the vertex position when rendered, its X,y, and z using the aPosition component, VTexCoord is passed to the fragment shader as output, with a value of aTexCoord
1.2 Fragment shaders:texture.fsh
The higher the precision, the more ↑ the effect, but the shader speed in vec2 vTexCoord; Uniform uniform vTexCoord variable that accepts vertex input, whose value is constant for the duration of shader execution sampler2D type :2D texture
#version 300 es
precision mediump float;
out vec4 outColor;
in vec2 vTexCoord;
uniform sampler2D sTexture;
void main(){
outColor = texture(sTexture, vTexCoord);
}
Copy the code
The variable of the fragment’s OUT identifier is the color value of the output, sTexture carries the texture, and vTexCoord carries the coordinates. The texture function takes the color value of the value pixel as the output. It’s like rubbing a picture onto paper
2. Color effect processing of shaders
Shaders offer a great possibility for manipulating pixels. With RGBA, we can theoretically create all kinds of visual experiences, not to mention so Easy image effects.
2.1 Grayscale image special effects
The texture function returns a 4-dimensional vector that is the RGBA of a color. We just lightly change the RGB of outColor to G
---->[gray.fsh]----
#version 300 es
precision mediump float;
out vec4 outColor;
in vec2 vTexCoord;
uniform sampler2D sTexture;
void main(){ vec4 color= texture(sTexture, vTexCoord); Vec4 (color.g, color.g, color.g, 1.0); }Copy the code
2.2 Pure black and white image effects
There is also a gray scale calculation method 35911(first from left): G = R * 0.3 + G * 0.59 + B * 0.11; After turning gray, pure black and white images can be obtained according to the gray value, that is, if the pixel value is greater than the threshold value, it is black, and if the pixel value is less than the threshold value, it is white. The color flux can be controlled by changing the threshold value, threshold ↓ and flux ↓. Threshold =0, no, white through the threshold control, not too complex color map can be turned into line draft (third from the left).
#version 300 es
precision mediump float;
out vec4 outColor;
in vec2 vTexCoord;
uniform sampler2D sTexture;
const floatThreshold = 0.3; / / threshold voidmain(){
vec4 color= texture(sTexture, vTexCoord);
float r = color.r;
float g = color.g;
floatb = color.b; G = r * 0.3 + g * 0.59 + b * 0.11; g= g <= threshold ? 0.0, 1.0; Vec4 (g, g, g, 1.0); }Copy the code
2.3 Pass parameter control to shader
Threshold would be a bit weak if it could only be written in shader code. How do you put it into a program for dynamic control? For example:
---->[black_white.fsh]----
#version 300 es
precision mediump float;
out vec4 outColor;
in vec2 vTexCoord;
uniform sampler2D sTexture;
uniform floatuThreshold; / / uniform into the voidmain(){
vec4 color= texture(sTexture, vTexCoord);
float r = color.r;
float g = color.g;
floatb = color.b; G = r * 0.3 + g * 0.59 + b * 0.11; g= g <= uThreshold ? 0.0, 1.0; Vec4 (g, g, g, 1.0); }Copy the code
In fact, the previous vertex entry parameter is similar, in the drawing code to find the uThreshold handle and then assign a value can be followed by setThreshold method set value, external control by a Slider
/ / handle to find uThreshold = GLES30. GlGetUniformLocation (program,"uThreshold");
public void draw() {/ /... GLES30.glUseProgram(program); GLES30.glUniform1f(uThreshold, threshold); / / assignmentCopy the code
Don’t be surprised if you get a feel for shaders, this is just the beginning.
2.4 Negative film, nostalgia, cold tone
Negative is to subtract the RGB color value by 1 to obtain the relative color nostalgia is to turn the picture into yellow warm tone, cold tone just switch r and B color value, can achieve the opposite effect
---->[negative]---- r = 1.0-color.r; G = 1.0 - color.g; B = 1.0 - color.b; -- -- -- - > [with] - g + r + r = 0.393 * 0.769 * 0.189 * b; G = 0.349 * r + 0.686 * g + 0.168 * b; B = 0.272 * r + 0.534 * g + 0.131 * b; -- -- -- - > [cold] - b = r + g + 0.189 * 0.769 * 0.393 * b; G = 0.349 * r + 0.686 * g + 0.168 * b; R = 0.272 * r + 0.534 * g + 0.131 * b;Copy the code
The rest of the code is similar, the core is the color value algorithm. Of course, you can also control these coefficients through variables, which can be a simple image editor.
4.5. Time-lapse effect
The bigger the ARG, the bluer it gets
#version 300 es
precision mediump float;
out vec4 outColor;
in vec2 vTexCoord;
uniform sampler2D sTexture;
void main() {floatArg = 3.0; vec4 color= texture(sTexture, vTexCoord);float r = color.r;
float g = color.g;
float b = color.b;
b = sqrt(b)*arg;
if(b) > 1.0 b = 1.0; Vec4 (r, g, b, 1.0); }Copy the code
3. Coordinate effect processing of shaders
In addition to color values, one of the most important data available is that texture coordinates can be used for positional manipulation, such as symmetry, rotation, scaling, splitscreen, etc
3.1 Reverse picture X and Y
Now vTexCoord records the positions of these pixels. Changing vTexCoord will change the position width of the pixels to 1.0. If you just take 1.0-pos.x, the pixels on the right will move to the left (figure 2), and so on
-- -- -- - > [against] x -#version 300 es
precision mediump float;
out vec4 outColor;
in vec2 vTexCoord;
uniform sampler2D sTexture;
void main(){ vec2 pos = vTexCoord.xy; Pos. X = 1.0 - pos. X; outColor = texture(sTexture, pos); } -- -- -- - > [against] y -- -- --#version 300 es
precision mediump float;
out vec4 outColor;
in vec2 vTexCoord;
uniform sampler2D sTexture;
void main(){ vec2 pos = vTexCoord.xy; Pos. Y = 1.0 - pos. Y; outColor = texture(sTexture, pos); } -- -- -- - > [x, y] -#version 300 es
precision mediump float;
out vec4 outColor;
in vec2 vTexCoord;
uniform sampler2D sTexture;
void main(){ vec2 pos = vTexCoord.xy; Pos. X = 1.0 - pos. X; Pos. Y = 1.0 - pos. Y; outColor = texture(sTexture, pos); }Copy the code
3.2 split screen
For example, if y is greater than 0.5, the position of the read texture is pos.y-0.5, which is equivalent to rendering the upper part. You can also adjust the parameter 0.5 to achieve unequal split screen.
binary
#version 300 es
precision mediump float;
out vec4 outColor;
in vec2 vTexCoord;
uniform sampler2D sTexture;
void main(){
vec2 pos = vTexCoord.xy;
if(pos.y<= 0.5) {pos.y = pos.y; }else{pos.y = pos.y -0.5; } outColor = texture(sTexture, pos); }Copy the code
Can also be left and right split mirror:
#version 300 es
precision mediump float;
out vec4 outColor;
in vec2 vTexCoord;
uniform sampler2D sTexture;
void main(){
vec2 pos = vTexCoord;
if(pos.x > 0.5) {pos.x = 1.0 - pos.x; } outColor = texture(sTexture, pos); }Copy the code
Three points
#version 300 es
precision mediump float;
out vec4 outColor;
in vec2 vTexCoord;
uniform sampler2D sTexture;
void main(){
vec2 pos = vTexCoord.xy;
if(pos.y<= 1.0/3.0) {pos.y = pos.y * 1.0; }else if(pos. Y < = 2.0/3.0) {pos. Y = (pos) y - 1.0/3.0) * 1.0; }else{pos.y = (pos.y - 2.0/3.0) * 1.0; } outColor = texture(sTexture, pos); }Copy the code
Four points
#version 300 es
precision mediump float;
out vec4 outColor;
in vec2 vTexCoord;
uniform sampler2D sTexture;
void main(){
vec2 pos = vTexCoord.xy;
if(pos.x <= 0.5){pos.x = pos.x; }else{pos.x = pos.x -0.5; }if(pos.y<= 0.5) {pos.y = pos.y; }else{pos.y = pos.y -0.5; } outColor = texture(sTexture, pos); }Copy the code
You might think it would be nice to fill it up in a quad screen (center), but it would be even better if each splitter could handle different effects (right)
#version 300 es
precision mediump float;
out vec4 outColor;
in vec2 vTexCoord;
uniform sampler2D sTexture;
void main(){
vec2 pos = vTexCoord.xy;
if(pos.x <= 0.5){pos.x = pos.x * 2.0; }else{pos.x = (pos.x -0.5) * 2.0; }if(pos.y<= 0.5) {pos.y = pos.y * 2.0; }else{pos.y = (pos.y -0.5) * 2.0; } outColor = texture(sTexture, pos); }Copy the code
Four points effect is also very simple, but is divided into four pieces to judge, respectively processing just the core algorithm is introduced above. Do you feel like you’re writing complex objects without realizing it?
#version 300 es
precision mediump float;
out vec4 outColor;
in vec2 vTexCoord;
uniform sampler2D sTexture;
void main(){
vec2 pos = vTexCoord.xy;
vec4 result;
if(pos. X < = 0.5 & pos. Y < = 0.5) {/ / upper left pos. X = pos. * 2.0 x; Pos. y = pos.y * 2.0; vec4 color = texture(sTexture, pos); Result = vec4(color.g, color.g, color.g, 1.0); }else if(pos) x > = 0.5 & pos) y < = 0.5) {/ / upper right pos. X = (pos. X - 0.5) * 2.0; Pos.y = (pos.y -0.5) * 2.0; vec4 color= texture(sTexture, pos);float r = color.r;
float g = color.g;
floatb = color.b; G = r * 0.3 + g * 0.59 + b * 0.11; G = g <= 0.4? 0.0, 1.0; Result = vec4(g, g, g, 1.0); }else if(pos. 0.5 && y > pos. X < 0.5) {/ / lower left pos. Y = pos. Y * 2.0; Pos. X = pos. X * 2.0; vec4 color= texture(sTexture, pos);float r = color.r;
float g = color.g;
float b = color.b;
r = 0.393* r + 0.769 * g + 0.189* b;
g = 0.349 * r + 0.686 * g + 0.168 * b;
b = 0.272 * r + 0.534 * g + 0.131 * b;
result = vec4(r, g, b, 1.0);
}else if(pos. 0.5 && y > pos. X > 0.5) {/ / on the pos. Y = (pos. Y - 0.5) * 2.0; Pos.x = (pos.x -0.5) * 2.0; vec4 color= texture(sTexture, pos);float r = color.r;
float g = color.g;
float b = color.b;
b = 0.393* r + 0.769 * g + 0.189* b;
g = 0.349 * r + 0.686 * g + 0.168 * b;
r = 0.272 * r + 0.534 * g + 0.131 * b;
result = vec4(r, g, b, 1.0);
}
outColor = result;
}
Copy the code
3.3. Local effects
Once we can control the position, we can do some interesting things. For example, local effects can be used to specify certain areas, such as (ellipses)
It turned out to be very simple, judging by the distance to the designated point, you can intercept the area
#version 300 es
precision mediump float;
out vec4 outColor;
in vec2 vTexCoord;
uniform sampler2D sTexture;
void main() {floatCenterX = 0.4;floatCenterY = 0.8;floatRaduius = 0.3; vec2 pos = vTexCoord.xy; vec4 color= texture(sTexture, vTexCoord);float r = color.r;
float g = color.g;
float b = color.b;
if((pos.x-centerX)*(pos.x-centerX)+(pos.y-centerY)*(pos.y-centerY)<raduius*raduius){ 1.0); }else{outColor = vec4(r, g, b, 1.0); }}Copy the code
Note that since the width and height are different and the maximum value is 1.0, it is not surprising that the areas with different dimensions are ellipses. The solution is simple, just pass in an aspect ratio correction. The following rate can be used as a variable, which is passed in from Java code, and the Java Bitmap can get the width and height. Other three quantities can also be put forward, is a gray map of the searchlight if there is leisure, you can define a number of special effects, through variable control can become special effects searchlight, according to where, where special effects.
#version 300 es
precision mediump float;
out vec4 outColor;
in vec2 vTexCoord;
uniform sampler2D sTexture;
void main() {floatRate = 1000.0/1369.0;floatCenterX = 0.5;floatCenterY = 0.5 / rate;floatRaduius = 0.25; vec2 pos; pos.x = vTexCoord.x; pos.y= vTexCoord.y/rate; vec4 color= texture(sTexture, vTexCoord);float r = color.r;
float g = color.g;
float b = color.b;
if((pos.x-centerX)*(pos.x-centerX)+(pos.y-centerY)*(pos.y-centerY)<raduius*raduius){ 1.0); }else{outColor = vec4(r, g, b, 1.0); }}Copy the code
3.4. Lighting effect
According to the above effect, achieve a partial lighting effect
#version 300 es
precision mediump float;
out vec4 outColor;
in vec2 vTexCoord;
uniform sampler2D sTexture;
void main() {floatRate = 1000.0/1369.0;floatCenterX = 0.5;floatCenterY = 0.5 / rate;floatThe radius = 0.6;floatStrength = 150.0/255.0; //# Set light intensity
vec2 pos;
pos.x = vTexCoord.x;
pos.y= vTexCoord.y/rate;
vec4 color= texture(sTexture, vTexCoord);
float r = color.r;
float g = color.g;
float b = color.b;
float distance = sqrt((pos.x-centerX)*(pos.x-centerX)+(pos.y-centerY)*(pos.y-centerY));
if(distance<radius){// denotes the area of the circle // calculates the enhanced illumination value according to the distancefloatResult = strength*(1.0 - distance/radius); r = r+result; g = g+result; b = b+result; Vec4 (r, g, b, 1.0); }else{outColor = vec4(r, g, b, 1.0); }}Copy the code
3.5 Rectangular Mosaic
You need to specify the number of rows in a Mosaic, and how many are in a block like 100 pieces, 5 by 5, which is 20 pieces in a row. These parameters can be taken out to play
#version 300 es
precision mediump float;
out vec4 outColor;
in vec2 vTexCoord;
uniform sampler2D sTexture;
void main() {floatRate = 1000.0/1369.0;floatCellX = 5.0;floatCellY = 5.0;floatRowCount = 100.0; vec2 pos = vTexCoord; pos.x = pos.x*rowCount; pos.y = pos.y*rowCount/rate; Pos = vec2(floor(pos.x/cellX)*cellX/rowCount, floor(pos.y/cellY)*cellY/(rowCount/rate))+ 0.5/rowCount*vec2(cellX, cellY); outColor = texture(sTexture, pos); }Copy the code
Local effects and meeting, Mosaic is ok, local Mosaic is still far?
Partial Mosaic
#version 300 es
precision mediump float;
out vec4 outColor;
in vec2 vTexCoord;
uniform sampler2D sTexture;
void main() {floatRate = 1000.0/1369.0;floatCenterX = 0.4;floatCenterY = 0.3 / rate;floatThe radius = 0.15;floatCellX = 1.0;floatCellY = 1.0;floatRowCount = 100.0; vec2 pos; pos.x = vTexCoord.x; pos.y= vTexCoord.y/rate;float distance = sqrt((pos.x-centerX)*(pos.x-centerX)+(pos.y-centerY)*(pos.y-centerY));
if(distance<radius){// vec2 pos = vTexCoord; pos.x = pos.x*rowCount; pos.y = pos.y*rowCount/rate; Pos = vec2(floor(pos.x/cellX)*cellX/rowCount, floor(pos.y/cellY)*cellY/(rowCount/rate))+ 0.5/rowCount*vec2(cellX, cellY); outColor = texture(sTexture, pos); }else{ outColor = texture(sTexture, vTexCoord); }}Copy the code
3.6 Picture lattice
Similar to rectangular Mosaic, the image is divided into several blocks, and the pixel values of UVMosaic points are drawn within the radius of the cell, otherwise, white is drawn
#version 300 es
precision mediump float;
out vec4 outColor;
in vec2 vTexCoord;
uniform sampler2D sTexture;
void main() {floatRate = 1000.0/1369.0;floatCellX = 3.0;floatCellY = 3.0;floatRowCount = 100.0; vec2 sizeFmt=vec2(rowCount, rowCount/rate); vec2 sizeMsk=vec2(cellX, cellY/rate); vec2 posFmt = vec2(vTexCoord.x*sizeFmt.x, vTexCoord.y*sizeFmt.y); Vec2 posMsk = vec2(floor(posFtt.x/sizemsk.x)* sizemsk.x, Floor (posFTt.y/sizemsk.y)* sizemsk.y)+ 0.5*sizeMsk;float del = length(posMsk - posFmt);
vec2 UVMosaic = vec2(posMsk.x/sizeFmt.x, posMsk.y/sizeFmt.y);
vec4 result;
if (del< cellX/2.0)
result = texture(sTexture, UVMosaic);
elseResult = vec4 (1.0, 1.0, 1.0, 0.0); outColor = result; }Copy the code
Based on this, it is easy to achieve circular mosaics
#version 300 es// The hero sees... voidmain(){// The hero sees...else
result = texture(sTexture, vTexCoord);
outColor = result;
}
Copy the code
3.7 Image Dot
This special effect let me earn a lunch money, the need is to turn the picture gray, I had no clue smart idea, this is not a small version of the Mosaic, the Mosaic area black?
#version 300 es
precision mediump float;
out vec4 outColor;
in vec2 vTexCoord;
uniform sampler2D sTexture;
void main() {floatRate = 1000.0/1369.0;floatCellX = 1.0;floatCellY = 1.0;floatRowCount = 100.0;floatSpace = 4.0; vec2 sizeFmt=vec2(rowCount, rowCount/rate); vec2 sizeMsk=vec2(cellX, cellY/rate); vec2 posFmt = vec2(vTexCoord.x*sizeFmt.x, vTexCoord.y*sizeFmt.y); Vec2 posMsk = vec2(floor(posFtt.x/sizemsk.x)* sizemsk.x, Floor (posFTt.y/sizemsk.y)* sizemsk.y)+ 0.5*sizeMsk;float del = length(posMsk - posFmt);
vec2 UVMosaic = vec2(posMsk.x/sizeFmt.x, posMsk.y/sizeFmt.y);
vec4 result;
if< cellX/space (del) result = vec4 (0.2, 0.2, 0.2, 0.1);elseresult = texture(sTexture, vTexCoord); OutColor = vec4 (result. J g, result. J g, result, g, 1.0); }Copy the code
3.8 Out-of-body experience
The core is to periodically obtain a gradually enlarged, gradually transparent image and the original image for superposition
#version 300 es
precision highp float;
invec2 vTexCoord; out vec4 outColor; uniform sampler2D sTexture; // Pass in time uniformfloat uProgress;
void main () {
floatT = 0.7; / / cyclefloatMaxAlpha = 0.4; // Figure 2 maximum transparencyfloatMaxScale = 1.8; // The second picture magnifies the maximum ratio // the progressfloatprogress = mod(uProgress, t) / t; // 0~1 // Current transparencyfloatAlpha = maxAlpha * (1.0 - progress); // The current zoom scalefloatScale = 1.0 + (maxscale-1.0) * progress; WeakPos = VEC2 (0.5 + (vTexcoord.x-0.5)/scale, 0.5 + (vTexcoord.y-0.5)/scale); // The new layer texture coordinates corresponding to the texture pixel value vec4 weakMask = texture(sTexture, weakPos); vec4 mask = texture(sTexture, vTexCoord); // Texture pixel value mixing formula, get the actual color after mixing outColor = mask * (1.0-alpha) + weakMask * alpha; }Copy the code
Here I will use uProgress to present variables to facilitate color dynamics
So that’s the end of this video, you should know a little bit more about shader shaders and secondly, all of these effects can be used in cameras and video playback, which is one of the great things about OpenGL. This is already a long one, and there are some special effects that will be left for the camera and video subchapters.
@Zhang Fengjietele 2020.01.15 not allowed to transfer my public number: the king of programming contact me – email :[email protected] – wechat :zdl1994328 ~ END ~