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

我们两清 提交于 2019-12-01 08:39:09

问题


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. Here's a sample of my code in 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)

Even though the Physics Bodies are assigned the same catagoryBitMask as the gravity field, they just float there in zero G, only affected by the physicsworld gravity.


回答1:


Set the "downGravityCatagory" bit mask on the node:

dice.categoryBitMask = downGravityCatagory;

the physics's categoryBitMask is for physics collisions only.




回答2:


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?




回答3:


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

}

}


来源:https://stackoverflow.com/questions/31577723/lineargravityfield-is-not-affecting-physics-bodies-in-the-scene-scenekit

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!