WebGL笔记:图形旋转的原理和实现

旋转

1 )旋转的概念

  • 三维物体的旋转要比位移复杂一点,三维物体的旋转需要满足以下条件:
    • 旋转轴
    • 旋转方向
    • 旋转角度
  • 场景举例
    • 模型站在旋转轴的起点进行旋转
    • 模型要往左转还是往右转,就是旋转的方向
    • 模型旋转的大小就是旋转角度


2 )旋转方向的正负

  • 在webgl中,除裁剪空间之外的大部分功能都使用了右手坐标系
  • 在webgl中,可以暂且将其当成右手坐标系, 下图就是右手坐标系


  • 以上图为例

    • 当物体绕 z 轴,从x轴正半轴向y轴正半轴逆时针旋转时,是正向旋转,反之为负。
    • 当物体绕 x 轴,从y轴正半轴向z轴正半轴逆时针旋转时,是正向旋转,反之为负。
    • 当物体绕 y 轴,从z轴正半轴向x轴正半轴逆时针旋转时,是正向旋转,反之为负。
  • 如下图就是正向旋转

    • 围绕z轴(骑着z轴),从x轴到y轴逆时针转动就是正向旋转


旋转公式

  • 如下,让顶点围绕 z 轴旋转的场景


  • 已知
    • 点A的位置是(ax,ay,az)
    • 点A要围绕z轴旋转β度,转到点B的位置
  • 求:点A旋转后的bx、by位置
    • 因为∠β是已知的,∠α 可以通过点 A 得出
    • 所以我们可以得出
      ∠xOB = α + β
      
    • 那我们通过三角函数就可以推出bx、by
    • 设 ∠xOB = θ,则:
      bx = cosθ * |OA|
      by = sinθ * |OA| // 注意这里因为是旋转, 所以 |OA| === |OB|, 统一用 |OA|来表示
      
    • 上面的|OA|是点O到点A的距离,可以直接用点A求出
      |OA| = Math.sqrt(ax * ax + ay * ay)
      
    • 那我们接下来只需要知道cosθ和sinθ的值即可
    • 因为:θ = α + β
    • 所以,我们可以利用和角公式求cosθ和sinθ的值
      cosθ = cos(α + β)
      cosθ = cosα * cosβ - sinα * sinβ
      
      sinθ = sin(α + β)
      sinθ = cosβ * sinα + sinβ * cosα
      
    • 所以
      bx = cosθ * |OA|
      bx = (cosα * cosβ - sinα * sinβ) * |OA|
      bx = cosα * cosβ * |OA| - sinα * sinβ * |OA|
      
      by = sinθ * |OA|
      by = (cosβ * sinα + sinβ * cosα) * |OA|
      by = cosβ * sinα * |OA| + sinβ * cosα * |OA|
      
    • 因为
      cosα * |OA| = ax
      sinα * |OA| = ay
      
    • 所以我们可以简化bx、by的公式
      bx = ax * cosβ - ay * sinβ
      by = ay * cosβ + ax * sinβ
      
    • 上面的bx、by就是我们要求的答案

在着色器中旋转

  • 可以直接在着色器里写旋转公式

    <script id="vertexShader" type="x-shader/x-vertex">attribute vec4 a_Position;float angle = radians(80.0);float sinB = sin(angle);float cosB = cos(angle);void main() {gl_Position.x = a_Position.x * cosB - a_Position.y * sinB;gl_Position.y = a_Position.y * cosB + a_Position.x * sinB;gl_Position.z = a_Position.z;gl_Position.w = 1.0;}
    </script>
    
  • radians(float degree) 将角度转弧度

  • sin(float angle) 正弦

  • cos(float angle) 余弦

用js旋转图形

我们将顶点着色器里的正弦值和余弦值暴露给js,便可以用js旋转图形了

<script id="vertexShader" type="x-shader/x-vertex">attribute vec4 a_Position;uniform float u_SinB;uniform float u_CosB;void main() {gl_Position.x = a_Position.x * u_CosB-a_Position.y * u_SinB;gl_Position.y = a_Position.y * u_CosB+a_Position.x * u_SinB;gl_Position.z = a_Position.z;gl_Position.w = 1.0;}
</script>
  • 在js 中修改uniform 变量

    const u_SinB = gl.getUniformLocation(gl.program, 'u_SinB');
    const u_CosB = gl.getUniformLocation(gl.program, 'u_CosB');
    const angle = 0.3;
    gl.uniform1f(u_SinB, Math.sin(angle));
    gl.uniform1f(u_CosB, Math.cos(angle));
    
  • 之后让图形转起来

    !(function ani() {angle += 0.01;gl.uniform1f(u_SinB, Math.sin(angle));gl.uniform1f(u_CosB, Math.cos(angle));gl.clear(gl.COLOR_BUFFER_BIT);gl.drawArrays(gl.TRIANGLES, 0, 3);requestAnimationFrame(ani);
    })()
    

