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

Unity局部和世界坐标系相互转换的实现原理

注:本篇是基于唐老师的学习视频做的一些理论实践,需要提前知道一些线性代数的基础知识,原视频链接:

8.数学基础知识学习说明_哔哩哔哩_bilibili

前期准备:

知识点①:

        Unity中需要遵守的设定:

                1、我们约定变换顺序为:缩放->旋转->平移。

                2、我们约定旋转的顺序为:Z->X->Y。

知识点②:

        1、基础变换矩阵的构成规则:

        2、平移矩阵的定义:

                A=\begin{bmatrix} 1 & 0& 0 & tx \\ 0& 1& 0& ty\\ 0& 0& 1& tz\\ 0& 0&0 & 1 \end{bmatrix}       逆矩阵     A^{-1}=\begin{bmatrix} 1 & 0 & 0 & -tx \\ 0& 1 & 0& -ty\\ 0& 0& 1 & -tz\\ 0& 0& 0& 1 \end{bmatrix}

        3、旋转矩阵的定义:    

                       绕X轴旋转\beta度:                        绕Y轴旋转\beta度:                       绕Z轴旋转\beta度:

               \begin{bmatrix} 1 & 0 & 0 & 0\\ 0& cos\beta & -sin\beta &0 \\ 0& sin\beta & cos\beta &0 \\ 0& 0 & 0 & 1 \end{bmatrix}          \begin{bmatrix} 1 & 0 & 0 & 0\\ 0& cos\beta & -sin\beta &0 \\ 0& sin\beta & cos\beta &0 \\ 0& 0 & 0 & 1 \end{bmatrix}          \begin{bmatrix} 1 & 0 & 0 & 0\\ 0& cos\beta & -sin\beta &0 \\ 0& sin\beta & cos\beta &0 \\ 0& 0 & 0 & 1 \end{bmatrix}

                因为旋转矩阵是正交矩阵,所以它的逆矩阵就是它的转置矩阵。

                即:假设有旋转矩阵A,那么 A^{-1}=A^{T}

        4、缩放矩阵的定义:

                A=\begin{bmatrix} kx & 0 & 0 & 0\\ 0 & ky & 0 & 0\\ 0 & 0 & kz & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix}    逆矩阵   A^{-1}=\begin{bmatrix} 1/kx & 0 & 0 & 0\\ 0 & 1/ky & 0 & 0\\ 0 & 0 & 1/kz & 0\\ 0 & 0 & 0 & 1 \end{bmatrix}

局部坐标转世界:

        我们需要明白一个概念,在3D空间中,假设有一个结点R存在一个子节点A,那么如果R就是坐标原点,A的局部坐标系就是世界坐标系。如果结点R存在旋转,平移等变换,那么A的局部坐标依旧不会变,R的变换会带动A的变换。那么最终的世界坐标满足关系式:

{A}'=M*A

M代表R的变换矩阵,A代表R在原点时的世界坐标(即局部坐标),A'代表最终的世界坐标。

再根据知识点1,得到矩阵M=平移矩阵A×旋转矩阵B×缩放矩阵C

