l30c0d35
l30c0d35

Reputation: 807

Pulling force between two physics bodies connected by a joint

What I am trying to do:

I created two SCNNodes and corresponding SCNPhysicsBodys (both dynamic and affected by gravity) and I wanted to connect them using a SCNPhysicsHingeJoint. Just to test things out node1 has an additional joint in order to be pinned into the scene and not fall down due to gravity. The nodes are connected to one another by joint. So when I start the scene node1 is just pinned into the scene and node2 is hanging downwards. Now I want to ascertain the force pulling on the joint which should be equals -9.8 (assuming no swinging) because the gravitational acceleration is equals -9.8 (default value for gravity property) and the default mass is equals 1 whereof the force pulling on the joint should make -9.8. I do not want to calculate that force pulling though because my scene is meant to get considerably more complicated. Therefore I was wondering whether there is a property or method for figuring out the pulling force between two nodes and there physics bodies connected by a joint?

let node1 = SCNNode(geometry: SCNCylinder(radius: 0.125, height: 2))
node1.position.x = -1.625
node1.rotation = SCNVector4(1, 0, 0, Float.pi/2)
node1.physicsBody = SCNPhysicsBody(type: .dynamic, shape: SCNPhysicsShape(geometry: node1.geometry!, options: nil))
node1.physicsBody!.isAffectedByGravity = true
node1.physicsBody!.categoryBitMask = 1
node1.physicsBody!.contactTestBitMask = 1
node1.physicsBody!.collisionBitMask = 1
rootNode.addChildNode(node1)

let node2 = SCNNode(geometry: SCNBox(width: 3, height: 0.25, length: 2, chamferRadius: 0))
node2.physicsBody = SCNPhysicsBody(type: .dynamic, shape: SCNPhysicsShape(geometry: node2.geometry!, options: nil))
node2.physicsBody!.isAffectedByGravity = true
node2.physicsBody!.categoryBitMask = 1
node2.physicsBody!.contactTestBitMask = 1
node2.physicsBody!.collisionBitMask = 1
rootNode.addChildNode(node2)

let irrelevantJoint = SCNPhysicsHingeJoint(body: node1.physicsBody!, axis: SCNVector3(0, 1, 0), anchor: SCNVector3(0, 0, -0.125))
physicsWorld.addBehavior(irrelevantJoint)

let joint = SCNPhysicsHingeJoint(bodyA: node1.physicsBody!, axisA: SCNVector3(0, 1, 0), anchorA: SCNVector3(0, 0, 0.125),
                                 bodyB: node2.physicsBody!, axisB: SCNVector3(0, 0, 1), anchorB: SCNVector3(-1.5, 0, 0))
physicsWorld.addBehavior(joint)

What I tried:

I was hoping I could use the SCNPhysicsContactDelegate and the physicsWorld(_:didEnd:) to get the force (or impulse) on joint. Whenever the method is called a SCNPhysicsContact is being created which lets you access its collisionImpulse property, so I was hoping for a negative impulse which was not the case. I just got and collisionImpulse of 0. Any ideas on how to get the pulling force between two physics bodies connected by a joint?

Upvotes: 1

Views: 225

Answers (2)

Prydwen
Prydwen

Reputation: 541

As isp-zax described you can use delta v decided by the time passed and thus ascertain the acceleration.

var node1: SCNNode!
var timestamp: TimeInterval = 0
var lastVelocity: SCNVector3 = SCNVector3()
func renderer(_ renderer: SCNSceneRenderer, updateAtTime time: TimeInterval) {
    let dt = time - timestamp
    timestamp = time

    let velocity = node1.physicsBody!.velocity
    let dv = velocity.y - lastVelocity.y
    let a = Double(dv) / dt
    lastVelocity = velocity

    print("vertical acceleration: \(a) and vertical force: \(node1.physicsBody!.mass * a)")
}

You have to assign the delegate property of the SCNView to the handler which implements the method above. Additionally you need the handler to conform to the SCNSceneRendererDelegate protocol. The code above just computes the vertical acceleration but you can do the same in y and z direction.

Upvotes: 1

isp-zax
isp-zax

Reputation: 3873

Game physics simulation does not require force calculation in the simple joints. Those are geometrical constraints and convergence is achieved by solver iterations. Force calculation is an additional expense that costs computational time and in a comprehensive solver would be enabled explicitly and disabled by default. Not all solvers have that and looking at the SCNPhysicsWorld I don't see any signs of it, so I am pretty sure it is not implemented.

On a positive note, I believe that the calculation of the forces applied to each body in your scene is quite simple. You just have to update the current frame and previous frame velocities of the body each frame and calculate acceleration as their difference divided by the timestamp. Multiply it by the body mass and this will give you the force. In the same way, you can calculate the angular velocity and torque, based on the inertia of the body.

If you do need the force and torque in the joint this isn't as simple so the only thing I can suggest is to describe how you were planning to use it to see if there is an alternative solution to achieve this final goal.

Upvotes: 1

Related Questions