ARKit实战:如何实现任意门
ARKit实战:如何实现任意门
相关
到底有多强?苹果的增强现实框架:ARKit
ARKit进阶:物理世界
ARKit进阶:材质
技术
任意门特效的实现,主要用到了关于纹理、材质、光照的相关知识,掌握起来并不困难。
如果对相关知识不熟悉,可以看一下上面的文章。
github
如果对工程感兴趣,可以在github上找到源码。欢迎star, fork。
github地址:ARKit_trans-dimensional-room
效果
Demo视频合集
Demo视频合集有两段任意门视频,可以看看效果,分别是:pet_find_transDeminalRoom,
ARKit trans-dimensional room。
目标
我们的目标是要实现一个独立的隐藏空间,这个空间只有一个门留给用户展示,当用户走进去时,可以看到内部的细节。
思路
先构建一个封闭的空间,再用透明材质将它包裹起来,当用户进入这个空间后,可以将背景换成全景的图片,当用户走出时,将背景换回摄像头数据。
实现
实现分三部分:
1 . 处理ARKit检测到的平面
用于提示可以用于交互的平面,后期模拟物理世界也要用到。
- (void)renderer:(id<SCNSceneRenderer>)renderer didAddNode:(SCNNode *)node forAnchor:(ARAnchor *)anchor{
if ([anchor isKindOfClass:[ARPlaneAnchor class]] && !_stopDetectPlanes){
NSLog(@"detected plane");
[self addPlanesWithAnchor:(ARPlaneAnchor*)anchor forNode:node];
[self postInfomation:@"touch ground to place room"];
}
}
- (void)renderer:(id<SCNSceneRenderer>)renderer didUpdateNode:(SCNNode *)node forAnchor:(ARAnchor *)anchor{
if ([anchor isKindOfClass:[ARPlaneAnchor class]]){
NSLog(@"updated plane");
[self updatePlanesForAnchor:(ARPlaneAnchor*)anchor];
}
}
- (void)renderer:(id<SCNSceneRenderer>)renderer didRemoveNode:(SCNNode *)node forAnchor:(ARAnchor *)anchor{
if ([anchor isKindOfClass:[ARPlaneAnchor class]]){
NSLog(@"removed plane");
[self removePlaneForAnchor:(ARPlaneAnchor*)anchor];
}
}
2 . 放置transDimenRoom
对于隐藏空间,抽象成两个类来表达:transDimenRoom
,transDimenStruct
。
后者用于提供一些平板等基础结构,前者将这些结构拼成一个房间,留一个门框出来让用户能够看见里面。
当需要放置任意门时,就用+transDimenRoomAtPosition:
方法创建一个transDimenRoom
,当用户走进去时,用-hideWalls:
隐藏四周的墙壁,切换成全景背景。
@interface transDimenRoom : SCNNode
@property (nonatomic, strong) SCNNode *walls;
+(instancetype)transDimenRoomAtPosition:(SCNVector3)position;
//TODO:check if user in room
-(BOOL)checkIfInRoom:(SCNVector3)position;
-(void)hideWalls:(BOOL)hidden;
@end
3 . 检测到用户走进房间
目前为了简单起见,是判断用户与房间中心的距离,当距离小于1时,就认为用户进入了房间。
这里的逻辑以后会收归到transDimenRoom
中。
- (void)renderer:(id<SCNSceneRenderer>)renderer updateAtTime:(NSTimeInterval)time{
if (_room.presentationNode) {
SCNVector3 position = self.sceneView.pointOfView.presentationNode.worldPosition;
SCNVector3 roomCenter = _room.walls.worldPosition;
CGFloat distance = GLKVector3Length(GLKVector3Make(position.x - roomCenter.x, 0, position.z - roomCenter.z));
if (distance < 1){
NSLog(@"In room");
[self handleUserInRoom:YES];
return;
}
[self handleUserInRoom:NO];
}
}
展望
工程大致提供了让用户从真实世界进入虚拟空间的力能,目前功能还有一些问题需要改进:
- 进入房间后,用skyBox代替背景,会看不到门后的真实世界,考虑用shader去渲染门的内容
- 判断用户进入房间的方法比较粗糙