文档开发者中心
我的

ARKit 中用好 lookAt: 效率提升一倍

角度计算

在 AR 中,我们经常看到夹角的计算,常见的有让物体朝向手机,或者箭头从 A 点指向 B 点,一般都需要用到 atan2 等函数:
atan和atan2都是反正切函数,如:有两个点 point(x1,y1), 和 point(x2,y2);
那么这两个点形成的斜率的弧度计算方法分别是:
float radian = atan( (y2-y1)/(x2-x1) );
或
float radian = atan2( y2-y1, x2-x1 );

转化为角度:
float degree = arc / pi * 180

atan 和 atan2 区别在于:
1,参数的填写方式不同;
2,atan2 的优点在于x2-x1等于0时依然可以计算,但是atan函数除零会出错;

但实际上,我们可以不用这么麻烦,使用 ARKit 提供的 lookAt 方法可以让我们方便地完成“指向”操作。

lookAt 与 simdLookAt

lookAt操作可以让一个 node “指向”某个位置,默认的情况下,就是以 z 轴的正方向来对着目标位置。 如下图,飞机的头部指向了 z 轴的正方向。

这里,我们让飞机指向手机的位置,它只会执行一次,当手机移动时,飞机会保持原位而 localFront可以控制自身的旋转,比如让自己(SCNNode 对象)的 x 轴正方向朝向目标,只需要设置 localFront为 (1,0,0) 就可以了。
那么 worldUp是干什么的呢?其实它是用来限制意外旋转的。就是说,当物体 A lookAt 物体 B 的时候,物体 A 有可能会绕着 A-B 点的连线旋转,所以需要指定worldUp来限制。指定后在旋转时会尽可能减小与worldUp方向的夹角,所以就不会绕 A-B 连线随意旋转了。


比如,这种情况,也是满足 lookAt 条件的,但是飞机却歪了,这不是我们想要的,所以worldUp就是为了防止出现这种情况的。


如果采用下面的代码,指定了worldUp,就不会有这种情况了:

// 延迟 2 秒,将飞机的(0,0,-1)即尾部朝向手机,同时指定 up 为世界坐标的 y 轴正方向(0,1,0),这样飞机就不会歪了 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{         [self.shipNode simdLookAt:self.sceneView.pointOfView.simdPosition up:simd_make_float3(0, 1, 0) localFront:simd_make_float3(0, 0, -1)];     }); 复制代码


simd 版本作用也是一样的。


- (void)lookAt:(SCNVector3)worldTarget; - (void)lookAt:(SCNVector3)worldTarget up:(SCNVector3)worldUp localFront:(SCNVector3)localFront; // 对应的 simd 版本 - (void)simdLookAt:(simd_float3)worldTarget; - (void)simdLookAt:(simd_float3)worldTarget up:(simd_float3)worldUp localFront:(simd_float3)localFront; 复制代码

SCNLookAtConstraint 与 SCNBillboardConstraint

这两个操作是约束,类似 AutoLayout 的效果,可以实时更新,不管目标怎么动,也不管自身怎么动,都一直起作用。

SCNBillboardConstraint 就是俗称的“广告牌”效果,让物体始终正面对着相机(即手机)的位置,同时保持 y 轴不变(竖直方向不变,只水平旋转)。当然,也可以调整freeAxes让它保持 x 轴不变,绕 x 轴旋转。

// 始终指向相机位置 SCNBillboardConstraint *con = [SCNBillboardConstraint billboardConstraint]; con.freeAxes = SCNBillboardAxisY; self.shipNode.constraints = @[con]; 复制代码

可以看到,当左右水平移动时,飞机头部始终朝向相机方向;当手机从高处或低处看时,飞机保持竖直方向,这就是广告牌效果:

需要注意的是,广告牌会让旋转轴自动变竖直。如下图:


SCNLookAtConstraint 就没有那么多限制,可以自由旋转。同时,它也有localFront和worldUp,可以调整朝向的姿态并防止意外的旋转;另外它还有targetOffset来让你指向目标的某一侧;此外gimbalLockEnabled可以用来处理万向结锁问题。


惟一不同的是,SCNLookAtConstraint 默认是用 z 轴负方向(即飞




点赞
收藏
1
回复
6
分享
举报
浏览1418 编辑于2020-12-08 03:36未知归属地
全部评论
最多点赞
最新发布
最早发布

两线段的夹角如何计算呢,除了atan

6楼回复于2020-12-08 03:29 未知归属地

欢迎交流!!!

5楼回复于2019-11-13 01:35 未知归属地

谢谢版主称赞!!

4楼回复于2019-11-13 01:34 未知归属地

占楼了!!!

3楼回复于2019-11-12 06:50 未知归属地

沙发沙发!!

2楼回复于2019-11-12 06:50 未知归属地

感谢分享 !!!

1楼回复于2019-11-12 06:49 未知归属地
写回答
新增插入模板功能
一键使用模板,快速填写内容,轻松发帖~
知道了
  • 为了保障您的信息安全,请勿上传您的敏感个人信息(如您的密码等信息)和您的敏感资产信息(如关键源代码、签名私钥、调试安装包、业务日志等信息),且您需自行承担由此产生的信息泄露等安全风险。
  • 如您发布的内容为转载内容,请注明内容来源。

我要发帖子

目录 收起
角度计算
lookAt 与 simdLookAt
SCNLookAtConstraint 与 SCNBillboardConstraint
了解社区公约,与您携手共创和谐专业的开发者社区。