ARKit的使用示例

#import "ViewController.h"
#import <ARKit/ARKit.h>

@interface ViewController ()
<ARSCNViewDelegate,ARSessionDelegate>

#define YDUseARConfiguration ARWorldTrackingConfiguration //ARBodyTrackingConfiguration

@property (nonatomic, strong) ARSession *session;
@property (nonatomic, strong) YDUseARConfiguration *configuration;
@property (nonatomic, strong) ARSCNView *arView;
@property (nonatomic, strong) SCNNode *fromNode;
@property (nonatomic, strong) SCNNode *toNode;
@property (nonatomic, strong) SCNNode *planeNode;
@property (nonatomic, strong) SCNNode *zeroNode;
@property (weak, nonatomic) IBOutlet UILabel *messageLabel;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
    if ([YDUseARConfiguration supportsFrameSemantics:ARFrameSemanticPersonSegmentationWithDepth]) {
        NSLog(@"YDUseARConfiguration");
    }
    if ([ARFaceTrackingConfiguration supportsFrameSemantics:ARFrameSemanticPersonSegmentationWithDepth]) {
        NSLog(@"ARFaceTrackingConfiguration");
    }
    if ([ARBodyTrackingConfiguration supportsFrameSemantics:ARFrameSemanticPersonSegmentationWithDepth]) {
        NSLog(@"ARBodyTrackingConfiguration");
    }
    [self.view addSubview:self.arView];
    [self.view sendSubviewToBack:self.arView];
}

- (IBAction)resetPointFunc:(UIButton *)sender {
    [self.fromNode removeFromParentNode];
    [self.toNode removeFromParentNode];
    self.fromNode = nil;
    self.toNode = nil;
}


- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    [self.session runWithConfiguration:self.configuration];
}

- (void)viewWillDisappear:(BOOL)animated {
    [self.session pause];
}

- (YDUseARConfiguration *)configuration {
    if (!_configuration) {
        _configuration = [YDUseARConfiguration new];
        _configuration.planeDetection = ARPlaneDetectionHorizontal;
    }

    return _configuration;
}

- (ARSCNView *)arView {
    if (!_arView) {
        _arView = [[ARSCNView alloc] initWithFrame:self.view.bounds];
        _arView.session = self.session;
        _arView.delegate = self;
        _arView.scene = [SCNScene new];
        _arView.debugOptions = ARSCNDebugOptionShowFeaturePoints;//debug模式,显示追踪到的点位
    }
    return _arView;
}

- (ARSession *)session {
    if (!_session) {
        _session = [ARSession new];
        _session.delegate = self;
    }
    return _session;
}

- (SCNMaterial *)materialNamed:(NSString *)name {
    // 创建一个模型贴图立方体
    static NSMutableDictionary *materials = nil;
    if (!materials) {
        materials = [NSMutableDictionary new];
    }
    SCNMaterial *mat = materials[name];
    if (mat) {
        return mat;
    }
    mat = [SCNMaterial new];
    mat.lightingModelName = SCNLightingModelPhysicallyBased;
    mat.diffuse.contents = [UIImage imageNamed:@"tron-albedo"];
    mat.roughness.contents = [UIImage imageNamed:@"tron-albedo"];
    mat.metalness.contents = [UIImage imageNamed:@"tron-albedo"];
    mat.normal.contents = [UIImage imageNamed:@"tron-albedo"];
    mat.diffuse.wrapS = SCNWrapModeRepeat;
    mat.diffuse.wrapT = SCNWrapModeRepeat;
    mat.roughness.wrapS = SCNWrapModeRepeat;
    mat.roughness.wrapT = SCNWrapModeRepeat;
    mat.metalness.wrapS = SCNWrapModeRepeat;
    mat.metalness.wrapT = SCNWrapModeRepeat;
    mat.normal.wrapS = SCNWrapModeRepeat;
    mat.normal.wrapT = SCNWrapModeRepeat;
    
    materials[name] = mat;
    return mat;
}

