[Yugong Series] August 2023 WEBGL Topic - The Use of Light


foreword

Light in WebGL is similar to light in the real world and is a physical light simulation. WebGL uses ray tracing algorithms to simulate the reflection, refraction and scattering of light in 3D scenes to achieve realistic light and shadow effects.

In WebGL, the light source is the source of light, which can simulate different types of light sources, such as parallel light, point light source, spotlight, etc. Light is emitted from the light source, passes through various objects in the scene, and is captured by the camera to generate the final rendered image.

By adjusting the position, color, intensity and other parameters of the light source, different light and shadow effects can be achieved in WebGL, such as light and dark contrast, high light reflection, specular reflection, etc. These light and shadow effects can enhance the realism and expressiveness of 3D scenes.

1. The use of light

1. Type of light

1.1 Point light source

In WEBGL, a point light source is a type of light source that simulates the lighting effect produced by a point light source. Point light sources are usually used to simulate light sources that are relatively close, such as light bulbs, candles, etc. Compared with other types of light sources, the feature of point light source is that the object it illuminates becomes darker as it is farther away from the light source. At the same time, because it can only illuminate some specific spatial positions, it is not suitable for illuminating the entire scene or a certain area. Point light sources can control their lighting effects by setting their properties such as position, intensity, and color, and can be combined with other types of light sources to achieve more complex lighting effects. In WEBGL, by using point light sources, various lighting effects can be simulated in 3D scenes, thus making the scenes more realistic and vivid.

insert image description here

1.2 Parallel light

WEBGL (Web Graphics Library) is a JavaScript API for rendering interactive 3D and 2D graphics on web browsers. Parallel light is a type of light source in WEBGL. It is a light source parallel to a virtual ray, similar to a sun ray. All light directions are the same, so all shadow casting is parallel.

In WEBGL, we can use gl.LIGHT0 to create parallel light sources. A directional light source has a direction, which determines in which direction all light rays are emitted. Creating a parallel light source requires setting its position and direction. Usually we use the gl.uniformMatrix4fv() function to set the position and direction matrix of a parallel light source.

Directional light sources can be used to simulate the sun's rays in outdoor scenes, it can create shadow effects, and can also be used to create some special effects, such as the highlight part of the material.

insert image description here

1.3 Ambient light

In WebGL, ambient light (Ambient Light) is a kind of lighting that widely exists in the entire scene, and it is a supplement to the basic brightness of the surface of the object. Ambient light does not directly illuminate the surface of an object, but rather provides a background light that makes the scene look more natural. In WebGL, ambient light is usually produced by lights with a fixed direction or fixed color, and the color and intensity of ambient light can also be changed by adjusting the ambient color of a specific material. Ambient light can also be mixed into other types of lights to create more complex lighting effects.

insert image description here

2. Reflection of light

1. Light direction

"Light direction" refers to the opposite direction of the incident direction, that is, from the incident point to the direction of the light source.

insert image description here

2.1 Environmental Reflection

In WebGL, the environmental reflection of light refers to the influence of the ambient light reflected on the surface of the object on the appearance of the object. Ambient light is the average of ambient light reflected from all directions. It's usually very faint, but when it's focused on surface detail it can dramatically affect the appearance of an object.

Environment reflection can be achieved by setting the material property of the object. In WebGL, the influence of ambient reflections can be controlled using the ambient color property. This property is usually set to the base color of the object, which is multiplied by the color of the ambient light to calculate the final color.

In addition to material colors, WebGL also supports the use of ambient maps to simulate environmental reflections. An environment map is an image that contains color and radiance information for ambient light. When rendering an object, information from the environment map is used to calculate the influence of environment reflections.

Environment reflections can make objects look more real and lifelike as it simulates the effects of surrounding light. It is often used to create high-quality scenes and realistic effects in games.

Environmental reflection is for ambient light. In environmental reflection, the ambient light illuminates the object with uniformity and equal intensity in all aspects. The direction of reflection is the opposite direction of the incident light. The final color of the object is only related to the color of the incident light and the base color. related.

