Quiero crear una aplicación en la que pueda establecer puntos en el mundo real en la superficie detectada y, después de tener 4 o más puntos, cree un plano/polígono entre ellos con textura. Configuración básica del controlador:
@IBOutlet weak var sceneView: ARSCNView! let configuration = ARWorldTrackingConfiguration() var vectors: [SCNVector3] = [] var mostBottomYAxis: Float? { didSet { for (index, _) in vectors.enumerated() { vectors[index].y = self.mostBottomYAxis ?? vectors[index].y } } } var identifier: UUID? override func viewDidLoad() { super.viewDidLoad() self.sceneView.debugOptions = [ARSCNDebugOptions.showFeaturePoints, ARSCNDebugOptions.showWorldOrigin] self.sceneView.showsStatistics = true self.configuration.worldAlignment = .gravity // Y axis is Up and Down self.configuration.planeDetection = .horizontal // Detect horizontal surfaces self.sceneView.session.run(configuration) self.sceneView.autoenablesDefaultLighting = true self.sceneView.delegate = self self.registerGestureRecognizers() }Toque el método de gesto para agregar un vértice a la superficie:
@objc func handleTap(sender: UITapGestureRecognizer) { let sceneView = sender.view as! ARSCNView let tapLocation = sender.location(in: sceneView) if let raycast = sceneView.raycastQuery(from: tapLocation, allowing: .estimatedPlane, alignment: .horizontal), let result = sceneView.session.raycast(raycast).first { self.addItem(raycastResult: result) } } func addItem(raycastResult: ARRaycastResult) { let transform = raycastResult.worldTransform let thirdColumn = transform.columns.3 let vector = SCNVector3(x: thirdColumn.x, y: mostBottomYAxis ?? thirdColumn.y, z: thirdColumn.z) self.vectors.append(vector) self.addItem(toPosition: vector) }y métodos para dibujar polígonos:
func getGeometry(forVectors vectors: [SCNVector3]) -> SCNGeometry { let polygonIndices = Array(0...vectors.count).map({ Int32($0) }) let indices: [Int32] = [Int32(vectors.count)] + /* We have a polygon with this count of points */ polygonIndices /* The indices for our polygon */ let source = SCNGeometrySource(vertices: vectors) let indexData = Data(bytes: indices, count: indices.count * MemoryLayout<Int32>.size) let element = SCNGeometryElement(data: indexData, primitiveType: .polygon, primitiveCount: 1, bytesPerIndex: MemoryLayout<Int32>.size) // MARK: - Texture let textureCoordinates = [ CGPoint(x: 0, y: 0), CGPoint(x: 1, y: 0), CGPoint(x: 0, y: 1), CGPoint(x: 1, y: 1) ] let uvSource = SCNGeometrySource(textureCoordinates: textureCoordinates) let geometry = SCNGeometry(sources: [source, uvSource], elements: [element]) return geometry } func getNode(forVectors vectors: [SCNVector3]) -> SCNNode { let polyDraw = getGeometry(forVectors: vectors) let material = SCNMaterial() material.isDoubleSided = true material.diffuse.contents = UIImage(named: "Altezo_colormix_brilant") material.diffuse.wrapS = .repeat material.diffuse.wrapT = .repeat polyDraw.materials = [material] let node = SCNNode(geometry: polyDraw) return node } extension PlacePointsForPlaneViewController: ARSCNViewDelegate { func renderer(_ renderer: SCNSceneRenderer, didUpdate node: SCNNode, for anchor: ARAnchor) { guard let planeAnchor = anchor as? ARPlaneAnchor else { return } let y = planeAnchor.transform.columns.3.y if mostBottomYAxis == nil { mostBottomYAxis = y identifier = planeAnchor.identifier } if mostBottomYAxis! > y { mostBottomYAxis = y identifier = planeAnchor.identifier } // Remove existing plane nodes node.enumerateChildNodes { (childNode, _) in childNode.removeFromParentNode() } if planeAnchor.identifier == self.identifier { if self.vectors.count > 3 { let modelNode = getNode(forVectors: self.vectors) node.addChildNode(modelNode) } } } } Espero que sea mayormente autoexplicado. Tengo vectors que contienen puntos agregados manualmente. Quiero trabajar solo con una superficie que sea la más inferior (eso es lo que hace mostBottomYAxis e identifier ).
¿Qué estoy haciendo mal? ¿Por qué el polígono no se dibuja exactamente entre los puntos? Cuando traté de dibujar una línea entre dos puntos, funcionó.
Un problema más. ¿Cómo establecer las coordenadas de textura para dibujar correctamente la textura en el polígono y hacer que funcione no solo para 4 vértices sino para más (dinámicamente a medida que el usuario agrega más puntos y puede cambiar sus posiciones)?
Gracias por la ayuda
Editar: después de publicar la pregunta, probé diferentes nodos para agregar mi polígono personalizado y funciona bien si agregué a sceneView rootNode:
sceneView.scene.rootNode.addChildNode(modelNode)Así que esto ayuda con la posición del polígono. Pero todavía tengo problemas con la textura. ¿Cómo configurar la compensación/transformación de la textura para que funcione? Para que la textura rellene esta geometría personalizada y repita la textura en los bordes.