【笔记】《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/3D
        ctx.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);
        });
      }
      

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

IMX6LL|时钟控制

一.时钟控制模块 4个层次配置芯片时钟 晶振时钟PLL与PFD时钟PLL选择时钟根时钟/外设时钟 1.1晶振时钟 系统时钟来源 RTC时钟源&#xff1a;32.768KHz&#xff0c;连接RTC模块&#xff0c;进行时间计算。系统时钟&#xff1a;24MHz&#xff0c;芯片主晶振 1.2PLL和PFD倍频时钟…

十一、常用API——正则表达式

目录 练习1&#xff1a; 正则表达式的作用 正则表达式 字符类&#xff08;只匹配一个字符&#xff09; 预定义字符&#xff08;只匹配一个字符&#xff09; 数量词 类 Pattern 正则表达式的构造摘要 反斜线、转义和引用 字符类 行结束符 组和捕获 Unicode 支持 与…

leetcode234. 回文链表

题目 给你一个单链表的头节点 head &#xff0c;请你判断该链表是否为回文链表。如果是&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 示例 1&#xff1a; 输入&#xff1a;head [1,2,2,1] 输出&#xff1a;true示例 2&#xff1a; 输入&#xff1a;hea…

关于KT6368A双模蓝牙芯片的BLE在ios的lightblue大数量数据测试

测试简介 关于KT6368A双模蓝牙芯片的BLE在ios的lightblue app大数量数据测试 测试环境&#xff1a;iphone7 。KT6368A双模程序96B6 App&#xff1a;lightblue ios端 可以打开log日志查看通讯流程 测试数据&#xff1a;长度是1224个字节&#xff0c;单次直接发给KT6368A&a…

ELK之Filebeat输出日志格式设置及输出字段过滤和修改

一、Filebeat输出日志格式设置 1.1 编辑vim filebeat.yml文件,修改输出格式设置 # output to console output.console:codec.format: string: %{[@timestamp]} %{[message]}pretty: true### 1.2 测试 执行 ./filebeat -e 可以看到/tmp/access.log(目前文件里只有140.77.188…

【Java 设计模式】结构型之桥接模式

文章目录 1. 定义2. 应用场景3. 代码实现结语 桥接模式&#xff08;Bridge Pattern&#xff09;是一种结构型设计模式&#xff0c;它将抽象部分与实现部分分离&#xff0c;使它们可以独立变化&#xff0c;从而降低它们之间的耦合。桥接模式通过将抽象部分和实现部分分离&#x…

【PyTorch】PyTorch之Tensors操作篇

文章目录 前言一、Tensor创建1、TENSOR2、SPARSE_COO_TENSOR3、SPARSE_CSR_TENSOR4、ASARRAY5、AS_TENSOR6、FROM_NUMPY7、FROMBUFFER8、ZEROS和ZEROS_LIKE9、ONES和ONES_LIKE10、ARANGE11、LINSPACE12、LOGSPACE13、EYE14、EMPTY和EMPTY_LIKE15、FULL和FULL_LIKE 前言 介绍Te…

Docker搭建MySQL主从数据库-亲测有效

1、测试环境概述 1、使用MySQL5.7.35版本 2、使用Centos7操作系统 3、使用Docker20版本 案例中描述了整个测试的详细过程 2、安装Docker 2.1、如果已经安装docker,可以先卸载 yum remove -y docker \ docker-client \ docker-client-latest \ docker-common \ docker-l…

Nginx重写功能location与rewrite

1. location 从功能看 rewrite 和 location 似乎有点像&#xff0c;都能实现跳转&#xff0c;主要区别在于 rewrite 是在同一域名内更改获取资源的路径&#xff0c;而 location 是对一类路径做控制访问或反向代理&#xff0c;还可以proxy_pass 到其他机器。 rewrite 对访问的…

java数据结构与算法刷题-----LeetCode977. 有序数组的平方

