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

three.js+WebGL踩坑经验合集(6.1):负缩放,负定矩阵和行列式的关系(2D版本)

春节忙完一轮,总算可以继续来写博客了。希望在春节假期结束之前能多更新几篇。

这一篇会偏理论多一点。笔者本没打算在这一系列里面重点讲理论,所以像相机矩阵推导这种网上已经很多优质文章的内容,笔者就一笔带过。

然而关于负缩放,笔者未能找到从正负缩放到行列式正负的完整推导过程(可能是笔者没用对关键词吧,GPT也还没去用),中途也就找到了一个正/负定矩阵的概念。该说法已经有点正负缩放的意思了,所以本篇虽然侧重理论,但也会结合第5篇的坑进行阐述。

回顾第5篇

(5.2):THREE.Mesh和THREE.Line2在镜像处理上的区别

笔者在排查Line2镜像丢失的bug时,发现了three.js处理正反面的逻辑,它对接原生WebGL的正反面定义——三角面3个点的绕序(顺逆时针)。

three.js的实现机制是,如果物体的变换矩阵的秩(行列式)为负数,则指示物体做了带有负缩放矩阵的变换,就把逆时针旋转的三角面从背面改为正面。

从这一过程可以发现,对一个三角面应用负缩放时,其三个点的绕序会发生变化,而正缩放则不会。而一个缩放的正负,three.js是通过矩阵的秩进行判断的。

这里笔者再多嘴一下,如果矩阵的秩等于0,那么它就会把三角面的三个点变换到在同一直线上,或者会让两个或者3个点完全重合。笔者姑且称之为零定矩阵。与此同时,它也是个不可逆的矩阵。

本篇我们先拿2D的3*3矩阵来探讨行列式的正负对三点绕序的影响。3D的情况比较复杂,因为它涉及到不同轴的情况,笔者有很长一段时间以为3D无法定义负矩阵,直到研读了three.js的代码才恍然大悟。

推导过程有点繁琐,此处先给结论:矩阵缩放的正负,正负定矩阵,行列式的正负性这3者完全等价,正定矩阵不改变绕序,负定矩阵改变,零定矩阵是不可逆矩阵,它会让不共线的点变成共线甚至重合。

好,下面进入正题。

给定2D上的3个不共线的点O(x0, y0),A(x1,y1),B(x2,y2),要判断这3个点的绕序,可以作向量OA,OB,然后通过计算这两个2D向量的叉乘值得出。如下图所示,OA旋转到OB是顺时针。

对这3个点应用正定矩阵,对应两向量的叉乘结果不变,而应用负定矩阵,则叉乘结果改变,如下图所示。

然后我们给定一个3*3的2D变换矩阵(不管是2D点还是3D点,矩阵的阶数都比点的维数多1,目的是加法和乘法合并,前面讲过比较多次了,此处不再重复,实在不懂可以问我)。

对一个2D点应用矩阵,运算过程如下:

可见通过给点的最后一行补1,最后一列就实现了加法。

由于此处只研究2D点的绕序问题,因此最后一行的结果我们无需关注,在此场景它只为了让矩阵乘法计算可以正常进行。

下面我们的推导过程将分以下几步:

1 计算OA,OB向量及它们的叉乘值c

2 计算点O,A,B应用矩阵后的结果O',A',B'

3 计算向量O'A',O'B'以及它们的叉乘值c'

4 考察c和c'符号的一致性,并给出一致性跟矩阵元素的关系

5 上述关系对应到行列式上验证上面给出的结论

OA和OB是(x1-x0,y1-y0),以及(x2-x0, y2-y0),为了书写简便,后面会把x1-x0记为Δx1,y1-y0记为Δy1,其它类似。

两向量(x1,y1),(x2,y2)的2D叉乘公式为x1*y2-x2*y1,所以OA和OB的叉乘结果为

至此,第一步计算完成。

第二步,计算矩阵变换后的O,A,B,如上所述,其结果为

第三步,计算O'A',O'B'和他们俩的叉乘值

类似地有

然后叉乘值为

这个推导过程可能会让对数学不敏感的小伙伴们感到蛋疼,所以笔者曾经考虑过要不要牺牲一定的严谨性,拿个特殊点,简单点的变量来做演示。如果实在看不下去,小伙伴们可以让O=(0,0),A=(1,0),B=(0,1)来演算一遍,找下感觉。对于2D来说,拿特殊点是没有任何毛病的,除非你拿了重合的点或者共线的3点。

我们对照下OA和OB的叉乘,以及O'A'和O'B的叉乘,后者等于前者乘以(m11m22-m22*m11), 因此判断向量变换前叉积符号的一致性,只需要判断m11m22-m22*m11的符号即可。可见,矩阵对不共线3点绕序的影响仅跟矩阵的4个元素有关,而跟你的取点无关。

现在我们把刚才说到的矩阵搬过来,看看它跟行列式的关系。

发现计算结果只取了3*3矩阵中的前面两阶的元素做了一个行列式的计算。而第三列中的元素,因为它只管平移,并且跟点坐标无关,所以它在计算向量的时候就已经被消去了。至于第三行,因为它是为了将加法和乘法合并,不是本文的关注点,所以全程我们都没有让它参与到计算当中。

然而three.js自带的Matrix3类,它的行列式值则是严格按照数学的定义,按3阶行列式来书写:

那为什么我们在使用的过程中没有出现任何问题呢?我们把刚才3*3矩阵乘以点的计算公式拿过来。

为了让点变换的过程中,为合并而补充的那个1保持不变,我们应该让第三行的计算结果

m31*x+m32*y+m33恒等于1,因此结果不能受x和y影响,所以m31和m32要等于0,而剩下的m33,自然就等于1了。也就是说,这一行填充的是单位矩阵的数值。

熟悉行列式运算法则的小伙伴应该一眼就看得出来,用到第三列元素的项都要跟0相乘,否则就是跟1相乘。但为了照顾更多的小伙伴,笔者也按3阶行列式的定义演算一遍。

可见,用单位矩阵填充第3行以后,其行列式的值跟2阶行列式出来的结果完全一致,证毕。

这里需要注意的一点是,three.js的Matrix3允许第三行不使用单位矩阵的数值。这时候,它的行列式符号不能在2D变换的场景下判断矩阵的正负性。

推导完成了,来小结一下(注意以下结论均建立在Matrix3做2D变换的场景):

1 正负缩放矩阵,正负定矩阵,行列式正负完全等价(此外还有零的情况)

2 正负矩阵的性质:不共线的3个2D点,正矩阵不会修改它们的绕序,负矩阵会

3 three.js利用这一性质,根据WebGL正反面的规则修复单面材质镜像后不能正确显示的问题

4 零矩阵会使它们共线或者共点,且不可逆

5 判断一个矩阵的正负,用的是3*3矩阵前两行两列所构成的行列式的符号。若想对齐到3阶矩阵,则第三行必须按照单位矩阵进行填充,否则会出现错误的结果

现在我们来简单聊聊3D,为什么前面说3D比2D复杂。

大家脑补一下,我们给2D点直接加上z坐标,全部设置为0。如果我们应用x方向负缩放或者y方向负缩放的话,那么应用前面的结论一点毛病都没有,但若应用z负缩放,则所有的点都不会有任何变化,哪怕你不设置为0,只要z值完全一样,那翻转后,也就是z值统一改成一样的数字,但这时候,其实正反面已经颠倒了。

就这么一个简单的情况,本文的结论就已经无法应用到3D上了,所以今天我们就先到这里,后面我会跟大家继续探讨3D矩阵的正负缩放问题,敬请期待!

相关文章:

three.js+WebGL踩坑经验合集(6.1):负缩放,负定矩阵和行列式的关系(2D版本)

