[Serie Yugong] Agosto de 2023 Tema WEBGL - El uso de la luz


prefacio

La luz en WebGL es similar a la luz en el mundo real y es una simulación de luz física. WebGL utiliza algoritmos de trazado de rayos para simular el reflejo, la refracción y la dispersión de la luz en escenas 3D para lograr efectos de luces y sombras realistas.

En WebGL, la fuente de luz es la fuente de luz, que puede simular diferentes tipos de fuentes de luz, como luz paralela, fuente de luz puntual, foco, etc. La luz se emite desde la fuente de luz, pasa a través de varios objetos en la escena y es capturada por la cámara para generar la imagen renderizada final.

Al ajustar la posición, el color, la intensidad y otros parámetros de la fuente de luz, se pueden lograr diferentes efectos de luz y sombra en WebGL, como contraste de luz y oscuridad, reflejo de luz alto, reflejo especular, etc. Estos efectos de luces y sombras pueden mejorar el realismo y la expresividad de las escenas 3D.

1. El uso de la luz

1. Tipo de luz

1.1 Fuente de luz puntual

En WEBGL, una fuente de luz puntual es un tipo de fuente de luz que simula el efecto de iluminación producido por una fuente de luz puntual. Las fuentes de luz puntuales se suelen utilizar para simular fuentes de luz que están relativamente cerca, como bombillas, velas, etc. En comparación con otros tipos de fuentes de luz, la característica de la fuente de luz puntual es que el objeto que ilumina se vuelve más oscuro a medida que se aleja de la fuente de luz. Al mismo tiempo, debido a que solo puede iluminar algunas posiciones espaciales específicas, no es adecuado para iluminar toda la escena o un área determinada. Las fuentes de luz puntuales pueden controlar sus efectos de iluminación configurando sus propiedades, como la posición, la intensidad y el color, y se pueden combinar con otros tipos de fuentes de luz para lograr efectos de iluminación más complejos. En WEBGL, mediante el uso de fuentes de luz puntuales, se pueden simular varios efectos de iluminación en escenas 3D, lo que hace que las escenas sean más realistas y vívidas.

inserte la descripción de la imagen aquí

1.2 Luz paralela

WEBGL (Biblioteca de gráficos web) es una API de JavaScript para renderizar gráficos 3D y 2D interactivos en navegadores web. La luz paralela es un tipo de fuente de luz en WEBGL. Es una fuente de luz paralela a un rayo virtual, similar a un rayo de sol. Todas las direcciones de luz son iguales, por lo que todas las sombras son paralelas.

En WEBGL, podemos usar gl.LIGHT0 para crear fuentes de luz paralelas. Una fuente de luz direccional tiene una dirección que determina en qué dirección se emiten todos los rayos de luz. Crear una fuente de luz paralela requiere establecer su posición y dirección. Por lo general, usamos la función gl.uniformMatrix4fv() para establecer la matriz de posición y dirección de una fuente de luz paralela.

Las fuentes de luz direccional se pueden usar para simular los rayos del sol en escenas al aire libre, pueden crear efectos de sombra y también se pueden usar para crear algunos efectos especiales, como la parte resaltada del material.

inserte la descripción de la imagen aquí

1.3 Luz ambiental

En WebGL, la luz ambiental (Ambient Light) es un tipo de iluminación que existe ampliamente en toda la escena y es un complemento del brillo básico de la superficie del objeto. La luz ambiental no ilumina directamente la superficie de un objeto, sino que proporciona una luz de fondo que hace que la escena parezca más natural. En WebGL, la luz ambiental generalmente se produce mediante luces con una dirección fija o un color fijo, y el color y la intensidad de la luz ambiental también se pueden cambiar ajustando el color ambiental de un material específico. La luz ambiental también se puede mezclar con otros tipos de luces para crear efectos de iluminación más complejos.

inserte la descripción de la imagen aquí

2. Reflexión de la luz

1. Dirección de la luz

"Dirección de la luz" se refiere a la dirección opuesta a la dirección incidente, es decir, desde el punto incidente hasta la dirección de la fuente de luz.

inserte la descripción de la imagen aquí

2.1 Reflexión Ambiental

En WebGL, el reflejo ambiental de la luz se refiere a la influencia de la luz ambiental reflejada en la superficie del objeto sobre la apariencia del objeto. La luz ambiental es el promedio de la luz ambiental reflejada desde todas las direcciones. Por lo general, es muy tenue, pero cuando se enfoca en los detalles de la superficie, puede afectar drásticamente la apariencia de un objeto.

El reflejo del entorno se puede lograr estableciendo la propiedad material del objeto. En WebGL, la influencia de los reflejos ambientales se puede controlar mediante la propiedad de color ambiental. Esta propiedad generalmente se establece en el color base del objeto, que se multiplica por el color de la luz ambiental para calcular el color final.

Además de los colores de los materiales, WebGL también admite el uso de mapas ambientales para simular reflejos ambientales. Un mapa ambiental es una imagen que contiene información de color y resplandor para la luz ambiental. Al representar un objeto, la información del mapa del entorno se utiliza para calcular la influencia de los reflejos del entorno.

Los reflejos del entorno pueden hacer que los objetos se vean más reales y realistas, ya que simula los efectos de la luz circundante. A menudo se usa para crear escenas de alta calidad y efectos realistas en los juegos.

La reflexión ambiental es para la luz ambiental. En la reflexión ambiental, la luz ambiental ilumina el objeto con uniformidad e igual intensidad en todos los aspectos. La dirección de reflexión es la dirección opuesta a la luz incidente. El color final del objeto solo está relacionado con el color de la luz incidente y el color base.

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

inserte la descripción de la imagen aquí

2.2 Reflexión difusa

El reflejo difuso de la luz en WebGL significa que cuando la luz incide en la superficie, debido a factores como la rugosidad de la superficie y el material del objeto en sí, parte de la luz se dispersará en todas las direcciones en lugar de reflejarse en la superficie. mismo ángulo como reflexión especular. . Este proceso de dispersión es la reflexión difusa. El efecto de la reflexión difusa es más natural, lo que puede hacer que la superficie del objeto sea más realista y mejorar el sentido tridimensional de la escena. En WebGL, la implementación de la reflexión difusa se puede realizar calculando el ángulo entre la luz y la superficie normal y el coeficiente de dispersión del material de la superficie.

El color de la luz reflejada en reflexión difusa depende no solo del color de la luz incidente, el color base de la superficie, sino también del ángulo de incidencia formado por la luz incidente y el vector normal de la superficie del objeto.

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

inserte la descripción de la imagen aquí

2.3 Reflexiones mixtas

Cuando la reflexión difusa y la reflexión ambiental existen al mismo tiempo, al sumar los dos se obtendrá el color final observado del objeto.

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

3. Caso

3.1 Vector normal fijo

<!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>

inserte la descripción de la imagen aquí

3.2 Cálculo de vectores normales

<!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>

inserte la descripción de la imagen aquí

Supongo que te gusta

Origin blog.csdn.net/aa2528877987/article/details/132136842
Recomendado
Clasificación