linearGravityField() 不影响场景 SceneKit 中的物理体

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

我正在尝试使用 SCNPhysicsField.linearGravityField 对象来仅影响场景中的特定对象。问题是,我似乎无法让它影响任何事情。这是我在 Swift:

中的代码示例
let downGravityCatagory = 1 << 0
let fieldDown = SCNPhysicsField.linearGravityField()
let fieldUp = SCNPhysicsField.linearGravityField()
let fieldNode = SCNNode()

let sceneView = view as! SCNView
sceneView.scene = scene
sceneView.scene!.physicsWorld.gravity = SCNVector3(x: 0, y: 0, z: 0)

fieldDown.categoryBitMask = downGravityCatagory
fieldDown.active = true
fieldDown.strength = 3
fieldNode.physicsField = fieldDown
scene.rootNode.addChildNode(fieldNode)

var dice = SCNNode()
//I then attach geometry here
dice.physicsBody = SCNPhysicsBody(type: SCNPhysicsBodyType.Dynamic, shape: SCNPhysicsShape(geometry: dice.geometry!, options: nil))
dice.physicsBody?.categoryBitMask = downGravityCatagory
scene.rootNode.addChildNode(dice)

即使 Physics Bodies 被分配了与重力场相同的 catagoryBitMask,它们只是以零 G 漂浮在那里,仅受 physicsworld 重力影响。

在节点上设置 "downGravityCatagory" 位掩码:

dice.categoryBitMask = downGravityCatagory;

物理的 categoryBitMask 仅用于物理碰撞。

我正在努力让我的球落得更快。现在它下降得非常慢。我尝试使用这个答案。我想我很接近,但我真的不知道。代码:

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

有什么技巧可以得到 "real-world" 类型的引力吗?

根据@tedesignz 的建议,这里是稍微修改过的工作代码:

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...")

}

}