<环境反射光颜色>=<入射光颜色>*表面基底色>

insert image description here

2.2 Diffuse reflection

The diffuse reflection of light in WebGL means that when the light hits the surface, due to factors such as the roughness of the surface and the material of the object itself, part of the light will be scattered in all directions instead of being reflected at the same angle like specular reflection. . This scattering process is diffuse reflection. The effect of diffuse reflection is more natural, which can make the surface of the object more realistic and enhance the three-dimensional sense of the scene. In WebGL, the implementation of diffuse reflection can be realized by calculating the angle between the light and the surface normal and the scattering coefficient of the surface material.

The color of the reflected light in diffuse reflection depends not only on the color of the incident light, the base color of the surface, but also the angle of incidence formed by the incident light and the normal vector of the surface of the object.

入射角a 可以通过 光线方向和法线方向 的点积来计算:
1<光线方向>·<法线方向> = cosa
2<漫反射光颜色>=<入射光颜色>*<表面基底色>(<光线方向>*<法
线方向>)

insert image description here

2.3 Mixed reflections

When diffuse reflection and ambient reflection exist at the same time, adding the two will get the final observed color of the object

<表面的反射光颜色> = <漫反射光颜色>+<环境反射光颜色>

3. Case

3.1 Fixed normal vector

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
  <script src="../lib/index.js"></script>
  <style>
    * {
      
      
      margin: 0;
      padding: 0;
    }

    canvas{
      
      
      margin: 50px auto 0;
      display: block;
      background: yellow;
    }
  </style>
</head>
<body>
<canvas id="canvas" width="400" height="400">
  此浏览器不支持canvas