便有如下代码:

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class Test : MonoBehaviour
{public Transform targetTrans;private void Start(){Vector4 startPos = new Vector4(targetTrans.localPosition.x, targetTrans.localPosition.y, targetTrans.localPosition.z, 1);Matrix4x4 scaleMatrix = ScaleMatrix(transform.localScale.x, transform.localScale.y, transform.localScale.z);Matrix4x4 rotateMatrix = RotateYMatrix(transform.eulerAngles.y)*RotateXMatrix(transform.eulerAngles.x)*RotateZMatrix(transform.eulerAngles.z);Matrix4x4 translateMatrix = TranslateMatrix(transform.position.x, transform.position.y, transform.position.z);//按照缩放->旋转(按照Z->X->Y顺序旋转)->平移的变换顺序Vector4 resPos = translateMatrix * rotateMatrix * scaleMatrix * startPos;Debug.Log(string.Format("局部坐标转世界坐标={0}",resPos));Debug.Log(string.Format("调用UnityAPI的结果={0}",transform.TransformPoint(startPos)));}//缩放矩阵private Matrix4x4 ScaleMatrix(float x,float y,float z){Matrix4x4 targetMatrix = new Matrix4x4();targetMatrix.m00 = x;targetMatrix.m11 = y;targetMatrix.m22 = z;targetMatrix.m33 = 1;return targetMatrix;}//旋转矩阵(X轴)private Matrix4x4 RotateXMatrix(float angle){Matrix4x4 targetMatrix = new Matrix4x4();targetMatrix.m00 = 1;targetMatrix.m11 = Mathf.Cos(angle * Mathf.Deg2Rad);targetMatrix.m12 = -Mathf.Sin(angle * Mathf.Deg2Rad);targetMatrix.m21 = Mathf.Sin(angle * Mathf.Deg2Rad);targetMatrix.m22 = Mathf.Cos(angle * Mathf.Deg2Rad);targetMatrix.m33 = 1;return targetMatrix;}//旋转矩阵(Y轴)private Matrix4x4 RotateYMatrix(float angle){Matrix4x4 targetMatrix = new Matrix4x4();targetMatrix.m00 = Mathf.Cos(angle * Mathf.Deg2Rad);targetMatrix.m02 = Mathf.Sin(angle * Mathf.Deg2Rad);targetMatrix.m11 = 1;targetMatrix.m20 = -Mathf.Sin(angle * Mathf.Deg2Rad);targetMatrix.m22 = Mathf.Cos(angle * Mathf.Deg2Rad);targetMatrix.m33 = 1;return targetMatrix;}//旋转矩阵(Z轴)private Matrix4x4 RotateZMatrix(float angle){Matrix4x4 targetMatrix = new Matrix4x4();targetMatrix.m00 = Mathf.Cos(angle * Mathf.Deg2Rad);targetMatrix.m01 = -Mathf.Sin(angle * Mathf.Deg2Rad);targetMatrix.m10 = Mathf.Sin(angle * Mathf.Deg2Rad);targetMatrix.m11 = Mathf.Cos(angle * Mathf.Deg2Rad);targetMatrix.m22 = 1;targetMatrix.m33 = 1;return targetMatrix;}//平移矩阵private Matrix4x4 TranslateMatrix(float x,float y,float z){Matrix4x4 targetMatrix = new Matrix4x4();targetMatrix.m03 = x;targetMatrix.m13 = y;targetMatrix.m23 = z;targetMatrix.m00 = 1;targetMatrix.m11 = 1;targetMatrix.m22 = 1;targetMatrix.m33 = 1;return targetMatrix;}
}

挂载脚本:

我们用了Unity自带的局部转世界的APITransform.TransformPoint进行结果对比,发现最终的计算结果是一样的(忽略第四个参数1.0,代表的含义是点)。

世界坐标转局部:

        由刚刚的{A}'=M*A公式推导,其实可以得到:

                                        ​​​​​​​                M^{-1}*{A}'=A

        即局部坐标=逆变换*世界坐标

由上面的性质得到已知  矩阵M=平移矩阵A×旋转矩阵B×缩放矩阵C,那么矩阵M的逆矩阵

                                                         M^{-1}=C^{-1}*B^{-1}*A^{-1}

矩阵A,B,C的逆矩阵都可以根据知识点2得到结果,最终就可以根据世界坐标和逆变换反推导局部坐标。

相关文章:

Unity局部和世界坐标系相互转换的实现原理

注:本篇是基于唐老师的学习视频做的一些理论实践,需要提前知道一些线性代数的基础知识,原视频链接: 8.数学基础知识学习说明_哔哩哔哩_bilibili 前期准备: 知识点①: Unity中需要遵守的设定:…...

MySQL通用语法 -DDL、DML、DQL、DCL

SQL 全称 Structured Query Language,结构化查询语言。操作关系型数据库的编程语言,定义了 一套操作关系型数据库统一标准 。 SQL通用语法 MySQL语言的通用语法。 SQL语句可以单行或多行书写,以分号结尾。SQL语句可以使用空格/缩进来增强…...

C# 6.0 连接elasticsearch数据库

在 C# 6.0 中连接 Elasticsearch 数据库,您可以使用官方的 Elasticsearch 客户端库 NEST。NEST 是一个高性能的 .NET 客户端,用于与 Elasticsearch 进行交互。以下是一个详细的步骤指南,帮助您在 C# 6.0 项目中连接和操作 Elasticsearch。 1. 安装 NEST 包 首先,您需要在您…...

占个坑:利用工作以外的时间,用numpy实现MLP-手写识别

背景 随着近半年的正式工作,一直在做的都是模型后处理相关的,逐渐意识到技术的自我迭代陷入了瓶颈。组里都是搞模型的,对于缺少模型背景的我,很难深刻理解同事将模型和业务结合时好的idear,这使得我难以掌握组里最核心…...

抽象之诗:C++模板的灵魂与边界

引言 在计算机科学的浩瀚长河中,C模板如同一颗璀璨的星辰,以其独特的泛型编程方式为程序设计注入了灵魂。它是抽象的艺术,是类型的舞蹈,是效率与灵活性的交响乐。模板不仅是一种技术工具,更是一种哲学思考&#xff0c…...

后端统一接口返回状态【初步模板】

后端统一接口返回状态【模板】 文章目录 后端统一接口返回状态【模板】1 .Result类编写2 .Constants类编写3 .更改Controller层下的类return格式 开发过程中,每个接口的返回格式设计都是一样的,这样可以大大提高开发效率。 项目结构如下图:分…...

呼入机器人:24小时客户服务的未来趋势

呼入机器人:24小时客户服务的未来趋势 作者:开源大模型智能呼叫中心系统FreeAICC,Github:https://github.com/FreeIPCC/FreeAICC 在当今快节奏的商业环境中,客户服务已成为企业竞争的核心要素之一。随着人工智能技术…...

whisper.cpp: PC端测试 -- 电脑端部署音频大模型

whisper.cpp: PC端测试 1.环境需要2.构建项目3.PC测试 1.环境需要 以下是经实验验证可行的环境参考,也可尝试其他版本。 (1)PC:Ubuntu 22.04.4 (2)软件环境:如下表所示 工具版本安装Anacond…...

WPF ControlTemplate 控件模板

区别于 DataTemplate 数据模板,ControlTemplate 是控件模板,是为自定义控件的 Template 属性服务的,Template 属性类型就是 ControlTemplate。 演示, 自定义一个控件 MyControl,包含一个字符串类型的依赖属性。 pub…...

序列化和反序列化(一)

因为通过这段时间的学习,发现,序列化和反序列化的考点和漏洞在平时遇到的还是比较多的,而且自己也没有特别去学习过这个知识点,所以在这里写一篇关于这里序列化和反序列话的博客,废话就停止在这里了。 在介绍具体的序列…...

Kubeadm+Containerd部署k8s(v1.28.2)集群(非高可用版)

Kubeadm+Containerd部署k8s(v1.28.2)集群(非高可用版) 文章目录 Kubeadm+Containerd部署k8s(v1.28.2)集群(非高可用版)一.环境准备1.服务器准备2.环境配置3.设置主机名4.修改国内镜像源地址5.配置时间同步6.配置内核转发及网桥过滤二.容器运行时Containerd安装(所有节点)…...

取子串(指针)

#include <stdio.h> #include <string.h>char* substr(char *s, int startloc, int len) {static char result[51]; // 定义一个足够大的静态数组来存储结果static char result1[] {N,U,L,L,\0};int i, j;// 检查startloc是否在字符串的范围内if (startloc < 1…...

Linux系列之如何更换Centos yum源?

系列博客专栏&#xff1a; JVM系列博客专栏SpringBoot系列博客 环境 Centos7Xshell7 问题描述 最近安装了一个虚拟机&#xff0c;准备用来学习&#xff0c;不过使用yum命令安装一些软件&#xff0c;不过使用这个命令时候&#xff0c;提示 Cannot find a valid baseurl fo…...

过滤器和拦截器的区别详解

文章目录 过滤器和拦截器的区别详解1. 来源不同2. 触发时机不同3. 实现原理不同4. 支持的项目类型不同5. 使用场景不同6. 核心区别总结**总结** 过滤器和拦截器的区别详解 在 Web 开发中&#xff0c;过滤器&#xff08;Filter&#xff09; 和 拦截器&#xff08;Interceptor&a…...

centos使用mkisofs构建无人值守镜像(附官方学习文档)

安装mkisofs yum install -y mkisofs 挂载镜像并确认 并拷贝文件(/mnt 为我们的工作目录) 1.3 准备自动应答文件(保存为 ins.ks) 修改系统引导 实际上就是添加inst.ks 这个引导参数 传递应答文件 传统模式引导 UEFI模式引导 打包镜像 通用选项 -v&#xff1a;启用详细模式&a…...

Pyside6+qml+Qtcreator项目实战

Pyside6+qml+Qtcreator项目实战 B站视频教程,进去后记得点赞。最终运行效果: PYTHON and QT QUICK - Custom Buttons With QML And JavaScript - [MODERN GUI]-#012 开发环境: 1、Qt 6.7.2 2、Pyside6 3、Python 3.11.4 4、Windows 10 原视频是用的Qt5,我这里采用Qt6重新…...

秒鲨后端之MyBatis【1】环境的搭建和核心配置文件详解

​ 别忘了请点个赞收藏关注支持一下博主喵&#xff01;&#xff01;&#xff01;! ! ! Mybatis简介 MyBatis历史 MyBatis最初是Apache的一个开源项目iBatis, 2010年6月这个项目由Apache Software Foundation迁移到了Google Code。随着开发团队转投Google Code旗下&#xff…...

编译原理复习---目标代码生成

适用于电子科技大学编译原理期末考试复习。 1. 目标代码 是目标机器的汇编代码或机器码&#xff0c;在本课程中指的是类似于汇编代码的一种形式&#xff0c;由一条条的指令构成目标代码。 抽象机指令格式&#xff1a;OP 目的操作数&#xff0c;源操作数。 我们要做的&…...

Winnows基础(2)

Target 了解常见端口及服务&#xff0c;熟练cmd命令&#xff0c;编写简单的 .bat 病毒程序。 Trail 常见服务及端口 80 web 80-89 可能是web 443 ssl心脏滴血漏洞以及一些web漏洞测试 445 smb 1433 mssql 1521 oracle 2082/2083 cpanel主机管理系统登陆&#xff08;国外用的…...

酒蒙子骰子小程序系统

酒蒙子流量变现小程序小游戏 后端tp8 前端uniapp 会员变现 分销推广 流量主 …...

Cursor实现用excel数据填充word模版的方法

cursor主页&#xff1a;https://www.cursor.com/ 任务目标&#xff1a;把excel格式的数据里的单元格&#xff0c;按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例&#xff0c;…...

Leetcode 3576. Transform Array to All Equal Elements

Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接&#xff1a;3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到&#xf…...

【解密LSTM、GRU如何解决传统RNN梯度消失问题】

解密LSTM与GRU&#xff1a;如何让RNN变得更聪明&#xff1f; 在深度学习的世界里&#xff0c;循环神经网络&#xff08;RNN&#xff09;以其卓越的序列数据处理能力广泛应用于自然语言处理、时间序列预测等领域。然而&#xff0c;传统RNN存在的一个严重问题——梯度消失&#…...

从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)

