From the previous article we learned how the fragment shader is written:

Chip shader

The chip shader shaderf.fsh

// The texture coordinates varying lowp VEC2 varyTextCoord; Uniform sampler2D colorMap; // Uniform sampler2D colorMap; voidmainGl_FragColor = texture2D(colorMap, varyTextCoord); gl_FragColor = texture2D(colorMap, varyTextCoord); // The return value should be vec4, which is RGBA, the color value. }Copy the code

Gl_FragColor GLSL built-in variable (assign pixel color values) that has been defined in advance in the GLSL language and has corresponding special meanings. The built-in function GLSL pre-encapsulated function texture2D(texture sampler, texture coordinates) to get the corresponding coordinate pixel (read the pixel, read the color value of each pixel).

We know that the Sampler is the built-in data provided by GLSL that texture objects can use, and that sampler is usually defined in a fragment shader and is decorated with uniform modifiers, meaning that the variable cannot be modified. You can see from the code above that there is also a sampler2D that declares the type of sampler. This represents only a two-dimensional texture type. Sampler1D sampler2D, sampler3D said different dimension of texture types.

Uniform sampler2D, which adds a texture to the tile shader.

uniform sampler2D colorMap;
Copy the code

We also use GLSL’s built-in texture function to sample the color value of the texture.

 gl_FragColor = texture2D(colorMap, varyTextCoord);
Copy the code

Texture unit

The sampler2D variable declared here is uniform, but we don’t assign it glUniform. In general, we need to use glUniform1i () to pass texture objects from the CPU to the shader in video memory. The glUniform1i () function is used because we only need to pass in an index value (location) to the texture sampler so that we can set multiple textures in a single shard shader.

The index is called the ‘Texture Unit’ : the position of a Texture is usually called a Texture Unit. The default texture unit for a texture is 0, which is the default active texture unit. The main purpose of the texture unit is to allow us to use more than one texture in the shader.

If we pass in only one texture object, we don’t have to worry about the texture unit. But when there are multiple texture objects to be passed in, we must specify the texture objects and bind them one by one into the shader using the glUniform1i () function in the main function.

By assigning texture units to the sampler, we can bind multiple textures at once, as long as we activate the corresponding texture unit first. Just like glBindTexture, we can use the management ActiveTexture to activate the texture unit and pass in the texture unit we need to use.

GlActiveTexture (GL_TEXTURE0) is activated before binding the texture; glBindTexture(GL_TEXTURE_2D, texture);Copy the code

After activating the texture unit, the subsequent glBindTexture function call binds the texture to the currently active texture unit, GL_TEXTURE0, which is always activated by default.

OpenGL provides 16 texture units for us to use, which means we can activate GL_TEXTURE0 through GL_TEXTRUE15. They are all defined in order, so we can also get GL_TEXTURE8 by GL_TEXTURE0 + 8, which is useful when we need to loop through some texture units.

Texture blending

GLSL’s built-in mix function combines the two textures and outputs the final color value.

varying vec2 TexCoord;
uniform sampler2D ourTexture1;
uniform sampler2D ourTexture2;
void main() {gl_FragColor = mix(texture(ourTexture1, TexCoord), texture(ourTexture2, TexCoord), 0.2); }Copy the code
genType mix (genType x, genType y, float⋅(1− A)+y⋅ ACopy the code

The Mix function takes two values as parameters and interpolates them linearly with respect to the third parameter. (Linear interpolation is an interpolation method for one-dimensional data, which estimates values based on the left and right adjacent data points of the point to be interpolated in the one-dimensional data sequence. Of course, it doesn’t average the data size of the two points (it does average the data size of the two points), but distributes their specific gravity according to the distance to the two points).

For example, if the third value is 0.0, it returns the first input; If it is 1.0, the second input value is returned. Entering 0.2 returns 80% of the first input color and 20% of the second input color, a blend of the two textures.

Setting multiple textures

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture1);
glUniform1i(glGetUniformLocation(ourShader.Program, "ourTexture1"), 0); // Manually set glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, texture2); glUniform1i(glGetUniformLocation(ourShader.Program,"ourTexture2"), 1);
Copy the code

Note that we used glUniform1i to set the uniform sampler position values, or texture units. By setting up glUniform1i, we ensure that each uniform sampler corresponds to the correct texture unit

To use glUniform1i () as a shader inside and program to pass in values, you need to know two parameters. One is that the object receiving the information inside the shader is the location. One is the external data object. Strictly speaking, the incoming data itself is not done by this function, which simply tells the shader which sampler object the texture object corresponds to.

glTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels) GL_TEXTURE_1D, GL_TEXTURE_2D, GL_TEXTURE_3D The level of loading, usually set to 0, which indicates the level of the original image that has not been reduced. Parameter 3: the color value of the texture GL_RGBA, which indicates the internal format of the texture. The internal format is the format in which our pixel data is stored on the graphics card. GL_RGB here obviously means that the color value of the pixel in the texture is stored in RGB format. Parameter 4: texture width parameter 5: texture height parameter 6: border, border width, usually 0. Parameter 7: format (which describes the format in which pixels are stored in memory) Parameter 8: type (which describes the data type in memory) Parameter 9: texture data

Texture flip

