[Serie Yugong] Tema WEBGL en agosto de 2023 - Método de vértice y método de índice de métodos de dibujo


prefacio

Los métodos de dibujo de WEBGL incluyen principalmente los siguientes tipos:

  1. gl.drawArrays: Dibuje gráficos directamente usando matrices de vértices. Este método necesita pasar un tipo de enumeración para representar el tipo de gráfico básico que se dibujará, por ejemplo, gl.TRIANGLES significa usar triángulos para dibujar, gl.POINTS significa usar puntos para dibujar, gl.LINES significa usar segmentos de línea para dibujar, etc Este método puede modificar los gráficos dibujados modificando los datos de vértice en la matriz de vértice.

  2. gl.drawElements: Dibuje gráficos utilizando una matriz indexada. Este método es similar a gl.drawArrays, pero necesita pasar una matriz de índice para indicar el orden de los vértices al dibujar gráficos. El uso de una matriz de índice puede reducir de manera efectiva la cantidad de vértices repetidos y mejorar el rendimiento del dibujo.

  3. gl.drawArraysInstanced: use matrices de vértices y matrices instanciadas para dibujar múltiples gráficos similares. Este método necesita pasar una matriz instanciada para representar los atributos de varias instancias, como el color, la posición, etc. Este método se puede utilizar para dibujar una gran cantidad de gráficos similares, mejorando así el rendimiento del dibujo.

  4. gl.drawElementsInstanced: dibuje múltiples gráficos similares utilizando matrices indexadas y matrices instanciadas. Este método es similar a gl.drawArraysInstanced, pero necesita pasar una matriz de índice para indicar el orden de los vértices. El uso de una matriz de índice puede reducir de manera efectiva la cantidad de vértices repetidos y mejorar el rendimiento del dibujo.

  5. gl.drawRangeElements: use una matriz de índice para dibujar parte de los gráficos. Este método puede especificar el índice de inicio y el índice final del dibujo, de modo que solo se pueda dibujar una parte de los gráficos. Este método se puede utilizar para dibujar gráficos complejos, como diferentes partes del modelo.

Estos métodos de dibujo se pueden seleccionar y utilizar de acuerdo con las necesidades y escenarios reales. En aplicaciones prácticas, también se pueden lograr gráficos y efectos más complejos combinando múltiples métodos de dibujo.

1. Método de vértice

1. El concepto de método de vértice

El método de vértice de WebGL se refiere al uso de datos de vértice para describir objetos 3D en WebGL. Todo objeto 3D está formado por una serie de vértices que se organizan en una malla de triángulos, formando una superficie.

El beneficio de usar datos de vértices es que puede reducir en gran medida la cantidad de datos que deben transferirse. Por lo general, los objetos 3D contienen una gran cantidad de datos de vértices, pero muchos de estos datos son redundantes y la cantidad de datos se puede reducir si varios triángulos comparten el mismo vértice.

En WebGL, los datos de vértices generalmente consisten en la siguiente información:

  1. Información de posición en el espacio 3D: representada por tres números de coma flotante (x, y, z).

  2. Coordenadas de textura de vértice: representadas por dos números de coma flotante (u, v).

  3. Vector normal de vértice: representado por tres números de coma flotante (x, y, z), que se utiliza para calcular la iluminación.

  4. Otros atributos: como color de vértice, transparencia, etc.

En WebGL, los pasos generales para usar el método de vértice son los siguientes:

  1. Cree un programa sombreador de vértices para procesar datos de vértices.

  2. Cree un programa de sombreado de fragmentos que procese los colores de los píxeles.

  3. Cargue datos de modelos 3D y conviértalos a un formato que WebGL pueda usar. Normalmente, los datos del modelo se cargan desde archivos externos, como OBJ, PLY, etc.

  4. Pase los datos del vértice al programa sombreador de vértices para renderizar el modelo 3D.

  5. Los colores de los píxeles se calculan en el programa fragment shader y se muestran en la pantalla.

  6. Finalmente, el resultado renderizado se muestra en la pantalla utilizando un contexto WebGL.

Al usar el método de vértices, WebGL puede representar una gran cantidad de objetos 3D complejos de manera muy eficiente para lograr una escena 3D más realista.
inserte la descripción de la imagen aquí

2. Caso

