【问题标题】:Setting up the Orientation of 3D Text in Arkit application在 Arkit 应用程序中设置 3D 文本的方向
【发布时间】:2018-06-06 08:14:35
【问题描述】:

我基本上有两个 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)

Line3:这基本上是垂直组件。所以,这条线的终点是:

(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)
}

如果有人能解释我在上述函数中所做的更改,我将非常高兴。这样所有三个文本都对用户清晰可见,并且不会相互重叠。

【问题讨论】:

    标签: ios swift arkit


    【解决方案1】:

    看着你的问题,我假设你想在你的两点之间居中显示你的 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

    希望对你有帮助...

    【讨论】:

    • 非常感谢伙计。这真的很有帮助!我还有一个疑问。我创建了一个函数,可以创建圆柱体。但在某些情况下它会失败。我可以发布它是一个新问题
    猜你喜欢
    • 1970-01-01
    • 2017-12-20
    • 1970-01-01
    • 1970-01-01
    • 2016-07-21
    • 1970-01-01
    • 2014-01-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多