完整代码

<canvas id="canvas"></canvas>
<script id="vertexShader" type="x-shader/x-vertex">attribute vec4 a_Position;uniform float u_SinB;uniform float u_CosB;void main() {gl_Position.x = a_Position.x * u_CosB - a_Position.y * u_SinB;gl_Position.y = a_Position.y * u_CosB + a_Position.x * u_SinB;gl_Position.z = a_Position.z;gl_Position.w = 1.0;}
</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);// 获取Uniform变量const u_SinB = gl.getUniformLocation(gl.program, 'u_SinB')const u_CosB = gl.getUniformLocation(gl.program, 'u_CosB')// 修改uniform 变量let angle = 0.3gl.uniform1f(u_SinB, Math.sin(angle))gl.uniform1f(u_CosB, Math.cos(angle))gl.clearColor(0.0, 0.0, 0.0, 1.0);gl.clear(gl.COLOR_BUFFER_BIT);gl.drawArrays(gl.TRIANGLES, 0, 3);!(function ani() {angle += 0.01;gl.uniform1f(u_SinB, Math.sin(angle));gl.uniform1f(u_CosB, Math.cos(angle));gl.clear(gl.COLOR_BUFFER_BIT);gl.drawArrays(gl.TRIANGLES, 0, 3);requestAnimationFrame(ani);})()
</script>

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

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

相关文章

HarmonyOS应用开发实战—登录页面【ArkTS】

文章目录 本页面实战效果预览图一.HarmonyOS应用开发1.1HarmonyOS 详解1.2 ArkTS详解二.HarmonyOS应用开发实战—登录页面【ArkTS】2.1 ArkTS页面源码2.2 代码解析2.3 心得本页面实战效果预览图 一.HarmonyOS应用开发 1.1HarmonyOS 详解 HarmonyOS(鸿蒙操作系统)是华为公司…

【计算机网络笔记】以太网

系列文章目录 什么是计算机网络&#xff1f; 什么是网络协议&#xff1f; 计算机网络的结构 数据交换之电路交换 数据交换之报文交换和分组交换 分组交换 vs 电路交换 计算机网络性能&#xff08;1&#xff09;——速率、带宽、延迟 计算机网络性能&#xff08;2&#xff09;…

Kafka事务机制:原理和实践

Kafka事务机制&#xff1a;原理和实践 Apache Kafka 是一个分布式流处理平台&#xff0c;广泛用于构建实时数据管道和流应用程序。它不仅以高吞吐量、可扩展性和容错能力著称&#xff0c;还提供了事务支持&#xff0c;以确保数据的完整性和一致性。在这篇博客中&#xff0c;我…

现代C++之万能引用、完美转发、引用折叠

现代C之万能引用、完美转发、引用折叠 0.导语1.问题引入2.引入万能引用3.万能引用出现场合4.理解左值与右值4.1 精简版4.2 完整版4.3 生命周期延长4.4 生命周期延长应用5.区分万能引用6.表达式的左右值性与类型无关7.引用折叠和完美转发7.1 引用折叠之本质细节7.2 示例与使用7.…

【libGDX】Mesh纹理贴图

1 前言 纹理贴图的本质是将图片的纹理坐标与模型的顶点坐标建立一一映射关系。纹理坐标的 x、y 轴正方向分别朝右和朝下&#xff0c;如下。 2 纹理贴图 本节将使用 Mesh、ShaderProgram、Shader 实现纹理贴图&#xff0c;OpenGL ES 的实现见博客 → 纹理贴图&#xff0c;本节完…

excel表格在线编辑(开源版)

文章目录 前言一、Luckysheetvue3vite 例子如有启发&#xff0c;可点赞收藏哟~ 前言 本文记录好用的开源在线表格 具体如图显示 另外记录下更名后的univer~&#xff0c;如下图&#xff08;有兴趣可自行详细了解&#xff09; univer 在线思维导图 一、Luckysheet 参考git…

微服务--05--配置管理

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 配置管理这些问题都可以通过统一的配置管理器服务解决。而Nacos不仅仅具备注册中心功能&#xff0c;也具备配置管理的功能&#xff1a; 1.配置共享1.1.添加共享配置…

C#,数值计算——插值和外推,径向基函数插值(RBF_inversemultiquadric)的计算方法与源程序