春节忙完一轮,总算可以继续来写博客了。希望在春节假期结束之前能多更新几篇。 这一篇会偏理论多一点。笔者本没打算在这一系列里面重点讲理论,所以像相机矩阵推导这种网上已经很多优质文章的内容,笔者就一笔带过。 然而关于负缩放&#xf…...

【开源免费】基于SpringBoot+Vue.JS体育馆管理系统(JAVA毕业设计)

本文项目编号 T 165 ,文末自助获取源码 \color{red}{T165,文末自助获取源码} T165,文末自助获取源码 目录 一、系统介绍二、数据库设计三、配套教程3.1 启动教程3.2 讲解视频3.3 二次开发教程 四、功能截图五、文案资料5.1 选题背景5.2 国内…...

《大数据时代“快刀”:Flink实时数据处理框架优势全解析》

在数字化浪潮中,数据呈爆发式增长,实时数据处理的重要性愈发凸显。从金融交易的实时风险监控,到电商平台的用户行为分析,各行业都急需能快速处理海量数据的工具。Flink作为一款开源的分布式流处理框架,在这一领域崭露头…...

antdesignvue统计数据源条数、计算某列合计值、小数计算不精确多了很多小数位

1.在</a-table>下方加如下代码 <div>数据总条数&#xff1a;{ {tableData.length}}&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp <template>A列合计&#xff1a;{ {sum}}</template> </div> 注&#xff1a;tableData为<a-tabl…...

02.05、链表求和

02.05、[中等] 链表求和 1、题目描述 给定两个用链表表示的整数&#xff0c;每个节点包含一个数位。 这些数位是反向存放的&#xff0c;也就是个位排在链表首部。 编写函数对这两个整数求和&#xff0c;并用链表形式返回结果。 2、解题思路 本题要求对两个链表表示的整数…...

dmfldr实战

dmfldr实战 本文使用达梦的快速装载工具&#xff0c;对测试表进行数据导入导出。 新建测试表 create table “BENCHMARK”.“TEST_FLDR” ( “uid” INTEGER identity(1, 1) not null , “name” VARCHAR(24), “begin_date” TIMESTAMP(0), “amount” DECIMAL(6, 2), prim…...

Kafka 副本机制(包含AR、ISR、OSR、HW 和 LEO 介绍)

文章目录 Kafka 副本机制&#xff08;包含AR、ISR、OSR、HW 和 LEO 介绍&#xff09;1. 副本的基本概念2. 副本同步和一致性2.1 AR&#xff08;Assigned Replicas&#xff09;2.2 ISR&#xff08;In-Sync Replicas&#xff09;2.3 OSR&#xff08;Out-of-Sync Replicas&#xf…...

爬虫基础(二)Web网页的基本原理

一、网页的组成 网页由三部分构成&#xff1a;HTML、JavaScript、CSS。 &#xff08;1&#xff09;HTML HTML 相当于网页的骨架&#xff0c;它通过使用标签来定义网页内容的结构。 举个例子&#xff1a; 它把图片标签为img、把视频标签为video&#xff0c;然后组合到一个界面…...

外网访问禅道软件项目管理系统

禅道项目管理软件是一款国产的开源免费项目管理软件&#xff0c;专注于研发项目管理&#xff0c;旨在帮助企业或团队提高项目管理的效率和质量。 本文将详细的介绍如何在 Windows 系统电脑端下载运行禅道软件项目管理系统&#xff0c;并且结合路由侠内网穿透实现外网访问本地的…...

Python 梯度下降法(五):Adam Optimize

文章目录 Python 梯度下降法&#xff08;五&#xff09;&#xff1a;Adam Optimize一、数学原理1.1 介绍1.2 符号说明1.3 实现流程 二、代码实现2.1 函数代码2.2 总代码2.3 遇到的问题2.4 算法优化 三、优缺点3.1 优点3.2 缺点 四、相关链接 Python 梯度下降法&#xff08;五&a…...

笔试-二进制

