ARKit实战:如何实现任意门

ARKit实战:如何实现任意门

相关

到底有多强?苹果的增强现实框架:ARKit
ARKit进阶:物理世界
ARKit进阶:材质

技术

任意门特效的实现,主要用到了关于纹理、材质、光照的相关知识,掌握起来并不困难。
如果对相关知识不熟悉,可以看一下上面的文章。

github

如果对工程感兴趣,可以在github上找到源码。欢迎star, fork。
github地址:ARKit_trans-dimensional-room

效果

Demo视频合集
Demo视频合集有两段任意门视频,可以看看效果,分别是:pet_find_transDeminalRoom,
ARKit trans-dimensional room。

ARKit实战:如何实现任意门_第1张图片
cover

目标

我们的目标是要实现一个独立的隐藏空间,这个空间只有一个门留给用户展示,当用户走进去时,可以看到内部的细节。

思路

先构建一个封闭的空间,再用透明材质将它包裹起来,当用户进入这个空间后,可以将背景换成全景的图片,当用户走出时,将背景换回摄像头数据。

实现

实现分三部分:
1 . 处理ARKit检测到的平面
用于提示可以用于交互的平面,后期模拟物理世界也要用到。

- (void)renderer:(id)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)renderer didUpdateNode:(SCNNode *)node forAnchor:(ARAnchor *)anchor{
    if ([anchor isKindOfClass:[ARPlaneAnchor class]]){
        NSLog(@"updated plane");
        [self updatePlanesForAnchor:(ARPlaneAnchor*)anchor];
    }
}
- (void)renderer:(id)renderer didRemoveNode:(SCNNode *)node forAnchor:(ARAnchor *)anchor{
    if ([anchor isKindOfClass:[ARPlaneAnchor class]]){
        NSLog(@"removed plane");
        [self removePlaneForAnchor:(ARPlaneAnchor*)anchor];
    }
}

2 . 放置transDimenRoom
对于隐藏空间,抽象成两个类来表达:transDimenRoomtransDimenStruct
后者用于提供一些平板等基础结构,前者将这些结构拼成一个房间,留一个门框出来让用户能够看见里面。
当需要放置任意门时,就用+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)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];
        
    }
}

展望

工程大致提供了让用户从真实世界进入虚拟空间的力能,目前功能还有一些问题需要改进:

  1. 进入房间后,用skyBox代替背景,会看不到门后的真实世界,考虑用shader去渲染门的内容
  2. 判断用户进入房间的方法比较粗糙

你可能感兴趣的:(ARKit实战:如何实现任意门)