📜  WebGL-旋转(1)

📅  最后修改于: 2023-12-03 14:48:25.831000             🧑  作者: Mango

WebGL-旋转

简介

WebGL是一项用于在Web浏览器中呈现3D图形的技术。 通过利用GPU的强大计算能力和硬件加速功能,WebGL可提供更流畅的3D图形显示。WebGL-旋转是WebGL编程中的一种基本技术,它允许开发者以一定的角度旋转3D场景。

实现方式
步骤1:初始化WebGL上下文

在使用WebGL之前,需要先从canvas元素中获取WebGL上下文对象。该对象提供了与OpenGL ES 2.0 API相似的方法来执行3D图形渲染。

const canvas = document.getElementById('canvas');
const gl = canvas.getContext('webgl');
步骤2:定义顶点坐标和颜色

在WebGL中,可以通过顶点来描述3D对象的形状和坐标。一些基本形状的顶点已经被定义,如立方体(cube)、球(sphere)等。当然,也可以根据需要自定义顶点。

//定义正方体的顶点坐标
const vertices = [
  -1, -1,  1,
  1, -1,  1,
  1,  1,  1,
  -1,  1,  1,

  -1, -1, -1,
  -1,  1, -1,
  1,  1, -1,
  1, -1, -1,

  -1,  1, -1,
  -1,  1,  1,
  1,  1,  1,
  1,  1, -1,

  -1, -1, -1,
  1, -1, -1,
  1, -1,  1,
  -1, -1,  1,

  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 colors = [
  1, 0, 0, 1,
  1, 0, 0, 1,
  1, 0, 0, 1,
  1, 0, 0, 1,

  0, 1, 0, 1,
  0, 1, 0, 1,
  0, 1, 0, 1,
  0, 1, 0, 1,

  0, 0, 1, 1,
  0, 0, 1, 1,
  0, 0, 1, 1,
  0, 0, 1, 1,

  1, 1, 0, 1,
  1, 1, 0, 1,
  1, 1, 0, 1,
  1, 1, 0, 1,

  0, 1, 1, 1,
  0, 1, 1, 1,
  0, 1, 1, 1,
  0, 1, 1, 1,

  1, 0, 1, 1,
  1, 0, 1, 1,
  1, 0, 1, 1,
  1, 0, 1, 1,
];
步骤3:定义着色器

着色器是WebGL中必不可少的一部分。着色器控制着顶点的绘制方式和颜色等属性。在WebGL中,有两种类型的着色器:顶点着色器和片段着色器。顶点着色器负责处理顶点的位置和颜色等属性,而片段着色器则负责处理像素的颜色。

在WebGL中,可以通过以下方式来定义着色器:

//定义顶点着色器
const vertexShaderSrc = `
  attribute vec3 a_position;
  attribute vec4 a_color;
  varying vec4 v_color;

  uniform mat4 u_matrix;

  void main() {
    gl_Position = u_matrix * vec4(a_position, 1.0);
    v_color = a_color;
  }
`;

//定义片段着色器
const fragmentShaderSrc = `
  precision mediump float;

  varying vec4 v_color;

  void main() {
    gl_FragColor = v_color;
  }
`;

//编译顶点着色器
const vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vertexShaderSrc);
gl.compileShader(vertexShader);

//编译片段着色器
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, fragmentShaderSrc);
gl.compileShader(fragmentShader);
步骤4:创建程序对象

在WebGL中,程序对象是将顶点着色器和片段着色器连接到一起的最终对象。可以通过以下方式来创建程序对象:

//创建程序对象
const program = gl.createProgram();

//将顶点着色器连接到程序对象
gl.attachShader(program, vertexShader);

//将片段着色器连接到程序对象
gl.attachShader(program, fragmentShader);

//连接着色器程序
gl.linkProgram(program);
步骤5:绑定缓冲区对象

WebGL中的缓冲区对象用于存储顶点坐标和颜色等属性。可以通过以下方式来创建并绑定缓冲区对象:

//创建并绑定顶点坐标缓冲区对象
const positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);

//创建并绑定颜色缓冲区对象
const colorBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
步骤6:设置属性指针

属性指针是一组指令,它们告诉WebGL如何从缓冲区对象中获取顶点数据。可以通过以下方式来设置属性指针:

//设置顶点着色器中的属性指针
const positionAttributeLocation = gl.getAttribLocation(program, 'a_position');
gl.enableVertexAttribArray(positionAttributeLocation);
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.vertexAttribPointer(positionAttributeLocation, 3, gl.FLOAT, false, 0, 0);

//设置顶点着色器中的颜色属性指针
const colorAttributeLocation = gl.getAttribLocation(program, 'a_color');
gl.enableVertexAttribArray(colorAttributeLocation);
gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
gl.vertexAttribPointer(colorAttributeLocation, 4, gl.FLOAT, false, 0, 0);
步骤7:设置矩阵

