如何使用 Arkit Scenekit 创建类似 qlone 3d 扫描仪应用程序的 AR 圆顶
how to create AR dome like qlone 3d scanner app using Arkit Scenekit
我想在 Scenekit 中创建 AR 圆顶形状几何体,就像在 qlone 3D 扫描仪应用程序中创建的一样。
请参考以下链接以获得视觉效果。
https://www.youtube.com/watch?v=0JQZmTT3KO0
https://3dscanexpert.com/qlone-3d-scanning-ios-app/
enter image description here
模型 IO api MDLMesh.newEllipsoid 创建圆顶,现在我们需要在圆顶的每个部分上放置瓷砖。
- 创建圆顶并获取顶点并使用顶点创建图块并将它们作为单独的 SCNNode 放置。
import UIKit
import SceneKit
import ARKit
import ModelIO
class ARDome : SCNNode {
private var sceneView: ARSCNView!
private var radius: Float = 0.0
private var radialSegments: Int = 0
private var verticalSegments: Int = 0
private var maxDistanceToFocusPoint: Float = 0.05
private var minSize = SIMD3<Float>(0.01, 0.01, 0.01)
var tilesContinuousHitCount = [SCNNode:Int]()
private var extent = SIMD3<Float>(0.01, 0.01, 0.01) {
didSet {
extent = max(extent, minSize)
}
}
init(sceneView: ARSCNView, radius: Float, radialSegments: Int, verticalSegments: Int) {
super.init()
self.sceneView = sceneView
self.radius = radius
self.radialSegments = radialSegments
self.verticalSegments = verticalSegments
//self.categoryBitMask = 0x0
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func domeSkeleton() {
let mesh = MDLMesh.newEllipsoid(withRadii: vector_float3(radius, radius, radius), radialSegments: radialSegments, verticalSegments: verticalSegments, geometryType: MDLGeometryType.lines, inwardNormals: true, hemisphere: true, allocator: nil)
self.geometry = SCNGeometry(mdlMesh: mesh)
self.geometry?.firstMaterial?.diffuse.contents = UIColor.systemYellow
self.geometry?.firstMaterial?.isDoubleSided = true
}
func placeTiles() {
guard let geometry = self.geometry else { return }
let vertices = helper.testim(geo: geometry)
let rings = vertices.chunked(into: radialSegments + 1)
for base in 0..<(verticalSegments/2) {
let bottom = base + 1
let top = base
for i in 0..<(radialSegments) {
let rectNode = helper.getNode(lb: rings[bottom][i], lt: rings[top][i], rt: rings[top][i+1], rb: rings[bottom][i+1])
self.addChildNode(rectNode)
}
}
}
}
import Foundation
import ARKit
class DomeTile: SCNNode {
public var processed = false
init(geometry: SCNGeometry) {
super.init()
self.geometry = geometry
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
帮手Class
import UIKit
import SceneKit
import ARKit
import ModelIO
class helper {
public static func getNode(lb: SCNVector3, lt: SCNVector3, rt: SCNVector3, rb: SCNVector3) -> DomeTile{
let vertices: [SCNVector3] = [lb, lt, rt, rb,]
let source = SCNGeometrySource(vertices: vertices)
let indices: [UInt16] = [0, 1, 2, 0, 2, 3,]
let element = SCNGeometryElement(indices: indices, primitiveType: .triangles)
let geometry = SCNGeometry(sources: [source], elements: [element])
geometry.firstMaterial?.isDoubleSided = true
geometry.firstMaterial?.diffuse.contents = UIColor.systemBlue.withAlphaComponent(0.7)
let node = DomeTile(geometry: geometry)
return node
}
public static func testim(geo: SCNGeometry) -> [SCNVector3] {
//let rect = SCNBox(width: 40.0, height: 40.0, length: 5.0, chamferRadius: 0.0)
let srcs = geo.sources(for: .vertex)
guard let src = srcs.first else { exit(1)}
let bperC = src.bytesPerComponent
let stride = src.dataStride / bperC
let offset = src.dataOffset / bperC
let vectorCount = src.vectorCount
let vertices = src.data.withUnsafeBytes { (buffer : UnsafePointer<Float>) -> [SCNVector3] in
var result = Array<SCNVector3>()
for i in 0...vectorCount - 1 {
let start = i * stride + offset
let x = buffer[start]
let y = buffer[start + 1]
let z = buffer[start + 2]
result.append(SCNVector3(x, y, z))
}
return result
}
return vertices
}
}
extension Array {
func chunked(into size: Int) -> [[Element]] {
return stride(from: 0, to: count, by: size).map {
Array(self[[=11=] ..< Swift.min([=11=] + size, count)])
}
}
}
我想在 Scenekit 中创建 AR 圆顶形状几何体,就像在 qlone 3D 扫描仪应用程序中创建的一样。 请参考以下链接以获得视觉效果。
https://www.youtube.com/watch?v=0JQZmTT3KO0
https://3dscanexpert.com/qlone-3d-scanning-ios-app/
enter image description here
模型 IO api MDLMesh.newEllipsoid 创建圆顶,现在我们需要在圆顶的每个部分上放置瓷砖。
- 创建圆顶并获取顶点并使用顶点创建图块并将它们作为单独的 SCNNode 放置。
import UIKit
import SceneKit
import ARKit
import ModelIO
class ARDome : SCNNode {
private var sceneView: ARSCNView!
private var radius: Float = 0.0
private var radialSegments: Int = 0
private var verticalSegments: Int = 0
private var maxDistanceToFocusPoint: Float = 0.05
private var minSize = SIMD3<Float>(0.01, 0.01, 0.01)
var tilesContinuousHitCount = [SCNNode:Int]()
private var extent = SIMD3<Float>(0.01, 0.01, 0.01) {
didSet {
extent = max(extent, minSize)
}
}
init(sceneView: ARSCNView, radius: Float, radialSegments: Int, verticalSegments: Int) {
super.init()
self.sceneView = sceneView
self.radius = radius
self.radialSegments = radialSegments
self.verticalSegments = verticalSegments
//self.categoryBitMask = 0x0
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func domeSkeleton() {
let mesh = MDLMesh.newEllipsoid(withRadii: vector_float3(radius, radius, radius), radialSegments: radialSegments, verticalSegments: verticalSegments, geometryType: MDLGeometryType.lines, inwardNormals: true, hemisphere: true, allocator: nil)
self.geometry = SCNGeometry(mdlMesh: mesh)
self.geometry?.firstMaterial?.diffuse.contents = UIColor.systemYellow
self.geometry?.firstMaterial?.isDoubleSided = true
}
func placeTiles() {
guard let geometry = self.geometry else { return }
let vertices = helper.testim(geo: geometry)
let rings = vertices.chunked(into: radialSegments + 1)
for base in 0..<(verticalSegments/2) {
let bottom = base + 1
let top = base
for i in 0..<(radialSegments) {
let rectNode = helper.getNode(lb: rings[bottom][i], lt: rings[top][i], rt: rings[top][i+1], rb: rings[bottom][i+1])
self.addChildNode(rectNode)
}
}
}
}
import Foundation
import ARKit
class DomeTile: SCNNode {
public var processed = false
init(geometry: SCNGeometry) {
super.init()
self.geometry = geometry
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
帮手Class
import UIKit
import SceneKit
import ARKit
import ModelIO
class helper {
public static func getNode(lb: SCNVector3, lt: SCNVector3, rt: SCNVector3, rb: SCNVector3) -> DomeTile{
let vertices: [SCNVector3] = [lb, lt, rt, rb,]
let source = SCNGeometrySource(vertices: vertices)
let indices: [UInt16] = [0, 1, 2, 0, 2, 3,]
let element = SCNGeometryElement(indices: indices, primitiveType: .triangles)
let geometry = SCNGeometry(sources: [source], elements: [element])
geometry.firstMaterial?.isDoubleSided = true
geometry.firstMaterial?.diffuse.contents = UIColor.systemBlue.withAlphaComponent(0.7)
let node = DomeTile(geometry: geometry)
return node
}
public static func testim(geo: SCNGeometry) -> [SCNVector3] {
//let rect = SCNBox(width: 40.0, height: 40.0, length: 5.0, chamferRadius: 0.0)
let srcs = geo.sources(for: .vertex)
guard let src = srcs.first else { exit(1)}
let bperC = src.bytesPerComponent
let stride = src.dataStride / bperC
let offset = src.dataOffset / bperC
let vectorCount = src.vectorCount
let vertices = src.data.withUnsafeBytes { (buffer : UnsafePointer<Float>) -> [SCNVector3] in
var result = Array<SCNVector3>()
for i in 0...vectorCount - 1 {
let start = i * stride + offset
let x = buffer[start]
let y = buffer[start + 1]
let z = buffer[start + 2]
result.append(SCNVector3(x, y, z))
}
return result
}
return vertices
}
}
extension Array {
func chunked(into size: Int) -> [[Element]] {
return stride(from: 0, to: count, by: size).map {
Array(self[[=11=] ..< Swift.min([=11=] + size, count)])
}
}
}