简体   繁体   English

如何3D旋转Arkit文本(Swift4)

[英]how to 3d rotate arkit text (Swift4)

My code below takes text and places 3d text in argument reality. 我下面的代码接受文本并将3d文本置于实参中。 The problem is that I cannot rotate the text. 问题是我无法旋转文本。 I can just move it around in a 2d direction. 我可以沿2D方向移动它。 I would like to be move and rotate the text. 我想移动和旋转文本。 I dont know how to do this. 我不知道该怎么做。 I have not seen any online tutorials on this problem. 我还没有看到有关此问题的任何在线教程。 Currently this is a swift 4 problem. 当前,这是一个迅速的4问题。

    import UIKit
import SceneKit
import ARKit
class TextNode: SCNNode{
var textGeometry: SCNText!
init(text: String, depth: CGFloat = 1, font: String = "Helvatica", textSize: CGFloat = 3, colour: UIColor) {

    super.init()
    textGeometry = SCNText(string: text , extrusionDepth: depth)
    textGeometry.font = UIFont(name: font, size: textSize)
    textGeometry.flatness = 0
    textGeometry.firstMaterial?.diffuse.contents = colour
    self.geometry = textGeometry
    self.scale = SCNVector3(0.01, 0.01 , 0.01)
}

required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") }

}
extension ViewController: UITextFieldDelegate{

    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {

        if let textEntered = textField.text,
            let textRange = Range(range, in: textEntered) {

            let updatedText = textEntered.replacingCharacters(in: textRange, with: string)
            print("User Has Entered \(updatedText)")

            DispatchQueue.main.async {
                self.textNode.textGeometry.string = updatedText
            }
        }

        return true
    }


}


class ViewController: UIViewController {


    /////
var name: String?
@IBOutlet var theBar: UITextField!

@IBOutlet var augmentedRealityView: ARSCNView!

    //2. Create Our ARWorld Tracking Configuration
    let configuration = ARWorldTrackingConfiguration()

    //3. Create Our Session
    let augmentedRealitySession = ARSession()

    //4. Create A Variable To Store The Current Nodes Rotation Around It's Y-Axis
    var currentAngleY: Float = 0.0
    var isRotating = false
    var currentNode: SCNNode?


