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

news2025/1/23 1:04:21

矩阵

  • 矩阵(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>

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C语言——指针(四)

&#x1f4dd;前言&#xff1a; 上篇文章C语言——指针&#xff08;三&#xff09;对指针和数组进行了讲解&#xff0c;今天主要更深入的讲解一下不同类型指针变量的特点&#xff1a; 1&#xff0c;字符指针变量 2&#xff0c;数组指针变量 3&#xff0c;函数指针变量 &#x1…

Spring MVC学习随笔-控制器(Controller)开发详解:控制器跳转与作用域(一)

学习视频&#xff1a;孙哥说SpringMVC&#xff1a;结合Thymeleaf&#xff0c;重塑你的MVC世界&#xff01;&#xff5c;前所未有的Web开发探索之旅 第五章、SpringMVC控制器开发详解 三 5.1 核心要点 3.流程跳转 5.2 JavaWeb中流程跳转的核心回顾 5.2.1 JavaWeb中流程跳转的核…

(数据结构)顺序表的查找

静态分配代码&#xff1a; #include<stdio.h> #include<stdlib.h> #define MAX 100 typedef struct LinkList {int data[MAX];int lenth; }Link; //初始化 void CreateList(Link* L) {L->lenth 0;for (int i 0; i < MAX; i){L->data[i] 0;} } //插入 …

【算法专题】二分查找

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

没了解死锁怎么能行?进来看看,一文带你拿下死锁产生的原因、死锁的解决方案。

&#x1f308;&#x1f308;&#x1f308;今天给大家分享的是死锁产生的原因&#xff0c;以及如何解决死锁问题。 清风的CSDN博客 &#x1f6e9;️&#x1f6e9;️&#x1f6e9;️希望我的文章能对你有所帮助&#xff0c;有不足的地方还请各位看官多多指教&#xff0c;大家一起…

ORA-00257: archiver error. Connect internal only, until freed 的解决方法

归档文件存储空间不足&#xff0c;导致出现该问题。 当我们将数据库的模式修改为归档模式的时候&#xff0c;如果没有指定归档目录&#xff0c;默认的归档文件就会放到Flash Recovery Area的目录&#xff0c;但是这个目录是有大小限制的&#xff0c;如果超过了这个大小&#x…

专升本期间部分的C语言程序整理

说明 这些程序是我在专升本期间在CSDN上上传的作业、练习等&#xff0c;仅为学习备考的一小部分程序&#xff0c;整理成一篇文章&#xff0c;方便专升本的学弟学妹参考。 时间&#xff1a;2021年~2022年专升本期间 字符串题 输入字符串提取 数字字符 并 求和 &#xff08;4处…

【排序】直接插入排序和希尔排序

目录 一、排序思想 1、直接插入排序 2、希尔排序 二、代码实现 三、性能比较 四、排序总结 1、直接插入排序 2、希尔排序 一、排序思想 1、直接插入排序 基本思想&#xff1a;把待排序的序列选取一个整数逐个插入到已经排好的有序序列中&#xff0c;直到所有整数都插入…

Android自定义View实现八大行星绕太阳转动效果

最近尝试使用Android自定义View实现了一个8大行星绕太阳转动的自定义View效果&#xff0c;效果静态图如下所示&#xff1a; 还没来得及对该效果进行比较通用的包装&#xff0c;仅仅实现效果&#xff0c;有兴趣的可以继续扩展、美化、包装一下。 核心代码就一个类PlanetsView。 …

ZLMediakit-method ANNOUNCE failed: 401 Unauthorized(ffmpeg、obs推流rtmp到ZLM发现的问题)

错误截图 解决办法&#xff1a;能推流成功&#xff0c;但是不能写入到wvp数据库中 修改配置文件config.ini 改成0 修改之后 重启服务 systemctl restart zlm*推流成功 解决办法&#xff1a;能推流&#xff0c;能写入数据库中 替换zlm版本&#xff0c;可以用我文章中提供的编译…

阅读软件OmniReader Pro mac功能特色

OmniReader Pro mac是一款文字识别和阅读软件&#xff0c;它可以将印刷体和手写体的文字转换为数字文本&#xff0c;并将其朗读出来。该软件适用于视力受损、阅读困难、语言障碍等用户&#xff0c;可以帮助他们更加轻松地获取信息和阅读文本。 OmniReader Pro具有简洁直观的用户…

为何全球电商都在拼“质价比”?

远在西雅图的希拉里&#xff0c;在著名的“黑色星期五”大促开始之前&#xff0c;她就已经准备好了一份购物清单。 然而&#xff0c;她发现身边的朋友们总是拉她组团购物。 在朋友和社交媒体的持续轰炸下&#xff0c;希拉里决定尝试一下这个让人贼上头的Temu。 最终&#xf…

linux之buildroot(3)配置软件包

Linux之buildroot(3)配置软件包 Author&#xff1a;Onceday Date&#xff1a;2023年11月30日 漫漫长路&#xff0c;才刚刚开始… 全系列文章请查看专栏: buildroot编译框架_Once_day的博客-CSDN博客。 参考文档&#xff1a; Buildroot - Making Embedded Linux Easymdev.t…

idea通过remote远程调试云服务器

引用了第三方的包&#xff0c;调试是看不到运行流程&#xff0c;于是想到了idea的remote方法 -agentlib:jdwptransportdt_socket,servery,suspendn,address9002 写一个.sh文件并启动 nohup java -jar -agentlib:jdwptransportdt_socket,servery,suspendn,address9002 ./demo.j…

vr工业制造流程3D模拟仿真可视化展示

工业仿真3D数字化展示系统具有多方面的独特之处&#xff0c;主要体现在以下几个方面&#xff1a; 1、真实感和交互性&#xff1a;该系统可以将实际的工业设备、产品、场景等进行数字化建模&#xff0c;通过三维图形技术将其呈现在计算机屏幕上&#xff0c;使用户可以在虚拟环境…

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

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

网络之路27:IRF设备堆叠

正文共&#xff1a;3210 字 34 图&#xff0c;预估阅读时间&#xff1a;5 分钟 目录 网络之路第一章&#xff1a;Windows系统中的网络 0、序言 1、Windows系统中的网络1.1、桌面中的网卡1.2、命令行中的网卡1.3、路由表1.4、家用路由器 网络之路第二章&#xff1a;认识企业设备…

使用策略模式彻底消除if-else

文章目录 使用策略模式彻底消除if-else1. 场景描述2. if-else方式3. 策略模式 使用策略模式彻底消除if-else 如果一个对象有很多的行为&#xff0c;如果不用恰当的模式&#xff0c;这些行为就只好使用多重的条件选择语句来实现&#xff0c;这样会显得代码逻辑很臃肿&#xff0c…

TEMU三季度销售额或达50亿美金,多多跨境已成第二增长引擎

2023年11月28日&#xff0c;拼多多发布了2023年第三季度业绩报告。 报告显示&#xff0c;三季度的收入为688.4亿元&#xff0c;同比增长93.9%&#xff0c;按照美国通用会计准则&#xff0c;实现净利润155.4亿元&#xff0c;净利润率达到22.6%。 拼多多将近翻倍的业绩成长&…

mybatis整合(手动添加jar包方式)

操作步骤 创建数据库 建立user表 放入数据 1、创建javaweb工程并添加Jar包 用到的jar包 junit 用于测试 mybatis框架&#xff1a;mybatis-3.5.9.jar mysql数据库&#xff1a;mysql-connector-java-8.0.28.jar 2、添加MyBatis核心配置文件 <?xml version"1.0"…