应用题 将符合区间[l,r]内的十进制整数转换为二进制表示&#xff0c;请问不包含“101”的整数个数是多少&#xff1f; 实现 l int(input("请输入下限l&#xff0c;其值大于等于1&#xff1a;")) r int(input("请输入上限r&#xff0c;其值大于等于l&#x…...

springboot 2.7.6 security mysql redis jwt配置例子

数据库结构用的是若依的数据库基本结构,ruoyi.vip。 总体参考了文章&#xff1a;https://blog.csdn.net/qq_45847507/article/details/126681110 本文章只包含不同的地方&#xff0c;相同的不再赘述。 1、创建spring工程&#xff0c;jdk1.8&#xff0c;maven。 pom.xml中依赖部…...

FreeRTOS从入门到精通 第十六章(任务通知)

参考教程&#xff1a;【正点原子】手把手教你学FreeRTOS实时系统_哔哩哔哩_bilibili 一、任务通知简介 1、概述 &#xff08;1&#xff09;任务通知顾名思义是用来通知任务的&#xff0c;任务控制块中的结构体成员变量ulNotifiedValue就是这个通知值。 &#xff08;2&#…...

TensorFlow 简单的二分类神经网络的训练和应用流程

展示了一个简单的二分类神经网络的训练和应用流程。主要步骤包括&#xff1a; 1. 数据准备与预处理 2. 构建模型 3. 编译模型 4. 训练模型 5. 评估模型 6. 模型应用与部署 加载和应用已训练的模型 1. 数据准备与预处理 在本例中&#xff0c;数据准备是通过两个 Numpy 数…...

无人机图传模块 wfb-ng openipc-fpv,4G

openipc 的定位是为各种模块提供底层的驱动和linux最小系统&#xff0c;openipc 是采用buildroot系统编译而成&#xff0c;因此二次开发能力有点麻烦。为啥openipc 会用于无人机图传呢&#xff1f;因为openipc可以将现有的网络摄像头ip-camera模块直接利用起来&#xff0c;从而…...

.cc扩展名是什么语言?C语言必须用.c为扩展名吗?主流编程语言扩展名?Java为什么不能用全数字的文件名?

.cc扩展名是什么语言? .cc是C语言使用的扩展名&#xff0c;一种说法是它是c with class的简写&#xff0c;当然C语言使用的扩展名不止.cc和.cpp, 还包含.cxx, .c, .C等&#xff0c;这些在不同编译器系统采用的默认设定不同&#xff0c;需要区分使用。当然&#xff0c;编译器提…...

【MyDB】4-VersionManager 之 3-死锁及超时检测

【MyDB】4-VersionManager 之 3-死锁及超时检测 死锁及超时检测案例背景LockTable锁请求与等待管理 addvm调用addputIntoList&#xff0c;isInList&#xff0c;removeFromList 死锁检测 hasDeadLock方法资源释放与重分配 参考资料 死锁及超时检测 本章涉及代码&#xff1a;top/…...

【Linux】使用管道实现一个简易版本的进程池

文章目录 使用管道实现一个简易版本的进程池流程图代码makefileTask.hppProcessPool.cc 程序流程&#xff1a; 使用管道实现一个简易版本的进程池 流程图 代码 makefile ProcessPool:ProcessPool.ccg -o $ $^ -g -stdc11 .PHONY:clean clean:rm -f ProcessPoolTask.hpp #pr…...

【OpenGL】OpenGL游戏案例(二)

文章目录 特殊效果数据结构生成逻辑更新逻辑 文本渲染类结构构造函数加载函数渲染函数 特殊效果 为提高游戏的趣味性&#xff0c;在游戏中提供了六种特殊效果。 数据结构 PowerUp 类只存储存活数据&#xff0c;实际逻辑在游戏代码中通过Type字段来区分执行 class PowerUp …...

28. 【.NET 8 实战--孢子记账--从单体到微服务】--简易报表--报表定时器与报表数据修正

这篇文章是《.NET 8 实战–孢子记账–从单体到微服务》系列专栏的《单体应用》专栏的最后一片和开发有关的文章。在这片文章中我们一起来实现一个数据统计的功能&#xff1a;报表数据汇总。这个功能为用户查看月度、年度、季度报表提供数据支持。 一、需求 数据统计方面&…...

Java 泛型<? extends Object>

在 Java 泛型中&#xff0c;<? extends Object> 和 <?> 都表示未知类型&#xff0c;但它们在某些情况下有细微的差异。泛型的引入是为了消除运行时错误并增强类型安全性&#xff0c;使代码更具可读性和可维护性。 在 JDK 5 中引入了泛型&#xff0c;以消除编译时…...

FPGA|使用quartus II通过AS下载POF固件

1、将开发板设置到AS下载挡位&#xff0c;或者把下载线插入到AS端口 2、打开quartus II&#xff0c;选择Tools→Programmer→ Mode选择Active Serial Programming 3、点击左侧Add file…&#xff0c;选择 .pof 文件 →start 4、勾选program和verify&#xff08;可选&#xff0…...

“新月之智”智能战术头盔系统(CITHS)

新月人物传记&#xff1a;人物传记之新月篇-CSDN博客 相关文章链接&#xff08;更新&#xff09;&#xff1a; 星际战争模拟系统&#xff1a;新月的编程之道-CSDN博客 新月智能护甲系统CMIA--未来战场的守护者-CSDN博客 目录 一、引言 二、智能头盔控制系统概述 三、系统架…...

php:代码中怎么搭建一个类似linux系统的crontab服务

一、前言 最近使用自己搭建的php框架写一些东西&#xff0c;需要用到异步脚本任务的执行&#xff0c;但是是因为自己搭建的框架没有现成的机制&#xff0c;所以想自己搭建一个类似linux系统的crontab服务的功能。 因为如果直接使用linux crontab的服务配置起来很麻烦&#xff0…...

【LeetCode: 958. 二叉树的完全性检验 + bfs + 二叉树】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…...

MinDoc 安装与部署

下载可执行文件 mindoc mindoc_linux_amd64.zip 上传并解压压缩包 cd /opt mkdir mindoc cd mindocunzip mindoc_linux_amd64.zip 创建数据库 CREATE DATABASE mindoc_db DEFAULT CHARSET utf8mb4 COLLATE utf8mb4_general_ci; 配置数据库 将解压目录下 conf/app.conf.exam…...

从0开始使用面对对象C语言搭建一个基于OLED的图形显示框架(基础组件实现)

目录 基础组件实现 如何将图像和文字显示到OLED上 如何绘制图像 如何绘制文字 如何获取字体&#xff1f; 如何正确的访问字体 如何抽象字体 如何绘制字符串 绘制方案 文本绘制 更加方便的绘制 字体附录 ascii 6x8字体 ascii 8 x 16字体 基础组件实现 我们现在离手…...

windows系统如何检查是否开启了mongodb服务

windows系统如何检查是否开启了mongodb服务&#xff01;我们有很多软件开发&#xff0c;网站开发时候需要使用到这个mongodb数据库&#xff0c;下面我们看看&#xff0c;如何在windows系统内排查&#xff0c;是否已经启动了本地服务。 在 Windows 系统上&#xff0c;您可以通过…...

VS安卓仿真器下载失败怎么办?

如果网络不稳定&#xff0c;则VS的安卓仿真器很容易下载失败&#xff0c;如下 Downloaded file <USER_HOME>\AppData\Local\Temp\xamarin-android-sdk\x86_64-35_r08.zip not found for Android SDK archive https://dl.google.com/android/repository/sys-img/google_a…...

计算机网络一点事(24)

TCP可靠传输&#xff0c;流量控制 可靠传输&#xff1a;每字节对应一个序号 累计确认&#xff1a;收到ack则正确接收 返回ack推迟确认&#xff08;不超过0.5s&#xff09; 两种ack&#xff1a;专门确认&#xff08;只有首部无数据&#xff09; 捎带确认&#xff08;带数据…...