WebGL笔记:矩阵旋转运算的原理和实现

矩阵

  • 矩阵(Matrix)是一个按照矩形纵横排列的复数集合
    • 矩阵就像一个矩形的阵盘,通过其中纵横排列的元素
    • 我们可以摆出不同功能的阵法,比如位移矩阵、旋转矩阵、缩放矩阵 …
    • 在矩阵中的每一行,或者每一列数字构成的集合,可以视之为向量


  • 关于复数 z = a + bi
    • 实数: b = 0
      • 有理数: 整数和分数
      • 无理数: eg: 圆周率 π, sqrt(2)
    • 虚数: b != 0

向量

  • 向量,又叫矢量,它是一个用于表示方向和量的对象
  • 在webgl 里的向量有1维向量、2维向量、3维向量和4维向量
    • 1维向量中有1个数字,对应的是单轴坐标系里的点位
    • 2维向量中有2个数字,对应的是2维坐标系里的点位
    • 3维向量中有3个数字,对应的是3维坐标系里的点位
    • 4维向量中有4个数字,对应的是3维坐标系里的点位,外加一个附加数据,至于这个数据是什么,要看我们的项目需求

矩阵和向量的乘法

  • 矩阵和向量的乘法图


  • 矩阵乘以向量时,向量是几维的,那矩阵中就应该有几个向量
  • 如上图向量v 是2维的,那么矩阵中就有2组向量,这两组向量可以是横着的两组向量,也可以是竖着的两组向量
    • 横着的两组向量是:向量(a,b)、向量(e,f)
    • 竖着的两组向量是:向量(a,e)、向量(b,f)
    • 横着的两组遵循的规则是行主序,即将矩阵中的一行数据视之为一个向量
    • 竖着的两组遵循的规则是列主序,即将矩阵中的一列数据视之为一个向量
  • 我们是使用行主序,还是列主序,这就得看规则的定制者
  • 在webgl 里,矩阵元素的排列规则是列主序
  • 数学中常用的写法是行主序,所以我们接下来就用行主序例子
    • 矩阵和向量相乘的规则就是让矩阵中的每个向量和向量v相乘。
    • 向量和向量相乘,就是在求向量的点积,其结果是一个实数,而不再是向量
    • 比如上图中,向量(a,b)乘以向量v(x,y)的结果是:
      a * x + b * y
      
  • 因为a、b、x、y都是实数,所以其结果也是实数
  • 上图中,矩阵m乘以向量v 会得到两个结果,即ax+byex+fy
  • 这两个结果会构成一个新的向量v’(x’,y’)
    x' = a * x + b * y
    y' = e * x + f * y
    
  • 这时我们可以将其和数学里的旋转公式做一下比较
  • 点A(ax,ay)围绕z轴旋β度,其旋转后的位置是点B(bx,by),则:
    bx = cosβ * ax - sinβ * ay
    by = sinβ * ax + cosβ * ay
    
  • 对比上面的两组公式,试想一下
  • 向量v是可以当成一个点位
  • 那我现在就让向量v代表的位置,就是点A的位置。
  • 那么矩阵m乘以向量v,是不是可以让向量v代表的这个点位旋转β度呢?
  • 如果可以,那么矩阵里的元素应该满足什么条件呢?
  • 满足以下条件即可
    a = cosβ
    b = -sinβ
    e = sinβ
    f = cosβ
    
  • 这样,用矩阵乘以向量的方法得到的旋转结果和用数学公式得到的结果就是一样的,即;
    a * x + b * y = cosβ * ax - sinβ * ay
    e * x + f * y = sinβ  *ax + cosβ * ay
    


  • 最终我们就可以用矩阵乘以向量的方式让点p旋转β度
  • 也就是说,可以用矩阵乘以向量的方式求向量OA旋转了 β \beta β° 的位置


### 在着色器中书写矩阵