</canvas>
</body>
</html>
<script>

  const ctx = document.getElementById('canvas')

  const gl = ctx.getContext('webgl')

  // 创建着色器源码
  const VERTEX_SHADER_SOURCE = `
    attribute vec4 aPosition;
    attribute vec4 aNormal;
    varying vec4 vColor;

    uniform mat4 mat;
    void main() {
      // 定义点光源的颜色
      vec3 uPointLightColor = vec3(1.0,1.0,0.0);

      // 点光源的位置
      vec3 uPointLightPosition = vec3(-5.0,6.0,10.0);

      // 环境光
      vec3 uAmbientLightColor = vec3(0.2,0.2,0.2);

      // 物体表面的颜色
      vec4 aColor = vec4(1.0,0.0,0.0,1.0);

      // 顶点的世界坐标
      vec4 vertexPosition = mat * aPosition;

      // 点光源的方向
      vec3 lightDirection = normalize(uPointLightPosition - vec3(vertexPosition));

      // 环境反射
      vec3 ambient = uAmbientLightColor * vec3(aColor);

      // 计算入射角 光线方向和法线方向的点积
      float dotDeg = dot(lightDirection, vec3(aNormal));

      // 漫反射光的颜色
      vec3 diffuseColor = uPointLightColor * vec3(aColor) * dotDeg;

      gl_Position = vertexPosition;
      vColor = vec4(ambient + diffuseColor, aColor.a);
    }
  `; // 顶点着色器

  const FRAGMENT_SHADER_SOURCE = `
    precision lowp float;
    varying vec4 vColor;

    void main() {
      gl_FragColor = vColor;
    }
  `; // 片元着色器

  const program = initShader(gl, VERTEX_SHADER_SOURCE, FRAGMENT_SHADER_SOURCE)

  const aPosition = gl.getAttribLocation(program, 'aPosition');
  const aNormal = gl.getAttribLocation(program, 'aNormal');
  const mat = gl.getUniformLocation(program, 'mat');

  const vertices = new Float32Array([
    // 0123
    1, 1, 1,
    -1, 1, 1,
    -1,-1, 1,
    1,-1, 1,
    // 0345
    1, 1, 1,
    1,-1, 1,
    1,-1,-1,
    1, 1,-1,
    // 0156
    1, 1, 1,
    1, 1, -1,
    -1, 1,-1,
    -1, 1,1,
    // 1267
    -1, 1, 1,
    -1,1, -1,
    -1, -1,-1,
    -1,-1,1,
    // 2347
    -1,-1, 1,
    1,-1, 1,
    1,-1,-1,
    -1,-1,-1,
    // 4567
    1,-1,-1,
    1, 1,-1,
    -1, 1,-1,
    -1,-1,-1,
  ])

  const buffer = gl.createBuffer();
  gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
  gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
  gl.vertexAttribPointer(aPosition, 3, gl.FLOAT, false, 0, 0);
  gl.enableVertexAttribArray(aPosition)

  // 法向量
  const normals = new Float32Array([
    0.0,0.0,1.0,0.0,0.0,1.0,0.0,0.0,1.0,0.0,0.0,1.0,
    0.0,0.0,-1.0,0.0,0.0,-1.0,0.0,0.0,-1.0,0.0,0.0,-1.0,
    -1.0,0.0,0.0,-1.0,0.0,0.0,-1.0,0.0,0.0,-1.0,0.0,0.0,
    1.0,0.0,0.0,1.0,0.0,0.0,1.0,0.0,0.0,1.0,0.0,0.0,
    0.0,1.0,0.0,0.0,1.0,0.0,0.0,1.0,0.0,0.0,1.0,0.0,
    0.0,-1.0,0.0,0.0,-1.0,0.0,0.0,-1.0,0.0,0.0,-1.0,0.0,
  ])
  const normalBuffer = gl.createBuffer();
  gl.bindBuffer(gl.ARRAY_BUFFER, normalBuffer);
  gl.bufferData(gl.ARRAY_BUFFER, normals, gl.STATIC_DRAW);
  gl.vertexAttribPointer(aNormal, 3, gl.FLOAT, false, 0, 0);
  gl.enableVertexAttribArray(aNormal)

  const indeces = new Uint8Array([
    0,1,2,0,2,3,
    4,5,6,4,6,7,
    8,9,10,8,10,11,
    12,13,14,12,14,15,
    16,17,18,16,18,19,
    20,21,22,20,22,23,
  ])
  const indexBuffer = gl.createBuffer();
  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
  gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indeces, gl.STATIC_DRAW);

  const vm = getViewMatrix(3,3,5,0.0,0.0,0.0,0.0,0.6,0.0);
  const perspective = getPerspective(30, ctx.width / ctx.height, 100, 1);
  gl.enable(gl.DEPTH_TEST);
  gl.uniformMatrix4fv(mat, false, mixMatrix(perspective, vm));
  gl.drawElements(gl.TRIANGLES, indeces.length, gl.UNSIGNED_BYTE, 0);

</script>

insert image description here

3.2 Calculation of normal vectors

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
  <script src="../lib/index.js"></script>
  <style>
    * {
      
      
      margin: 0;
      padding: 0;
    }

    canvas{
      
      
      margin: 50px auto 0;
      display: block;
      background: yellow;
    }
  </style>
</head>
<body>
<canvas id="canvas" width="400" height="400">
  此浏览器不支持canvas
