使用webGL创建正方体

270 阅读2分钟

实现效果

1733282648212.png

初始化shader

顶点着色器

<script id="vertexSource" type="x-shader/v-vertex">
  attribute vec4 a_Position;   
  attribute vec4 a_Color; 
  uniform mat4 u_transFromMatirx;  //用于正方体旋转效果
  varying vec4 v_Color;
  void main(){
    gl_Position= u_transFromMatirx * a_Position;
    gl_PointSize= 20.0;
    v_Color = a_Color;
  }
</script> 

片元着色器

<script id="fragmentSource" type="x-shader/v-fragment">
  precision highp float;  //精度 
  varying vec4 v_Color;
  void main(){
    gl_FragColor= v_Color;
  }
</script>

创建程序program使用initShader 对着色器进行编译

export const initShader = (gl, vertexSource, fragmentSource) => {
  let vertexShader = gl.createShader(gl.VERTEX_SHADER);
  let fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);

  gl.shaderSource(vertexShader, vertexSource);
  gl.shaderSource(fragmentShader, fragmentSource);

  gl.compileShader(vertexShader);
  gl.compileShader(fragmentShader);

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

  gl.linkProgram(program);
  gl.useProgram(program);

  return program;
};

着色器点数据颜色数据赋值

      // 获取顶点着色器变量
      let positionLocation = gl.getAttribLocation(program, "a_Position");
      let colorLocation = gl.getAttribLocation(program, "a_Color");
      let transFromMatirxLocaiton = gl.getUniformLocation(
        program,
        "u_transFromMatirx"
      );

      // 创建数据缓冲区
      let points = new Float32Array();
      let { vertics, index, color } = initCube(0.5);  //initCube接收正方形的大小参数得到 正方形 定点、索引、颜色数据
      
      //顶点
      let buffer = gl.createBuffer(); 
      gl.bindBuffer(gl.ARRAY_BUFFER, buffer); 
      gl.bufferData(gl.ARRAY_BUFFER, vertics, gl.STATIC_DRAW);
      
      //颜色
      let colorBuffer = gl.createBuffer();
      gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
      gl.bufferData(gl.ARRAY_BUFFER, color, gl.STATIC_DRAW);
      gl.vertexAttribPointer(
        colorLocation,
        3,
        gl.FLOAT,
        false,
        3 * Float32Array.BYTES_PER_ELEMENT,
        0
      );
      gl.enableVertexAttribArray(colorLocation);

      // 索引
      let indexBuffer = gl.createBuffer();
      gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
      gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, index, gl.STATIC_DRAW);

      gl.enable(gl.DEPTH_TEST);  //开始深度缓冲区 防止正方形渲染出现异常问题 

正方形 定点、索引、颜色数据

export const initCube = (h) => {
  let pointsArr = new Float32Array(
    [
      [-h, h, h],
      [-h, -h, h],
      [h, -h, h],
      [h, h, h], 
      [-h, h, -h], 
      [-h, -h, -h],
      [h, -h, -h], 
      [h, h, -h],
    ].flat()
  );

  /**
   * 
   *   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, 7, 6, 4, 6, 5 
   */
  let index = new Uint8Array([
    0, 1, 2, 0, 2, 3,    // 前
    3, 2, 6, 3, 6, 7,    // 右
    4, 0, 3, 4, 3, 7,    // 上
    4, 5, 1, 4, 1, 0,    // 左
    1, 5, 6, 1, 6, 2,    // 下
    4, 5, 6, 4, 6, 7     // 后 
  ]);

  let color = new Float32Array([
    1.0,1.0,1.0,//v0 近平面 右上 颜色
    1.0,0.0,1.0,//v1 近平面 左上 颜色
    1.0,0.0,1.0,//v2 近平面 左下 颜色
    1.0,1.0,0.0,//v3 近平面 右下 颜色
    1.0,0.0,1.0,//v4 远平面 右下 颜色
    1.0,1.0,1.0,//v5 远平面 左下 颜色
    0.0,0.0,1.0,//v6 远平面 左上 颜色
    0.0,1.0,1.0 //v7 远平面 右上 颜色
]); 


  return {
    vertics: pointsArr,
    index: index,
    color:color
  };
};