1 ) 核心代码

  • 在着色器中建立矩阵对象
    • mat2 是二维矩阵对象
<script id="vertexShader" type="x-shader/x-vertex">
    attribute vec4 a_Position;
    float angle = radians(40.0);
    float sinB = sin(angle);
    float cosB = cos(angle);
    mat2 m2 = mat2(
      cosB, sinB,
      -sinB, cosB
    );
    void main() {
      gl_Position = vec4(
        m2 * vec2(a_Position),
        a_Position.z, a_Position.w
      );
    }
</script>

2 )完整代码

<canvas id="canvas"></canvas>
<script id="vertexShader" type="x-shader/x-vertex">
  attribute vec4 a_Position;
  float angle = radians(40.0);
  float cosB = cos(angle);
  float sinB = sin(angle);
  // 列主序
  mat2 m2 = mat2(
    cosB, sinB,
    -sinB, cosB
  );
  void main() {
    gl_Position = vec4(
      m2 * vec2(a_Position),
      a_Position.z, a_Position.w
    );
  }
</script>
<script id="fragmentShader" type="x-shader/x-fragment">
  void main() {
    gl_FragColor = vec4(1.0, 1.0, 0.0, 1.0);
  }
</script>
<script type="module">
  import { initShaders } from './utils.js';

  const canvas = document.getElementById('canvas');
  canvas.width = window.innerWidth;
  canvas.height = window.innerHeight;
  const gl = canvas.getContext('webgl');

  const vsSource = document.getElementById('vertexShader').innerText;
  const fsSource = document.getElementById('fragmentShader').innerText;
  initShaders(gl, vsSource, fsSource);

  const vertices = new Float32Array([
    0.0, 0.1,
    -0.1, -0.1,
    0.1, -0.1
  ])

  const vertexBuffer = gl.createBuffer();
  gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
  gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
  const a_Position = gl.getAttribLocation(gl.program, 'a_Position');
  gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);
  gl.enableVertexAttribArray(a_Position);
  gl.clearColor(0.0, 0.0, 0.0, 1.0);
  gl.clear(gl.COLOR_BUFFER_BIT);
  gl.drawArrays(gl.TRIANGLES, 0, 3);
</script>

用js建立矩阵对象并传递给着色器

1 )核心代码

  • 在顶点着色器中建立uniform变量

    <script id="vertexShader" type="x-shader/x-vertex">
        attribute vec4 a_Position;
        uniform mat2 u_Matrix;
        void main() {
          gl_Position = vec4(
            u_Matrix * vec2(a_Position),
            a_Position.z, a_Position.w
          );
        }
    </script>
    
  • 获取并修改uniform 变量

    const u_Matrix = gl.getUniformLocation(gl.program, 'u_Matrix');
    let angle = 0.2;
    const [sinB, cosB] = [Math.sin(angle), Math.cos(angle)];
    const matrix = [
        cosB, sinB,
        -sinB, cosB
    ];
    gl.uniformMatrix2fv(u_Matrix, false, matrix);
    
  • 后面我们也可以在其中添加动画

    const u_Matrix = gl.getUniformLocation(gl.program, 'u_Matrix');
    let angle = 0.2;
    !(function animate() {
        angle += 0.02;
        const [sinB, cosB] = [Math.sin(angle), Math.cos(angle)];
        const matrix = [
            cosB, sinB,
            -sinB, cosB
        ];
        gl.uniformMatrix2fv(u_Matrix, false, matrix);
        gl.clear(gl.COLOR_BUFFER_BIT);
        gl.drawArrays(gl.TRIANGLES, 0, 3);
        requestAnimationFrame(animate)
    })()
    

2 )完整代码

<canvas id="canvas"></canvas>
<script id="vertexShader" type="x-shader/x-vertex">
  attribute vec4 a_Position;
  // 列主序
  uniform mat2 u_Matrix;
  void main() {
    gl_Position = vec4(
      u_Matrix * vec2(a_Position),
      a_Position.z,a_Position.w
    );
  }
