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.mzph.cn/news/180170.shtml

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

相关文章

人工智能_AI服务器安装清华开源_CHATGLM大语言模型_GLM-6B安装部署_人工智能工作笔记0092

看到的这个开源的大模型,很牛,~关键让我们自己也可以部署体验一把了,虽然不知道具体内部怎么构造的但是,也可以自己使用也挺好. 可以部署在自己的机器上也可以部署在云服务器上. 安装以后,是可以使用python代码进行提问,然后返回结果的,这样就可以实现我们自己的chat应用了, …

仿美团外卖源码/在线外卖平台源码PHP/支持多商户+多样化配送费+本土外卖+支持第三方配送

源码简介&#xff1a; 进云仿美团外卖源码&#xff0c;作为外卖平台源码&#xff0c;它不仅支持多商户、多样化配送费、本土外卖&#xff0c;还支持第三方配送。 进云仿美团外卖源码是一个进云源生插件&#xff0c;支持多商户多样化配送费模式本土外卖平台支持第三方配送&…

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

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

蓝桥杯day02——移动机器人

1.题目 有一些机器人分布在一条无限长的数轴上&#xff0c;他们初始坐标用一个下标从 0 开始的整数数组 nums 表示。当你给机器人下达命令时&#xff0c;它们以每秒钟一单位的速度开始移动。 给你一个字符串 s &#xff0c;每个字符按顺序分别表示每个机器人移动的方向。L 表…

基于Vue+SpringBoot的个人健康管理系统

项目编号&#xff1a; S 040 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S040&#xff0c;文末获取源码。} 项目编号&#xff1a;S040&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 健康档案模块2.2 体检档案模块2.3 健…

C语言第三十六弹--实现转移表的多种方法

使用C语言通过多种方法实现转移表 方法一、普通法 思路&#xff1a;如图实现多种操作&#xff0c;首先创建菜单&#xff0c;需要运行一次再判断条件&#xff0c;所以通过do{}while(); 循环来实现多次。有多种选择&#xff0c;使用switch case选择语句&#xff0c;再在对应case…

内网渗透(哈希传递)

概念 早期SMB协议明文在网络上传输数据&#xff0c;后来诞生了LM验证机制&#xff0c;LM机制由于过于简单&#xff0c;微软提出了WindowsNT挑战/响应机制&#xff0c;这就是NTLM。 哈希传递前提 同密码(攻击主机与实现主机两台要密码一致)。 NTLM协议 加密ntlm哈希 转换成…

uniapp中uni.navigateBack返回后刷新页面数据