    /////
var textNode: TextNode!

fileprivate func judo() {
    augmentedRealityView.scene.rootNode.addChildNode(textNode)
    textNode.position = SCNVector3(0, 0, -1.5)
}



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

@IBAction func changeTextColour(){
    let snapShot = self.augmentedRealityView.snapshot()



    UIImageWriteToSavedPhotosAlbum(snapShot, self, #selector(image(_:didFinishSavingWithError:contextInfo:)), nil)
}

@objc func image(_ image: UIImage, didFinishSavingWithError error: Error?, contextInfo: UnsafeRawPointer) {
    if let error = error {
        print("Error Saving ARKit Scene \(error)")
    } else {
        print("ARKit Scene Successfully Saved")
    }}


    @objc func scaleCurrentNode(_ gesture: UIPinchGestureRecognizer) {

        if !isRotating, let selectedNode = currentNode{

            if gesture.state == .changed {

                let pinchScaleX: CGFloat = gesture.scale * CGFloat((selectedNode.scale.x))
                let pinchScaleY: CGFloat = gesture.scale * CGFloat((selectedNode.scale.y))
                let pinchScaleZ: CGFloat = gesture.scale * CGFloat((selectedNode.scale.z))
                selectedNode.scale = SCNVector3Make(Float(pinchScaleX), Float(pinchScaleY), Float(pinchScaleZ))
                gesture.scale = 1

            }

            if gesture.state == .ended {}
        }
    }

    @objc func rotateNode(_ gesture: UIRotationGestureRecognizer){

        if let selectedNode = currentNode{

            //1. Get The Current Rotation From The Gesture
            let rotation = Float(gesture.rotation)

            //2. If The Gesture State Has Changed Set The Nodes EulerAngles.y
            if gesture.state == .changed{
                isRotating = true
                selectedNode.eulerAngles.y = currentAngleY + rotation
            }

            //3. If The Gesture Has Ended Store The Last Angle Of The CurrentNode
            if(gesture.state == .ended) {
                currentAngleY = selectedNode.eulerAngles.y
                isRotating = false
            }
        }

    }



    override func viewDidLoad() {
        super.viewDidLoad()
        augmentedRealityView.automaticallyUpdatesLighting = true
        theBar.delegate = self as? UITextFieldDelegate
        textNode = TextNode(text: theBar.text!, colour: .white)
        augmentedRealityView.scene.rootNode.addChildNode(textNode)
        textNode.position = SCNVector3(0, 0, -1.5)
           augmentedRealityView.automaticallyUpdatesLighting = true
        //1. Run The ARSession
        augmentedRealityView.session = augmentedRealitySession
        augmentedRealitySession.run(configuration, options: [.resetTracking, .removeExistingAnchors])

        //2. Add A UIPinchGestureRecognizer So We Can Scale Our TextNode
        let scaleGesture = UIPinchGestureRecognizer(target: self, action: #selector(scaleCurrentNode(_:)))
        self.view.addGestureRecognizer(scaleGesture)

        //3. Add A Tap Gesture Recogizer So We Can Place Our TextNode
        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(placeOrAssignNode(_:)))
        self.view.addGestureRecognizer(tapGesture)

        //4. Add A Rotation Gesture Recogizer So We Can Rotate Our TextNode
        let rotateGesture = UIRotationGestureRecognizer(target: self, action: #selector(rotateNode(_:)))
        self.view.addGestureRecognizer(rotateGesture)
    }

    @objc func placeOrAssignNode(_ gesture: UITapGestureRecognizer){

        //1. Get The Current Location Of The Tap
        let currentTouchLocation = gesture.location(in: self.augmentedRealityView)

        //2. If We Hit An SCNNode Set It As The Current Node So We Can Interact With It
        if let nodeHitTest = self.augmentedRealityView.hitTest(currentTouchLocation, options: nil).first?.node{

            currentNode = nodeHitTest
            return
        }

        //3. Do An ARHitTest For Features Points So We Can Place An SCNNode
        if let hitTest = self.augmentedRealityView.hitTest(currentTouchLocation, types: .featurePoint).first {

            //4. Get The World Transform
            let hitTestPosition = hitTest.worldTransform.columns.3

            //5. Add The TestNode At The Desired Position
            createTextFromPosition(SCNVector3(hitTestPosition.x, hitTestPosition.y, hitTestPosition.z))
            return

        }

    }
    func createTextFromPosition(_ position: SCNVector3){

        let textNode = SCNNode()

        //1. Create The Text Geometry With String & Depth Parameters
        let textGeometry = SCNText(string: theBar.text! , extrusionDepth: 1)

        //2. Set The Font With Our Set Font & Size
        textGeometry.font = UIFont(name: "Helvatica", size: 1)

        //3. Set The Flatness To Zero (This Makes The Text Look Smoother)
        textGeometry.flatness = 0

        //4. Set The Colour Of The Text
        textGeometry.firstMaterial?.diffuse.contents = UIColor.white

        //5. Set The Text's Material
        textNode.geometry = textGeometry

        //6. Set The Pivot At The Center
        let min = textNode.boundingBox.min
        let max = textNode.boundingBox.max

        textNode.pivot = SCNMatrix4MakeTranslation(
            min.x + (max.x - min.x)/2,
            min.y + (max.y - min.y)/2,
            min.z + (max.z - min.z)/2
        )

        //7. Scale The Text So We Can Actually See It!
        textNode.scale = SCNVector3(0.005, 0.005 , 0.005)

        //8. Add It To The Hierachy & Position It
        self.augmentedRealityView.scene.rootNode.addChildNode(textNode)
        textNode.position = position

        //9. Set It As The Current Node
        currentNode = textNode
    }
    func changeColour(_ value: Int){
        if value == 0{
            textNode.textGeometry.firstMaterial?.diffuse.contents = UIColor.lightGray
        }
    }
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        if let name = UserDefaults.standard.value(forKey: "name") as? String{
            theBar.text = name
        }
        theBar.delegate = self as? UITextFieldDelegate
        if name == String(1) {
            textNode = TextNode(text: theBar.text!, colour: .red)
            augmentedRealityView.scene.rootNode.addChildNode(textNode)
            textNode.position = SCNVector3(0, 0, -1.5)
        }

        let configuration = ARWorldTrackingConfiguration()
        configuration.planeDetection = .horizontal
        augmentedRealityView.session.run(configuration)




    }
}
//////////////////////////////////////

A SCNNode object has a rotation property you can utilize. SCNNode对象具有可以使用的旋转属性。 I don't see where you're setting it in your code. 我看不到您在代码中的设置位置。

https://developer.apple.com/documentation/scenekit/scnnode/1408034-rotation https://developer.apple.com/documentation/scenekit/scnnode/1408034-rotation

// Sample code: Rotates node to the `heading`
public func nodeRotation(heading: Double) -> SCNVector4 {
    return SCNVector4(0, 1, 0, Double.pi - ((heading * (Double.pi/180)) - Double.pi))
}

textNode.rotation = nodeRotation(heading: 45.0)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM