当前位置: 首页 > news >正文

WebGL编程指南 - 高级变换与动画基础

  • 学习使用一个矩阵变换库,该库封装了矩阵运算的数学细节。
  • 快速上手使用该矩阵库,对图形进行复合变换。
  • 在该矩阵库的帮助下,实现简单的动画效果。

矩阵变换库:cuon-matrix.js

OpenGL中的函数:

书中 cuon-matrix.js 函数库中是这样实现的:

函数库主要创建了一个Matrix4类(构造函数),在该类原型函数下绑定了众多方法,许多函数之前都留有注释,我们主要看一下代码最前面的注释:

/** * This is a class treating 4x4 matrix.* This class contains the function that is equivalent to OpenGL matrix stack.* The matrix after conversion is calculated by multiplying a conversion matrix from the right.* The matrix is replaced by the calculated result.*/

根据注释可知,该函数库主要处理4×4的矩阵,对标OpenGL中矩阵处理函数。函数库提供了一个名为Matrix4的对象(构造函数),我们可以通过new方法创建它的实例,对象内部挂载了许多关于矩阵计算的方法。

这样使用函数库的方法,写起来更加简单

  • 矩阵的创建方式:
// RotatedTriangle_Matrix.js
...// 创建旋转矩阵let radian = (Math.PI * ANGLE) / 180.0 // 转换为弧度制let cosB = Math.cos(radian)let sinB = Math.sin(radian)// 注意WebGL中矩阵是列主序的let xformMatrix = new Float32Array([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,])...
// RotatedTriangle_Matrix4.js
...// 创建旋转矩阵// 为旋转矩阵创建Matrix4对象let xformMatrix = new Matrix4()// 将xformMatrix设置为旋转矩阵xformMatrix.setRotate(ANGLE, 0, 0, 1)
...
  • 传输矩阵数据
// RotatedTriangle_Matrix.js
...// 将旋转图形所需数据传输给顶点着色器let u_xformMatrix = gl.getUniformLocation(gl.program, 'u_xformMatrix')if (!u_xformMatrix) {console.log('Failed to get the storage location of u_xformMatrix')}gl.uniformMatrix4fv(u_xformMatrix, false, xformMatrix)
...
// RotatedTriangle_Matrix4.js
...let u_xformMatrix = gl.getUniformLocation(gl.program, 'u_xformMatrix')if (!u_xformMatrix) {console.log('Failed to get the storage location of u_xformMatrix')}gl.uniformMatrix4fv(u_xformMatrix, false, xformMatrix.elements)
...

Matrix4在不提供数据直接初始化的情况下,其挂载的element元素就是一个单位阵,之后大部分操作都是对element元素进行的。

从上表可见,Matrix4对象有两种方法:

  • 一种方法的名称中含有前缀set,这一类方法会根据参数计算出变换矩阵,然后将变换矩阵写入自身;
  • 另一种方法的名称中不含set前缀,这一类方法在计算出变换矩阵后,会将自身与计算出的变换矩阵相乘,最终结果写入Matrix4对象。

复合变换RotatedTranslatedTriangle.js

相关内容:采用Matirx4对象,运用矩阵乘法模拟符合变换。
相关函数:Matrix4.setRotate(), Matrix4.translate()

注意:矩阵乘法的先后顺序与模型变换的先后顺序有关,不能随意变化(矩阵乘法不满足乘法交换律)。

注意是 左乘

一个模型可能经过了多次变换,将这些变换全部复合成一个等效的变换,就得到了模型变换(model transformation),或称建模变换(modeling transformation),相应的,模型变换的矩阵称为模型矩阵(model matrix)。

重写Rotatedtriangle_Matrix4 代码:

  • 命名习惯,在顶点着色器中命名uniform变量(mat4)为u_ModelMatrix,取模型矩阵之意。
// 顶点着色器
var VSHADER_SOURCE ='attribute vec4 a_Position;\n' +'uniform mat4 u_ModelMatrix;\n' +'void main(){\n' +'  gl_Position = u_ModelMatrix * a_Position;\n' +'}\n'
  • 构建矩阵时,采用Matrix4对象,先设置对象为旋转矩阵,再和平移矩阵相乘。
  // 创建Matrix4对象let modelMatrix = new Matrix4()// 旋转角度let ANGLE = 90.0// 平移距离let Tx = 0.5// 设置模型矩阵为旋转矩阵modelMatrix.setRotate(ANGLE, 0, 0, 1)// 将模型矩阵乘以平移矩阵modelMatrix.translate(Tx, 0, 0)// 将模型矩阵传输给顶点着色器let u_ModelMatrix = gl.getUniformLocation(gl.program, 'u_ModelMatrix')if (!u_ModelMatrix) {console.log('Failed to get the storage location of u_ModelMatrix')}gl.uniformMatrix4fv(u_ModelMatrix, false, modelMatrix.elements)