矩阵用于旋转、缩放和位移3D物体。可以使用以下代码创建一个旋转矩阵并设置WebGL中的矩阵:

//创建旋转矩阵
const matrix = mat4.create();
mat4.rotate(matrix, matrix, angleInRadians, [0, 1, 0]);

//将矩阵传递到顶点着色器中
const matrixLocation = gl.getUniformLocation(program, 'u_matrix');
gl.uniformMatrix4fv(matrixLocation, false, matrix);
步骤8:绘制顶点

完成以上步骤后,就可以开始绘制顶点了。可以通过以下代码来完成绘制:

//启用WebGL并绘制顶点
gl.useProgram(program);
gl.drawArrays(gl.TRIANGLES, 0, 36);
实例

下面是一个完整的WebGL-旋转实例:

<html>
  <head>
    <title>WebGL-旋转</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gl-matrix/2.8.1/gl-matrix-min.js"></script>
  </head>
  <body>
    <canvas id="canvas" width="400" height="400"></canvas>

    <script>
      const canvas = document.getElementById('canvas');
      const gl = canvas.getContext('webgl');

      const vertices = [
        -1, -1,  1,
        1, -1,  1,
        1,  1,  1,
        -1,  1,  1,

        -1, -1, -1,
        -1,  1, -1,
        1,  1, -1,
        1, -1, -1,

        -1,  1, -1,
        -1,  1,  1,
        1,  1,  1,
        1,  1, -1,

        -1, -1, -1,
        1, -1, -1,
        1, -1,  1,
        -1, -1,  1,

        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 colors = [
        1, 0, 0, 1,
        1, 0, 0, 1,
        1, 0, 0, 1,
        1, 0, 0, 1,

        0, 1, 0, 1,
        0, 1, 0, 1,
        0, 1, 0, 1,
        0, 1, 0, 1,

        0, 0, 1, 1,
        0, 0, 1, 1,
        0, 0, 1, 1,
        0, 0, 1, 1,

        1, 1, 0, 1,
        1, 1, 0, 1,
        1, 1, 0, 1,
        1, 1, 0, 1,

        0, 1, 1, 1,
        0, 1, 1, 1,
        0, 1, 1, 1,
        0, 1, 1, 1,

        1, 0, 1, 1,
        1, 0, 1, 1,
        1, 0, 1, 1,
        1, 0, 1, 1,
      ];

      const vertexShaderSrc = `
        attribute vec3 a_position;
        attribute vec4 a_color;
        varying vec4 v_color;

        uniform mat4 u_matrix;

        void main() {
          gl_Position = u_matrix * vec4(a_position, 1.0);
          v_color = a_color;
        }
      `;

      const fragmentShaderSrc = `
        precision mediump float;

        varying vec4 v_color;

        void main() {
          gl_FragColor = v_color;
        }
      `;

      const vertexShader = gl.createShader(gl.VERTEX_SHADER);
      gl.shaderSource(vertexShader, vertexShaderSrc);
      gl.compileShader(vertexShader);

      const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
      gl.shaderSource(fragmentShader, fragmentShaderSrc);
      gl.compileShader(fragmentShader);

      const program = gl.createProgram();
      gl.attachShader(program, vertexShader);
      gl.attachShader(program, fragmentShader);
      gl.linkProgram(program);

      const positionBuffer = gl.createBuffer();
      gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
      gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);

      const colorBuffer = gl.createBuffer();
      gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
      gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);

      const positionAttributeLocation = gl.getAttribLocation(program, 'a_position');
      gl.enableVertexAttribArray(positionAttributeLocation);
      gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
      gl.vertexAttribPointer(positionAttributeLocation, 3, gl.FLOAT, false, 0, 0);

      const colorAttributeLocation = gl.getAttribLocation(program, 'a_color');
      gl.enableVertexAttribArray(colorAttributeLocation);
      gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
      gl.vertexAttribPointer(colorAttributeLocation, 4, gl.FLOAT, false, 0, 0);

      function drawScene(angleInRadians) {
        gl.clearColor(0, 0, 0, 0);
        gl.clear(gl.COLOR_BUFFER_BIT);

        const matrix = mat4.create();
        mat4.rotate(matrix, matrix, angleInRadians, [0, 1, 0]);

        const matrixLocation = gl.getUniformLocation(program, 'u_matrix');
        gl.uniformMatrix4fv(matrixLocation, false, matrix);

        gl.useProgram(program);
        gl.drawArrays(gl.TRIANGLES, 0, 36);
      }

      let angle = 0;
      function render() {
        angle += Math.PI / 100;
        drawScene(angle);
        requestAnimationFrame(render);
      }
      requestAnimationFrame(render);
    </script>
  </body>
</html>
结论

通过以上介绍,我们了解了WebGL-旋转的基本实现方式。WebGL提供了丰富的API,对于需要使用3D图形渲染的应用和网站开发者来说,WebGL是一个十分强大的工具。使用WebGL,可以将更加生动、真实的3D场景呈现在用户面前。