- (void)renderer:(id <SCNSceneRenderer>)renderer didAddNode:(SCNNode *)node forAnchor:(ARAnchor *)anchor {
    if ([anchor isKindOfClass:[ARPlaneAnchor class]]) {
//        if (self.planeNode) {
//            [self.planeNode removeFromParentNode];
//        }
//
//        ARPlaneAnchor *planeAnchor = (ARPlaneAnchor *)anchor;
//        SCNBox *plane = [SCNBox boxWithWidth:3.0 height:3.0 length:3.0 chamferRadius:0];
//        SCNMaterial *transparentMaterial = [SCNMaterial new];
//        transparentMaterial = [self materialNamed:@"tron"];
//        plane.materials = @[transparentMaterial, transparentMaterial, transparentMaterial, transparentMaterial, transparentMaterial, transparentMaterial];
//        SCNNode *planeNode = [SCNNode nodeWithGeometry:plane];
//        planeNode.position = SCNVector3Make(
//                                            node.position.x,
//                                            node.position.y,
//                                            node.position.z - 6.0
//                                            );
//        [node addChildNode:planeNode];
//        self.planeNode = planeNode;
        // Y轴线
        SCNTube *tubey = [SCNTube tubeWithInnerRadius:0 outerRadius:0.001 height:50];
        tubey.firstMaterial.diffuse.contents = [UIColor greenColor];
        SCNNode *tubeNodey = [SCNNode nodeWithGeometry:tubey];
        tubeNodey.position = SCNVector3Make(0, 2.5, 0);
        [node addChildNode:tubeNodey];
        // X轴线
        SCNTube *tubex = [SCNTube tubeWithInnerRadius:0 outerRadius:0.001 height:50];
        tubex.firstMaterial.diffuse.contents = [UIColor redColor];
        SCNNode *tubeNodex = [SCNNode nodeWithGeometry:tubex];
        tubeNodex.position =  SCNVector3Make(0, 0, 0);
        tubeNodex.rotation = SCNVector4Make(1, 0, 0, M_PI/2);
        [node addChildNode:tubeNodex];
        
        // Z轴线
        SCNTube *tubez = [SCNTube tubeWithInnerRadius:0 outerRadius:0.001 height:50]; // 声明一个形体(此处为圆柱体)
        tubez.firstMaterial.diffuse.contents = [UIColor blueColor];
        SCNNode *tubeNodez = [SCNNode nodeWithGeometry:tubez]; // 通过上述形体创建一个物体
        tubeNodez.position =  SCNVector3Make(0, 0, 0);
        tubeNodez.rotation = SCNVector4Make(0, 0, 1, M_PI/2);
        [node addChildNode:tubeNodez];
        
        _zeroNode = node; // ARAnchor这个是AR世界的一个点对象 node是坐标原点
        
        // 设置下面两句不再寻找平面,后面计算参照现有平面
        self.configuration.planeDetection = ARPlaneDetectionNone;
        [self.arView.session runWithConfiguration:self.configuration];
        
        dispatch_async(dispatch_get_main_queue(), ^{
            self.messageLabel.text = @"已经寻找到了一个平面";//[NSString stringWithFormat:@"planeAnchor.extent.x:%.4f", planeAnchor.extent.x];
        });
    }
}

- (void)renderer:(id<SCNSceneRenderer>)renderer didRemoveNode:(SCNNode *)node forAnchor:(ARAnchor *)anchor {
    if (self.planeNode == self.planeNode) {
        dispatch_async(dispatch_get_main_queue(), ^{
            self.messageLabel.text = @"请寻找一个平面";
            [self resetPointFunc:nil];
            if (self.planeNode) {
                [self.planeNode removeFromParentNode];
            }
        });
    }
}

