在 Arkit 应用程序中设置 3D 文本的方向
Setting up the Orientation of 3D Text in Arkit application
我基本上有两个 3D 点。让我们假设两点的坐标是:
(x: 1, y: 1, z: 1)
和 (x: 2, y: 2, z: 2)
.
基本上,我有三行:
Line1:直接连接点1和点2。所以,这条线的终点是:
(x: 1, y: 1, z: 1)
和 (x: 2, y: 2, z: 2)
.
Line2:这基本上是水平分量。所以,这条线的终点是:
(x: 1, y: 1, z: 1)
和 (x: 2, y: 2, z: 1)
.
第 3 行:这基本上是垂直分量。所以,这条线的终点是:
(x: 1, y: 1, z: 1)
和 (x: 1, y: 1, z: 2)
.
现在,我正在尝试添加 3D 文本。我想在我的行上方显示我的文本。因为我有三行,所以我将显示三个文本。所以,我想知道文本的坐标(对于所有三个不同的行,这样它们就不会重叠)以及为文本设置的方向(这样它们总是对用户正确可见,即使如果他旋转手机等)。
创建文字如下:
func AddText(pos1: SCNVector3?, pos2: SCNVector3?) {
var txtNode = SCNNode()
let d = self.distanceBetweenPoints(A: pos1!, B: pos2!)
let distanceString = String(format: "%.2f", d)
let txtGeometry = SCNText(string: distanceString, extrusionDepth: 1.0)
txtGeometry.firstMaterial?.diffuse.contents = UIColor.red
txtGeometry.alignmentMode = kCAAlignmentCenter
txtGeometry.truncationMode = kCATruncationMiddle
txtNode.removeFromParentNode()
txtNode = SCNNode(geometry: txtGeometry)
txtNode.position = SCNVector3(((pos1?.x)! + (pos2?.x)!)/2, ((pos1?.y)! + (pos2?.y)!)/2, ((pos1?.z)! + (pos2?.z)!)/2)
txtNode.scale = SCNVector3(0.005, 0.005, 0.005)
sceneView.scene.rootNode.addChildNode(txtNode)
}
如果有人能解释一下我在上面的函数中所做的更改,我将非常高兴。这样所有三个文本都对用户清晰可见并且不会相互重叠。
看着你的问题,我假设你想在你的两点之间和它们之间的线上方集中显示你的 SCNText,并响应相机位置的变化,例如永远面对当下pointOfView
.
因此我创建了一个 SCNNode Subclass
可以相对轻松地处理此问题:
class TextNode: SCNNode{
var textGeometry: SCNText!
/// Creates An SCNText Geometry
///
/// - Parameters:
/// - text: String (The Text To Be Displayed)
/// - depth: Optional CGFloat (Defaults To 1)
/// - font: UIFont
/// - textSize: Optional CGFloat (Defaults To 3)
/// - colour: UIColor
init(text: String, depth: CGFloat = 1, font: String = "Helvatica", textSize: CGFloat = 0.1, colour: UIColor) {
super.init()
//1. Create A Billboard Constraint So Our Text Always Faces The Camera
let constraints = SCNBillboardConstraint()
//2. Create An SCNNode To Hold Out Text
let node = SCNNode()
let max, min: SCNVector3
let tx, ty, tz: Float
//3. Set Our Free Axes
constraints.freeAxes = .Y
//4. Create Our Text Geometry
textGeometry = SCNText(string: text, extrusionDepth: depth)
//5. Set The Flatness To Zero (This Makes The Text Look Smoother)
textGeometry.flatness = 0
//6. Set The Alignment Mode Of The Text
textGeometry.alignmentMode = kCAAlignmentCenter
//7. Set Our Text Colour & Apply The Font
textGeometry.firstMaterial?.diffuse.contents = colour
textGeometry.firstMaterial?.isDoubleSided = true
textGeometry.font = UIFont(name: font, size: textSize)
//8. Position & Scale Our Node
max = textGeometry.boundingBox.max
min = textGeometry.boundingBox.min
tx = (max.x - min.x) / 2.0
ty = min.y
tz = Float(depth) / 2.0
node.geometry = textGeometry
node.scale = SCNVector3(0.001, 0.001, 0.001)
node.pivot = SCNMatrix4MakeTranslation(tx, ty, tz)
self.addChildNode(node)
self.constraints = [constraints]
}
/// Places The TextNode Between Two SCNNodes
///
/// - Parameters:
/// - nodeA: SCNode
/// - nodeB: SCNode
func placeBetweenNodes(_ nodeA: SCNNode, and nodeB: SCNNode){
let minPosition = nodeA.position
let maxPosition = nodeB.position
let x = ((maxPosition.x + minPosition.x)/2.0)
let y = (maxPosition.y + minPosition.y)/2.0 + 0.01
let z = (maxPosition.z + minPosition.z)/2.0
self.position = SCNVector3(x, y, z)
}
required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") }
}
如何使用它的示例如下(请注意,我没有在节点之间划线)但是这应该为您指明正确的方向:
/// Generates Two SCNNodes & Places An SCNTextGeometry Between Them
func generateNodes(){
//1. Create An SCNSphere
let sphereNode = SCNNode()
let sphereNodeGeometry = SCNSphere(radius: 0.01)
sphereNodeGeometry.firstMaterial?.diffuse.contents = UIColor.cyan
sphereNode.geometry = sphereNodeGeometry
//2. Add The Starter Node And Place It 0.5m To The Left Of Our World Origin
let starterNode = sphereNode.clone()
starterNode.position = SCNVector3(-0.5, 0, -0.5)
self.augmentedRealityView.scene.rootNode.addChildNode(starterNode)
//3. Add The End Node And Place It 0.5m To The Right Of Our World Origin
let endNode = sphereNode.clone()
endNode.position = SCNVector3(0.5, 0, -0.5)
self.augmentedRealityView.scene.rootNode.addChildNode(endNode)
//4. Although We Know The Distance Between The Nodes Is 1m, Calculate It Anyway
if let formattedDistance = calculateDistanceBetween(starterNode, and: endNode)?.distance{
//5. Create The Distance Label
let distanceLabel = TextNode(text: "\(formattedDistance)m", colour: .white)
//6. Call The TextNode Place Between Nodes Function To Center The Text Between The Nodes
distanceLabel.placeBetweenNodes(starterNode, and: endNode)
//7. Add It To Our Scene
self.augmentedRealityView.scene.rootNode.addChildNode(distanceLabel)
}
}
/// Calculates The Distance Between Two SCNNodes
///
/// -
/// - Returns: (distance: Float, nodeA: GLKVector3, nodeB: GLKVector3)
func calculateDistanceBetween(_ starterNode: SCNNode, and endNode: SCNNode) -> (distance: Float, nodeA: GLKVector3, nodeB: GLKVector3)?{
//1. Convert The SCNVector3 Positions To GLKVector3
let nodeAVector3 = GLKVector3Make(starterNode.position.x, starterNode.position.y, starterNode.position.z)
let nodeBVector3 = GLKVector3Make(endNode.position.x, endNode.position.y, endNode.position.z)
//2. Calculate The Distance
let distance = GLKVector3Distance(nodeAVector3, nodeBVector3)
let meters = Measurement(value: Double(distance), unit: UnitLength.meters)
print("Distance Between Markers Nodes = \(String(format: "%.2f", meters.value))m")
//4. Return The Distance A Positions Of The Nodes
return (distance: distance , nodeA: nodeAVector3, nodeB: nodeBVector3)
}
如果您有兴趣,可以从这里获得更深入和完整评论的示例:Measuring In ARKit
希望对您有所帮助...
我基本上有两个 3D 点。让我们假设两点的坐标是:
(x: 1, y: 1, z: 1)
和 (x: 2, y: 2, z: 2)
.
基本上,我有三行:
Line1:直接连接点1和点2。所以,这条线的终点是:
(x: 1, y: 1, z: 1)
和 (x: 2, y: 2, z: 2)
.
Line2:这基本上是水平分量。所以,这条线的终点是:
(x: 1, y: 1, z: 1)
和 (x: 2, y: 2, z: 1)
.
第 3 行:这基本上是垂直分量。所以,这条线的终点是:
(x: 1, y: 1, z: 1)
和 (x: 1, y: 1, z: 2)
.
现在,我正在尝试添加 3D 文本。我想在我的行上方显示我的文本。因为我有三行,所以我将显示三个文本。所以,我想知道文本的坐标(对于所有三个不同的行,这样它们就不会重叠)以及为文本设置的方向(这样它们总是对用户正确可见,即使如果他旋转手机等)。
创建文字如下:
func AddText(pos1: SCNVector3?, pos2: SCNVector3?) {
var txtNode = SCNNode()
let d = self.distanceBetweenPoints(A: pos1!, B: pos2!)
let distanceString = String(format: "%.2f", d)
let txtGeometry = SCNText(string: distanceString, extrusionDepth: 1.0)
txtGeometry.firstMaterial?.diffuse.contents = UIColor.red
txtGeometry.alignmentMode = kCAAlignmentCenter
txtGeometry.truncationMode = kCATruncationMiddle
txtNode.removeFromParentNode()
txtNode = SCNNode(geometry: txtGeometry)
txtNode.position = SCNVector3(((pos1?.x)! + (pos2?.x)!)/2, ((pos1?.y)! + (pos2?.y)!)/2, ((pos1?.z)! + (pos2?.z)!)/2)
txtNode.scale = SCNVector3(0.005, 0.005, 0.005)
sceneView.scene.rootNode.addChildNode(txtNode)
}
如果有人能解释一下我在上面的函数中所做的更改,我将非常高兴。这样所有三个文本都对用户清晰可见并且不会相互重叠。
看着你的问题,我假设你想在你的两点之间和它们之间的线上方集中显示你的 SCNText,并响应相机位置的变化,例如永远面对当下pointOfView
.
因此我创建了一个 SCNNode Subclass
可以相对轻松地处理此问题:
class TextNode: SCNNode{
var textGeometry: SCNText!
/// Creates An SCNText Geometry
///
/// - Parameters:
/// - text: String (The Text To Be Displayed)
/// - depth: Optional CGFloat (Defaults To 1)
/// - font: UIFont
/// - textSize: Optional CGFloat (Defaults To 3)
/// - colour: UIColor
init(text: String, depth: CGFloat = 1, font: String = "Helvatica", textSize: CGFloat = 0.1, colour: UIColor) {
super.init()
//1. Create A Billboard Constraint So Our Text Always Faces The Camera
let constraints = SCNBillboardConstraint()
//2. Create An SCNNode To Hold Out Text
let node = SCNNode()
let max, min: SCNVector3
let tx, ty, tz: Float
//3. Set Our Free Axes
constraints.freeAxes = .Y
//4. Create Our Text Geometry
textGeometry = SCNText(string: text, extrusionDepth: depth)
//5. Set The Flatness To Zero (This Makes The Text Look Smoother)
textGeometry.flatness = 0
//6. Set The Alignment Mode Of The Text
textGeometry.alignmentMode = kCAAlignmentCenter
//7. Set Our Text Colour & Apply The Font
textGeometry.firstMaterial?.diffuse.contents = colour
textGeometry.firstMaterial?.isDoubleSided = true
textGeometry.font = UIFont(name: font, size: textSize)
//8. Position & Scale Our Node
max = textGeometry.boundingBox.max
min = textGeometry.boundingBox.min
tx = (max.x - min.x) / 2.0
ty = min.y
tz = Float(depth) / 2.0
node.geometry = textGeometry
node.scale = SCNVector3(0.001, 0.001, 0.001)
node.pivot = SCNMatrix4MakeTranslation(tx, ty, tz)
self.addChildNode(node)
self.constraints = [constraints]
}
/// Places The TextNode Between Two SCNNodes
///
/// - Parameters:
/// - nodeA: SCNode
/// - nodeB: SCNode
func placeBetweenNodes(_ nodeA: SCNNode, and nodeB: SCNNode){
let minPosition = nodeA.position
let maxPosition = nodeB.position
let x = ((maxPosition.x + minPosition.x)/2.0)
let y = (maxPosition.y + minPosition.y)/2.0 + 0.01
let z = (maxPosition.z + minPosition.z)/2.0
self.position = SCNVector3(x, y, z)
}
required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") }
}
如何使用它的示例如下(请注意,我没有在节点之间划线)但是这应该为您指明正确的方向:
/// Generates Two SCNNodes & Places An SCNTextGeometry Between Them
func generateNodes(){
//1. Create An SCNSphere
let sphereNode = SCNNode()
let sphereNodeGeometry = SCNSphere(radius: 0.01)
sphereNodeGeometry.firstMaterial?.diffuse.contents = UIColor.cyan
sphereNode.geometry = sphereNodeGeometry
//2. Add The Starter Node And Place It 0.5m To The Left Of Our World Origin
let starterNode = sphereNode.clone()
starterNode.position = SCNVector3(-0.5, 0, -0.5)
self.augmentedRealityView.scene.rootNode.addChildNode(starterNode)
//3. Add The End Node And Place It 0.5m To The Right Of Our World Origin
let endNode = sphereNode.clone()
endNode.position = SCNVector3(0.5, 0, -0.5)
self.augmentedRealityView.scene.rootNode.addChildNode(endNode)
//4. Although We Know The Distance Between The Nodes Is 1m, Calculate It Anyway
if let formattedDistance = calculateDistanceBetween(starterNode, and: endNode)?.distance{
//5. Create The Distance Label
let distanceLabel = TextNode(text: "\(formattedDistance)m", colour: .white)
//6. Call The TextNode Place Between Nodes Function To Center The Text Between The Nodes
distanceLabel.placeBetweenNodes(starterNode, and: endNode)
//7. Add It To Our Scene
self.augmentedRealityView.scene.rootNode.addChildNode(distanceLabel)
}
}
/// Calculates The Distance Between Two SCNNodes
///
/// -
/// - Returns: (distance: Float, nodeA: GLKVector3, nodeB: GLKVector3)
func calculateDistanceBetween(_ starterNode: SCNNode, and endNode: SCNNode) -> (distance: Float, nodeA: GLKVector3, nodeB: GLKVector3)?{
//1. Convert The SCNVector3 Positions To GLKVector3
let nodeAVector3 = GLKVector3Make(starterNode.position.x, starterNode.position.y, starterNode.position.z)
let nodeBVector3 = GLKVector3Make(endNode.position.x, endNode.position.y, endNode.position.z)
//2. Calculate The Distance
let distance = GLKVector3Distance(nodeAVector3, nodeBVector3)
let meters = Measurement(value: Double(distance), unit: UnitLength.meters)
print("Distance Between Markers Nodes = \(String(format: "%.2f", meters.value))m")
//4. Return The Distance A Positions Of The Nodes
return (distance: distance , nodeA: nodeAVector3, nodeB: nodeBVector3)
}
如果您有兴趣,可以从这里获得更深入和完整评论的示例:Measuring In ARKit
希望对您有所帮助...