文章目录 一、前言1.1、[uni.navigateBack](https://uniapp.dcloud.net.cn/api/router.html#navigateback) 二、方法2.1、父页面设置钩子函数onBackPress2.2、uni.$emit和uni.$on监听通知数据变更2.2.1、子页面2.2.2、父页面 2.3、onShow钩子函数处理数据2.3.1、子页面2.3.2、父…

使用Python实现SVM来解决二分类问题

下面是一个使用Python实现SVM来解决二分类问题的例子&#xff1a; # 导入所需的库 from sklearn.datasets import make_blobs from sklearn.model_selection import train_test_split from sklearn.svm import SVC import matplotlib.pyplot as plt# 生成一个二分类数据集 X, …

MES系统的功能清单

MES系统的功能清单 一、生产计划管理 1. 订单和生产计划制定&#xff1a;根据客户需求和市场状况&#xff0c;制定生产计划和订单&#xff0c;确保生产资源的合理分配和生产进度的有效管理。 2. 生产排程&#xff1a;根据生产计划和订单&#xff0c;结合设备、人员、物料等资…

iOS 通用链接的配置(Universal Links)

一、打开Associated Domains 1.首先登录 苹果开发者网站 2.Certificates, Identifiers & Profiles 下的Identifiers 找到要配追的Identifiers 点进去 3.打开Associated Domains然后保存 二、更新Profile文件 如果我们使用自动的&#xff0c;可以忽略这一步&#xff0c;…

与珎同行录-开篇-231129

与珎同行录-开篇 珎就是对陪伴并帮助我写代码的AI的昵称 能不能读懂这个绕口令问题呢? 连续的椎体的相邻椎体质心的相邻质心的质心作为当前质心所在的椎体的质心, 该质心的方向代表该椎体的上下方向 如何代码实现呢? 还是没看懂…好吧最终的算法是:

使用Pytorch从零开始构建扩散模型-DDPM

知识回顾: [1] 生成式建模概述 [2] Transformer I&#xff0c;Transformer II [3] 变分自编码器 [4] 生成对抗网络&#xff0c;高级生成对抗网络 I&#xff0c;高级生成对抗网络 II [5] 自回归模型 [6] 归一化流模型 [7] 基于能量的模型 [8] 扩散模型 I, 扩散模型 II 引言 去噪…

什么是量子优势?

量子优势是量子计算领域正在积极努力的里程碑&#xff0c;量子计算机可以解决最强大的非量子或经典计算机无法解决的问题。 量子是指原子和分子的尺度&#xff0c;在这个尺度上&#xff0c;我们所经历的物理定律被打破&#xff0c;并且应用了一组不同的、违反直觉的定律。量子…

西南科技大学数字电子技术实验二(SSI逻辑器件设计组合逻辑电路及FPGA实现 )预习报告

一、计算/设计过程 说明:本实验是验证性实验,计算预测验证结果。是设计性实验一定要从系统指标计算出元件参数过程,越详细越好。用公式输入法完成相关公式内容,不得贴手写图片。(注意:从抽象公式直接得出结果,不得分,页数可根据内容调整) 1、1位半加器 真值表: 逻…

【TC3xx芯片】TC3xx芯片的Clock System功能详解

目录 前言 正文 1.时钟源 1.1 有源晶振和无源晶振 1.1.1 无源晶振 1.1.2 有源晶振 1.1.3 有源晶振和无源晶振的区别 1.1 振荡器电路&#xff08;OSC&#xff09; 1.1.1外部输入时钟模式 1.1.2 外部晶体 / 陶瓷谐振器模式 1.1.3 OSC控制寄存器 1.1.4 配置OSC 1.1.5…

LeetCode(35)螺旋矩阵【矩阵】【中等】

目录 1.题目2.答案3.提交结果截图 链接&#xff1a; 54. 螺旋矩阵 1.题目 给你一个 m 行 n 列的矩阵 matrix &#xff0c;请按照 顺时针螺旋顺序 &#xff0c;返回矩阵中的所有元素。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,2,3],[4,5,6],[7,8,9]] 输出&#xff1a…

仿制剧情吧网站源码 帝国CMS剧情介绍模板

帝国CMS7.5剧情介绍模板&#xff0c;仿制剧情吧网站的风格。该模板并非用于直接播放电影&#xff0c;而是用文字描述剧情&#xff0c;同时包含手机版。本站免费分享供站长学习研究使用。采用伪静态技术&#xff0c;无需生成HTML。出于美观考虑&#xff0c;自带数据仅供本地环境…

【古月居《ros入门21讲》学习笔记】13_服务数据的定义与使用

目录 说明&#xff1a; 1. 服务模型 2. 实现过程&#xff08;C&#xff09; 自定义服务数据 Person.srv文件内容 Person.srv文件内容说明 编译配置 在package.xml文件中添加功能包依赖 在CMakeLists.txt中添加编译选项 编译生成语言相关文件 创建服务器代码&#xf…

Kafka 保证消息消费全局顺序性

当有消息被生产出来的时候&#xff0c;如果没有指定分区或者指定 key &#xff0c;那么消费会按照【轮询】的方式均匀地分配到所有可用分区中&#xff0c;但不一定按照分区顺序来分配 我们知道&#xff0c;在 Kafka 中消费者可以订阅一个或多个主题&#xff0c;并被分配一个或多…