设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile&#xff0c;新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...

linux 下常用变更-8

1、删除普通用户 查询用户初始UID和GIDls -l /home/ ###家目录中查看UID cat /etc/group ###此文件查看GID删除用户1.编辑文件 /etc/passwd 找到对应的行&#xff0c;YW343:x:0:0::/home/YW343:/bin/bash 2.将标红的位置修改为用户对应初始UID和GID&#xff1a; YW3…...

【HTML-16】深入理解HTML中的块元素与行内元素

HTML元素根据其显示特性可以分为两大类&#xff1a;块元素(Block-level Elements)和行内元素(Inline Elements)。理解这两者的区别对于构建良好的网页布局至关重要。本文将全面解析这两种元素的特性、区别以及实际应用场景。 1. 块元素(Block-level Elements) 1.1 基本特性 …...

Unity | AmplifyShaderEditor插件基础(第七集:平面波动shader)

目录 一、&#x1f44b;&#x1f3fb;前言 二、&#x1f608;sinx波动的基本原理 三、&#x1f608;波动起来 1.sinx节点介绍 2.vertexPosition 3.集成Vector3 a.节点Append b.连起来 4.波动起来 a.波动的原理 b.时间节点 c.sinx的处理 四、&#x1f30a;波动优化…...

鸿蒙DevEco Studio HarmonyOS 5跑酷小游戏实现指南

1. 项目概述 本跑酷小游戏基于鸿蒙HarmonyOS 5开发&#xff0c;使用DevEco Studio作为开发工具&#xff0c;采用Java语言实现&#xff0c;包含角色控制、障碍物生成和分数计算系统。 2. 项目结构 /src/main/java/com/example/runner/├── MainAbilitySlice.java // 主界…...

AGain DB和倍数增益的关系

我在设置一款索尼CMOS芯片时&#xff0c;Again增益0db变化为6DB&#xff0c;画面的变化只有2倍DN的增益&#xff0c;比如10变为20。 这与dB和线性增益的关系以及传感器处理流程有关。以下是具体原因分析&#xff1a; 1. dB与线性增益的换算关系 6dB对应的理论线性增益应为&…...

并发编程 - go版

1.并发编程基础概念 进程和线程 A. 进程是程序在操作系统中的一次执行过程&#xff0c;系统进行资源分配和调度的一个独立单位。B. 线程是进程的一个执行实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。C.一个进程可以创建和撤销多个线程;同一个进程中…...