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

OpenGL ES Cube map

OpenGL ES cube mapping is essentially a texture map, a 3D texture map. The texture created by a cube map is called a cube map texture, which consists of six separate 2D textures, each of which is a face of the cube map.

The texture of the cube is sampled by a 3D vector (S, T, R) as the texture coordinates. This 3D vector is only used as the direction vector. OpenGL ES gets the texture pixels that the direction vector touches on the surface of the cube as the sampling result. The direction vector touches the texture position of the cubic graph as the sampling point, requiring the center of the cubic graph to be at the origin.

The faces of the cube must be specified in much the same way as 2D textures, and each face must be square (width and height must be the same).

The use of cube texture is basically the same as 2D texture, first generate a texture, activate the corresponding texture unit, and then bind toGL_TEXTURE_CUBE_MAPType texture.

GLuint textureID;
glGenTextures(1, &textureID);
glBindTexture(GL_TEXTURE_CUBE_MAP, textureID);
Copy the code

Since the cube contains six textures, one for each texture, call is requiredglTexImage2DFunction 6 times, OpenGL ES provides 6 different texture targets for the cube graph, corresponding to the 6 sides of the cube graph, and the 6 texture targets increase by 1 in sequence.

Texture Target bearing
GL_TEXTURE_CUBE_MAP_POSITIVE_X right
GL_TEXTURE_CUBE_MAP_NEGATIVE_X On the left
GL_TEXTURE_CUBE_MAP_POSITIVE_Y on
GL_TEXTURE_CUBE_MAP_NEGATIVE_Y Under the
GL_TEXTURE_CUBE_MAP_POSITIVE_Z after
GL_TEXTURE_CUBE_MAP_NEGATIVE_Z before

Load the 6 corresponding image data of the cube into the texture, where m_pSkyBoxRenderImg is the array of image data:

glGenTextures(1, &m_TextureId);
glBindTexture(GL_TEXTURE_CUBE_MAP, m_TextureId);
for (int i = 0; i < sizeof(m_pSkyBoxRenderImg) / sizeof(NativeImage); ++i)
{
	glTexImage2D(
			GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0,
			GL_RGBA, m_pSkyBoxRenderImg[i].width, m_pSkyBoxRenderImg[i].height, 0, GL_RGBA, GL_UNSIGNED_BYTE, m_pSkyBoxRenderImg[i].ppPlane[0]); } glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); glBindTexture(GL_TEXTURE_CUBE_MAP,0);
Copy the code

Similar to normal 2D textures, before objects can be drawn with cube textures, the corresponding texture units need to be activated and bound to the cube. The difference is that in the corresponding fragment shader, the sampler becomes a samplerCube and the texture coordinates become 3d direction vectors.

#version 300 es
precision mediump float;
in vec3 v_texCoord;
layout(location = 0) out vec4 outColor;
uniform samplerCube s_SkyBox;
void main(a)
{
    outColor = texture(s_SkyBox, v_texCoord);
}
Copy the code

Sky box drawing:

// draw SkyBox
glUseProgram(m_ProgramObj);
glBindVertexArray(m_SkyBoxVaoId);
glUniformMatrix4fv(m_MVPMatLoc, 1, GL_FALSE, &m_MVPMatrix[0] [0]);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_CUBE_MAP, m_TextureId);
glUniform1i(m_SamplerLoc, 0);
glDrawArrays(GL_TRIANGLES, 0.36);
Copy the code

Next we want to draw a cube inside the skybox and have the surface of the cube reflect the properties of its surroundings.

Schematic diagram of reflection of objects in skybox:

Where, I represents the observation direction vector, which can be calculated by subtracting the camera position (observer) coordinates from the current vertex coordinates. N represents the normal vector of the object, and R represents the reflection vector. The reflection vector R is calculated by using GLSL’s built-in function Reflect. Finally, the reflection vector R is used as the direction vector to sample the square graph, and the sampling result (a color value corresponding to the reflection environment) is returned. The end result looks like an object reflecting off the skybox.

Vertex shaders used to draw objects in skyboxes (reflecting ambient colors) :

#version 300 es
precision mediump float;
layout(location = 0) in vec3 a_position;
layout(location = 1) in vec3 a_normal;
uniform mat4 u_MVPMatrix;
uniform mat4 u_ModelMatrix;
out vec3 v_texCoord;
out vec3 v_normal;
void main(a)
{
    gl_Position = u_MVPMatrix * vec4(a_position, 1.0);
    v_normal = mat3(transpose(inverse(u_ModelMatrix))) * a_normal;
    v_texCoord = vec3(u_ModelMatrix * vec4(a_position, 1.0));
}
Copy the code

Fragment shaders used to draw objects in skyboxes (reflecting ambient colors) :

#version 300 es
precision mediump float;
in vec3 v_texCoord;
in vec3 v_normal;
layout(location = 0) out vec4 outColor;
uniform samplerCube s_SkyBox;
uniform vec3 u_cameraPos;
void main(a)
{
    float ratio = 1.00 / 1.52;
    vec3 I = normalize(v_texCoord - u_cameraPos);
    / / reflection
    vec3 R = reflect(I, normalize(v_normal));
    / / refraction
    //vec3 R = refract(I, normalize(v_normal), ratio);
    outColor = texture(s_SkyBox, R);
}
Copy the code

Draw sky box and box cube:

UpdateMVPMatrix(m_MVPMatrix, m_AngleX, m_AngleY, 1.0, (float) screenW / screenH);
// draw SkyBox
glUseProgram(m_ProgramObj);
glBindVertexArray(m_SkyBoxVaoId);
glUniformMatrix4fv(m_MVPMatLoc, 1, GL_FALSE, &m_MVPMatrix[0] [0]);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_CUBE_MAP, m_TextureId);
glUniform1i(m_SamplerLoc, 0);
glDrawArrays(GL_TRIANGLES, 0.36);

UpdateMVPMatrix(m_MVPMatrix, m_AngleX, m_AngleY, 0.4 f, (float) screenW / screenH);
// draw Cube
glUseProgram(m_CubeProgramObj);
glBindVertexArray(m_CubeVaoId);
glUniformMatrix4fv(m_CubeMVPMatLoc, 1, GL_FALSE, &m_MVPMatrix[0] [0]);
glUniformMatrix4fv(m_CubeModelMatLoc, 1, GL_FALSE, &m_ModelMatrix[0] [0]);
glUniform3f(m_ViewPosLoc,  0.0 f.0.0 f.1.8 f);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_CUBE_MAP, m_TextureId);
glUniform1i(m_CubeSamplerLoc, 0);
glDrawArrays(GL_TRIANGLES, 0.36);
Copy the code

Implementation code path: NDK_OpenGLES_3_0

reference

Learnopengl.com/Advanced-Op…

Contact and exchange