3D世界相机防抖杆的机制探究

简介: 前一篇在学习使用UnReal的时候,了解到了一个非常好的概念 spring arm, 给相机加上这个组件后,能防止相机同步目标物体时,过于频繁的移动导致的抖动。于是乎,想到 天眼3d地图中由于数据频繁的位移抖动导致的视觉效果不佳,遂动手实践一番,写一个PigeonGL的防抖功能。 ## 弹簧 - 拟物 说到防抖,最常见的就是电流按键防抖,简单暴力的去除按键接触电极时频繁的接通断开的

前一篇在学习使用UnReal的时候,了解到了一个非常好的概念 spring arm, 给相机加上这个组件后,能防止相机同步目标物体时,过于频繁的移动导致的抖动。于是乎,想到 天眼3d地图中由于数据频繁的位移抖动导致的视觉效果不佳,遂动手实践一番,写一个PigeonGL的防抖功能。

弹簧 - 拟物

说到防抖,最常见的就是电流按键防抖,简单暴力的去除按键接触电极时频繁的接通断开的电流毛刺。在web领域对应的就是搜索时,延时处理,防止频繁处理搜索请求。而在3d世界中的防抖,则是真真正正的要把抖动的毛刺变成一条平滑曲线而不是去除,所以我就yy了一下,想起来我的破旧小电驴过减震带的颠簸,轮子上的那个巨大的废物减震弹簧应该关系巨大,干脆造一个虚拟弹簧来实现spring arm,固定在相机和目标物体的上面连接起来,计算出由于物体移动位移造成弹簧末端的移动速度,做出类似于css中的ease-out的效果。

计算

弹簧高中物理学过一个 虎克公式 ,既弹簧绳长量和产生的拉力成正比
屏幕快照 2019-01-03 下午4.55.42.png

  F = k * X 

(F: 拉力 牛 , X: 位移 米)
弹簧的拉力和被拉开的位移成正比;
求出拉力F可以反向通过加速度公式;

 F = m * a;

得出加速度 a = k * X / m;

另外又有速度公式

  Vt = V0 + a * t;

最终得出

  Vt = V0 + k * X / m;

映射速度

经过一系列的计算,得出了速度的最终函数,经过简化系数,可以抽象成下列函数

let v += speedRatio * x

其中x 可以理解为,目标物体从某个位置的到另一个位置间的距离 差 , 这里我设

X = targetCenter[0] - nowCenter[0];
Y = targetCenter[1] - nowCenter[1];

OK,这样我们可以计算出速度了!速度这个概念 对经常做js动画的人来说,可以理解为每一帧的运动距离,我们的速度单位为 m/frame (1frame = 1/fps s)因此可以得出每一帧的距离,接下来只需要设置定时函数,把地图的每一帧加上这个距离

 this.eachX += this.speedRatio*(this.targetCenter[0] - this.nowCenter[0])*1/30;//30帧的时间 约1s
 this.eachY += this.speedRatio*(this.targetCenter[1] - this.nowCenter[1])*1/30;
 this.timeout = setTimeout(()=>{
        this.nowCenter[0] += this.eachX;
        this.nowCenter[1] += this.eachY;
       
      },30);//每帧30ms

每次判断是否已经移动到目标点

      if( (this.eachX>0?-1:1)*(this.nowCenter[0] - this.targetCenter[0])<0){
           this.nowCenter = this.targetCenter;
           this.eachX = this.eachY = 0;//到终点后,速度归零
           this.pigeonMap.cameraControl.setCenter(this.nowCenter);
           this.pigeonMap.cameraControl.updateCamera();
           return;
        }
        //没有归零则继续加速
        this.pigeonMap.cameraControl.setCenter(this.nowCenter);
        this.pigeonMap.cameraControl.updateCamera();
        this.toCenter();

然后要支持,弹簧伸缩到一半的时候,目标物体又发生移动,此时要根据当前的位移距离重新计算出加速度,然后累计到当前速度上。

      this.nowCenter = this.pigeonMap.cameraControl.map.center;
      this.targetCenter = newPosition;
      this.eachX += this.speedRatio*(this.targetCenter[0] - this.nowCenter[0])*1/30;//30帧的时间
      this.eachY += this.speedRatio*(this.targetCenter[1] - this.nowCenter[1])*1/30;
      if(this.timeout)clearTimeout(this.timeout);

现在每当我重新设置目标位置时,就会重新获得拉力,把相机拉向小车,并且ease-out到小车位置

最后

实用主义者认为 有物理意义的 数学知识才是值得学习的!

相关文章
|
29天前
|
机器学习/深度学习 数据采集 算法
【传知代码】无监督动画中关节动画的运动表示-论文复现
本文探讨了数据驱动的无监督动画技术,尤其是针对关节动画的运动表示。研究提出三个主要贡献:1) 使用区域表示增强一阶运动稳定性;2) 明确建模背景运动以稳定点识别;3) 在无监督空间中解耦形状和姿态防止形状转移。通过这些改进,无监督运动转移的精度提升,特别是对关节对象的动画。作者还创建了一个新的TED演讲者数据集,证明了方法的有效性,其性能优于现有技术。文章总结了监督和无监督图像动画方法,并介绍了关节动画的基本原理,包括骨架、关节表示和姿势表示。核心逻辑涉及一阶运动模型、PCA-based运动估计和背景运动估计,以及图像生成过程。
【传知代码】无监督动画中关节动画的运动表示-论文复现
|
1月前
复现sci顶刊中的画中画(局部细节放大)
复现sci顶刊中的画中画(局部细节放大)
179 0
|
10月前
|
运维 监控 新能源
Baumer工业相机堡盟工业相机如何通过BGAPISDK进行定序器编程:根据每次触发信号移动感兴趣区域(C#)
Baumer工业相机堡盟工业相机如何通过BGAPISDK进行定序器编程:根据每次触发信号移动感兴趣区域(C#)
66 0
|
10月前
|
运维 监控 新能源
Baumer工业相机堡盟工业相机如何通过BGAPISDK进行定序器编程:根据每次触发信号移动感兴趣区域(C++)
Baumer工业相机堡盟工业相机如何通过BGAPISDK进行定序器编程:根据每次触发信号移动感兴趣区域(C++)
70 0
|
12月前
|
算法 机器人
m基于万能逼近原理自适应模糊控制算法的多自由度AUV运动控制抗干扰补偿simulink仿真
m基于万能逼近原理自适应模糊控制算法的多自由度AUV运动控制抗干扰补偿simulink仿真
142 0
|
机器学习/深度学习 传感器 算法
基于Bellhop算法模拟海底地形起伏条件下的传播特性附Matlab 源码
基于Bellhop算法模拟海底地形起伏条件下的传播特性附Matlab 源码
|
Java
手把手一步一步教你使用Java开发一个大型街机动作闯关类游戏05图像仿射变换(平移和缩放操作)
手把手一步一步教你使用Java开发一个大型街机动作闯关类游戏05图像仿射变换(平移和缩放操作)
125 0
|
前端开发
妙啊!动画还可以这样控制?
妙啊!动画还可以这样控制?
260 0
妙啊!动画还可以这样控制?
|
前端开发 程序员
Threejs - 灯光?投影?? 有光的地方就会有影子
Threejs - 灯光?投影?? 有光的地方就会有影子