Next, explore textures.

Texture is simply an image. The process of mapping an image to a graph is called texture mapping.

Let’s say you have the following graph and triangle and you want to map part of the graph to the triangle.

The result is this:

This is a small example of texture mapping.

The basic principle of

Note that OpenGL draws objects in 3D and textures in 2D, so texture mapping maps 2D textures to 3D objects, just like wrapping an object in a piece of paper, but following certain rules.

Objects drawn in OpenGL have coordinates, each point corresponds to x, Y, z coordinates, and texture also has its coordinates, as long as every point in the 3D object corresponds to a point in the 2D texture, then the texture can be mapped to the 3D object.

The coordinates of the texture are calledTextured coordinate system. It has a range of only

Its coordinate origin is located in the lower left corner, the horizontal right is the S axis, the vertical up is the Y axis. Regardless of the actual texture image size, the maximum horizontal and vertical coordinates are 1.

For example, if the actual map has a resolution of 512 x 256 pixels, the 512th horizontal pixel corresponds to texture coordinate 1, and the 256th vertical pixel corresponds to texture coordinate 1. However, it is best to use a texture map with 2 to the power of n pixels.

The basic idea of texture mapping is to first specify appropriate texture coordinates for each vertex in the pixel, then determine the selected texture region in the texture map by texture coordinates, and finally map the content in the selected texture region to the specified pixel according to texture coordinates.

Texture mapping is reflected in OpenGL’s rendering pipeline: in the rendering pipeline, vertex shaders are first carried out to draw the rough shape of the object, and then rasterization is carried out to raster the object into many fragments, and then fragment shaders are carried out to color each fragment of the graph.

In the rasterization stage, texture coordinates will be generated based on the vertex shader’s processing of the texture and the interpolation between the segment and each vertex, and then the interpolated results will be fed into the segment shader.

Shader operation

Shaders also change when using textures instead of drawing directly.

Vertex shaders:

attribute vec4 a_Position;
attribute vec2 a_TextureCoordinates;
varying vec2 v_TextureCoordinates;
uniform mat4 u_ModelMatrix;
uniform mat4 u_ViewMatrix;
uniform mat4 u_ProjectionMatrix;
uniform mat4 u_Matrix;

void main() {
    v_TextureCoordinates = a_TextureCoordinates ;
    gl_Position = u_ProjectionMatrix * u_ViewMatrix * u_ModelMatrix * a_Position;
}
Copy the code

The v_TextureCoordinates variable is added to the vertex shader. It is of type VARYING, which means variable type. This variable is processed during rasterization and then passed into the fragment shader.

Fragment shader

precision mediump float;
uniform sampler2D u_TextureUnit;
varying vec2 v_TextureCoordinates;

void main(){
	// No texture color assignment: gl_FragColor = u_Color;
    gl_FragColor = texture2D(u_TextureUnit,v_TextureCoordinates);
}
Copy the code

The v_TextureCoordinates1 variable is the one that accepts the value passed in from the vertex shader, and the u_TextureUnit variable is the sampler used and is of type sampler2D.

The fragment shader after using the texture assigns values to the colors using the texture2D function.

The texture2D function is used to sample, taking pixels from the texture and assigning them to the gl_FragColor variable, which is the final color.

The upper code

With an overview of shader code, it’s time to move on to the upper level Java code.