- (void)session:(ARSession *)session didUpdateFrame:(ARFrame *)frame {
    ARBody2D *body = [frame detectedBody];
    if (body) {
    
    }
    dispatch_async(dispatch_get_main_queue(), ^{
        if (self.zeroNode) {
//            SCNVector3 zerolocation = [self.arView projectPoint:self.zeroNode.worldPosition];
//            self.messageLabel.text = [NSString stringWithFormat:@"%.2f,%.2f",zerolocation.x,zerolocation.y];
        }
    });
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    CGPoint point = [touches.anyObject locationInView:self.arView];
//    NSArray<ARHitTestResult *> *result = [self.arView hitTest:point types:ARHitTestResultTypeFeaturePoint];
//    if (result.count != 0) {
//        // If there are multiple hits, just pick the closest plane
//        ARHitTestResult * hitResult = [result firstObject];
    if (!self.zeroNode) {
        return;
    }
    // 将三维点转为二位平面点坐标+深度(z值)
    SCNVector3 zeroLocation = [self.arView projectPoint:self.zeroNode.worldPosition];
    // 将屏幕点+深度转为AR世界中的点坐标
    SCNVector3 location = [self.arView unprojectPoint:SCNVector3Make(point.x, point.y, zeroLocation.z)];
        if (!self.fromNode) {
            SCNSphere *calculareTube = [SCNSphere sphereWithRadius:0.01];
            calculareTube.firstMaterial.diffuse.contents = [UIColor colorWithRed:255 green:255 blue:0 alpha:0.6];
            self.fromNode = [SCNNode nodeWithGeometry:calculareTube];
            //    设置节点的位置为捕捉到的平地的锚点的中心位置  SceneKit框架中节点的位置position是一个基于3D坐标系的矢量坐标SCNVector3Make
            self.fromNode.position = location;
//            SCNVector3Make(
//                                                      hitResult.worldTransform.columns[3].x,
//                                                      hitResult.worldTransform.columns[3].y,
//                                                      hitResult.worldTransform.columns[3].z
//                                                      );
            [self.arView.scene.rootNode addChildNode:self.fromNode];
        } else {
            if (self.toNode) {
                [self.toNode removeFromParentNode];
            }
            SCNSphere *calculareTube = [SCNSphere sphereWithRadius:0.01];
            calculareTube.firstMaterial.diffuse.contents = [UIColor colorWithRed:255 green:0 blue:255 alpha:0.6];
            self.toNode = [SCNNode nodeWithGeometry:calculareTube];
            //    设置节点的位置为捕捉到的平地的锚点的中心位置  SceneKit框架中节点的位置position是一个基于3D坐标系的矢量坐标SCNVector3Make
            self.toNode.position = location;
//            SCNVector3Make(
//                                                      hitResult.worldTransform.columns[3].x,
//                                                      hitResult.worldTransform.columns[3].y,
//                                                      hitResult.worldTransform.columns[3].z
//                                                      );
            [self.arView.scene.rootNode addChildNode:self.toNode];
            
            SCNNode *previousNode = self.fromNode;
            SCNNode *currentNode = self.toNode;

            CGFloat distance = sqrt((previousNode.position.x-currentNode.position.x)*(previousNode.position.x-currentNode.position.x)+(previousNode.position.z-currentNode.position.z)*(previousNode.position.z-currentNode.position.z));
            
            dispatch_async(dispatch_get_main_queue(), ^{
                self.messageLabel.text = [NSString stringWithFormat:@"上两点距离:%f 米",distance];
            });
        }
        
//    }
    
}

@end

 一个很好的demo地址  https://www.jianshu.com/p/46ded5b1fa00

//画线(这里无法设定线条的宽度)
    func line(to vector:SCNVector3,color:UIColor) -> SCNNode {
        let indices : [UInt32] = [0,1]//指数
        let source = SCNGeometrySource(vertices: [self,vector]) // 创建一个几何容器

        let element = SCNGeometryElement(indices: indices, primitiveType: .line)//用线的方式来创造一个几何元素(线)
        let geomtry = SCNGeometry(sources: [source], elements: [element])//几何
        geomtry.firstMaterial?.diffuse.contents = color//渲染颜色
        let node = SCNNode(geometry: geomtry)//返回一个节点
        return node
        
    }

 

posted @ 2020-11-27 13:40  雨筱逸悠  阅读(464)  评论(0编辑  收藏  举报