webgl学习笔记

简单封装绘制前流程


前言

webgl绘制前流程复杂繁琐,这里将其做一个简单封装,以便了解其流程。


提示:以下是本篇文章正文内容,下面案例可供参考

一、引入cuon-utils.js和cuon-matrix.js

import cuonUtils from './cuon-utils'

import cuonMatrix from './cuon-matrix'

cuonUtils封装了一些webgl方法,这里就用来创建webgl程序,cuonMatrix提供矩阵方法,这里拿来设置modelMatrix

二、主要流程

1.先获取着色器申明变量getAttribLocation

2.将顶点信息写入缓冲区对象 将数据保存

3.设置getUniformLocation

4.创建VP矩阵

5.绘制时先分配缓冲对象并启用赋值,再绘制


总结

有错误希望大佬指正

代码(mesh.js):

import cuonUtils from './cuon-utils'
import cuonMatrix from './cuon-matrix'

class mesh {
  /* 
    attributeData:{
      vertices:Float32Array,
      normals:Float32Array,
      indices:Uint8Array,
    }
  */
  constructor(gl,attributeData={}){
    this.gl = gl

    this.modelMatrix = new cuonMatrix.Matrix4();
    
    this.geometry = {}

    this.material = {
      VSHADER_SOURCE:`
      attribute vec3 a_Position;
      attribute vec3 a_Normal;
      // attribute vec3 a_Color;
      uniform mat4 u_ModelMatrix;
      uniform mat4 u_VPMatrix;
      // varying vec3 v_Color;
      varying vec3 v_Normal;
      void main(){
        // v_Color = a_Color;
        v_Normal = a_Normal;
        gl_Position = u_VPMatrix * u_ModelMatrix * vec4( a_Position , 1.0 );
      }`,
      FSHADER_SOURCE:`
      #ifdef GL_ES
      precision mediump float;
      #endif
      // varying vec3 v_Color;
      varying vec3 v_Normal;
      void main(){
        // gl_FragColor = vec4( v_Color , 1.0 );
        gl_FragColor = vec4( v_Normal , 1.0 );
        // gl_FragColor = vec4( 1.0 , 0 ,0 , 1.0 );
      }`
    }

    this.program = cuonUtils.createProgram( gl, this.material.VSHADER_SOURCE , this.material.FSHADER_SOURCE )
    
    this.setAttribute(attributeData)
  }

  /* 
    设置uniform
    @param type 数据类型
    @param target uniform名称 (string)
    @param value  uniform值
    @param isBefore 是否为预先准备(只获取UniformLocation)
    @return void
  */
  setUniform(type,target,value){
    if(this.gl.program !== this.program){
      this.gl.useProgram(this.program);
    }

    let u_target;
    if(this.program[target] === void 0){
      u_target = this.gl.getUniformLocation( this.program, target );
      if (u_target < 0) {
        console.log(`无法获取${target}uniform`);
        return;
      }
      this.program[target] = u_target
    }else{
      u_target = this.uniformTarget[target]
    }
    
    if(type == 'bool'){

    }
    if(type == 'int'){

    }
    if(type == 'float'){

    }
    if(type == 'vec3'){

    }
    if(type == 'mat4'){
      this.gl.uniformMatrix4fv(u_target,false,value)
    }
  }