完整代码:

// RotatedTranslatedTriangle.js
// 顶点着色器
var VSHADER_SOURCE ='attribute vec4 a_Position;\n' +'uniform mat4 u_ModelMatrix;\n' +'void main(){\n' +'  gl_Position = u_ModelMatrix * a_Position;\n' +'}\n'
// 片元着色器
var FSHADER_SOURCE ='void main(){\n' + ' gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n' + '}\n'// 主函数
function main() {// 获取canvas元素let canvas = document.getElementById('webgl')// 获取WebGL上下文let gl = getWebGLContext(canvas)if (!gl) {console.log('Failed to get the rendering context for WebGL')return}// 初始化着色器if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {console.log('Failed to initialize shaders')return}// 设置顶点位置let n = initVertexBuffers(gl)if (n < 0) {console.log('Failed to set the positions of the vertices')return}// 创建Matrix4对象let modelMatrix = new Matrix4()// 旋转角度let ANGLE = 90.0// 平移距离let Tx = 0.5// 设置模型矩阵为旋转矩阵modelMatrix.setRotate(ANGLE, 0, 0, 1)// 将模型矩阵乘以平移矩阵modelMatrix.translate(Tx, 0, 0)// 将模型矩阵传输给顶点着色器let u_ModelMatrix = gl.getUniformLocation(gl.program, 'u_ModelMatrix')if (!u_ModelMatrix) {console.log('Failed to get the storage location of u_ModelMatrix')}gl.uniformMatrix4fv(u_ModelMatrix, false, modelMatrix.elements)// 设置背景色gl.clearColor(0.0, 0.0, 0.0, 1.0)// 清空绘图区gl.clear(gl.COLOR_BUFFER_BIT)// 绘制三角形gl.drawArrays(gl.TRIANGLES, 0, n)
}function initVertexBuffers(gl) {// 设置类型化数组和顶点数let vertices = new Float32Array([0.0, 0.3, -0.3, -0.3, 0.3, -0.3])let n = 3// 创建缓冲区对象let vertexBuffer = gl.createBuffer()if (!vertexBuffer) {console.log('Failed to create the buffer object')return -1}// 绑定缓冲区gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer)// 缓冲区写入数据gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STREAM_DRAW)let a_Position = gl.getAttribLocation(gl.program, 'a_Position')if (a_Position < 0) {console.log('Failed to get the storage location of a_Position')return -1}// 将缓冲区分配给attribute变量gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0)// 开启attribute变量(连接)gl.enableVertexAttribArray(a_Position)return n
}

动画-RotatingTriangle.js

相关内容:通过JavaScript灵活设计WebGL系统,通过反复变换和重绘图形生成动画效果;setInterval()系列函数和requestAnimationgFrame()系列函数的异同。
相关函数:setInterval(), requestAnimationFrame(), cancelAnimationFrame()

机制一:在t0、t1、t2、t3等时刻反复调用同一个函数来绘制三角形。
机制二:每次绘制之前,清除上次绘制的内容,并使三角形旋转相应的角度。

基于此,该实例程序与前面的示例有以下三点区别:

  • 实现反复调用绘制函数的机制(机制一)
  • 定义绘制函数,在绘制函数中包括清空绘图区、向着色器传值、绘制三步
  • 由于程序需要反复绘制,所以在一开始就指定了背景色。
