linearGravityField() is not affecting physics bodies in the scene SceneKit

前端 未结 3 486
半阙折子戏
半阙折子戏 2021-01-14 21:07

I\'m trying to use a SCNPhysicsField.linearGravityField object to affect only specific objects in my scene. The problem is, that I can\'t seem to get it to affect anything.

相关标签:
3条回答
  • 2021-01-14 21:38

    Set the "downGravityCatagory" bit mask on the node:

    dice.categoryBitMask = downGravityCatagory;
    

    the physics's categoryBitMask is for physics collisions only.

    0 讨论(0)
  • 2021-01-14 21:45

    I am trying to get my ball to fall faster. Right now it falls really slowly. I tried using this answer. I think I am close, but I do not really know. The code:

    import Cocoa
    import SceneKit
    
    class AppController : NSObject {
    
    @IBOutlet weak var _sceneView: SCNView!
    
    @IBOutlet weak var _pushButton: NSButton!
    
    @IBOutlet weak var _resetButton: NSButton!
    
    private let _mySphereNode = SCNNode()
    
    private let _gravityFieldNode = SCNNode()
    
    private let downGravityCategory = 1 << 0
    
    private func setupScene() {
    
        // setup ambient light source
        let ambientLightNode = SCNNode()
        ambientLightNode.light = SCNLight()
        ambientLightNode.light!.type = SCNLightTypeAmbient
        ambientLightNode.light!.color = NSColor(white: 0.35, alpha: 1.0).CGColor
        // add ambient light the scene
        _sceneView.scene!.rootNode.addChildNode(ambientLightNode)
    
        // setup onmidirectional light
        let omniLightNode = SCNNode()
        omniLightNode.light = SCNLight()
        omniLightNode.light!.type = SCNLightTypeOmni
        omniLightNode.light!.color = NSColor(white: 0.56, alpha: 1.0).CGColor
        omniLightNode.position = SCNVector3Make(0.0, 200.0, 0.0)
        _sceneView.scene!.rootNode.addChildNode(omniLightNode)
    
        // add plane
        let myPlane = SCNPlane(width: 125.0, height: 2000.0)
        myPlane.widthSegmentCount = 10
        myPlane.heightSegmentCount = 10
        myPlane.firstMaterial!.diffuse.contents = NSColor.orangeColor().CGColor
        myPlane.firstMaterial!.specular.contents = NSColor.whiteColor().CGColor
        let planeNode = SCNNode()
        planeNode.geometry = myPlane
        // rotote -90.0 degrees about the y-axis, then rotate -90.0 about the x-axis
        var rotMat = SCNMatrix4MakeRotation(-3.14/2.0, 0.0, 1.0, 0.0)
        rotMat = SCNMatrix4Rotate(rotMat, -3.14/2.0, 1.0, 0.0, 0.0)
        planeNode.transform = rotMat
        planeNode.position = SCNVector3Make(0.0, 0.0, 0.0)
        // add physcis to plane
        planeNode.physicsBody = SCNPhysicsBody.staticBody()
        // add plane to scene
        _sceneView.scene!.rootNode.addChildNode(planeNode)
    
    
        // gravity folks...
        // first, set the position for field effect
        let gravityField = SCNPhysicsField.linearGravityField()
        gravityField.categoryBitMask = downGravityCategory
        gravityField.active = true
        gravityField.strength = 3.0
        gravityField.exclusive = true
        _gravityFieldNode.physicsField = gravityField
        _sceneView.scene!.rootNode.addChildNode(_gravityFieldNode)
        // attach the sphere node to the scene's root node
        _mySphereNode.categoryBitMask = downGravityCategory
        _sceneView.scene!.rootNode.addChildNode(_mySphereNode)
    }
    
    private func setupBall() {
    
        let radius = 25.0
    
        // sphere geometry
        let mySphere = SCNSphere(radius: CGFloat(radius))
        mySphere.geodesic = true
        mySphere.segmentCount = 50
        mySphere.firstMaterial!.diffuse.contents = NSColor.purpleColor().CGColor
        mySphere.firstMaterial!.specular.contents = NSColor.whiteColor().CGColor
    
        // position sphere geometry, add it to node
        _mySphereNode.position = SCNVector3(0.0, CGFloat(radius), 0.0)
        _mySphereNode.geometry = mySphere
    
        // physics body and shape
        _mySphereNode.physicsBody = SCNPhysicsBody(type: .Dynamic, shape: SCNPhysicsShape(geometry: mySphere, options: nil))
        _mySphereNode.physicsBody!.mass = 0.125
    }
    
    private func stopBall() {
    
        _mySphereNode.geometry = nil
        _mySphereNode.physicsBody = nil
    }
    
    override func awakeFromNib() {
    
        // assign empty scene
        _sceneView.scene = SCNScene()
    
        setupScene()
    
        setupBall()
    }
    
    @IBAction func moveBall(sender: AnyObject) {
    
        let forceApplied = SCNVector3Make(35.0, 0.0, 0.0)
    
        if _mySphereNode.physicsBody?.isResting == true {
    
            _mySphereNode.physicsBody!.applyForce(forceApplied, impulse: true)
        }
        else if _mySphereNode.physicsBody?.isResting == false {
            print("ball not at rest...")
        }
        else {
            print("No physics associated with the node...")
        }
    
    }
    
    @IBAction func resetBall(sender: AnyObject) {
    
        // remove the ball from the sphere node
        stopBall()
    
        // reset the ball
        setupBall()
    }
    }
    

    Is there some trick to get "real-world" type gravity?

    0 讨论(0)
  • 2021-01-14 21:49

    Based on what @tedesignz suggested, here is the slightly modified working code:

    import Cocoa
    import SceneKit
    
    class AppController : NSObject, SCNPhysicsContactDelegate {
    
    @IBOutlet weak var _sceneView: SCNView!
    
    @IBOutlet weak var _pushButton: NSButton!
    
    @IBOutlet weak var _resetButton: NSButton!
    
    private let _mySphereNode = SCNNode()
    
    private let _myPlaneNode = SCNNode()
    
    private let _gravityFieldNode = SCNNode()
    
    private let BallType = 1
    private let PlaneType = 2
    private let GravityType = 3
    
    private func setupScene() {
    
        // setup ambient light source
        let ambientLightNode = SCNNode()
        ambientLightNode.light = SCNLight()
        ambientLightNode.light!.type = SCNLightTypeAmbient
        ambientLightNode.light!.color = NSColor(white: 0.35, alpha: 1.0).CGColor
        // add ambient light the scene
        _sceneView.scene!.rootNode.addChildNode(ambientLightNode)
    
        // setup onmidirectional light
        let omniLightNode = SCNNode()
        omniLightNode.light = SCNLight()
        omniLightNode.light!.type = SCNLightTypeOmni
        omniLightNode.light!.color = NSColor(white: 0.56, alpha: 1.0).CGColor
        omniLightNode.position = SCNVector3Make(0.0, 200.0, 0.0)
        _sceneView.scene!.rootNode.addChildNode(omniLightNode)
    
        // add plane
        let myPlane = SCNPlane(width: 125.0, height: 150.0)
        myPlane.widthSegmentCount = 10
        myPlane.heightSegmentCount = 10
        myPlane.firstMaterial!.diffuse.contents = NSColor.orangeColor().CGColor
        myPlane.firstMaterial!.specular.contents = NSColor.whiteColor().CGColor
        _myPlaneNode.geometry = myPlane
        // rotote -90.0 degrees about the y-axis, then rotate -90.0 about the x-axis
        var rotMat = SCNMatrix4MakeRotation(-3.14/2.0, 0.0, 1.0, 0.0)
        rotMat = SCNMatrix4Rotate(rotMat, -3.14/2.0, 1.0, 0.0, 0.0)
        _myPlaneNode.transform = rotMat
        _myPlaneNode.position = SCNVector3Make(0.0, 0.0, 0.0)
    
        // add physcis to plane
        _myPlaneNode.physicsBody = SCNPhysicsBody(type: .Static, shape: SCNPhysicsShape(geometry: myPlane, options: nil))
        // configure physics body
        _myPlaneNode.physicsBody!.contactTestBitMask = BallType
        _myPlaneNode.physicsBody!.collisionBitMask = BallType
        _myPlaneNode.physicsBody!.categoryBitMask = PlaneType
    
    
        // add plane to scene
        _sceneView.scene!.rootNode.addChildNode(_myPlaneNode)
        // add sphere node
        _sceneView.scene!.rootNode.addChildNode(_mySphereNode)
    
        // gravity folks...
        // first, set the position for field effect
        let gravityField = SCNPhysicsField.linearGravityField()
        gravityField.categoryBitMask = GravityType
        gravityField.active = true
        gravityField.direction = SCNVector3(0.0, -9.81, 0.0)
        print(gravityField.direction)
        gravityField.strength = 10.0
        gravityField.exclusive = true
        _gravityFieldNode.physicsField = gravityField
        _sceneView.scene!.rootNode.addChildNode(_gravityFieldNode)
    
        // set the default gravity to zero vector
        _sceneView.scene!.physicsWorld.gravity = SCNVector3(0.0, 0.0, 0.0)
    }
    
    private func setupBall() {
    
        let radius = 25.0
    
        // sphere geometry
        let mySphere = SCNSphere(radius: CGFloat(radius))
        mySphere.geodesic = true
        mySphere.segmentCount = 50
        mySphere.firstMaterial!.diffuse.contents = NSColor.purpleColor().CGColor
        mySphere.firstMaterial!.specular.contents = NSColor.whiteColor().CGColor
    
        // position sphere geometry, add it to node
        _mySphereNode.position = SCNVector3(0.0, CGFloat(radius), 0.0)
        _mySphereNode.geometry = mySphere
    
        // physics body and shape
        _mySphereNode.physicsBody = SCNPhysicsBody(type: .Dynamic, shape: SCNPhysicsShape(geometry: mySphere, options: nil))
        _mySphereNode.physicsBody!.mass = 0.125
        _mySphereNode.physicsBody!.contactTestBitMask = PlaneType
        _mySphereNode.physicsBody!.collisionBitMask = PlaneType
        _mySphereNode.physicsBody!.categoryBitMask = (BallType | GravityType)
    
    }
    
    private func stopBall() {
    
        _mySphereNode.geometry = nil
        _mySphereNode.physicsBody = nil
    }
    
    override func awakeFromNib() {
    
        // assign empty scene
        _sceneView.scene = SCNScene()
        // contact delegate
        _sceneView.scene!.physicsWorld.contactDelegate = self
    
        setupScene()
    
        setupBall()
    }
    
    @IBAction func moveBall(sender: AnyObject) {
    
        let forceApplied = SCNVector3Make(5.0, 0.0, 0.0)
    
        if _mySphereNode.physicsBody?.isResting == true {
    
            _mySphereNode.physicsBody!.applyForce(forceApplied, impulse: true)
        }
        else if _mySphereNode.physicsBody?.isResting == false {
            print("ball not at rest...")
        }
        else {
            print("No physics associated with the node...")
        }
    
    }
    
    @IBAction func resetBall(sender: AnyObject) {
    
        // remove the ball from the sphere node
        stopBall()
    
        // reset the ball
        setupBall()
    }
    
    
    /*** SCENEKIT DELEGATE METHODS ***/
    func physicsWorld(world: SCNPhysicsWorld, didBeginContact contact: SCNPhysicsContact) {
    
        print("we have contact...")
    
    }
    
    func physicsWorld(world: SCNPhysicsWorld, didEndContact contact: SCNPhysicsContact) {
    
        print("No longer touching...")
    
    }
    
    }
    
    0 讨论(0)
提交回复
热议问题