When using OpenGL functions to load a texture into a graph, we often encounter the problem that the texture is upside down. The reason is because OpenGL requires the texture coordinate origin (0,0) to be in the lower left corner.

  1. The rotation matrix is used to flip the graph. Without flipping the texture, the vertex coordinates of the graph are rotated 180 degrees, while the texture coordinates remain unchanged.
RotateMatrix GLuint rotate = glGetUniformLocation(self.myprograme,"rotateMatrix"); // Get the degree of shading rotationfloatRadians = 180 * 3.14159f / 180.0f; // Find the sine \ cosine of PI radiansfloat s = sin(radians);
float c = cos(radians);
    
GLfloat zRotation[16] = {
        c, -s, 0, 0, s, c, 0, 0, 0, 0, 1.0, 0, 0.0, 0, 0, 1.0}; GlUniformMatrix4fv (rotate, 1, GL_FALSE, (GL)float *)&zRotation[0]);
/*
glUniformMatrix4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) location: for the ID in the shader count: number of transpose value: pointer */Copy the code

2. When decompressing the image, flip the source file

// Convert UIImage to CGImageRef CGImageRef spriteImage = [UIImage imageNamed:fileName]. Size_t width = CGImageGetWidth(spriteImage); size_t height = CGImageGetHeight(spriteImage); GLubyte * spriteData = (GLubyte *) calloc(width * height *4, sizeof(GLubyte)); CGContextRef spriteContext = CGBitmapContextCreate(spriteData, width, height, 8, width*4,CGImageGetColorSpace(spriteImage), kCGImageAlphaPremultipliedLast); // On CGContextRef, draw the image CGRect rect = CGRectMake(0, 0, width, height); CGContextDrawImage(spriteContext, CGRectMake(0, 0, width, height), spriteImage); CGContextTranslateCTM(spriteContext, rect.origin.x, rect.origin.y); CGContextTranslateCTM(spriteContext, 0, rect.size.height); CGContextScaleCTM (spriteContext, 1.0, 1.0); CGContextTranslateCTM(spriteContext, -rect.origin.x, -rect.origin.y); CGContextDrawImage(spriteContext, rect, spriteImage); // Release context CGContextRelease(spriteContext); // Bind the texture to the default texture ID glBindTexture(GL_TEXTURE_2D, 0);Copy the code

CGContextDrawImage uses the Core Graphics framework, which has a different coordinate system than UIKit. The origin of the UIKit frame is in the upper-left corner of the screen, and the origin of the Core Graphics frame is in the lower-left corner of the screen. CGContextDrawImage parameter 1: drawing context parameter 2: RECT coordinate parameter 3: drawing image

3. Modify the texture coordinates of the slice shader

varying lowp vec2 varyTextCoord;
uniform sampler2D colorMap;
void main() { //gl_FragColor = texture2D(colorMap, varyTextCoord); Gl_FragColor = texture2D (colorMap, vec2 (varyTextCoord. X, 1.0 - varyTextCoord. Y)); // Since the texture coordinates range from 0 to 1, we use 1 to subtract the texture coordinates when flipping.Copy the code

4. Modify vertex shader texture coordinates

attribute vec4 position;
attribute vec2 textCoordinate;
varying lowp vec2 varyTextCoord;

void main() { //varyTextCoord = textCoordinate; VaryTextCoord = vec2 (textCoordinate. X, 1.0 - textCoordinate. Y); gl_Position = position; // Since the texture coordinates range from 0 to 1, we use 1 to subtract the texture coordinates when flipping.Copy the code

It is also possible to flip vertex coordinates directly in the vertex shader:

attribute vec4 position;
attribute vec2 textCoordinate;
varying lowp vec2 varyTextCoord;

void main() { varyTextCoord = textCoordinate; / / varyTextCoord = vec2 (textCoordinate. X 1.0 - textCoordinate. Y); Gl_Position = vec4(position.x, -position.y, position.z, 1.0f); } // When flipping vertices, instead of subtracting the Y value by 1, the vertices are in the range of -1 to 1, so we can just add the negative sign to flip the vertexCopy the code

5. Modify directly from the source texture coordinate data

// The original coordinates GLfloatAttrArr [] = {0.5 f to 0.5 f to 0.0 f to 1.0 f to 1.0 f, / / right - 0.5 f, 0.5 f to 0.0 f, f 0.0, 0.0, f / / upper left - 0.5 f, 0.5 f, f 0.0, 0.0 f, 1.0 f, / / lower left 0.5 f, f 0.5, 0.0 f, f 1.0, 0.0, f / / upper right - 0.5 f, f 0.5, 0.0 f, f 0.0, 0.0, f / / upper left 0.5 f to 0.5 f, 0.0 f, f 1.0, 1.0, f / / lower}; // The changed coordinate GLfloatAttrArr [] = {0.5 f to 0.5 f to 1.0 f to 1.0 f to 0.0 f to 0.5 f to 0.5 f to 1.0 f to 0.0 f to 1.0 f to 0.5 f to 0.5 f to 1.0 f to 0.0 f to 0.0 f to 0.5 f, 0.5 f to 1.0 f, f, 1.0 1.0 f to 0.5 f, 0.5 f to 1.0 f, 0.0 f, f 1.0, 0.5, f - 0.5 f to 1.0 f, f 1.0, 0.0, f};Copy the code

Renderings before flipping:

Flipped effect picture:

The part reference: teacher CC www.jianshu.com/p/848d982db…