</script>
<script id="fragmentShader" type="x-shader/x-fragment">
  void main() {
    gl_FragColor = vec4(1.0, 1.0, 0.0, 1.0);
  }
</script>

<script type="module">
  import { initShaders } from './utils.js';

  const canvas = document.getElementById('canvas');
  canvas.width = window.innerWidth;
  canvas.height = window.innerHeight;
  const gl = canvas.getContext('webgl');

  const vsSource = document.getElementById('vertexShader').innerText;
  const fsSource = document.getElementById('fragmentShader').innerText;
  initShaders(gl, vsSource, fsSource);

  const vertices = new Float32Array([
    0.0, 0.1,
    -0.1, -0.1,
    0.1, -0.1
  ]);

  const vertexBuffer = gl.createBuffer();
  gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
  gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
  const a_Position = gl.getAttribLocation(gl.program, 'a_Position');
  gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);
  gl.enableVertexAttribArray(a_Position);

  const u_Matrix = gl.getUniformLocation(gl.program, 'u_Matrix');
  let angle = 0.5;
  const sinB = Math.sin(angle);
  const cosB = Math.cos(angle);
  const matrix = [
    cosB, sinB,
    -sinB, cosB
  ];
  gl.uniformMatrix2fv(u_Matrix, false, matrix);
  gl.clearColor(0.0, 0.0, 0.0, 1.0);
  gl.clear(gl.COLOR_BUFFER_BIT);
  gl.drawArrays(gl.TRIANGLES, 0, 3);

  !(function animate() {
    angle += 0.05;
    const sinB = Math.sin(angle);
    const cosB = Math.cos(angle);
    const matrix = [
      cosB, sinB,
      -sinB, cosB
    ];
    gl.uniformMatrix2fv(u_Matrix, false, matrix);
    gl.clear(gl.COLOR_BUFFER_BIT);
    gl.drawArrays(gl.TRIANGLES, 0, 3);
    requestAnimationFrame(animate);
  })()
</script>
  • 以上是最简单的二维矩阵,我们也可以给顶点着色器一个四维矩阵

四维矩阵在着色器里的处理

  • 应用原理和二维矩阵是一样的

1 )核心代码

<script id="vertexShader" type="x-shader/x-vertex">
    attribute vec4 a_Position;
    float angle = radians(10.0);
    float cosB = cos(angle);
    float sinB = sin(angle);
    mat4 m4 = mat4(
      cosB, sinB, 0.0, 0.0,
      -sinB, cosB, 0.0, 0.0,
      0.0, 0.0, 1.0, 0.0,
      0.0, 0.0, 0.0, 1.0
    );
    void main() {
      gl_Position = m4 * a_Position;
    }
</script>

2 )完整代码

<canvas id="canvas"></canvas>
<script id="vertexShader" type="x-shader/x-vertex">
  attribute vec4 a_Position;
  float angle = radians(10.0);
  float cosB = cos(angle);
  float sinB = sin(angle);
  // 列主序
  mat4 m4 = mat4(
    cosB, sinB, 0.0, 0.0,
    -sinB, cosB, 0.0, 0.0,
    0.0, 0.0, 1.0, 0.0,
    0.0, 0.0, 0.0, 1.0
  );
  void main() {
    gl_Position = m4 * a_Position;
  }
</script>
<script id="fragmentShader" type="x-shader/x-fragment">
  void main() {
    gl_FragColor = vec4(1.0, 1.0, 0.0, 1.0);
  }