</canvas>
</body>
</html>
<script>

  const ctx = document.getElementById('canvas')

  const gl = ctx.getContext('webgl')

  // 创建着色器源码
  const VERTEX_SHADER_SOURCE = `
    attribute vec4 aPosition;
    attribute vec4 aNormal;
    varying vec4 vColor;

    uniform mat4 mat;
    void main() {
      // 定义点光源的颜色
      vec3 uPointLightColor = vec3(1.0,1.0,0.0);

      // 点光源的位置
      vec3 uPointLightPosition = vec3(-5.0,6.0,10.0);

      // 环境光
      vec3 uAmbientLightColor = vec3(0.2,0.2,0.2);

      // 物体表面的颜色
      vec4 aColor = vec4(1.0,0.0,0.0,1.0);

      // 顶点的世界坐标
      vec4 vertexPosition = mat * aPosition;

      // 点光源的方向
      vec3 lightDirection = normalize(uPointLightPosition - vec3(vertexPosition));

      // 环境反射
      vec3 ambient = uAmbientLightColor * vec3(aColor);

      // 计算入射角 光线方向和法线方向的点积
      float dotDeg = dot(lightDirection, vec3(aNormal));

      // 漫反射光的颜色
      vec3 diffuseColor = uPointLightColor * vec3(aColor) * dotDeg;

      gl_Position = vertexPosition;
      vColor = vec4(ambient + diffuseColor, aColor.a);
    }
  `; // 顶点着色器

  const FRAGMENT_SHADER_SOURCE = `
    precision lowp float;
    varying vec4 vColor;

    void main() {
      gl_FragColor = vColor;
    }
  `; // 片元着色器

  const program = initShader(gl, VERTEX_SHADER_SOURCE, FRAGMENT_SHADER_SOURCE)

  const aPosition = gl.getAttribLocation(program, 'aPosition');
  const aNormal = gl.getAttribLocation(program, 'aNormal');
  const mat = gl.getUniformLocation(program, 'mat');

  const vertices = new Float32Array([
    // 0123
    1, 1, 1,
    -1, 1, 1,
    -1,-1, 1,
    1,-1, 1,
    // 0345
    1, 1, 1,
    1,-1, 1,
    1,-1,-1,
    1, 1,-1,
    // 0156
    1, 1, 1,
    1, 1, -1,
    -1, 1,-1,
    -1, 1,1,
    // 1267
    -1, 1, 1,
    -1,1, -1,
    -1, -1,-1,
    -1,-1,1,
    // 2347
    -1,-1, 1,
    1,-1, 1,
    1,-1,-1,
    -1,-1,-1,
    // 4567
    1,-1,-1,
    1, 1,-1,
    -1, 1,-1,
    -1,-1,-1,
  ])

  const buffer = gl.createBuffer();
  gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
  gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
  gl.vertexAttribPointer(aPosition, 3, gl.FLOAT, false, 0, 0);
  gl.enableVertexAttribArray(aPosition)

  // 通过顶点来计算法向量 start =============
  const res = []
  for (let i = 0; i < vertices.length; i+=12) {
      
      
    const item = cross(
      [
        vertices[i],
        vertices[i+1],
        vertices[i+2]
      ],
      [
        vertices[i+3],
        vertices[i+4],
        vertices[i+5]
      ])
    for (let j = 0; j < 4; j++) {
      
      
      res.push(...item)
    }
  }
  // 法向量
  const normals = new Float32Array(res)
  // 通过顶点来计算法向量  end =============

  const normalBuffer = gl.createBuffer();
  gl.bindBuffer(gl.ARRAY_BUFFER, normalBuffer);
  gl.bufferData(gl.ARRAY_BUFFER, normals, gl.STATIC_DRAW);
  gl.vertexAttribPointer(aNormal, 3, gl.FLOAT, false, 0, 0);
  gl.enableVertexAttribArray(aNormal)

  const indeces = new Uint8Array([
    0,1,2,0,2,3,
    4,5,6,4,6,7,
    8,9,10,8,10,11,
    12,13,14,12,14,15,
    16,17,18,16,18,19,
    20,21,22,20,22,23,
  ])
  const indexBuffer = gl.createBuffer();
  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
  gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indeces, gl.STATIC_DRAW);

  const vm = getViewMatrix(3,3,5,0.0,0.0,0.0,0.0,0.6,0.0);
  const perspective = getPerspective(30, ctx.width / ctx.height, 100, 1);
  gl.enable(gl.DEPTH_TEST);
  gl.uniformMatrix4fv(mat, false, mixMatrix(perspective, vm));
  gl.drawElements(gl.TRIANGLES, indeces.length, gl.UNSIGNED_BYTE, 0);

</script>

insert image description here

Guess you like

Origin blog.csdn.net/aa2528877987/article/details/132136842