// RotatedTranslatedTriangle.js
// 顶点着色器
var VSHADER_SOURCE ='attribute vec4 a_Position;\n' +'uniform mat4 u_ModelMatrix;\n' +'void main(){\n' +'  gl_Position = u_ModelMatrix * a_Position;\n' +'}\n'
// 片元着色器
var FSHADER_SOURCE ='void main(){\n' + ' gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n' + '}\n'
// 旋转速度(度/秒)
var ANGLE_STEP = 45.0// 主函数
function main() {// 获取canvas元素let canvas = document.getElementById('webgl')// 获取WebGL上下文let gl = getWebGLContext(canvas)if (!gl) {console.log('Failed to get the rendering context for WebGL')return}// 初始化着色器if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {console.log('Failed to initialize shaders')return}// 设置顶点位置let n = initVertexBuffers(gl)if (n < 0) {console.log('Failed to set the positions of the vertices')return}// 设置背景色gl.clearColor(0.0, 0.0, 0.0, 1.0)// 获取u_ModelMatrix变量存储位置let u_ModelMatrix = gl.getUniformLocation(gl.program, 'u_ModelMatrix')if (!u_ModelMatrix) {console.log('Failed to get the storage location of u_ModelMatrix')}// 三角形当前旋转角度let currentAngle = 0.0// 模型矩阵,Matrix4对象let modelMatrix = new Matrix4()// 开始绘制三角形let tick = function () {currentAngle = animate(currentAngle) // 更新旋转角draw(gl, n, currentAngle, modelMatrix, u_ModelMatrix)requestAnimationFrame(tick) // 请求浏览器调用tick}tick()
}function initVertexBuffers(gl) {// 设置类型化数组和顶点数let vertices = new Float32Array([0.0, 0.3, -0.3, -0.3, 0.3, -0.3])let n = 3// 创建缓冲区对象let vertexBuffer = gl.createBuffer()if (!vertexBuffer) {console.log('Failed to create the buffer object')return -1}// 绑定缓冲区gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer)// 缓冲区写入数据gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STREAM_DRAW)let a_Position = gl.getAttribLocation(gl.program, 'a_Position')if (a_Position < 0) {console.log('Failed to get the storage location of a_Position')return -1}// 将缓冲区分配给attribute变量gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0)// 开启attribute变量(连接)gl.enableVertexAttribArray(a_Position)return n
}
function draw(gl, n, currentAngle, modelMatrix, u_ModelMatrix) {// 设置旋转矩阵modelMatrix.setRotate(currentAngle, 0, 0, 1)// 旋转前加个平移// modelMatrix.translate(0.5, 0, 0)// 将旋转矩阵传输给顶点着色器gl.uniformMatrix4fv(u_ModelMatrix, false, modelMatrix.elements)// 清空绘图区gl.clear(gl.COLOR_BUFFER_BIT)// 绘制三角形gl.drawArrays(gl.TRIANGLES, 0, n)
}// 记录上一次调用函数的时刻
var g_last = Date.now()
// 更新旋转角
function animate(angle) {// 计算距离上次调用经过多长时间let now = Date.now()let elapsed = now - g_last // 毫秒g_last = now// 根据上次调用的时间,更新当前旋转角度let newAngle = angle + (ANGLE_STEP * elapsed) / 1000.0return (newAngle %= 360)
}

重复调用函数的方法:

  // 开始绘制三角形let tick = function () {currentAngle = animate(currentAngle) // 更新旋转角draw(gl, n, currentAngle, modelMatrix, u_ModelMatrix) // 绘制三角形requestAnimationFrame(tick) // 请求浏览器调用tick}tick()

该方法是一个诞生较早的方法,其出现时浏览器还没有支持多标签页,所以在现代浏览器中,不论标签页是否被激活,该方法都会反复调用func,如果标签页较多,就会增加浏览器的负荷。

这一方法只有当标签页处于激活状态时才会生效,基于此也无法指定重复调用的时间间隔。

更新旋转角度:

...
// 旋转速度(度/秒)
var ANGLE_STEP = 45.0
...
// 记录上一次调用函数的时刻
var g_last = Date.now()
// 更新旋转角
function animate(angle) {// 计算距离上次调用经过多长时间let now = Date.now()let elapsed = now - g_last // 毫秒g_last = now// 根据上次调用的时间,更新当前旋转角度let newAngle = angle + (ANGLE_STEP * elapsed) / 1000.0return (newAngle %= 360)
}

animate()是更新旋转角的主要部分,该函数配合当前旋转角currentAngle变量、全局变量ANGLE_STEP变量(旋转速度)和g_last(上一次调用函数的时刻)使用,基本思路是:根据本次调用与上次调用之间的时间间隔来决定这一帧的旋转角度比上一帧大出多少

绘制函数的设计:

/*** 绘制三角形* @param {WebGLRenderingContext} gl 上下文对象* @param {number} n 顶点数量 int* @param {number} currentAngle 当前旋转角度 float* @param {Martix4} modelMatrix 根据当前的旋转角度计算出的旋转矩阵,存储在Martix4对象中* @param {number} u_ModelMatrix 顶点着色器中同名的uniform变量的存储位置 uint*/
function draw(gl, n, currentAngle, modelMatrix, u_ModelMatrix) {// 设置旋转矩阵modelMatrix.setRotate(currentAngle, 0, 0, 1)// 将旋转矩阵传输给顶点着色器gl.uniformMatrix4fv(u_ModelMatrix, false, modelMatrix.elements)// 清空绘图区gl.clear(gl.COLOR_BUFFER_BIT)// 绘制三角形gl.drawArrays(gl.TRIANGLES, 0, n)
}

 参考:【《WebGL编程指南》读书笔记-高级变换与动画基础】_webgl高级-CSDN博客

相关文章:

WebGL编程指南 - 高级变换与动画基础

学习使用一个矩阵变换库&#xff0c;该库封装了矩阵运算的数学细节。快速上手使用该矩阵库&#xff0c;对图形进行复合变换。在该矩阵库的帮助下&#xff0c;实现简单的动画效果。 矩阵变换库&#xff1a;cuon-matrix.js OpenGL中的函数&#xff1a; 书中 cuon-matrix.js 函数…...

银行客户贷款行为数据挖掘与分析

#1024程序员节 | 征文# 在新时代下&#xff0c;消费者的需求结构、内容与方式发生巨大改变&#xff0c;企业要想获取更多竞争优势&#xff0c;需要借助大数据技术持续创新。本文分析了传统商业银行面临的挑战&#xff0c;并基于knn、逻辑回归、人工神经网络三种算法&#xff0…...

制程质量管理方案设计

质量管理系统框架——QMS 涵盖产生产制造体系的全生命周期的质量管理过程 与SAP、WMS、MES、OA等业务系统进行集成&#xff0c;整合各业务系统中的质量信息 利用整合的全价值链质量信息&#xff0c;寻找质量改进点和质量创新点 系统功能模块管理 系统管理&#xff1a;用户管理…...

uniapp移动端优惠券! 附源码!!!!

本文为常见的移动端uniapp优惠券&#xff0c;共有6种优惠券样式&#xff08;参考了常见的优惠券&#xff09;&#xff0c;文本内容仅为示例&#xff0c;您可在此基础上调整为你想要的文本 预览效果 通过模拟数据&#xff0c;实现点击使用优惠券让其变为灰色的效果&#xff08;模…...

【分布式技术】中间件-zookeeper安装配置

文章目录 安装部署1. 安装ZooKeeper2. 配置ZooKeeper3. 启动ZooKeeper服务器4. 使用ZooKeeper命令行客户端5. 使用ZooKeeper的四个基本操作6. ZooKeeper集群模式7. 安全和权限8. 监控和日志 相关文献 安装部署 在Linux环境中操作ZooKeeper通常涉及以下几个方面&#xff1a; 1…...

高等数学 7.6高阶线性微分方程

文章目录 一、线性微分方程的解的结构*二、常数变易法 方程 d 2 y d x 2 P ( x ) d y d x Q ( x ) f ( x ) (1) \cfrac{\mathrm{d}^2 y}{\mathrm{d}x^2} P(x) \cfrac{\mathrm{d}y}{\mathrm{d}x} Q(x) f(x) \tag{1} dx2d2y​P(x)dxdy​Q(x)f(x)(1) 叫做二阶线性微分方程。…...

LSP的建立

MPLS需要为报文事先分配好标签&#xff0c;建立一条LSP&#xff0c;才能进行报文转发。LSP分为静态LSP和动态LSP两种。 静态LSP的建立 静态LSP是用户通过手工为各个转发等价类分配标签而建立的。由于静态LSP各节点上不能相互感知到整个LSP的情况&#xff0c;因此静态LSP是一个…...

huggingface的数据集下载(linux下clone)

1. 安装lfs sudo apt-get install git-lfs 或者 apt-get install git-lfs 2. git lfs install git lfs install 3. git clone dataset包 第2&#xff0c;3步骤的截图如下&#xff1a;...

Java使用dom4j生成kml(xml)文件遇到No such namespace prefix: xxx is in scope on:问题解决