</script>
<script type="module">
  import { initShaders } from './utils.js';

  const canvas = document.getElementById('canvas');
  canvas.width = window.innerWidth;
  canvas.height = window.innerHeight;
  const gl = canvas.getContext('webgl');

  const vsSource = document.getElementById('vertexShader').innerText;
  const fsSource = document.getElementById('fragmentShader').innerText;
  initShaders(gl, vsSource, fsSource);

  const vertices = new Float32Array([
    0.0, 0.1,
    -0.1, -0.1,
    0.1, -0.1
  ])

  const vertexBuffer = gl.createBuffer();
  gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
  gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
  const a_Position = gl.getAttribLocation(gl.program, 'a_Position');
  gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);
  gl.enableVertexAttribArray(a_Position);

  gl.clearColor(0.0, 0.0, 0.0, 1.0);
  gl.clear(gl.COLOR_BUFFER_BIT);
  gl.drawArrays(gl.TRIANGLES, 0, 3);
</script>

用js向顶点着色器传递四维矩阵

1 )核心代码

const u_Matrix = gl.getUniformLocation(gl.program, 'u_Matrix');
let angle = 0.1;
const [sinB, cosB] = [Math.sin(angle), Math.cos(angle)];
const matrix = [
    cosB, sinB, 0.0, 0.0,
    -sinB, cosB, 0.0, 0.0,
    0.0, 0.0, 1.0, 0.0,
    0.0, 0.0, 0.0, 1.0
];
gl.uniformMatrix4fv(u_Matrix, false, matrix);

2 )完整代码

<canvas id="canvas"></canvas>
<script id="vertexShader" type="x-shader/x-vertex">
  attribute vec4 a_Position;
  // 列主序
  uniform mat4 u_Matrix;
  void main() {
    gl_Position = u_Matrix * a_Position;
  }
</script>
<script id="fragmentShader" type="x-shader/x-fragment">
  void main() {
    gl_FragColor = vec4(1.0,1.0,0.0,1.0);
  }
</script>
<script type="module">
  import { initShaders } from './utils.js';

  const canvas = document.getElementById('canvas');
  canvas.width = window.innerWidth;
  canvas.height = window.innerHeight;
  const gl = canvas.getContext('webgl');

  const vsSource = document.getElementById('vertexShader').innerText;
  const fsSource = document.getElementById('fragmentShader').innerText;
  initShaders(gl, vsSource, fsSource);

  const vertices = new Float32Array([
    0.0, 0.1,
    -0.1, -0.1,
    0.1, -0.1
  ]);

  const vertexBuffer = gl.createBuffer();
  gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
  gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
  const a_Position = gl.getAttribLocation(gl.program, 'a_Position');
  gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);
  gl.enableVertexAttribArray(a_Position);

  const u_Matrix = gl.getUniformLocation(gl.program, 'u_Matrix');
  let angle = 0.5;
  const sinB = Math.sin(angle);
  const cosB = Math.cos(angle);
  const matrix = [
    cosB, sinB, 0, 0,
    -sinB, cosB, 0, 0,
    0, 0, 1, 0,
    0, 0, 0, 1
  ];
  gl.uniformMatrix4fv(u_Matrix, false, matrix);

  gl.clearColor(0.0, 0.0, 0.0, 1.0);
  gl.clear(gl.COLOR_BUFFER_BIT);
  gl.drawArrays(gl.TRIANGLES, 0, 3);

  !(function animate() {
    angle += 0.05;
    const sinB = Math.sin(angle);
    const cosB = Math.cos(angle);
    const matrix = [
      cosB, sinB, 0, 0,
      -sinB, cosB, 0, 0,
      0, 0, 1, 0,
      0, 0, 0, 1
    ];
    gl.uniformMatrix4fv(u_Matrix, false, matrix);

    gl.clear(gl.COLOR_BUFFER_BIT);
    gl.drawArrays(gl.TRIANGLES, 0, 3);
    requestAnimationFrame(animate);
  })()
</script>

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

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

相关文章

设计模式-结构型模式之代理设计模式

文章目录 八、代理设计模式 八、代理设计模式 代理设计模式通过代理控制对象的访问&#xff0c;可以详细访问某个对象的方法&#xff0c;在这个方法调用处理&#xff0c;或调用后处理。既(AOP微实现) 。 代理有分静态代理和动态代理&#xff1a; 静态代理&#xff1a;在程序…