加上旋转效果

  let rotateX = 0.005;  //旋转角度
  let rotateY = 0.005;  //旋转角度

  let transfiomMatrix = mat4.create();  //合成矩阵
  let rotateYMatrix = mat4.create();  //y轴旋转
  let rotateXMatrix = mat4.create();  //x轴旋转

  const render = () => {
  
    //y轴旋转
    mat4.rotateY(rotateYMatrix, rotateYMatrix, rotateY);
    //x轴旋转
    mat4.rotateX(rotateXMatrix, rotateXMatrix, rotateX);
    
    //旋转效果叠加
    mat4.multiply(transfiomMatrix, rotateYMatrix, rotateXMatrix);
    
    // 顶点着色器transfiomMatrix赋值
    gl.uniformMatrix4fv(transFromMatirxLocaiton, false, transfiomMatrix);
    
    gl.clear(gl.COLOR_BUFFER_BIT);
    
    gl.drawElements(gl.TRIANGLES, 36, gl.UNSIGNED_BYTE, 0);
    
    requestAnimationFrame(render);
  };
  render();

完成代码

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <canvas id="canvas" width="500px" height="500px"></canvas>
    <script src="/utils/gl-matrix.js"></script>
    <script id="vertexSource" type="x-shader/v-vertex">
      attribute vec4 a_Position;
      attribute vec4 a_Color;
      uniform mat4 u_transFromMatirx;
      varying vec4 v_Color;
      void main(){
        gl_Position= u_transFromMatirx * a_Position;
        gl_PointSize= 20.0;
        v_Color = a_Color;
      }
    </script>

    <script id="fragmentSource" type="x-shader/v-fragment">
      precision highp float;
      uniform sampler2D u_Sampler;
      varying vec4 v_Color;
      void main(){
        gl_FragColor= v_Color;
      }
    </script>
    <script type="module">
      import { initShader } from "./utils/shader.js";
      import { initCube } from "./utils/createCube.js";
      let canvas = document.getElementById("canvas");
      let gl = canvas.getContext("webgl");
      let mat4 = glMatrix.mat4;

      const vsSource = document.getElementById("vertexSource").innerText;
      const fsSource = document.getElementById("fragmentSource").innerText;

      let program = initShader(gl, vsSource, fsSource);

      let positionLocation = gl.getAttribLocation(program, "a_Position");
      let colorLocation = gl.getAttribLocation(program, "a_Color");
      let transFromMatirxLocaiton = gl.getUniformLocation(
        program,
        "u_transFromMatirx"
      );

      // 顶点
      let points = new Float32Array();
      let buffer = gl.createBuffer();
      let { vertics, index, color } = initCube(0.5);
      gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
      gl.bufferData(gl.ARRAY_BUFFER, vertics, gl.STATIC_DRAW);

      gl.vertexAttribPointer(
        positionLocation,
        3,
        gl.FLOAT,
        false,
        3 * Float32Array.BYTES_PER_ELEMENT,
        0
      );
      gl.enableVertexAttribArray(positionLocation);

      let colorBuffer = gl.createBuffer();
      gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
      gl.bufferData(gl.ARRAY_BUFFER, color, gl.STATIC_DRAW);
      gl.vertexAttribPointer(
        colorLocation,
        3,
        gl.FLOAT,
        false,
        3 * Float32Array.BYTES_PER_ELEMENT,
        0
      );
      gl.enableVertexAttribArray(colorLocation);

      // 索引
      let indexBuffer = gl.createBuffer();
      gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
      gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, index, gl.STATIC_DRAW);

      gl.enable(gl.DEPTH_TEST);

      let rotateX = 0.005;
      let rotateY = 0.005;

      let transfiomMatrix = mat4.create();
      let rotateYMatrix = mat4.create();
      let rotateXMatrix = mat4.create();

      const render = () => {
        mat4.rotateY(rotateYMatrix, rotateYMatrix, rotateY);
        mat4.rotateX(rotateXMatrix, rotateXMatrix, rotateX);
        mat4.multiply(transfiomMatrix, rotateYMatrix, rotateXMatrix);
        gl.uniformMatrix4fv(transFromMatirxLocaiton, false, transfiomMatrix);
        gl.clear(gl.COLOR_BUFFER_BIT);
        gl.drawElements(gl.TRIANGLES, 36, gl.UNSIGNED_BYTE, 0);
        requestAnimationFrame(render);
      };
      render();
    </script>
  </body>
</html>