技术标签: slam
Vector3.Slerp 球形插值详解
首先上官方的文档信息,方面还没有看过的同学学习。
static function Vector3 Slerp (Vector3 from, Vector3to, float t)
Spherically interpolates between two vectors.
球形插值在两个向量之间。
我感觉叫“弧线插值”更直观一些。
Interpolates from towards to by amount t. The returned vector's magnitude will be interpolated between magnitudesof from and to.
通过t数值在from和to之间插值。返回的向量的长度将被插值到from到to的长度之间。
另外官方API上面还给了一个例子如下
//在日出和日落之间动画弧线
usingUnityEngine;
usingSystem.Collections;
publicclass example : MonoBehaviour
{
publicTransform sunrise;
publicTransform sunset;
voidUpdate()
{
//弧线的中心
Vector3 center = sunrise.position + sunset.position * 0.5f;
//向下移动中心,垂直于弧线
center -= newVector3(0, 1, 0);
//相对于中心在弧线上插值
Vector3 riseRelCenter = sunrise.position - center;
Vector3 setRelCenter = sunset.position - center;
transform.position = Vector3.Slerp(riseRelCenter,
setRelCenter, Time.time);
transform.position += center;
}
}
下面进入对这个函数的详细解释。
初识这个函数的同学们对这个函数都不是很理解,既然是球形插值了,那么为什么用这个函数的时候却这么复杂呢,又要找中心点,又要中心点偏移的弄了半天。其实这是从这个函数的实现方法所决定的。咱们还是上例子来看比较清楚。
首先定义两个向量 a(2,1,0); b(-2,1,0); 然后咱们以这两个坐标点和原点来构建一个三角形,如下图所示:
咱们以a和b两个向量来做插值,假设分10等份,代码比较简单,如下代码
for(inti = 1; i < 10; ++i)
{
Vector3 drawVec = Vector3.Slerp(a, b, 0.1f * i);
Debug.DrawLine(Vector3.zero, drawVec, Color.yellow);
}
可以看到咱们并没有像官方给的例子那样,做那么多的操作,效果也是杠杠滴!
但是,你不能被表象所欺骗,这样的效果虽然可以,但是却无法控制插值的曲线,也就是那个弧度,虽然你可以调整向量a和向量b的值来调节弧度,比方说a(1,1,0),b(-1,1,0)效果如下,可以看到弧度已经明显变平很多。
但是我们在实际运用这个函数的时候往往向量a和向量b是固定的,我们想要的是控制这个弧度,那么怎么办呢,其实也就是改变画这个弧度的中心点位置。上面两个示意图上面中心点我们都是用的坐标原点,我们现在想要在不改变a和a的情况下来改变插值的弧度,就只能自己找出一个中心点,这也就是官方实例中求中心点的由来了。
//弧线的中心
Vector3 center = (a + b) * 0.5f;
//我们把中心点向下移动中心,垂直于弧线
center -= newVector3(0, 0.5f, 0);
// 求出新的中心点到向量a和向量b的
Vector3 vecA = a - center;
Vector3 vecB = b - center;
for(inti = 0; i <= 10; ++i)
{
Vector3 drawVec = Vector3.Slerp(vecA, vecB, 0.1f * i);
Debug.DrawLine(center, drawVec, Color.yellow);
}
求出中心点后我们再来画一个示意图看看
(至于为什么要 求出新的中心点到向量a和向量b的vecA和vecB是因为,我们在球形插值的时候要的是两个vector3,而这个vector3是要向量a和向量b到中心点的向量,如果我们不求出vecA和vecB的话不论你怎么插值,其实都是从坐标原点进行的插值,你是控制不了插值的弧度的。)
从上面的效果图我们可以看到插值出来的弧度开始和结束点并不是a、b两点,而是这两个点向下的偏移量,而这个偏移量正好是向量conter的负值,所以我们在求出drawVec之后需要对其做修正处理。
在求出drawVec之后加上下面的代码
drawVec += center;
然后再看效果图
现在的效果图就是我们想要的插值效果了,要想控制弧度,只用调节centor的偏移量就可以了。
比方说我们加上这样一条
center -= new Vector3(0, 2f, 0);
可以看到效果如下
这个弧度是不是就更平了呢。
好,看到现在还没有睡着的同学们,我只能说一句你们有福了,下面可是大餐哦。
上面咱们介绍的都是有局限性的,比方说向量a和向量b对于Y轴可是左右对称的,并且X,Y轴的值也是相等的,这在实际运用中可是非常不常见的,现在咱们对向量a做一个比较小的改动看看,把向量a改为(2,1,0),那么效果如下所示
哇咔咔,居然还是好好的球形插值啊,哈哈,各位同学别激动,咱们把向量a的Y轴也调整一下看看,把a改为(2,4,0)效果如下图所示
哇咔咔。。效果是不是非常明显啊,说好的球形插值呢?怎么成了这个样子!!哈哈,各位同学别着急啊,咱们这个球形插值和核心其实就是center点的位置,只要我们求的这个center点的位置在a和b连线中心点的垂线上面,那么就是一个完整的左右对称的插值了。
下面咱们加入如下代码
Vector3 centorProject = Vector3.Project(centor, mStart - mEnd); // 中心点在两点之间的投影
centor = Vector3.MoveTowards(centor, centorProject, 1f); // 沿着投影方向移动移动距离(距离越大弧度越小)
效果如下所示(中心的垂线和起始两条线用蓝色标示出来了)
所以我们完整的运用Vector3.Slerp的代码应该是这样子滴
//在日出和日落之间动画弧线
usingUnityEngine;
usingSystem.Collections;
publicclass example : MonoBehaviour
{
publicTransform sunrise;
publicTransform sunset;
voidUpdate()
{
//弧线的中心
Vector3 center = sunrise.position + sunset.position * 0.5f;
Vector3 centorProject = Vector3.Project(centor, sunrise.position - sunset.position); // 中心点在两点之间的投影
centor = Vector3.MoveTowards(centor, centorProject, 1f); // 沿着投影方向移动移动距离(距离越大弧度越小)
//相对于中心在弧线上插值
Vector3 riseRelCenter = sunrise.position - center;
Vector3 setRelCenter = sunset.position - center;
transform.position = Vector3.Slerp(riseRelCenter, setRelCenter, Time.time);
transform.position += center;
}
}
看到这里各位同学是不是觉得已经掌握了Vector3.Slerp了呢?O(∩_∩)O哈哈~
NONONO!!!!
咱们上面的实例还是有局限性滴,谁告诉你了Vector3的Z轴必须是0了?,咱们对a和b的Z轴在做修改。a((2, 4, -1)),b((-1, 1, 2)),看下效果图
哇咔咔。。是不是又出问题了?还需要改代码?NO!这是因为我们锁定了视角方向来看的,看上面的2D 选项是不是已经选择了啊,哈哈。那么既然Z轴有值了我们就不能已平面视角来看了,等我们把2D锁定给关闭了转换个视角看看。
这样看是不是就顺眼多了呢?哈哈,至此我们的讲解总算结束了,大家可以洗洗了,哈哈。。。
等下!谁说可以睡了?我可没说哦,难道大家对我说的都这么信吗?有句古话说的好啊,尽信书则不如无书。。
// 沿着投影方向移动移动距离(距离越大弧度越小)
centor = Vector3.MoveTowards(centor, centorProject, 1f);
在这句代码中我写了个注释(距离越大弧度越小)那么谁能告诉我距离越小会怎么样呢?大家是不是觉得距离越小弧度就越大呢?嘿嘿。。这就掉坑里了吧。
这个距离的小是相对的,尽量是不能小于0.01的,至于为啥是0.01呢,我就试了下0.01和0.001。。。哈哈。。就是这么不负责。。
如果这个距离小于0.01的话插值的方向就是不可控了,至于为什么呢?因为过于小的话就是a到b两点之间的一条线了,垂直于一条线的平面可是海里去了,谁知道在哪里呢。所以大家在用的时候切记这点啊,不能过于追求极限导致结果不可控。还有。。我是不是比较啰嗦啊。。上面我说的是距离啊,是距离,不是值,这个值是可以为负值的啊,负值的话插值的弧线就在这边了,转个向而已。
好了,讲解总算是可以结束了。累死我了。。哇咔咔。。
下面是测试源码,有兴趣的同学玩玩吧
privateVector3 mStart = newVector3(2, 4, -1);
privateVector3 mEnd = newVector3(-1, 1, 2);
// Update is called once per frame
privatevoid Update()
{
Debug.DrawLine(newVector3(-100, 0, 0), newVector3(100, 0, 0), Color.green);
Debug.DrawLine(newVector3(0, -100, 0), newVector3(0, 100, 0), Color.green);
Debug.DrawLine(Vector3.zero, mStart, Color.red);
Debug.DrawLine(Vector3.zero, mEnd, Color.red);
Debug.DrawLine(mStart, mEnd, Color.red);
Vector3 centor = (mStart + mEnd) * 0.5f;
Vector3 centorProject = Vector3.Project(centor, mStart - mEnd); // 中心点在两点之间的投影
centor = Vector3.MoveTowards(centor, centorProject, 1f); // 沿着投影方向移动移动距离(距离越大弧度越小)
Debug.DrawLine(centor, mStart, Color.blue);
Debug.DrawLine(centor, mEnd, Color.blue);
Debug.Log(string.Format("{0} : {1}", Vector3.Distance(centor, mStart), Vector3.Distance(centor, mEnd)));
for(inti = 1; i < 10; ++i)
{
Vector3 drawVec = Vector3.Slerp(mEnd - centor, mStart - centor, 0.1f * i);
drawVec += centor;
Debug.DrawLine(centor, drawVec, 5 == i ? Color.blue : Color.yellow);
}
}
在系统升级过程中往往需要对flash进行裸数据的标记读写,对于nand flash 的系统不能像nor flash一样在任意位置上进行裸数据读写,如果Nand flash存在坏块,并且正好处于读写的位置上,数据就比较容易出错了。nand flash 存在坏块特性,往往在底层驱动去对坏块的规避处理,但是对于非文件系统的nand flash往往因为坏块的存在,产生读写地址的偏差导致裸数据读写的错误,因此nand flash 不建议采用离散增量写的方式,避免因为坏块的存在,实际地址发生偏差。对于小于...
为什么不选择UUID在分布式场景下,很多人选择了 UUID 作为 ID ,UUID 目前有 5 个版本,分别是:版本1:依赖于时间戳和 MAC 地址,容易被攻击;版本2:将版本 1 的时间戳前四位换为 POSIX 的 UID 或 GID,问题同上;版本3:基于 MD5 哈希算法生成,生成随机分布的ID需要唯一的种子,这可能导致许多数据结构碎片化;版本4:基于随机数或伪随机数生成,除了随机性外没有提供其他信息;版本5:通过 SHA-1 哈希算法生成,生成随机分布的ID需要唯一的种子,这可能导致许多
罗毅,花名北纬。这个名字,如果是混过天涯论坛的大龄网民应该都不陌生,北纬67度3分周公子(简称北纬)虐杀易烨卿MM的世纪大战至今还是天涯神贴 ,当时更是有看客赋诗形容:“目睹此帖,开怀大笑,行走论坛,此帖独尊。”可见其影响力。罗毅取花名为北纬,可以说是怀念这段经典,致敬周公子。孔子说,40而不惑。如今的罗毅应该就是这个状态了,对人情世故有所清明,对自己的状态,尤其是所做的工作有着清楚的认知,对未来...
新版Android Studio(4.1.1 for Windows 64-bit)的安装教程(超详细)获取Android Studio软件在心仪的磁盘新建文件夹:AndroidStudio(文件夹名随意,但是不能有空格),在AndroidStudio下继续新建几个子文件夹为后续安装以及以后编程做准备:studio(安装位置)、sdk(存放SDK)、work(项目文件夹)。链接:Android Studio下载地址点击链接之后跳转Android Studio的下载地址会直接看到软件的下载入口,版本
交叉编译,错误的爆发如海啸…整整搞了我两天。之前简单的程序以及静态库交叉编译都成功了,我还沾沾自喜,没想到一涉及到大型项目,多重调用就GG。淦!来说正题~背景手上的一个项目,有多个模块,每个模块有一堆类组成,这个模块还调用好多个静态库/动态库。需求是要把这个模块编译后也生成静态库来供一个main.exe调用。哦忘了,这一系列操作都是要交叉编译环境下的。交代完毕。一. 交叉编译libzmq源码传送门这里提醒一下,有两点比较注意。就是 ./configure修改配置这里:host和tar
卷积神经网络是深度学习中一个很流行的网络模型,它的原理和过程我就不在此介绍了,感兴趣的可以去看一下https://blog.csdn.net/kane7csdn/article/details/83617086。在这里,介绍一下反卷积过程(可以叫做deconvolution,或者也可以称作convolution transpose)。反卷积也可以理解为逆卷积,顾名思义,卷积的逆过程。...
STRICT_TRANS_TABLES:在该模式下,如果一个值不能插入到一个事务表中,则中断当前的操作,对非事务表不做任何限制NO_ZERO_IN_DATE:在严格模式,不接受月或日部分为0的日期。如果使用IGNORE选项,我们为类似的日期插入'0000-00-00'。在非严格模式,可以接受该日期,但会生成警告。NO_ZERO_DATE:在严格模式,不要将 '0000-00...
出现问题:kali由于没有公钥,无法验证下列签名[email protected]:~# sudo apt update &amp;&amp; sudo apt install git vim -y命中:1 http://mirrors.aliyun.com/kali kali-rolling InRelease获取:2 http://ppa.launchpad.net/hzwhuang/ss-qt...
效果效果比较简单,是在浏览器运行实现的。源代码至于具体的图片,大家可以根据需求自行添加即可~下面是源代码。<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=gb2312" /><title>JS实现图片翻书效果</title><META http-equiv
魔兽世界怀旧服服务器进不去怎么办?今天魔兽世界杯旧服服务器正式上线了,不过由于玩家过多导致服务器负载,出现了各种玩家进不去、排队、断开连接等问题,玩家们对于这些问题很无奈又不知怎么解决,下面我们就一起来看看解决方法吧!魔兽世界怀旧服服务器负载断开连接怎么办在魔兽世界怀旧服即将开启之时,在8月26日凌晨官方发布了最新PVP服务器负载提醒,由于在同一个服务器中,有过多的玩家在同一个服务器进行角色的创建...
授人以鱼不如授人以渔,目的不是为了教会你具体项目开发,而是学会学习的能力。希望大家分享给你周边需要的朋友或者同学,说不定大神成长之路有博哥的奠基石。。。QQ技术互动交流群:ESP8266&32 物联网开发 群号622368884,不喜勿喷一、你如果想学基于Arduino的ESP8266开发技术一、基础篇二、网络篇三、应用篇四、高级篇1.理论基础参考博主线上博文:在前面的博文中,博主主要通过...
1.MVCMVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,一种软件设计典范,用一种业务逻辑、数据、界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑。MVC被独特的发展起来用于映射传统的输入、处理和输出功能在一个逻辑的图形化用户界面的结构中。...