  //设置geo数据
  setAttribute(attributeData){
    let gl = this.gl;
    this.program.a_Position = gl.getAttribLocation(this.program, "a_Position");
    this.program.a_Normal = gl.getAttribLocation(this.program, "a_Normal");

    let vertices = attributeData.vertices

    let normals = attributeData.normals

    let texCoords = new Float32Array([   // 纹理的坐标
        1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0,    // v0-v1-v2-v3 front
        0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0,    // v0-v3-v4-v5 right
        1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0,    // v0-v5-v6-v1 up
        1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0,    // v1-v6-v7-v2 left
        0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0,    // v7-v4-v3-v2 down
        0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0     // v4-v7-v6-v5 back
    ]);

    let indices = attributeData.indices

    //将顶点信息写入缓冲区对象
    this.geometry.vertexBuffer = this.initArrayBufferForLaterUse( vertices, 3, gl.FLOAT);
    this.geometry.normalBuffer = this.initArrayBufferForLaterUse( normals, 3, gl.FLOAT);
    // this.geometry.texCoordBuffer = this.initArrayBufferForLaterUse( texCoords, 2, gl.FLOAT);
    this.geometry.indexBuffer = this.initElementArrayBufferForLaterUse( indices, gl.UNSIGNED_BYTE);
    // if (!this.geometry.vertexBuffer || !this.geometry.normalBuffer || !this.geometry.texCoordBuffer || !this.geometry.indexBuffer) {
    //     return this.$message.error("顶点信息写入缓冲区对象错误");;
    // }
    if (!this.geometry.vertexBuffer || !this.geometry.normalBuffer || !this.geometry.indexBuffer) {
      return this.$message.error("顶点信息写入缓冲区对象错误");;
    }

    this.geometry.numIndices = indices.length;

    //取消绑定焦点的数据
    gl.bindBuffer(gl.ARRAY_BUFFER, null);
    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
  }

  draw(){
    let gl = this.gl;
    let program = this.program
    //分配缓冲对象并启用赋值
    this.initAttributeVariable(gl, program.a_Position, this.geometry.vertexBuffer); //顶点坐标
    this.initAttributeVariable(gl, program.a_Normal, this.geometry.normalBuffer); //法向量
    // this.initAttributeVariable(gl, program.a_TexCoord, this.geometry.texCoordBuffer); //纹理坐标
    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.geometry.indexBuffer);

    //设置好纹理对象,开启使用0号的纹理
    // gl.activeTexture(gl.TEXTURE0);
    // gl.bindTexture(gl.TEXTURE_2D, texture);
    this.setUniform('mat4',"u_ModelMatrix",this.modelMatrix.elements)
    gl.drawElements(gl.TRIANGLES, this.geometry.numIndices, this.geometry.indexBuffer.type, 0);
  }

  //初始化缓冲区对象
  initElementArrayBufferForLaterUse(data, type) {
    let gl = this.gl;
    let buffer = gl.createBuffer(); //创建一个缓冲区对象
    if (!buffer) {
        console.log("无法创建缓冲区对象");
        return;
    }

    //将数据写入缓冲区
    gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buffer);
    gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, data, gl.STATIC_DRAW);

    buffer.type = type;

    return buffer;
  }
  //初始化缓冲区对象
  initArrayBufferForLaterUse(data, num, type) {
    let gl = this.gl;
    let buffer = gl.createBuffer(); // 创建一个缓冲区对象
    if (!buffer) {
        console.log("无法创建缓冲区对象");
        return;
    }

    //将数据写入缓冲区对象
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
    gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);

    //保留必要的信息,以便后面使用
    buffer.num = num;
    buffer.type = type;

    return buffer;
  }

  //绑定attribute
  initAttributeVariable(gl, a_attribute, buffer) {
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
    gl.vertexAttribPointer(a_attribute, buffer.num, buffer.type, false, 0, 0);
    gl.enableVertexAttribArray(a_attribute);
  }


}

export default mesh

使用:

<template>
  <div>
    <div>
      <canvas id="mycanvas"></canvas>
    </div>
  </div>
</template>