Similar to creating an OpenGL ProgramId, using a texture requires creating a texture ID.

	 /** * Returns the ID of the OpenGl texture after the image is loaded@param context
     * @param resourceId
     * @return* /
    public static int loadTexture(Context context, int resourceId) {
        final int[] textureObjectIds = new int[1];
        glGenTextures(1, textureObjectIds, 0);
        if (textureObjectIds[0] = =0) {
            Timber.d("Could not generate a new OpenGL texture object.");
            return 0;
        }
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inScaled = false;
        final Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), resourceId, options);

        if (bitmap == null) {
            Timber.d("resource Id could not be decoded");
            glDeleteTextures(1, textureObjectIds, 0);
            return 0;
        }

        glBindTexture(GL_TEXTURE_2D, textureObjectIds[0]);

        // Set the filter mode for zooming out
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
        // Set the filter mode for zooming in
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

        // Load the texture into OpenGL, read the Bitmap data defined by the Bitmap, and copy it to the currently bound texture object
        // The currently bound texture object will be attached to the texture image.
        texImage2D(GL_TEXTURE_2D, 0, bitmap, 0);

        bitmap.recycle();
        
        // Automatically generates all required multi-level fade textures for the currently bound texture
        // Generate MIP map
        glGenerateMipmap(GL_TEXTURE_2D);

        // Unbind the texture to avoid accidentally changing the texture with other texture methods
        glBindTexture(GL_TEXTURE_2D, 0);

        return textureObjectIds[0];
    }
Copy the code
  1. The first to useglGenTexturesCreate the texture ID.
  2. If the creation fails, useglDeleteTexturesDelete and exit.
  3. After successful creation, use theglBindTextureThe texture ID () function binds the texture ID to the texture target.
  4. It then sets how the texture filters when zoomed in and out.
  5. To usetexImage2DBind texture targets to Bitmap images.
  6. useglGenerateMipmapFunction to generate multilevel fade texture and MIP texture maps.
  7. To useglBindTextureFunction unbind.

GlBindTexture function

The highlight here is the glBindTexture function.

It binds the texture name to the specified active texture unit. When a texture is bound to a target, the previously bound texture object of the target texture unit is automatically disconnected. The texture target is bound to 0 by default, so if you want to disconnect, you should also bind the texture target to 0.

So the glBindTexture(GL_TEXTURE_2D, 0) is called at the end of the code to unbind.

When a texture is bound, OpenGL operations on the bound target are applied to the bound texture, and a query on the bound target returns the state of the bound texture on it.

That is, the texture target becomes an alias for the texture bound to it, and a texture name of 0 refers to its default texture. Therefore, when you call glTexParameteri to set the filter method for the texture target, you are also setting the filter method for the texture.

Bind values in the texture

Once the texture shader ID is created and set, it is time to bind and set variables in the shader language.

		// Bind variables in the shader script
        uTextureUnitAttr = glGetUniformLocation(mProgram, U_TEXTURE_UNIT)
		mTextureId = TextureHelper.loadTexture(mContext,R.drawable.texture)
		// Activate the texture unit
        glActiveTexture(GL_TEXTURE0)
        // Bind the texture target
        glBindTexture(GL_TEXTURE_2D, mTextureId)
        // Assign to the sample2D variable in the fragment shader
        glUniform1i(uTextureUnitAttr, 0)

Copy the code

The sampler2D variable of Uniform type is defined in the shader script, which is bound and assigned by the upper application code. Variables of type VARYING are passed by the vertex shader and no additional assignment is required.

The next step is to activate the texture unit using the glActiveTexture function. In a system, the data of texture units is limited. In the source code, there are thirty-two texture units defined from GL_TEXTURE0 to GL_TEXTURE31, but the exact number depends on the model.

This can be found using the GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS constant.

   var intBuffer:IntBuffer = IntBuffer.allocate(1)
   glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS,intBuffer)
   LogUtil.d("max combined texture image units " + intBuffer[0])
Copy the code

Once the texture unit is activated, you need to bind the texture target.

A texture unit contains multiple types of texture targets, such as GL_TEXTURE_1D, GL_TEXTURE_2D, CUBE_MAP, and so on.

Because a texture unit is an alias for a texture, anything you do to a texture unit is the same as anything you do to a texture. Extract some of the operations done to the texture into the function, and finally load the texture and bind it to the texture target.

Assign a value of 0 to the sampler using the glUniform1i function, which corresponds to activating the texture unit. Since the active texture unit is 0, the assignment is also 0. If it’s not consistent here, you can’t see anything directly.

The actual effect

After binding and setting the values in the fragment shader, the rest of the process is the same as drawing the basic graphics.

The specific rendering operations are defined in the fragment shader, while the upper layer code does not need to pay much attention to, in the case of the vertex shader unchanged, you can even just change the fragment shader value to draw different texture effects.

Summary & confusion of nouns

It is easy to confuse the texture unit and texture target above.

GL_TEXTURE0, GL_TEXTURE1, GL_TEXTURE2 are texture units. The number of texture units on a machine is limited, depending on the specific model. GlActiveTexture activates specific texture units.

A texture unit contains multiple types of texture targets: GL_TEXTURE_1D, GL_TEXTURE_2D, CUBE_MAP, and so on.

GlGenTextures generates a value of int that is a texture. GlBindTexture binds the texture to the target, and all operations performed on the target are reflected in the texture.

The texture target requires a Bitmap to be attached via the texImage2D function.

reference

  1. http://blog.csdn.net/opengl_es/article/details/19852277
  2. http://blog.csdn.net/artisans/article/details/76695614

Finally, if you think the article is good, welcome to pay attention to wechat public number: