#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 }