【笔记】《WebGL 编程指南》第 2 章 WebGL 入门

  • 第一个 WebGL 程序

    • 【P42】 默认情况下,<canvas>是透明的

    • 【P44】 它不直接提供绘图方法,而是提供一种叫上下文(context)的机制来进行绘图。

    • 【P45】 计算机系统通常使用红、绿、蓝这三原色组合来表示颜色,这种颜色表示方式被称为RGB格式,当a (透明度)加进来之后,就成为RGBA格式。

    • <!DOCTYPE html>
      <html><head><script src="index.js"></script></head><body onload="main()"><canvas id="canvas" width="400" height="400">你的浏览器不支持 canvas。</canvas></body>
      </html>
      function main() {var canvas = document.getElementById('canvas');// 错误检查if (!canvas) {alert('无法获取 <canvas> 标签。');return;}var ctx = canvas.getContext('2d'); // 参数指定 2D/3Dctx.fillRect(120, 10, 150, 150); // 参数 x y width height
      }
      
  • 清空绘图区

    • 本节代码
      var gl = getWebGLContext(canvas);
      if (!gl) {alert('无法获取初始化 WebGL。');return;
      }gl.clearColor(0.5, 0.5, 0.5, 1.0);
      gl.clear(gl.COLOR_BUFFER_BIT);
      
    • 书中引用的一些库:
      <script src="https://rodger.global-linguist.com/webgl/lib/webgl-utils.js"></script>
      <script src="https://rodger.global-linguist.com/webgl/lib/webgl-debug.js"></script>
      <script src="https://rodger.global-linguist.com/webgl/lib/cuon-utils.js"></script>
      
    • 指定背景色
      • gl.clearColor(r, g, b, a)
        // 三个参数的值都是 [0.0, 1.0]
        
      • 【P50】 一旦指定了背景色之后,背景色就会驻存在WebGL系统(WebGL System)中,在下一次调用gl∙clearcols()方法前不会改变。
    • 清空 <canvas>
      • gl.clear(gl.COLOR_BUFFER_BIT);
        
      • 【P51】 清空绘图区域,实际上是在清空颜色缓冲区(color buffer),传递参数gi-color_buffer_bit就是在告诉WebGL清空颜色缓冲区。
  • 绘制一个点 1(着色器介绍)

    • JS 代码
    • 不像之前用 canvas 绘制 2D 矩形那样简单,用 WebGL 绘制一个点必须要用着色器
    • WebGL 需要的两种着色器
      • 【P55】 顶点着色器(Vertex shader):顶点着色器是用来描述顶点特性(如位置、颜色等)的程序。顶点(vertex)是指二维或三维空间中的一个点,比如二维或三维图形的端点或交点。绘制一个点(版本1) 25
      • 【P56】 片元着色器(Fragment shader):进行逐片元处理过程如光照(见第8章“光照”)的程序。片元(fragment)是一个WebGL术语,你可以将其理解为像素(图像的单元)。
      • 658d2d34-f15a-4de4-85b5-d92f22872e68
      • TODO 两者的区别?
    • 【P61】 WebGL程序包括运行在浏览器中的JavaScript和运行在WebGL系统的着色器程序这两个部分。
    • 【P58】 着色器使用类似于c的OpenGL ES着色器语言(GLSLES)来编写。
    • 使用着色器的基本框架
      gl = getWebGLContext(); // 获取 WebGL 上下文
      initShaders(); // 初始化着色器
      gl.clearColor(0, 0, 0, 0) // 设置背景色
      // 开始绘图
      
    • 【P61】 顶点着色器先执行,它对gl_Position变量和gl_PointSize变量进行赋值,并将它们传入片元着色器,然后片元着色器再执行。
    • 分析着色器

      • 顶点着色器:
        // `main()` 函数不能有参数,返回值必须为 `void`
        void main() {// `gl_Position`:内置变量,顶点位置,类型 `vec4`,必选。// vec4() 函数用于构造一个 vec4 实例。gl_Position = vec4(0.0, 0.0, 0.0, 1.0);// `gl_PointSize`:内置变量,顶点大小,类型 `float`,可选。gl_PointSize = 10.0;
        }
        
        • (PS:OpenGL ES 语言的 Markdown 代码块缩写为 glsl,但不一定支持。可以用 c 作为代替。 )
      • 注意:OpenGL ES 中整数不会自动转换为浮点数,gl_PointSize = 10 会报错!
      • vec4 类型 / 齐次坐标
        • 【P62】 vec4 表示由四个浮点数组成的矢量
        • 【P63】 由4个分量组成的矢量被称为齐次坐标
        • 【P63】 齐次坐标(x, y, z, w)等价于三维坐标(x∕w, y∕w, z/w)。所以如果齐次坐标的第4个分量是1,你就可以将它当做三维坐标来使用。
      • 片元着色器:
        void main() {// `gl_FragColor`:内置变量,顶点颜色,类型 `vec4`。gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
        }
        
    • 绘制操作

      • 绘制操作使用 gl.drawArrays() 进行。
        658d3668-96da-4315-b87c-8453bfabf077
      • gl.drawArrays(gl.POINTS, 0, 1);
        
    • WebGL 坐标系统

      • WebGL 使用右手坐标系。X 轴从左到右,Y 轴从下到上,Z 轴从你到屏幕。
      • 【P65】 观察者的眼睛位于原点(0Q 0.0, 0.0)处,视线则是沿着Z轴的负方向,从你指向屏幕
      • 658d38ed-c618-4a6e-89ad-0028b14981f4
      • WebGL 中坐标轴的范围是 [-1.0, 1.0]。
  • 绘制一个点 2(GLES -> JS 通信)

    • attribute 变量uniform 变量 能用来实现 GLES -> Javascript 的通信。
      • attribute 变量
        • 【P70】 关键词attribute被称为存储限定符(storage qualifier
        • 【P68】 attribute变量传输的是那些与顶点相关的数据
        • 【P68】 attribute变量是一种GLSLES变量,被用来从外部向顶点着色器内传输数据,只有顶点着色器能使用它。
      • uniform 变量
        • 【P68】 uniform变量传输的是那些对于所有顶点都相同(或与顶点无关)的数据
    • 【P70】 attribute变量必须声明成全局变量
    • 使用 attribute 变量通信的流程:获取变量地址 -> 设置变量值
    • GLES 代码:
      attribute vec4 aPos; // 外部参数void main() {gl_Position = aPos;gl_PointSize = 20.0;
      }
      
      JS 代码:
      // ...
      // 初始化 Shader
      if (!initShaders(gl, VERTEX_SHADER, FRAGMENT_SHADER)) {console.error('无法初始化着色器');
      }// 获取 aPos 变量地址
      // gl.program 在 initShaders() 调用之后自动创建
      var pos = gl.getAttribLocation(gl.program, 'aPos');
      // 设置 aPos 的值
      gl.vertexAttrib3f(pos, 0.5, 0.5, 0);gl.clearColor(0.5, 0.5, 0.5, 1.0);
      gl.clear(gl.COLOR_BUFFER_BIT);
      // ...
      
    • #+BEGIN_IMPORTANT
      注意:在 GLES 中声明的变量如果不用,会被编译器优化掉,导致在后面的 Javascript 中获取变量地址时失败!
      #+END_IMPORTANT
    • 658e232b-969c-4ba0-835f-24678d1ca94a
    • 658e2681-061a-4d6b-88e3-4bc4d9a8cfce
    • gl.vertexAttrib3f() 函数是其一系列函数中的一个
      • 3 表示矢量的元素个数,f 表示浮点数,i 表示整数,v 表示传入参数为矢量(数组)。
      • 如果传入的元素个数 < 目标变量的元素个数,那么 [v2, v3, v4] 的会被赋予默认值 [0, 0, 1](哪个少就补上哪个的默认值)。
      • gl.vertexAttribf1f(location, v1);
        gl.vertexAttribf2f(location, v1, v2);
        gl.vertexAttribf3f(location, v1, v2, v3);
        gl.vertexAttribf4f(location, v1, v2, v3, v4);gl.vertexAttribf1i(location, v1);
        gl.vertexAttribf2i(location, v1, v2);
        gl.vertexAttribf3i(location, v1, v2, v3);
        gl.vertexAttribf4i(location, v1, v2, v3, v4);gl.vertexAttribf1fv(location, arr);
        gl.vertexAttribf2fv(location, arr);
        gl.vertexAttribf3fv(location, arr);
        gl.vertexAttribf4fv(location, arr);
        
  • 通过鼠标点击绘点(响应点击事件)

    • 在线 Demo
      Javascript 源码
    • 坐标转换

      • var points = [];
        // 响应点击事件
        canvas.onmousedown = (event) => {console.clear();// 获取点击坐标// 转换步骤:页面坐标 -> canvas 坐标 -> WebGL 坐标// 这个坐标是页面坐标var x = event.clientX;var y = event.clientY;// 转换为 <canvas> 坐标// = 页面坐标 - <canvas> 左上角在页面中的坐标var rect = canvas.getBoundingClientRect();x = x - rect.left;y = y - rect.top;// 转换为 WebGL 坐标// 将原点从左上角移到中间位置console.log(x, y);y = -y;x = x + (-canvas.width / 2);y = y + (canvas.height / 2)// 缩放坐标轴x /= canvas.width / 2;y /= canvas.height / 2;console.log(x, y);points.push([x, y]);// 画点points.forEach((value) => {gl.vertexAttrib2fv(locPos, value);gl.drawArrays(gl.POINTS, 0, 1);});};
        
      • Canvas 坐标 -> WebGL 坐标 变换示意图
        (建议放大查看)
        外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传
    • 同时画多个点

      • gl.drawArrays() 函数是可以重复调用的,会在颜色缓冲区上继续绘制,也就是和之前的结果叠加。
      • var points = [];canvas.onmousedown = (event) => {// ...console.log(x, y);// 前面是一样的// 保存坐标points.push([x, y]);// 画点gl.clear(gl.COLOR_BUFFER_BIT);points.forEach((value) => {gl.vertexAttrib2fv(locPos, value);gl.drawArrays(gl.POINTS, 0, 1);});};
        
  • 改变点的颜色

    • 在线 Demo
      JS 源代码

    • 从 Javascript 向片元着色器中传递数据需要用 uniform 变量

      • 【P88】 uniform变量用来从JavaScript程序向顶点着色器和片元着色器传输“一致的”(不变的)数据。
    • 658f74d5-67e0-44d1-81c5-f3a8d417e99a

    • gl.uniform4f() 函数和 gl.VertexAttrub4f() 函数类似,也是一个系列的函数:
      658f74ff-4040-4cf7-ac0a-4d7ad40cf046

    • GLES 代码(片元着色器):

      precision mediump float; // 指定浮点数的精度为中等精度(包括范围和有效小数位)
      // 第五章讨论精度问题
      uniform vec4 uColor; // 外部参数
      void main(){gl_FragColor = uColor;
      }
      

      JS 代码:

      // 获取 uColor 变量地址
      var uColor = gl.getUniformLocation(gl.program, 'uColor');// ...
      canvas.onmousedown = function (event) {// 画点gl.clear(gl.COLOR_BUFFER_BIT);points.forEach((value) => {gl.vertexAttrib2fv(aPos, value);// 设置颜色(uColor)// 这里每次绘制都随机生成颜色var uColor = gl.getUniformLocation(gl.program, 'uColor');gl.drawArrays(gl.POINTS, 0, 1);});
      }
      gl.clear(gl.COLOR_BUFFER_BIT);points.forEach((value) => {gl.vertexAttrib2fv(aPos, value);// 设置颜色(uColor)// 这里每次绘制都随机生成颜色var uColor = gl.getUniformLocation(gl.program, 'uColor');gl.drawArrays(gl.POINTS, 0, 1);});
      }
      

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/422657.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

linux zabbix监控

zabbix总结 zabbix-server 10051 zabbix-agent 10050 zabbix-proxy 10051 1.监控项&#xff08;模板&#xff09;&#xff1a;获取监控数据 #模板直接链接到新的主机 2.触发器&#xff1a;设置一个值 在非合理区间报警 3.动作&#xff1a;可以帮忙发送通知&#xff08;告…

python:socket基础操作(2)-《udp发送信息》

基础发送udp信息 1.导入socket模块 2.使用udp模块 3.发送内容 4.关闭套接字 很简单的4步就可以实现udp的消息发送 import socket # 导入模块udp_socket socket.socket(socket.AF_INET,socket.SOCK_DGRAM) # 使用ipv4 udp协议udp_socket.sendto(b"hello world",(&…

protobuf 之诡异的文件流与压缩

只接上干货&#xff0c;内容较干。文章大概需要花费5分钟简单了解下。 1、Gzip 直接看源码头文件如上图。压缩对象 GzipOutputStream &#xff0c;通过函数操作可以看到整个文件流是比较完整并清晰。 因为它显示清晰包含了 从初始化 到 flush 到 close 的显示调用 2、Ostream…

二分查找(折半查找)

二分查找/折半查找 概述查找步骤代码示例输出结果 概述 二分查找&#xff08;Binary Search&#xff09;的前提是待查找的数据已经排好序。通过将待查找区间划分为两部分&#xff0c;并将目标值与中间值进行比较&#xff0c;可以确定目标值在左侧区间或右侧区间。然后将查找区…

P4学习(六)实验三:a Control Plane using P4Runtime

目录 一. 实验目的二.阅读MyController.py文件1.导入P4Runtime的库2.main部分1. P4InfoHelper 实例化2. 创建交换机连接3. 设置主控制器4. 安装 P4 程序5. 写入隧道规则6. 读取表项和计数器&#xff08;注释掉的部分&#xff09;7. 定时打印隧道计数器8. 异常处理9. 关闭交换机…

如何查看苹果手机的CPU型号?

摘要 本文将介绍如何在苹果手机上查看CPU型号。通过简单的设置操作&#xff0c;您可以轻松地获取您的iPhone的CPU型号信息。此外&#xff0c;我们还将介绍一些克魔助手可以提供的其他功能&#xff0c;如内存监控、GPU性能监控和网络抓包等&#xff0c;以帮助您优化和提升iOS应…

文件操作与IO(3)

文件内容的读写--数据流 这里我们将要讲到文件操作中的重要概念--流. 之前也在C语言讲解中提到了文件流的概念---读写文件内容 分为这几步:(1)打开文件;(2)读/写文件;(3)关闭文件. 数据流主要分为字节流和字符流. 字节流:以字节为单位进行读写(代表:InputStream,OutputStrea…

2.机器学习-K最近邻(k-Nearest Neighbor,KNN)分类算法原理讲解

2️⃣机器学习-K最近邻&#xff08;k-Nearest Neighbor&#xff0c;KNN&#xff09;分类算法原理讲解 个人简介一算法概述二算法思想2.1 KNN的优缺点 三实例演示3.1电影分类3.2使用KNN算法预测 鸢(yuan)尾花 的种类3.3 预测年收入是否大于50K美元 个人简介 &#x1f3d8;️&…

InnoDB的Buffer Pool

前置概念&#xff1a;一个数据页16KB&#xff0c;一个数据页可能有多个记录&#xff0c;即使我们只需要访问一条记录&#xff0c;需要把整个数据页加载到内存中&#xff0c;加载到内存后不是直接释放&#xff0c;而是缓存到内存当中&#xff08;当然对于buffer pool的缓存是在存…

自己构建webpack+vue3+ts

先看看我的目录结构&#xff08;我全局使用TS&#xff09;&#xff1a; 一、安装配置webpack打包 安装esno npm install esnoesno 是基于 esbuild 的 TS/ESNext node 运行时,有了它&#xff0c;就可以直接通过esno *.ts的方式启动脚本&#xff0c;package.json中添加 type:…

Quartus II使用小技巧

工程结构&#xff1a; 在建立完某项设计的文件后&#xff0c;依次在其里面新建四个文件夹&#xff0c;分别为&#xff1a;rtl、qprj、msim、doc。 rtl文件夹用于存放设计的源文件。 doc文件夹用于存放设计的一些文档性的资料。 qprj文件夹用于存放quaruts 工程以及quartus生…

SAP CDS VIEW实现行列转换

需求&#xff1a; 销售订单上的业务伙伴数据都在VBPA存储&#xff0c;根据PARVW来区分是售达方或者是送达方等等&#xff0c;有时候一些报表取数时有一些条件&#xff0c;比如售达方等于xxxxx并且送达方等于xxxxx&#xff0c;这时候就不是简单的一条sql就能搞定的事了&#xf…