WebGL笔记 (侧重理论基础向)

        要把Cesium,three.js 这些玩明白还是要有WebGL的知识的,不然只是官方demo的ctrl-cv侠,本笔记参考的教程 : 2022年WebGL入门教程(完结)_哔哩哔哩_bilibili

 

一、初级(二维)

1.1. 坐标系

        WebGL的工作区在canvas标签中运行,并与canvas有个边距,其内部是一个空间直角坐标系,x,y,z的范围都是∈[ -1 , 1 ] ,z轴是从屏幕里往外延申,最里面是-1

▲ 图:webGL坐标系

1.2. 生命周期

        顶点缓冲区:功能大概像画画一样,先把图形边框绘制出来,绘制出点位

        uniform数据:把顶点缓冲区的数据传给顶点着色器

        顶点着色器:给顶点画颜色

        图元装配:把顶点数据转换为矢量数据,如:存在3个顶点,这3个点是要绘制成一个面,还是三条线,还是一个点一条直线,还是三个点,等等。

        光栅器:矢量转栅格

        片元着色器:给栅格数据附上纹理和颜色

        归属测试:暂定

        模板测试:暂定

        深度测试:暂定

        融合:融合各方面的数据

        抖动:动态效果

        颜色缓冲区:用户可以看到的区域

1.3. 基础绘制

  1.3.1 绘制点 (输入固定位置)

        流程:初始化webgl控件、初始化着色器、初始化缓冲区、开始绘制

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <script src="glMatrix-0.9.6.min.js"></script>
    // 第三方库,集成了一些坐标投影函数
    <script>
      // 顶点着色器的配置
      let vertexstring = `
        attribute vec4 a_position;
        uniform     mat4    proj;
        void main(void){
            gl_Position =proj *  a_position;
            gl_PointSize=60.0;
        }
        `;
      // 片元着色器的配置
      let fragmentstring = `
        void main(void){
          gl_FragColor = vec4(0,0,1.0,1.0);
        }
        `;
      var projMat4 = mat4.create(); // 第三方库:投影影矩阵转换功能
      var webgl;
      function init() {
        initWebgl();
        initShader();
        initBuffer();
        draw();
      }
      // canvas中初始化webgl上下文
      function initWebgl() {
        let webglDiv = document.getElementById("myCanvas");
        webgl = webglDiv.getContext("webgl");
        webgl.viewport(0, 0, webglDiv.clientWidth, webglDiv.clientHeight);
        mat4.ortho(
          0,
          webglDiv.clientWidth,
          webglDiv.clientHeight,
          0,
          -1.0,
          1.0,
          projMat4
        );
      }
      // 配置顶点vertex_shader、片元着色器fragment_shader,建立渲染项目program
      function initShader() {
        let vsshader = webgl.createShader(webgl.VERTEX_SHADER);
        let fsshader = webgl.createShader(webgl.FRAGMENT_SHADER);
        webgl.shaderSource(vsshader, vertexstring);
        webgl.shaderSource(fsshader, fragmentstring);
        webgl.compileShader(vsshader);
        webgl.compileShader(fsshader);
        if (!webgl.getShaderParameter(vsshader, webgl.COMPILE_STATUS)) {
          var err = webgl.getShaderInfoLog(vsshader);
          alert(err);
          return;
        }
        if (!webgl.getShaderParameter(fsshader, webgl.COMPILE_STATUS)) {
          var err = webgl.getShaderInfoLog(fsshader);
          alert(err);
          return;
        }
        let program = webgl.createProgram();
        webgl.attachShader(program, vsshader);
        webgl.attachShader(program, fsshader);

        webgl.linkProgram(program);
        webgl.useProgram(program);

        webgl.program = program;
      }
      // 设置点并加入顶点缓冲区:使用attribute和uniform传递数据(这里没有用缓冲区、因为只有一个点)
      function initBuffer() {
        let pointPosition = new Float32Array([100.0, 100.0, 0.0, 1.0]);
        let aPsotion = webgl.getAttribLocation(webgl.program, "a_position");
        webgl.vertexAttrib4fv(aPsotion, pointPosition);
        let uniformProj = webgl.getUniformLocation(webgl.program, "proj");
        webgl.uniformMatrix4fv(uniformProj, false, projMat4);
      }
      // 开始绘制
      function draw() {
        webgl.clearColor(0.0, 0.0, 0.0, 1.0);
        webgl.clear(webgl.COLOR_BUFFER_BIT | webgl.DEPTH_BUFFER_BIT);
        webgl.drawArrays(webgl.POINTS, 0, 1);
      }
    </script>
  </head>

  <body onload="init()">
    <canvas id="myCanvas" width="1024" height="768"></canvas>
  </body>
</html>

1.3.2 绘制点(鼠标动态点击绘制)

          相较于固定输入的一个点位,新增的难点:获取点击时候的显示器坐标、显示器坐标转换为WebGL坐标(像素坐标转归一化zuo)

/** 其他省略,和上一个代码区域里面一样

..... 

*/

