directory

  1. Basic knowledge of lighting
  2. practice
  3. data
  4. harvest

The effect is as follows:

1. Basic knowledge of illumination

Classical lighting models calculate the light components individually to create a comprehensive lighting effect that is then added to specific points on the material surface. These include Ambient Lighting, Diffuse Lighting, and Specular Lighting.

Image from: Base Lighting

1.1 Ambient Lightiing

Ambient Lightiing does not come from any particular direction and is represented by a constant in the classical lighting model. To use it, just add an Ambient light constant to its source shader as a modulation for gl_Fragcolor

uniform vec4 ambient;
varying vec4 color;

void main{
    vec3 ambientLight = vec3(ambient);
    vec3 rgb = min(color.rgb * ambientLight,vec3(1.0));
    gl_FragColor = vec4(rgb,color.a);
}
Copy the code

1.2 Diffuse Lighting

Diffuse Lighting and specular light both relate to the direction of the source and the direction of the eye. So we introduce the concept of a normal vector.

A normal vector is a unit vector perpendicular to the surface of a vertex.

Since a vertex itself does not have a surface, it is just an independent point, we can use the vertices around it to calculate the surface of the vertex just like the vertex coordinates. The vertex direction is also passed to the shader as a location.

N is the unit normal of the vertex, and L is the direction of the unit vector from the vertex to the light source. Cmat is the color of the surface material, Cli is the color of the light, and Cdiff is the final scattering color.

The corresponding simplified shader code is as follows

Diffuse float diffuseStrength = 0.5; Vec3 unitNormal = normalize(vec3(u_ModelMatrix * vec4(a_normal, 1.0))); vec3 unitNormal = normalize(vec3(u_ModelMatrix * vec4(a_normal, 1.0))); Vec3 lightDir = normalize(lightPos - fragPos); Float diff = Max (dot(unitNormal, lightDir), 0.0); float diff = Max (dot(unitNormal, lightDir), 0.0); diffuse = diffuseStrength * diff * lightColor;Copy the code

1.3 Specular reflection

With only diffuse reflection, even the most beautiful model will lose its luster. We must find a way to show the highlight of the model. In this case, we should use specular reflection to light the model.

H represents the center of the Angle between the ray vector and the view vector (which can be transformed by the view matrix). It’s called a half Angle vector. Sexp is the resulting mirror color. The values of N, L, Cmat and Cli are the same as the scattered light equation

Image from: Base Lighting

The corresponding simplified shader code is as follows:

Specular float specularStrength = 0.9; Vec3 viewDir = normalize(viewpos-fragpos); vec3 viewDir = normalize(viewpos-fragpos); Vec3 reflectDir = reflect(-lightDir, unitNormal); // The Angle between the ray vector and the view vector (which can be converted by the view matrix) is centered. Called half Angle vector float spec = POW (Max (dot(unitNormal, reflectDir), 0.0), 16.0); specular = specularStrength * spec * lightColor;Copy the code

Second, the practice

For better display effect, we use ambient light, diffuse light and specular light based on the cube. Let’s do it in turn.

  1. Draw a cube with a picture texture
  2. Plus ambient light
  3. Plus diffuse light
  4. Add the reflected light from the mirror

2.1 Draw a cube and render the image texture

We can draw a cube by drawing six faces, or we can draw one face and project it. In this article we have the latter implementation

Let’s start with the shader. It’s easy. Pass in vertex coordinates, texture coordinates, MVP matrix, and texture

//cube_vertex.glsl precision mediump float; attribute vec3 aPosition; attribute vec2 aTexCoord; uniform mat4 uMatrix; varying vec2 v_texCoord; Void main() {gl_Position = uMatrix * vec4(aPosition,1.0); v_texCoord = aTexCoord; } //cube_fragment.glsl precision mediump float; varying vec2 v_texCoord; uniform sampler2D uTexture; void main() { gl_FragColor = texture2D(uTexture, v_texCoord); }Copy the code

You can then draw a face, set vertex and texture coordinates for each face, and then project the picture of each face according to the perspective projection transform. The key code is as follows: First determine the vertex coordinates and texture coordinates of each face

Val vertexData = floatArrayOf (/ / position / / texture coord - 0.5 f to 0.5 f to 0.5 f to 0.0 f to 0.0 f to 0.5 f to 0.5 f to 0.5 f to 1.0 f, 0.0 f, f, 0.5 0.5 f to 0.5 f, f 1.0, 1.0 f, f 0.5, 0.5 f to 0.5 f, f 1.0, 1.0 f to 0.5 f, 0.5 f to 0.5 f, f 0.0, 1.0, f - 0.5 f to 0.5 f, 0.5 f, f 0.0, 0.0, f - 0.5 f to 0.5 f, f, 0.5 0.0 f, f 0.0, 0.5 f to 0.5 f, f, 0.5 1.0 f, f 0.0, 0.5, f 0.5 f, f 0.5, 1.0 f, f 1.0, 0.5, f F 0.5, 0.5 f, f 1.0, 1.0 f to 0.5 f, f 0.5, 0.5 f, f 0.0, 1.0, f - 0.5 f to 0.5 f, f 0.5, 0.0, f 0.0 f to 0.5 f, f 0.5, 0.5 f, f 1.0, 0.0, f 0.5 f, f, 0.5-0.5 f, f 1.0, 1.0, f - 0.5 f to 0.5 f, 0.5 f, f 0.0, 1.0, f - 0.5 f to 0.5 f, 0.5 f, f 0.0, 1.0, f - 0.5 f to 0.5 f, 0.5 f, 0.0 f, f, 0.0-0.5 f to 0.5 f, f 0.5, 1.0 f, f 0.0, 0.5 f, f 0.5, 0.5 f, f 1.0, 0.0 f, f 0.5, 0.5 f to 0.5 f, f 1.0, 1.0, f 0.5 f to 0.5 f, 0.0-0.5 f, f, f 1.0, 0.5, f - 0.5 f to 0.5 f, f 0.0, 1.0, f 0.5 f to 0.5 f, f 0.5, 0.0 f, f 0.0, 0.5 f, f 0.5, 0.5 f, f 1.0, 0.0 f to 0.5 f, 0.5 f to 0.5 f to 0.0 f to 1.0 f to 0.5 f to 0.5 f to 0.5 f to 1.0 f to 1.0 f to 0.5 f to 0.5 f to 0.5 f to 1.0 f to 0.0 f to 0.5 f to 0.5 f to 0.5 f to 1.0 f to 0.0 f, 0.5 f to 0.5 f to 0.5 f to 0.0 f to 0.0 f to 0.5 f to 0.5 f to 0.5 f to 0.0 f to 1.0 f to 0.5 f to 0.5 f to 0.5 f to 0.0 f to 1.0 f to 0.5 f to 0.5 f to 0.5 f, 0.5 0.5 1.0 1.0 f, f, f, f, f 0.5, 1.0 f, f 0.0, 0.5 f, f 0.5, 0.5 f, f 1.0, 0.0 f to 0.5 f, f 0.5, 0.5 f, f 0.0, 0.0 f to 0.5 f, 0.5 f, 0.0 f to 0.5 f,, 1.0f) var vertexArrayBuffer = byteBuffer.allocateDirect (vertexData.size * BYTES_PER_FLOAT) .order(ByteOrder.nativeOrder()) .asFloatBuffer() .put(vertexData) vertexArrayBuffer.position(0)Copy the code

Let’s take a look at Render’s implementation

// Determine the perspective and view projection matrices on onSurfaceChanged. override fun onSurfaceChanged(gl: GL10? , width: Int, height: Int) { GLES20.glViewport(0, 0, width, Height) val whRadio = width/(height * 1.0f) matrix.setidentitym (projectionMatrix, 0) Matrix.perspectiveM(projectionMatrix, 0, 60f, whRadio, 1f, 100f) Matrix.setIdentityM(viewMatrix,0); SetLookAtM (viewMatrix,0, 2f,0f,3f, 0f,0f,0f, 0f,0f, 1f,0f)} Gles20.glclear (gles20.gl_COLOR_BUFFer_bit or GLes20.gl_depth_BUFFer_bit) gles20.gl_color_BUFFer_bit or GLes20.gl_depth_BUFFer_Bit) Gles20.glenable (gles20.gl_depth_test) Matrix. SetIdentityM (modeMatrix, gles20.glclearColor (0f, 0f, 0f, 1f) 0) // Use the rotation mode, only the rotation mode, to achieve the view transformation, RotateM (modeMatrix, 0, xRotation, 1f, 0f, 0f) 0f) Matrix.multiplyMM(mvpMatrix, 0, viewMatrix, 0, modeMatrix, 0) Matrix.multiplyMM(mvpMatrix, 0, projectionMatrix, 0, MvpMatrix, 0) GLES20 glUseProgram (mProgram). / / the MVP matrix data GLES20 glUniformMatrix4fv (uMatrixLoc, 1, false, mvpMatrix, Gles20.glactivetexture (gles20.gl_texture0) gles20.glBindTexture (gles20.gl_texture_2d, gles20.gl_texture_2d) gles20.gl_texture_2d skyBoxTexture) GLES20.glUniform1i(uTextureLoc, 0) GLES20.glEnableVertexAttribArray(aPositionLoc) cubeLight.vertexArrayBuffer.position(0); GLES20.glVertexAttribPointer(aPositionLoc, CubeLight.POSITION_COMPONENT_COUNT, GLES20.GL_FLOAT, false, CubeLight.STRIDE, cubeLight.vertexArrayBuffer) GLES20.glEnableVertexAttribArray(aTextureCoorLoc) cubeLight.vertexArrayBuffer.position(CubeLight.POSITION_COMPONENT_COUNT); GLES20.glVertexAttribPointer(aTextureCoorLoc, CubeLight.POSITION_TEXTURE_COUNT, GLES20.GL_FLOAT, false, CubeLight.STRIDE, cubeLight.vertexArrayBuffer) cubeLight.vertexArrayBuffer.position(0); GLES20. GlDrawArrays (GLES20. GL_TRIANGLES, 0 4)}Copy the code

See the code comments for details. The full code has been uploaded to github github.com/ayyb1988/me…

data

OpenGL Programming Guide

NDK OpenGL ES 3.0 development (9) : OpenGL ES 3.0 development (9) : COREANIMATION Draw cube + rotation

harvest

  1. Understand the classical feng’s illumination model
  2. Understand the principle of ambient light, diffuse light and specular light
  3. Split into multiple links gradually realized
  4. Code first to achieve cubic drawing

Since there is a lot of content involved in drawing the cube, the specific practice of lighting will be left for the next article. In the process of learning and practice, the map is very important. When you don’t know where to go, open the map and think about the destination, and you can quickly sort out the road to go. Come on together.

Thank you for reading the next article we continue to learn the practice of lighting part of the content, welcome to follow the public account “Audio and video development journey”, learn and grow together.

Welcome to communicate