Настройка ориентации 3D текста в приложении Arkit - PullRequest
0 голосов
/ 04 июня 2018

У меня в основном есть две 3D-точки.Предположим, что координаты двух точек:

(x: 1, y: 1, z: 1) и (x: 2, y: 2, z: 2).

В основном у меня есть три линии:

Линия 1: непосредственно соединяет точку1 и точка 2. Итак, конечными точками этой линии являются:

(x: 1, y: 1, z: 1) и (x: 2, y: 2, z: 2).

Линия 2: Это в основном горизонтальный компонент.Итак, конечные точки этой линии:

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

Я был бы очень рад, если бы кто-то мог объяснить изменения, которые будут сделаны в моей вышеупомянутой функции.Чтобы все три текста были хорошо видны пользователю и не перекрывали друг друга.

1 Ответ

0 голосов
/ 06 июня 2018

Глядя на ваш вопрос, я предполагаю, что вы хотите, чтобы ваш 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)

}

Если вам это интересно, вы можете получить более подробный и подробный пример здесь: Измерение вARKit

Надеюсь, это поможет ...

...