У меня есть ARSCNView
, который позволяет пользователям рисовать в трехмерном пространстве. Рисунок выглядит хорошо, если мы посмотрим на него под углом камеры, где мы его нарисовали, как на изображении 1 . Но когда я смотрю на него под другим углом, он выглядит не по форме, как на изображении 2 . Конечно, пользователи ожидают, что кольцо не изменит форму, если они посмотрят на него под другим углом.
Следующий код:
- Получение точки касания в 2d с помощью распознаватель жестов
- Нахождение соответствующей 3D-точки с помощью метода
hitTest
на sceneView
- Запрос на построение линии от предыдущей точки до текущей точки.
Код
@objc func panGesture(_ gestureRecognizer: UIPanGestureRecognizer) {
gestureRecognizer.minimumNumberOfTouches = 1
let results = self.sceneView.hitTest(gestureRecognizer.location(in: gestureRecognizer.view), types: ARHitTestResult.ResultType.featurePoint)
guard let result = results.first else {
return
}
if gestureRecognizer.state == .began {
vector1 = SCNVector3Make(result.worldTransform.columns.3.x, result.worldTransform.columns.3.y, result.worldTransform.columns.3.z)
} else if gestureRecognizer.state == .changed {
let vector2 = SCNVector3Make(result.worldTransform.columns.3.x, result.worldTransform.columns.3.y, result.worldTransform.columns.3.z)
guard let vector1 = vector1 else {
self.vector1 = vector2
return
}
let line = lineFrom(vector: vector1, toVector: vector2)
let lineNode = SCNNode(geometry: line)
sceneView.scene.rootNode.addChildNode(lineNode)
self.vector1 = vector2
} else if gestureRecognizer.state == .ended {
vector1 = nil
}
}
Думаю, мне нужно нормализовать горизонтальное расстояние от текущего положения устройства до каждой точки на чертеже. Я попытался сделать это, изменив эту строку:
let vector2 = SCNVector3Make(result.worldTransform.columns.3.x, result.worldTransform.columns.3.y, result.worldTransform.columns.3.z)
на:
let vector2 = SCNVector3Make(result.worldTransform.columns.3.x, result.worldTransform.columns.3.y, vector1.z - currentCameraPositionRelativeToOrigin.z - currentCameraRotation.z)
Но это только усугубило проблему. Я был бы признателен за любые указатели в правильном направлении.
Изменить: вот код, который отображает aws фактические сегменты линии:
class func lineThrough(points: [SCNVector3], width:Int = 20, closed: Bool = false, color: CGColor = UIColor.black.cgColor, mitter: Bool = false) -> SCNGeometry {
// Becouse we cannot use geometry shaders in metal, every point on the line has to be changed into 4 verticles
let vertices: [SCNVector3] = points.flatMap { p in [p, p, p, p] }
// Create Geometry Source object
let source = SCNGeometrySource(vertices: vertices)
// Create Geometry Element object
var indices = Array((0..<Int32(vertices.count)))
if (closed) {
indices += [0, 1]
}
let element = SCNGeometryElement(indices: indices, primitiveType: .triangleStrip)
// Prepare data for vertex shader
// Format is line width, number of points, should mitter be included, should line create closed loop
let lineData: [Int32] = [Int32(width), Int32(points.count), Int32(mitter ? 1 : 0), Int32(closed ? 1 : 0)]
let geometry = SCNGeometry(sources: [source], elements: [element])
geometry.setValue(Data(bytes: lineData, count: MemoryLayout<Int32>.size*lineData.count), forKeyPath: "lineData")
// map verticles into float3
let floatPoints = vertices.map { float3($0) }
geometry.setValue(NSData(bytes: floatPoints, length: MemoryLayout<float3>.size * floatPoints.count), forKeyPath: "vertices")
// map color into float
let colorFloat = color.components!.map { Float($0) }
geometry.setValue(NSData(bytes: colorFloat, length: MemoryLayout<simd_float1>.size * color.numberOfComponents), forKey: "color")
// Set the shader program
let program = SCNProgram()
program.fragmentFunctionName = "thickLinesFragment"
program.vertexFunctionName = "thickLinesVertex"
geometry.program = program
return geometry
}