介绍addAttribute和addNamepsace: addAttribute 方法 addAttribute 方法用于给XML元素添加属性。属性&#xff08;Attributes&#xff09;是元素的修饰符&#xff0c;提供了关于元素的额外信息&#xff0c;并且位于元素的开始标签中。属性通常用于指定元素的行为或样式&#…...

深入探讨Java中的LongAdder:使用技巧与避坑指南

文章目录 一、什么是LongAdder&#xff1f;二、LongAdder的简单使用示例代码&#xff1a; 三、LongAdder的工作原理四、LongAdder的常见使用场景五、使用LongAdder时的注意事项&#xff08;避坑指南&#xff09;1. 不要滥用LongAdder2. sum()方法与精度问题3. 避免过度使用rese…...

【本科毕业设计】基于单片机的智能家居防火防盗报警系统

基于单片机的智能家居防火防盗报警系统 相关资料链接下载摘要Abstract第1章 绪论1.1课题的背景1.2 研究的目的和意义 第2章 系统总体方案设计2.1 设计要求2.2 方案选择和论证2.2.1 单片机的选择2.2.2 显示方案的选择 第3章 系统硬件设计3.1 整体方案设计3.1.1 系统概述3.1.2 系…...

C语言 动态数据结构的C语言实现单向链表-2

建立一个单向链表 在单向链表中查找节点---查找尾节点 在单向链表中查找节点 --- 查找第 n 个节点 向单向链表中插入一个节点 向单向链表的尾部插入一个节点 向单向链表中某节点后插入一个节点 向单向链表中插入一个节点 删除单向链表中的某一节点 链表 vs 数组 动态数据结构...

Github 2024-10-23C开源项目日报 Top10

根据Github Trendings的统计,今日(2024-10-23统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量C项目10PLpgSQL项目1Redis - 内存数据库和数据结构服务器 创建周期:5411 天开发语言:C协议类型:BSD 3-Clause “New” or “Revised” Licen…...

ubuntu20.04 opencv4.0 /usr/local/lib/libgflags.a(gflags.cc.o): relocation报错解决

在一个只有ubuntu20.04的docker环境中配置opencv4.0.0, 什么库都没有&#xff0c;都要重新安装&#xff0c; 其他的问题在网上都找到了解决方案&#xff0c;唯独这个问题比较棘手&#xff1a; [ 86%] Linking CXX executable …/…/bin/opencv_annotation /usr/bin/ld: /usr/lo…...

android openGL ES详解——混合

一、混合概念 混合是一种常用的技巧&#xff0c;通常可以用来实现半透明。但其实它也是十分灵活的&#xff0c;你可以通过不同的设置得到不同的混合结果&#xff0c;产生一些有趣或者奇怪的图象。混合是什么呢&#xff1f;混合就是把两种颜色混在一起。具体一点&#xff0c;就…...

计网--物理层

目录 物理层的任务 1、常见概念 2、信道极限容量 3、传输介质 &#xff08;1&#xff09;导引型传输介质 &#xff08;2&#xff09;非导引型传输介质 4、信道复用技术 &#xff08;1&#xff09;频分 / 时分 复用 &#xff08;2&#xff09;波分复用WDM &#xff08;…...

算法的学习笔记—数组中的逆序对(牛客JZ51)

&#x1f600;前言 在算法和数据结构领域&#xff0c;"逆序对"是一个经典问题。它在数组中两个数字之间定义&#xff0c;若前面的数字大于后面的数字&#xff0c;则这两个数字组成一个逆序对。我们要做的就是&#xff0c;给定一个数组&#xff0c;找出数组中所有的逆…...

Golang | Leetcode Golang题解之第498题对角线遍历

题目&#xff1a; 题解&#xff1a; func findDiagonalOrder(mat [][]int) []int {m, n : len(mat), len(mat[0])ans : make([]int, 0, m*n)for i : 0; i < mn-1; i {if i%2 1 {x : max(i-n1, 0)y : min(i, n-1)for x < m && y > 0 {ans append(ans, mat[x…...

什么是全局污染?怎么避免全局污染?

全局污染&#xff08;Global Pollution&#xff09;是指在编程过程中&#xff0c;过度使用全局变量或对象导致命名冲突、代码可维护性下降及潜在错误增加的问题。在 JavaScript 等动态语言中&#xff0c;尤其需要关注全局污染的风险。 全局污染的影响 1. 命名冲突 3. 意外修改…...

C# 串口通信教程

串口通信&#xff08;Serial Communication&#xff09;是一种用于设备之间数据传输的常见方法&#xff0c;通常用于与外部硬件设备&#xff08;如传感器、机器人、微控制器&#xff09;进行通信。在 C# 中&#xff0c;System.IO.Ports 命名空间提供了与串口设备交互的功能&…...

树莓派超全系列教程文档--(61)树莓派摄像头高级使用方法

树莓派摄像头高级使用方法 配置通过调谐文件来调整相机行为 使用多个摄像头安装 libcam 和 rpicam-apps依赖关系开发包 文章来源&#xff1a; http://raspberry.dns8844.cn/documentation 原文网址 配置 大多数用例自动工作&#xff0c;无需更改相机配置。但是&#xff0c;一…...

(十)学生端搭建

本次旨在将之前的已完成的部分功能进行拼装到学生端&#xff0c;同时完善学生端的构建。本次工作主要包括&#xff1a; 1.学生端整体界面布局 2.模拟考场与部分个人画像流程的串联 3.整体学生端逻辑 一、学生端 在主界面可以选择自己的用户角色 选择学生则进入学生登录界面…...

可靠性+灵活性:电力载波技术在楼宇自控中的核心价值

可靠性灵活性&#xff1a;电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中&#xff0c;电力载波技术&#xff08;PLC&#xff09;凭借其独特的优势&#xff0c;正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据&#xff0c;无需额外布…...

【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)