// 使用顶点缓冲区
function initBuffer() {
  let aPsotion = webgl.getAttribLocation(webgl.program, "a_position");

  document.addEventListener("mousedown", function (e) {
    debugger;
    let x = e.clientX;
    let y = e.clientY;
    let rect = e.target.getBoundingClientRect();
    let pointx = (x - rect.left - 512) / 512; // 屏幕转WebGL坐标
    let pointy = (350 - (y - rect.top)) / 350;
    points.push(pointx);
    points.push(pointy);
    points.push(0);

    let pointPosition = new Float32Array(points);
    let pointBuffer = webgl.createBuffer(); // 创建缓冲区
    webgl.bindBuffer(webgl.ARRAY_BUFFER, pointBuffer); // 绑定缓冲区
    webgl.bufferData(webgl.ARRAY_BUFFER, pointPosition, webgl.STATIC_DRAW); // 缓冲区输入数据
    webgl.enableVertexAttribArray(aPsotion); // 启动:开始向GPU传输数据
    webgl.vertexAttribPointer(aPsotion, 3, webgl.FLOAT, false, 0, 0); // 配置项:位置、一次从顶点数组取几个数、顶点数组数据类型、是否归一化、间隔字节、偏移字节

    webgl.clearColor(0.0, 0.0, 0.0, 1.0);
    webgl.clear(webgl.COLOR_BUFFER_BIT | webgl.DEPTH_BUFFER_BIT);
    webgl.drawArrays(webgl.POINTS, 0, points.length / 3); // 绘制点
  });

  let uniformProj = webgl.getUniformLocation(webgl.program, "proj");
  webgl.uniformMatrix4fv(uniformProj, false, projMat4);
}
function draw() {
  webgl.clearColor(0.0, 0.0, 0.0, 1.0);
  webgl.clear(webgl.COLOR_BUFFER_BIT | webgl.DEPTH_BUFFER_BIT);
}

 1.3.3 绘制线

var points = [];
var colors=[];
function initBuffer() {
    let aPsotion = webgl.getAttribLocation(webgl.program, "a_position");
    let arr = [100.0,100.0,0,    200.0,200.0,0, 300.0,200.0,0 ,400,600,0];
    let vertexArr = new Float32Array(arr);
    let trangleBuffer =  webgl.createBuffer();
    webgl.bindBuffer(webgl.ARRAY_BUFFER,trangleBuffer);
    webgl.bufferData(webgl.ARRAY_BUFFER,vertexArr,webgl.STATIC_DRAW);
    webgl.enableVertexAttribArray(aPsotion);
    webgl.vertexAttribPointer(aPsotion,3, webgl.FLOAT, false, 0, 0);

    let uniformProj = webgl.getUniformLocation(webgl.program, "proj");
    webgl.uniformMatrix4fv(uniformProj, false, projMat4);
}
function draw() {
    webgl.clearColor(0.0, 0.0, 0.0, 1.0);
    webgl.clear(webgl.COLOR_BUFFER_BIT | webgl.DEPTH_BUFFER_BIT);
    webgl.drawArrays(webgl.LINES,0,4);        // 绘制线
    //webgl.drawArrays(webgl.LINE_STRIP,0,4)  // 绘制折现
    //webgl.drawArrays(webgl.LINE_LOOP,0,4)   // 绘制闭合线 
    
}

1.3.4 绘制三角形

var points = [];
var colors=[];
function initBuffer() {
    let aPsotion = webgl.getAttribLocation(webgl.program, "a_position");
    let arr = [100.0,100.0,0,    200.0,200.0,0, 300.0,200.0,0 ,400,600,0];
    let vertexArr = new Float32Array(arr);
    let trangleBuffer =  webgl.createBuffer();
    webgl.bindBuffer(webgl.ARRAY_BUFFER,trangleBuffer);
    webgl.bufferData(webgl.ARRAY_BUFFER,vertexArr,webgl.STATIC_DRAW);
    webgl.enableVertexAttribArray(aPsotion);
    webgl.vertexAttribPointer(aPsotion,3, webgl.FLOAT, false, 0, 0);

    let uniformProj = webgl.getUniformLocation(webgl.program, "proj");
    webgl.uniformMatrix4fv(uniformProj, false, projMat4);
}
function draw() {
    webgl.clearColor(0.0, 0.0, 0.0, 1.0);
    webgl.clear(webgl.COLOR_BUFFER_BIT | webgl.DEPTH_BUFFER_BIT);
    webgl.drawArrays(webgl.TRIANGLES,0,3);
    // webgl.drawArrays(webgl.TRIANGLE_STRIP,0,4);
    // webgl.drawArrays(webgl.TRIANGLE_FAN,0,4); 
}

图 三角形的绘制类型

1.3.5 索引缓冲区

         使用索引实现点位复用,以达到不用传入多个相同的点

1.4. 纹理

1.4.1 纹理映射

        理论: 在片元着色器中运行。原理:图片四个点作为控制点,然后插值映射到接受区域。

1.4.2 多重纹理

        (1)理论:一次性绘制多个纹理

        (2) 图像坐标系与纹理坐标系

▲ 图:图像坐标转纹理坐标    

1.4.3 动态变换与动画理论

        (1)基本理论

                Matrix4进行矩阵运算,一秒内快速变换数十次位置,形成动画。

        (2)数学运算

 ▲图:平移、缩放、旋转的矩阵运算

二、 中级(三维)

2.1 视点、目标点、视线

        意义:camera视角控制

 图:视点、目标点、视线

2.2 可视域

  意义:提升渲染效率

(1)正视投影

 图:正视投影

(2)透视投影

  图:透视投影

2.3 深度缓冲区与多边形偏移

          深度缓冲区:三维空间中,保存对象z值的缓冲区

          深度冲突:z值相同或十分相近的两个物体对象,会产生重影,解决方案就是深度检测算法

          多边形偏移:进行z值的offset偏移设置,使得z值稍微有差距,解决重影问题。

2.4 绘制正方体

知识点:三维场景中,逆时针绘画为正面,顺时针为背面

2.5 光照

1. 基本概念

        光源:平行光,点光源,环境光(各个方向光照一样)

        反射光:镜面反射,漫反射,环境反射

        法线:垂直于表面的向量


  未完待续

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值