在 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

希望对您有所帮助...