POSTGRESQL中如何利用SQL语句快速的进行同环比?

1. 引言 在数据驱动的时代&#xff0c;了解销售、收入或任何业务指标的同比和环比情况对企业决策至关重要。本文将深入介绍如何利用 PostgreSQL 和 SQL 语句快速、准确地进行这两种重要分析。 2. 数据准备 为了演示&#xff0c;假设我们有一张 sales 表&#xff0c;存储了销…

微信订阅号和服务号的区别

服务号和订阅号有什么区别&#xff1f;服务号转为订阅号有哪些作用&#xff1f;我们都知道&#xff0c;服务号一个月只能发4次文章&#xff0c;但是订阅号每天都能发文章。不过在接收消息这一方面&#xff0c;服务号群发的消息有消息提醒&#xff0c;并显示在对话框&#xff1b…

重新认识Word——样式

重新认识Word Word样式给所有一级标题加上一级标题样式修改标题一样式&#xff0c;符合要求 正文样式标题前的小黑点导航窗格样式的相互复制Word一键转PPT 话说回来&#xff0c;一个程序员平时可能还看不起office全家桶的软件&#xff0c;但是&#xff0c;在实际的生活运用中&a…

音视频的功耗优化

前言 在应用中&#xff0c;录制与音视频模块往往是高耗能的模块&#xff0c;设备容易发热&#xff0c;影响体验。 什么是功耗优化 手机有多个耗电模块&#xff0c; SOC(CPU&#xff0c;GPU&#xff0c;DDR)&#xff0c;Display&#xff0c;Audio&#xff0c;Video&#xff0…

thinkphp 5.1 对数据库查出来的字段进行预处理

比如数据库的设计是下面这样子&#xff1a; 我想展示的是这个样子&#xff1a; 前端可以处理。 Think PHP的处理方式&#xff1a; 定义属性 &#xff1a; $this->customize 任意值;//这里的之没有作用 <?phpnamespace app\hs\controller\shop;use app\daogou\mo…

Windows用户相关Dos命令演示

Windows用户相关Dos命令演示 1、查看当前用户 命令&#xff1a;whoami 2、查看主机名 命令: hostname 3、查看所有用户 命令&#xff1a;net user 4、查看指定的用户 命令&#xff1a;net user 用户名 5、添加用户 命令&#xff1a;net user 用户名 密码 /add 注…

数据链路层之VLAN基本概念和基本原理

学习的最大理由是想摆脱平庸&#xff0c;早一天就多一份人生的精彩&#xff1b;迟一天就多一天平庸的困扰。各位小伙伴&#xff0c;如果您&#xff1a; 想系统/深入学习某技术知识点… 一个人摸索学习很难坚持&#xff0c;想组团高效学习… 想写博客但无从下手&#xff0c;急需…

ASP.NET Core MVC过滤器

1、过滤器分为授权过滤、资源访问过滤、操作方法&#xff08;Action&#xff09;过滤、结果过滤、异常过滤、终结点过滤。上一次咱们没有说异常过滤和终结点过滤&#xff0c;不过老周后面会说的。对这些过滤器&#xff0c;你有印象就行了。 2、所有过滤器接口都有同步版本和异…

css 3D背景反转实现

body{/* 透视 */perspective: 800px; } div{transform-style:preserve-3d;width:259px;height:396px;margin: 100px auto;position: relative; } div img{position: absolute;width:259px;height:396px;left:0;top:0;transition: all linear 2s;z-index: 0; } div img:nth-chil…

[前 5 名] 最顶级的数据恢复软件解决方案列表

您是否在互联网上找到适用于 Windows PC 的前 5 名最受好评的数据恢复软件解决方案&#xff1f;嗯&#xff0c;在线市场上有很多工具可以恢复已删除的文件。但并不是所有的应用程序都值得使用它。值得信赖的文件恢复工具将有助于快速检索丢失、删除、格式化的数据并从计算机恢复…