服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...

Android Bitmap治理全解析:从加载优化到泄漏防控的全生命周期管理

引言 Bitmap&#xff08;位图&#xff09;是Android应用内存占用的“头号杀手”。一张1080P&#xff08;1920x1080&#xff09;的图片以ARGB_8888格式加载时&#xff0c;内存占用高达8MB&#xff08;192010804字节&#xff09;。据统计&#xff0c;超过60%的应用OOM崩溃与Bitm…...

Android 之 kotlin 语言学习笔记三(Kotlin-Java 互操作)

参考官方文档&#xff1a;https://developer.android.google.cn/kotlin/interop?hlzh-cn 一、Java&#xff08;供 Kotlin 使用&#xff09; 1、不得使用硬关键字 不要使用 Kotlin 的任何硬关键字作为方法的名称 或字段。允许使用 Kotlin 的软关键字、修饰符关键字和特殊标识…...

视觉slam十四讲实践部分记录——ch2、ch3

ch2 一、使用g++编译.cpp为可执行文件并运行(P30) g++ helloSLAM.cpp ./a.out运行 二、使用cmake编译 mkdir build cd build cmake .. makeCMakeCache.txt 文件仍然指向旧的目录。这表明在源代码目录中可能还存在旧的 CMakeCache.txt 文件,或者在构建过程中仍然引用了旧的路…...

【MATLAB代码】基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),附源代码|订阅专栏后可直接查看

文章所述的代码实现了基于最大相关熵准则(MCC)的三维鲁棒卡尔曼滤波算法(MCC-KF),针对传感器观测数据中存在的脉冲型异常噪声问题,通过非线性加权机制提升滤波器的抗干扰能力。代码通过对比传统KF与MCC-KF在含异常值场景下的表现,验证了后者在状态估计鲁棒性方面的显著优…...

MySQL 索引底层结构揭秘:B-Tree 与 B+Tree 的区别与应用

文章目录 一、背景知识&#xff1a;什么是 B-Tree 和 BTree&#xff1f; B-Tree&#xff08;平衡多路查找树&#xff09; BTree&#xff08;B-Tree 的变种&#xff09; 二、结构对比&#xff1a;一张图看懂 三、为什么 MySQL InnoDB 选择 BTree&#xff1f; 1. 范围查询更快 2…...

comfyui 工作流中 图生视频 如何增加视频的长度到5秒

comfyUI 工作流怎么可以生成更长的视频。除了硬件显存要求之外还有别的方法吗&#xff1f; 在ComfyUI中实现图生视频并延长到5秒&#xff0c;需要结合多个扩展和技巧。以下是完整解决方案&#xff1a; 核心工作流配置&#xff08;24fps下5秒120帧&#xff09; #mermaid-svg-yP…...