<script>
import Stats from './js/stats'//刷新率展示
import cuonMatrix from './js/cuon-matrix'
import Mesh from './js/mesh.js'
export default {
  data () {
    return {
      stats:'',//刷新率展示插件
      canvas:'',
      gl:'',

      clock:0,

      myMesh:'',
      myMesh2:'',
    }
  },
  mounted(){
    this.$nextTick(()=>{
      this.init()
    })
  },
  methods: {
    init(){
      let canvas = document.getElementById('mycanvas')
      canvas.width = 300
      canvas.height = 300
      canvas.style.border = '10px solid yellow'
      this.canvas = canvas

      this.gl = canvas.getContext('webgl')
      //刷新率插件
      this.initStats()
      this.main()
    },
    main(){
      let gl = this.gl
      if(!gl){return this.$message.error('垃圾浏览器')}

      //添加mesh
      let a01 = this.getAttributeData01()
      let a02 = this.getAttributeData02()
      this.myMesh = new Mesh( gl, a01 )
      this.myMesh2 = new Mesh( gl, a02 )

      //设置底色 和隐藏面消除
      gl.clearColor(0.0, 0.0, 0.0, 1.0);
      gl.enable(gl.DEPTH_TEST);

      //进入场景初始化
      this.animation()
    },
    animation(){
      this.clock += 1 
      this.stats.update();//更新刷新率插件
      this.draw(this.gl)
      // window.requestAnimationFrame(this.animation);
    },
    draw(gl){

      //获取视图VP矩阵
      let VPmat4 = this.getviewprojMatrix()
      // VPmat4.elements[12] = 8

      //开启隐藏面清除(深度测试)
      gl.enable(gl.DEPTH_TEST);

      //清空颜色和深度缓冲区
      gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

      //绘制图形
      this.myMesh.setUniform('mat4',"u_VPMatrix",VPmat4.elements)
      // console.log(this.myMesh)
      this.myMesh.draw()

      // VPmat4.elements[13] = 8
      this.myMesh2.modelMatrix.elements[13] = 8
      this.myMesh2.setUniform('mat4',"u_VPMatrix",VPmat4.elements)
      this.myMesh2.draw()
    },

    /* 
      获取vp矩阵
    */
    getviewprojMatrix(){
      let canvas = this.canvas
      //设置视角矩阵的相关信息(视点,视线,上方向)
      let viewMatrix = new cuonMatrix.Matrix4();
      viewMatrix.setLookAt(0,10,10,0,0,0,0,1,0);

      //设置透视投影矩阵
      let projMatrix = new cuonMatrix.Matrix4();
      projMatrix.setPerspective(75,canvas.width/canvas.height,0.1,1000);

      return projMatrix.multiply(viewMatrix)
    },
    /* 获取立方体数据 */
    getAttributeData01(){
      let attributeData = {}
      attributeData.vertices = new Float32Array([   // 单色立方体的顶点位置数据
        1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0,    // v0-v1-v2-v3 front
        1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0,    // v0-v3-v4-v5 right
        1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0,    // v0-v5-v6-v1 up
        -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 1.0,    // v1-v6-v7-v2 left
        -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, -1.0, 1.0, -1.0, -1.0, 1.0,    // v7-v4-v3-v2 down
        1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0     // v4-v7-v6-v5 back
      ]);
      attributeData.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,     // v0-v1-v2-v3 front
        1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0,     // v0-v3-v4-v5 right
        0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0,     // v0-v5-v6-v1 up
        -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0,     // v1-v6-v7-v2 left
        0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0,     // v7-v4-v3-v2 down
        0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0      // v4-v7-v6-v5 back
      ]);
      attributeData.indices = new Uint8Array([// 索引值
        0, 1, 2, 0, 2, 3,    // front
        4, 5, 6, 4, 6, 7,    // right
        8, 9, 10, 8, 10, 11,    // up
        12, 13, 14, 12, 14, 15,    // left
        16, 17, 18, 16, 18, 19,    // down
        20, 21, 22, 20, 22, 23     // back
      ]);
      return attributeData
    },
    /* 获取三角面数据 */
    getAttributeData02(){
      let attributeData = {}
      attributeData.vertices = new Float32Array([ 
        1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0
      ]);
      attributeData.normals = new Float32Array([ 
        0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0
      ]);
      attributeData.indices = new Uint8Array([// 索引值
        0, 1, 2,
      ]);
      return attributeData
    },
    /* 初始化刷新率 */
    initStats(){
      let stats = new Stats();
      this.stats = stats
      stats.showPanel( 0 ); // 0: fps, 1: ms, 2: mb, 3+: custom
      document.body.appendChild( stats.dom );
    },
  }
}
</script>

<style lang="scss" scoped>
</style>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值