The original article was first published on the wechat official account Byteflow

What is texture

In real life, a Texture is most commonly used to decorate 3D objects. It works like a sticker on the surface of an object to enrich the surface and details. In OpenGLES development, textures can be used as containers for storing data in addition to decorative surfaces.

So in OpenGLES, texture is actually a complex data set that can be sampled, which is the image data structure of GPU. Texture can be divided into 2D texture, cubic texture and 3D texture.

2D texture is the most commonly used and common form of texture in OpenGLES. It is a two-dimensional array of image data. A single data element in a texture is called a striatum or texture pixel.

A cube texture is a texture made up of six separate 2D texture faces. A cube texture pixel is read by using a three-dimensional coordinate (S, T, R) as the texture coordinate.

A 3D texture can be viewed as a 2D texture as an array of facets, similar to a cube texture, accessed using 3D coordinates.

What is texture mapping

In OpenGLES, texture mapping is to specify appropriate texture coordinates for the vertex coordinates of the pixel, select a specific texture region in the texture map through texture coordinates, and finally map the selected texture region to the specified pixel through the mapping relationship between texture coordinates and the vertex.

Texture mapping, also known as texture mapping, is simply to map the texture region specified by texture coordinates (texture coordinate system) to the rendering region corresponding to vertex coordinates (rendering coordinate system or OpenGLES coordinate system).

The four texture coordinates are T0 (0,0), T1 (0,1), T2 (1,1) and T3 (1,0) respectively.

4 texture coordinates are V0 (-1, 0.5), V1 (-1, -0.5), V2 (1, -0.5), V3 (1, 0.5)

Since OpenGLES draws in triangles, set the two triangles drawn to V0V1V2 and V0V2V3. When we adjust the order of texture coordinates to keep the vertex coordinates in the same order, as T0T1T2T3 -> T1T2T3T0, we draw a texture map rotated 90 degrees clockwise. So adjusting the corresponding relationship between texture coordinates and vertex coordinates can realize simple rotation of texture map.

Simple implementation of texture mapping

General steps for texture mapping:

  • Generate texture, compile link shader program
  • Determine texture coordinates and corresponding vertex coordinates
  • Load image data to texture, load texture coordinates and vertex coordinates to shader program
  • draw

Generate a texture and load image data into the texture

// Generate a texture and assign the texture ID to m_TextureId
glGenTextures(1, &m_TextureId); 

// bind texture m_TextureId to type GL_TEXTURE_2D
glBindTexture(GL_TEXTURE_2D, m_TextureId);

// Set the texture's s-axis stretch mode to Intercept
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 
// Set the texture T axis (vertical axis) stretch mode to Intercept
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

// Set the texture sampling mode
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

// Load image data in RGBA format
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_RenderImage.width, m_RenderImage.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, m_RenderImage.ppPlane[0]);

Copy the code

Slice shader script for texture sampling

#version 300 es                                     
precision mediump float;                            
invec2 v_texCoord; layout(location = 0) out vec4 outColor; uniform sampler2D s_TextureMap; // Declare the use of voidmain() {// texture() is the built-in sampling function, v_texCoord is the texture coordinates passed in by the vertex shader. Output sample RGBA value (4-dimensional vector) outColor = texture(s_TextureMap, v_texCoord); }Copy the code

Simple implementation code

// Generate texture, compile link shader program
void TextureMapSample::Init()
{
	//create RGBA texture
	glGenTextures(1, &m_TextureId);
	glBindTexture(GL_TEXTURE_2D, m_TextureId);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glBindTexture(GL_TEXTURE_2D, GL_NONE);

	char vShaderStr[] =
			"#version 300 es \n"
			"layout(location = 0) in vec4 a_position; \n"
			"layout(location = 1) in vec2 a_texCoord; \n"
			"out vec2 v_texCoord; \n"
			"void main() \n"
			"{ \n"
			" gl_Position = a_position; \n"
			" v_texCoord = a_texCoord; \n"
			"} \n";

	char fShaderStr[] =
			"#version 300 es \n"
			"precision mediump float; \n"
			"in vec2 v_texCoord; \n"
			"layout(location = 0) out vec4 outColor; \n"
			"uniform sampler2D s_TextureMap; \n"
			"void main() \n"
			"{ \n"
			" outColor = texture(s_TextureMap, v_texCoord); \n"
			"} \n";

	m_ProgramObj = GLUtils::CreateProgram(vShaderStr, fShaderStr, m_VertexShader, m_FragmentShader);
	if (m_ProgramObj)
	{
		m_SamplerLoc = glGetUniformLocation(m_ProgramObj, "s_TextureMap");
	}
	else
	{
		LOGCATE("TextureMapSample::Init create program fail"); }}// Load image data, texture coordinate and vertex coordinate data, draw and implement texture mapping
void TextureMapSample::Draw(int screenW, int screenH)
{
	LOGCATE("TextureMapSample::Draw()");

	if(m_ProgramObj == GL_NONE || m_TextureId == GL_NONE) return;
	GLfloat verticesCoords[] = {
			1.0 f.0.5 f.0.0 f.// Position 0
			1.0 f.0.5 f.0.0 f.// Position 1
			1.0 f.0.5 f.0.0 f.// Position 2
			1.0 f.0.5 f.0.0 f.// Position 3
	};

	GLfloat textureCoords[] = {
			0.0 f.0.0 f.// TexCoord 0
			0.0 f.1.0 f.// TexCoord 1
			1.0 f.1.0 f.// TexCoord 2
			1.0 f.0.0 f         // TexCoord 3
	};

	GLushort indices[] = { 0.1.2.0.2.3 };

	//upload RGBA image data
	glActiveTexture(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_2D, m_TextureId);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, m_RenderImage.width, m_RenderImage.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, m_RenderImage.ppPlane[0]);
	glBindTexture(GL_TEXTURE_2D, GL_NONE);

	// Use the program object
	glUseProgram (m_ProgramObj);

	// Load the vertex position
	glVertexAttribPointer (0.3, GL_FLOAT,
							GL_FALSE, 3 * sizeof (GLfloat), verticesCoords);
	// Load the texture coordinate
	glVertexAttribPointer (1.2, GL_FLOAT,
							GL_FALSE, 2 * sizeof (GLfloat), textureCoords);

	glEnableVertexAttribArray (0);
	glEnableVertexAttribArray (1);

	// Bind the RGBA map
	glActiveTexture(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_2D, m_TextureId);

	// Set the RGBA map sampler to texture unit to 0
	glUniform1i(m_SamplerLoc, 0);

	glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);

}

Copy the code

Results the figure

Implementation code path: github.com/githubhaoha…

Contact and exchange