flink源码分析之功能组件(四)-slot管理组件II

简介 本系列是flink源码分析的第二个系列&#xff0c;上一个《flink源码分析之集群与资源》分析集群与资源&#xff0c;本系列分析功能组件&#xff0c;kubeclient&#xff0c;rpc&#xff0c;心跳&#xff0c;高可用&#xff0c;slotpool&#xff0c;rest&#xff0c;metrics&…

机器学习笔记 - 异常检测之OneClass SVM算法简述

一、异常检测是什么? 如下图,理想中我们可以找到一个框住大部分正常样本的决策边界,而在边界外部的数据点(蓝点)即视为异常。 但实际情况下数据都没有标签,因此很难定义正常还是不正常。异常检测的主要挑战如下:正常与异常行为之间的界限往往并不明确、不同的应…

WEB安全之Python

WEB安全之python python-pyc反编译 python类似java一样&#xff0c;存在编译过程&#xff0c;先将源码文件*.py编译成 *.pyc文件&#xff0c;然后通过python解释器执行 生成pyc文件 创建一个py文件随便输入几句代码(1.py) 通过python交互终端 >>>import py_compil…

测试Centos上用Gunicorn启动的Django-Web服务在Django源文件有改变的情况下能否自动重载最新源码下的web服务

01-先上传最新的源码文件 参考博文 https://blog.csdn.net/wenhao_ir/article/details/134762966 进行 02-先在Django直接开web服务下修改源码测试 这是没有问题的&#xff0c;会自己重置。 03-开启gunicorn服务 cd /djangoproject/mmdj01/ gunicorn -c /djangoproject/mm…

泊车功能专题介绍 ———— 汽车全景影像监测系统性能要求及试验方法(国标未公布)

文章目录 术语和定义一般要求功能要求故障指示 性能要求响应时间图像时延单视图视野范围平面拼接视图视野平面拼接效果总体要求行列畸变拼接错位及拼接无效区域 试验方法环境条件仪器和设备车辆条件系统响应时间试验图像时延试验单视图视野范围试验平面拼接视图视野试验平面拼接…

【算法专题】二分查找

二分查找 二分查找1. 二分查找2. 在排序数组中查找元素的第一和最后一个位置3. 搜索插入位置4. x 的平方根5. 山脉数组的峰顶索引6. 寻找峰值7. 寻找旋转排序数组中的最小值8. 点名 二分查找 1. 二分查找 题目链接 -> Leetcode -704.二分查找 Leetcode -704.二分查找 题…

【SpringBoot】讲清楚日志文件lombok

文章目录 前言一、日志是什么&#xff1f;二、⽇志怎么⽤&#xff1f;三.自定义打印日志3.1在程序中得到日志对象3.2使用日志打印对象 四.⽇志级别4.1日志级别有什么用4.2 ⽇志级别的分类与使⽤ 五.日志持久化六.lombok6.1添加lobok依赖注意&#xff1a;使⽤ Slf4j 注解&#x…

vue权限管理解决方案

一. 什么是权限管理 权限控制是确保用户只能访问其被授权的资源和执行其被授权的操作的重要方面。而前端权限归根结底是请求的发起权&#xff0c;请求的发起可能有下面两种形式触发 页面加载触发页面上的按钮点击触发 总体而言&#xff0c;权限控制可以从前端路由和视图两个…

【算法刷题】Day11

文章目录 面试题 08.01. 三步问题题干&#xff1a;算法原理&#xff1a;1、状态表示2、状态转移方程3、初始化4、填表顺序5、返回值 代码&#xff1a; 209. 长度最小的子数组题干&#xff1a;算法原理&#xff1a;1、暴力枚举出所有的子数组的和2、利用单调性&#xff0c;使用“…