扩展SCNNode及其子级

时间:2018-06-23 09:26:27

标签: swift arkit

我正在制作一个简单的测量应用程序。目前,我将球体放置为SCNNodes,并在节点之间出现了一个标签,该标签显示了从节点1到节点2的线的长度。

这是创建标签的方式:

func addLabel() {
    let plane = SCNPlane(width: 0.07, height: 0.02)
    plane.cornerRadius = plane.height / 10

    let sks = SKScene(size: CGSize(width: plane.width * 10e3, height: plane.height * 10e3))
    sks.backgroundColor = UIColor(red: 0.1, green: 0.1, blue: 0.1, alpha: 0.7)

    currentLbl = SKLabelNode(text: "")
    currentLbl.fontSize = 110
    currentLbl.fontName = "Helvetica"
    currentLbl.verticalAlignmentMode = .center
    currentLbl.position = CGPoint(x: sks.frame.midX, y: sks.frame.midY)
    currentLbl.fontColor = .white

    sks.addChild(currentLbl)

    let material = SCNMaterial()
    material.isDoubleSided = true
    material.diffuse.contents = sks
    material.diffuse.contentsTransform = SCNMatrix4Translate(SCNMatrix4MakeScale(1, -1, 1), 0, 1, 0)

    plane.materials = [material]
    let node = SCNNode(geometry: plane)
    node.constraints = [SCNBillboardConstraint()]
    node.position = SCNVector3Make(0, 0, 0)
    let (minBound, maxBound) = node.boundingBox
    node.pivot = SCNMatrix4MakeTranslation( (maxBound.x + minBound.x)/2, minBound.y, 0.02/2)

    lblNodes.append(node)
    currentLblNode = node
    sceneView.scene.rootNode.addChildNode(node)
}

我想对这些标签节点的比例(在我的更新函数中)应用数学方程式,以保持两米的可读性。

var myNodes: [SCNNode] = []
let s = getMagicScalingNumber()

说我获得了上面的比例因子,并且有一个SCNNode数组,如何缩放所有节点及其各自的子节点,以便它们在视觉上保持比例。

如果SCNTransformConstraint()是这个选项,我将感谢一个实现它的示例。


修改:为澄清起见,我已经尝试过

currentLblNode.scale = SCNVector3Make(s, s, s)

似乎无效。

1 个答案:

答案 0 :(得分:4)

我知道这已经很晚了,但是我整理了一个例子,应该指出正确的方向。

在您的示例中,您实际上是在创建一个包含标签等的持有人SCNNode。

您可以将它们存储到[SCNNode]数组中,然后像这样转换它们的比例:

//--------------------------
// MARK: - ARSCNViewDelegate
//--------------------------

extension ViewController: ARSCNViewDelegate{

    func renderer(_ renderer: SCNSceneRenderer, updateAtTime time: TimeInterval) {

        if !nodesAdded.isEmpty, let currentCameraPosition = self.sceneView.pointOfView {
            updateScaleFromCameraForNodes(nodesAdded, fromPointOfView: currentCameraPosition)
        }

    }
}

class ViewController: UIViewController {

     @IBOutlet var sceneView: ARSCNView!

     var nodesAdded = [SCNNode]()

    //-----------------------
    // MARK: - View LifeCycle
    //-----------------------

    override func viewDidLoad() {
        super.viewDidLoad()

        //1. Generate Our Three Box Nodes
        generateBoxNodes()

        //2. Run The Session
        let configuration = ARWorldTrackingConfiguration()
        sceneView.session.run(configuration)
        sceneView.delegate = self

    }

    /// Generates Three SCNNodes With An SCNBox Geometry & Places Them In A Holder Node
    func generateBoxNodes(){

        //1. Create An SCNNode To Hold All Of Our Content
        let holderNode = SCNNode()

        //2. Create An Array Of Colours For Each Face
        let colours: [UIColor] = [.red, .green, .blue, .purple, .cyan, .black]

        //3. Create An SCNNode Wih An SCNBox Geometry
        let boxNode = SCNNode()
        let boxGeometry = SCNBox(width: 0.1, height: 0.1, length: 0.1, chamferRadius: 0.01)
        boxNode.geometry = boxGeometry

        //4. Create A Different Material For Each Face
        var materials = [SCNMaterial]()

        for i in 0..<5{
            let faceMaterial = SCNMaterial()
            faceMaterial.diffuse.contents = colours[i]
            materials.append(faceMaterial)
        }

        //5. Set The Geometries Materials
        boxNode.geometry?.materials = materials

        //6. Create Two More Nodes By Cloning The First One
        let secondBox = boxNode.flattenedClone()
        let thirdBox = boxNode.flattenedClone()

        //7. Position Them In A Line & Add To The Scene
        boxNode.position = SCNVector3(-0.2, 0, 0)
        secondBox.position = SCNVector3(0, 0, 0)
        thirdBox.position = SCNVector3(0.2, 0, 0)

        holderNode.addChildNode(boxNode)
        holderNode.addChildNode(secondBox)
        holderNode.addChildNode(thirdBox)
        holderNode.position = SCNVector3(0, 0, -1)
        self.sceneView.scene.rootNode.addChildNode(holderNode)

        nodesAdded.append(holderNode)
    }


    /// Updates The Contents Of Each Node Added To Our NodesAdded Array
    ///
    /// - Parameters:
    ///   - nodes: [SCNNode]
    ///   - pointOfView: SCNNode
    func updateScaleFromCameraForNodes(_ nodes: [SCNNode], fromPointOfView pointOfView: SCNNode){

        nodes.forEach { (node) in

            //1. Get The Current Position Of The Node
            let positionOfNode = SCNVector3ToGLKVector3(node.worldPosition)

            //2. Get The Current Position Of The Camera
            let positionOfCamera = SCNVector3ToGLKVector3(pointOfView.worldPosition)

            //3. Calculate The Distance From The Node To The Camera
            let distanceBetweenNodeAndCamera = GLKVector3Distance(positionOfNode, positionOfCamera)

            //4. Animate Their Scaling & Set Their Scale Based On Their Distance From The Camera
            SCNTransaction.begin()
            SCNTransaction.animationDuration = 0.5
            switch distanceBetweenNodeAndCamera {
            case 0 ... 0.5:
                node.simdScale = simd_float3(0.25, 0.25, 0.25)
            case 0.5 ... 1:
                node.simdScale = simd_float3(0.5, 0.5, 0.5)
            case 1 ... 1.5:
                node.simdScale = simd_float3(1, 1, 1)
            case 1.5 ... 2:
                node.simdScale = simd_float3(1.5, 1.5, 1.5)
            case 2 ... 2.5:
                node.simdScale = simd_float3(2, 2, 2)
            case 2.5 ... 3:
                node.simdScale = simd_float3(2.5, 2.5, 2.5)
            default:
                print("Default")
            }
            SCNTransaction.commit()
        }

    }


    override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) }

    override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) }

    override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() }

}

在这里,我只是设置“随机”值以说明比例尺的概念,具体取决于距相机的距离。

为了更好地说明这一点,这里提供了一个小样:

 const styles = {root: {
    height: 500,
    width: 200},}; 

希望这对您有帮助...