1 文本格式 using System; namespace Legalsoft.Truffer { public class RBF_inversemultiquadric : RBF_fn { private double r02 { get; set; } public RBF_inversemultiquadric(double scale 1.0) { this.r02 Globals.SQR(scale); …

鸿蒙4.0开发笔记之ArkTS语法的基础数据类型[DevEco Studio开发](七)

文章目录 一、基本数据类型的定义1、变量声明2、数字类型3、字符串类型4、布尔类型5、数组类型6、元组类型7、枚举类型8、联合类型&#xff08;少用&#xff09;9、未知Unkown类型10、未定义和空值类型 二、数据类型的使用1、组件内部声明变量不需要使用let关键字2、使用Divide…

【数据结构】树与二叉树(廿四):树搜索指定数据域的结点(算法FindTarget)

文章目录 5.3.1 树的存储结构5. 左儿子右兄弟链接结构 5.3.2 获取结点的算法1. 获取大儿子、大兄弟结点2. 搜索给定结点的父亲3. 搜索指定数据域的结点a. 算法FindTargetb. 算法解析c. 代码实现a. 使用指向指针的指针b. 直接返回找到的节点 4. 代码整合 5.3.1 树的存储结构 5.…

论文阅读 Forecasting at Scale (二)

最近在看时间序列的文章&#xff0c;回顾下经典 论文地址 项目地址 Forecasting at Scale 3.2、季节性 3.3、假日和活动事件3.4、模型拟合3.5、分析师参与的循环建模4、自动化预测评估4.1、使用基线预测4.2、建模预测准确性4.3、模拟历史预测4.4、识别大的预测误差 5、结论6、致…

前后端分离开发出现的跨域问题

先说说什么是跨域。 请求的URL地址中的协议、域名、端口号中的任意一个与当前URL不同就是跨域。 比如&#xff1a; 当前页面的URL请求的URL是否跨域原因htttp://localhost:8080htttps://localhost:8080是协议不同htttp://localhostll:8080htttp://localhost:8080是域名不同htt…

计算机网络高频面试八股文

目录&#xff1a; 网络分层结构三次握手两次握手可以吗&#xff1f;四次挥手第四次挥手为什么要等待2MSL&#xff1f;为什么是四次挥手&#xff1f;TCP有哪些特点&#xff1f;说说TCP报文首部有哪些字段&#xff0c;其作用又分别是什么&#xff1f;TCP和UDP的区别&#xff1f;…

IWDG和WWDG HAL库+cubeMX

一.IWDG 1.原理 启用IWDG后&#xff0c;LSI时钟会自动开启 2.IWDG溢出时间计算 3.IWDG配置步骤 4.HAL库相关函数介绍 HAL_IWDG_Init //使能IWDG&#xff0c;设置预分频系数和重装载值等 HAL_IWDG_Refresh //把重装载寄存器的值重载到计数器中&#xff0c;喂狗typedef str…

【C++ 程序设计入门基础】- 第3节-循环结构01

目录 循环结构 一、for 语句 for 循环案例 输入一个整数n&#xff0c;输出1&#xff5e;n的所有整数。 编译运行&#xff0c;查看输出结果 编译调试 for 循环结构语义分析 二、beak 语句 三、continue 语句 案例1&#xff1a; 案例2&#xff1a; 案例3&#xff1a; 循环…

5.27每日一题(判断函数在那个区间上有界:充分条件不是必要条件)

若f(x)在(a , b)上连续&#xff0c;且f(a0)&#xff0c;f&#xff08;b-0&#xff09;存在&#xff08;及函数的左右极限存在&#xff09;>f(x)在(a,b)上有界

开发知识点-CSS样式

CSS样式 fontCSS 外边距 —— 围绕在元素边框的空白区域# linear-gradient() ——创建一个线性渐变的 "图像"# transform ——旋转 元素![在这里插入图片描述](https://img-blog.csdnimg.cn/20191204100321698.png)# rotate() [旋转] # 边框 (border) —— 围绕元素内…

“SRP模型+”多技术融合在生态环境脆弱性评价模型构建、时空格局演变分析与RSEI 指数的生态质量评价及拓展

近年来&#xff0c;国内外学者在生态系统的敏感性、适应能力和潜在影响等方面开展了大量的生态脆弱性研究&#xff0c;他们普遍将生态脆弱性概念与农牧交错带、喀斯特地区、黄土高原区、流域、城市等相结合&#xff0c;评价不同类型研究区的生态脆弱特征&#xff0c;其研究内容…

day64 django中间件的复习使用

django中间件 django中间件是django的门户 1.请求来的时候需要先经过中间件才能达到真正的django后端 2.响应走的时候也需要经过中间件 ​ djangp自带七个中间件MIDDLEWARE [django.middleware.security.SecurityMiddleware,django.contrib.sessions.middleware.SessionMiddle…

在线教育机构如何借助小程序技术创新

随着人工智能AI技术的发展&#xff0c;我们的生活学习工作方式都在经历变化。在线教育也处于这场变化的核心之中&#xff0c;同样借助这股东风引来了行业的一波红利期。 在正式分享在线教育行业的开始&#xff0c;我们先简单搞清楚什么是在线教育。 在线教育行业是指通过互联…