java数据结构与算法刷题目录&#xff08;剑指Offer、LeetCode、ACM&#xff09;-----主目录-----持续更新(进不去说明我没写完)&#xff1a;https://blog.csdn.net/grd_java/article/details/123063846 文章目录 1. 时间复杂度 空间复杂度 O(n * l o g 2 n log_2{n} log2​…

Qt通用属性工具:随心定义,随时可见(三)

传送门: 《Qt通用属性工具&#xff1a;随心定义&#xff0c;随时可见&#xff08;一&#xff09;》 《Qt通用属性工具&#xff1a;随心定义&#xff0c;随时可见&#xff08;二&#xff09;》 《Qt通用属性工具&#xff1a;随心定义&#xff0c;随时可见&#xff08;三&#xf…

MFC 绘图

目录 MFC中绘图 CPaintDC&#xff0c;封装了在WM_PAINT消息中绘图的绘图设备 CClientDC类&#xff0c;封装了在客户区绘图的绘图设备 CGdiObject类(绘图对象类)&#xff0c;封装了各种绘图对象相关的操作 MFC中绘图 Windows绘图需要绘图设备&#xff0c;Win32&#xff1a;…

jvm -Djava.library.path 无法打开共享对象文件:

项目代码修改 java -jar -Xms1024m -Xmx1024m -Dloader.path/data/encrypt/lib -Djava.library.path/data/encrypt/libVtExtAPI.so server-1.0.0-SNAPSHOT.jar 重新启动

JavaScript基础语法

速通回顾一遍 引入方式 一般会把<script>标签置于<body>元素底部&#xff0c;改善显示速度&#xff1a; 内部脚本&#xff1a;<script></script>标签内外部脚本&#xff1a;<script src""></script>配置src 外部js文件中&…

Cacti 前台SQL注入漏洞复现(CVE-2023-39361)

0x01 产品简介 Cacti 是一套基于 PHP,MySQL,SNMP 及 RRDTool 开发的网络流量监测图形分析工具。 0x02 漏洞概述 该漏洞存在于graph_view.php文件中。默认情况下,访客用户无需身份验证即可访问graph_view.php,在启用情况下使用时会导致SQL注入漏洞。 攻击者可能利用此漏洞…

跨平台兼容,无限可能:Apple Remote Desktop for Mac让远程控制更简单

Apple Remote Desktop for Mac是一款远程桌面管理软件&#xff0c;提供了一系列强大的功能&#xff0c;让用户可以轻松地管理和控制远程计算机。以下是该软件的一些主要功能和特点&#xff1a; 实时远程访问和控制&#xff1a;使用Apple Remote Desktop&#xff0c;用户可以在…

文件操作函数总结(Linux)

目录 一、fopen/fclose 二、fgetc/getc/getchar 三、fputc/putc/putchar 四、fgets/gets 五、fputs/puts 六、fread/fwrite 六、open/close 七、ftell/fssek/rewind/fflush 八、sprintf/sscanf/fprintf/fscanf 九、opendir/closedir/readdir 十、stat 十一、动态/静态…

一款开源且不限制大小可以设置过期时间的支持分享的的开源文件共享系统picoshare 部署教程

1.拉取镜像 2.部署 创建目录 mkdir -p /opt/picoshare/data 部署 其中:"somesecretpass"是密码 docker run \--env "PORT4001" \--env "PS_SHARED_SECRETsomesecretpass" \--publish 10005:4001/tcp \--volume "/opt/picoshare/data:…

UG阵列-数字递增

在UG中&#xff0c;我们对一个文本进行阵列&#xff0c;可以得到很多个相同文本&#xff0c;但是如果文本中的数据是递增数列&#xff0c;需要用到表达式 先画一根参考线&#xff0c;标注参考线长度&#xff0c;并记录系统生成对应长度的表达式&#xff0c;例如p15 然后插入一个…