<!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 aColor;
    varying vec4 vColor;

    uniform mat4 mat;
    void main() {
      gl_Position = mat * aPosition;
      vColor = aColor;
    }
  `; // 顶点着色器

  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 aColor = gl.getAttribLocation(program, 'aColor');
  const mat = gl.getUniformLocation(program, 'mat');

  // 顶点
  const v0 = [1,1,1];
  const v1 = [-1,1,1];
  const v2 = [-1,-1,1];
  const v3 = [1,-1,1];
  const v4 = [1,-1,-1];
  const v5 = [1,1,-1];
  const v6 = [-1,1,-1];
  const v7 = [-1,-1,-1];
  const points = new Float32Array([
    ...v0,...v1,...v2, ...v0,...v2, ...v3, // 前
    ...v0,...v3,...v4, ...v0,...v4, ...v5, // 右
    ...v0,...v5,...v6, ...v0,...v6, ...v1, // 上面
    ...v1,...v6,...v7, ...v1,...v7, ...v2, // 左
    ...v7,...v4,...v3, ...v7,...v3, ...v2, // 底
    ...v4,...v7,...v6, ...v4,...v6, ...v5, // 后
  ])

  const buffer = gl.createBuffer();

  const BYTES = points.BYTES_PER_ELEMENT;

  gl.bindBuffer(gl.ARRAY_BUFFER, buffer);

  gl.bufferData(gl.ARRAY_BUFFER, points, gl.STATIC_DRAW);

  gl.vertexAttribPointer(aPosition, 3, gl.FLOAT, false, 0, 0);

  gl.enableVertexAttribArray(aPosition)

  const colorData = new Float32Array([
    1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,
    0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,
    0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,0,0,1,
    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,
  ])
  const colorBuffer = gl.createBuffer();
  gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
  gl.bufferData(gl.ARRAY_BUFFER, colorData, gl.STATIC_DRAW);
  gl.vertexAttribPointer(aColor, 3, gl.FLOAT, false, 0, 0);
  gl.enableVertexAttribArray(aColor)


  let eyex = 3;
  let eyey = 3;
  let eyez = 5;

  let deg = 0;
  function draw() {
      
      
    deg += 0.01;
    const rotate = getRotateMatrix(deg);
    const vm = getViewMatrix(eyex,eyey,eyez,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(mixMatrix(perspective, vm), rotate));
    gl.drawArrays(gl.TRIANGLES, 0, points.length / 3);

    requestAnimationFrame(draw)
  }

  draw()
</script>

inserte la descripción de la imagen aquí

En segundo lugar, el método de índice

1. El concepto de indexación

La indexación en WEBGL es una técnica para optimizar el rendimiento de la representación, que puede reducir la cantidad de vértices calculados repetidamente, reducir la cantidad de datos transmitidos y mejorar la eficiencia de la representación.

El método de índice puede acceder a los datos en la matriz de vértices (Matriz de vértices) a través de una matriz de índice (Matriz de índice), donde cada elemento de la matriz de índice es un puntero a un vértice en la matriz de vértice. La ventaja de usar matrices indexadas es que se puede mejorar el rendimiento al reducir la cantidad de veces que se recalculan los datos de vértice utilizando la misma reutilización de datos de vértice.

En WEBGL, el uso de la indexación requiere el uso de dos búferes: uno para almacenar datos de vértice y el otro para almacenar datos de índice. Durante el proceso de representación, WEBGL leerá los datos de vértice del búfer de vértice y luego accederá a los datos de vértice de acuerdo con la matriz de índice en el búfer de índice.

El siguiente es un proceso de renderizado WEBGL utilizando el método index:

1. Crear y vincular el búfer de vértice y el búfer de índice;

2. Escribir datos de vértices en el búfer de vértices;

3. Escriba la matriz de índice en el búfer de índice;

4. Use la función gl.drawElements para renderizar, que lee los datos de vértice en el búfer de vértice y la matriz de índice en el búfer de índice, y luego dibuja el triángulo.

El método de índice se usa muy comúnmente en la representación de modelos 3D, que no solo puede mejorar la eficiencia de la representación, sino también reducir la cantidad de datos transmitidos y reducir la ocupación del ancho de banda de la red.

2. Caso

gl.drawElements (modo, recuento, tipo, desplazamiento)

  • modo mismo gldrawArrays0
  • contar el número de vértices para dibujar
  • tipo vértice tipo de datos
  • La posición donde la matriz de índice de compensación comienza a dibujar

inserte la descripción de la imagen aquí

<!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 aColor;
    varying vec4 vColor;

    uniform mat4 mat;
    void main() {
      gl_Position = mat * aPosition;
      vColor = aPosition;
    }
  `; // 顶点着色器

  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 aColor = gl.getAttribLocation(program, 'aColor');
  const mat = gl.getUniformLocation(program, 'mat');

  const vertices = new Float32Array([
     1, 1, 1,
    -1, 1, 1,
    -1,-1, 1,
     1,-1, 1,
     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 indeces = new Uint8Array([
    0,1,2,0,2,3,
    0,3,4,0,4,5,
    0,5,6,0,6,1,
    1,6,7,1,7,2,
    7,4,3,7,3,2,
    4,6,7,4,6,5,
  ])
  const indexBuffer = gl.createBuffer();
  gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
  gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indeces, gl.STATIC_DRAW);

  let eyex = 3;
  let eyey = 3;
  let eyez = 5;

  let deg = 0;
  function draw() {
      
      
    deg += 0.01;
    const rotate = getRotateMatrix(deg);
    const vm = getViewMatrix(eyex,eyey,eyez,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(mixMatrix(perspective, vm), rotate));
    gl.drawElements(gl.TRIANGLES, indeces.length, gl.UNSIGNED_BYTE, 0);

    requestAnimationFrame(draw)
  }

  draw()
</script>

inserte la descripción de la imagen aquí

<!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 aColor;
    varying vec4 vColor;

    uniform mat4 mat;
    void main() {
      gl_Position = mat * aPosition;
      vColor = aColor;
    }
  `; // 顶点着色器

  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 aColor = gl.getAttribLocation(program, 'aColor');
  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,
  ])

  /*
     1, 1, 1,   0
    -1, 1, 1,   1
    -1,-1, 1,   2
     1,-1, 1,   3
     1,-1,-1,   4
     1, 1,-1,   5
    -1, 1,-1,   6
    -1,-1,-1,   7
  * */
  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 colors = new Float32Array([
    0.4,0.4,1.0,0.4,0.4,1.0,0.4,0.4,1.0,0.4,0.4,1.0,
    0.4,1.0,0.4,0.4,1.0,0.4,0.4,1.0,0.4,0.4,1.0,0.4,
    1.0,0.4,0.4,1.0,0.4,0.4,1.0,0.4,0.4,1.0,0.4,0.4,
    1.0,1.0,0.4,1.0,1.0,0.4,1.0,1.0,0.4,1.0,1.0,0.4,
    1.0,0.0,1.0,1.0,0.0,1.0,1.0,0.0,1.0,1.0,0.0,1.0,
    0.0,1.0,1.0,0.0,1.0,1.0,0.0,1.0,1.0,0.0,1.0,1.0,
  ])

  const colorBuffer = gl.createBuffer();
  gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
  gl.bufferData(gl.ARRAY_BUFFER, colors, gl.STATIC_DRAW);
  gl.vertexAttribPointer(aColor, 3, gl.FLOAT, false, 0, 0);
  gl.enableVertexAttribArray(aColor)

  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);

  let eyex = 3;
  let eyey = 3;
  let eyez = 5;

  let deg = 0;
  function draw() {
      
      
    deg += 0.01;
    const rotate = getRotateMatrix(deg);
    const vm = getViewMatrix(eyex,eyey,eyez,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(mixMatrix(perspective, vm), rotate));
    gl.drawElements(gl.TRIANGLES, indeces.length, gl.UNSIGNED_BYTE, 0);

    requestAnimationFrame(draw)
  }

  draw()
</script>

inserte la descripción de la imagen aquí

Resumir

El método de índice WEBGL es una tecnología para optimizar el proceso de dibujo WEBGL Comparado con el método de vértice, tiene los siguientes aspectos:

  1. Rendimiento optimizado del dibujo de triángulos: use la indexación para reducir el procesamiento de vértices repetido innecesario, lo que reduce el tiempo de procesamiento y el consumo de memoria al dibujar triángulos.

  2. Dibujo de modelos a gran escala: cuando se dibujan modelos a gran escala, el uso del método de índice puede mejorar significativamente la eficiencia del dibujo, reducir el consumo de memoria y reducir la carga de la GPU.

  3. Deformación del modelo dinámico: cuando el modelo se deforma, como la animación de personajes, el uso del método de índice puede evitar el recálculo y la transferencia de datos de vértice, ahorrar memoria y tiempo de procesamiento, y hacer que la animación sea más fluida.

  4. Dibujo de combinación de mallas múltiples: cuando es necesario dibujar un modelo con combinaciones de mallas múltiples, es más fácil administrar y combinar los datos mediante el método de indexación.

El método de indexación de WEBGL puede ayudarnos a optimizar el rendimiento y la eficiencia del proceso de dibujo de WEBGL y mejorar la experiencia del usuario y el rendimiento de las páginas web.

Supongo que te gusta

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