I've setup a scene with SceneKit where a ball is rolling on a plan.
I've simulated the grass friction with applyForce() in order to make it stop after a while (dampen & friction parameters do not reach that effect).
Everything works well till I play with runtime parameters, like scnScene.physicsWorld.timeStep, sceneView.preferredFramesPerSecond and scnScene.physicsWorld.speed.
I did a comparison with default gravity.
Let's take a plan, with a light slope and launch a ball on it:
let planSlope = (Float.pi/180.0)*3.0
planNode.rotation = SCNVector4(x:0, y:0, z:1, w: planSlope)
...
let impulse = Float(ballMass) * speed // N.s = m*v
let forceVector = simd_float3(1.0, 0.0, 0.0)
let force = SCNVector3(forceVector * impulse)
ballNode.physicsBody?.applyForce(force, asImpulse: true)
The ball will climb the slope up till a certain distance and come back after.
If I change timeStep, FPS or speed, the ball is still reaching the same point. That's great.
Now, I disable gravity and create a custom force to simulate it using applyForce():
scnScene.physicsWorld.gravity = SCNVector3(0.0, 0.0, 0.0)
func physicsWorld(_ physicsWorld: SCNPhysicsWorld, didUpdate physicsContact: SCNPhysicsContact) {
...
let gravity = simd_float3(0.0, -9.8, 0.0)
let mass = (ballNode.physicsBody?.mass)!
let force = SCNVector3(gravity * Float(mass))
ballNode.physicsBody?.applyForce(force, asImpulse: false)
This gives exactly the same good result with default constants:
scnScene.physicsWorld.speed = 1.0
scnScene.physicsWorld.timeStep = 1.0/60.0
sceneView.preferredFramesPerSecond = 60
But as soon as I change one of them, the distance changes:
scnScene.physicsWorld.speed = 2.0
scnScene.physicsWorld.timeStep = 1.0/120.0
sceneView.preferredFramesPerSecond = 30
So, I needed to take them into account on the force:
func physicsWorld(_ physicsWorld: SCNPhysicsWorld, didUpdate physicsContact: SCNPhysicsContact) {
...
let gravity = simd_float3(0.0, -9.8, 0.0)
// Compensate timeStep & FPS & Speed !?
gravity *= Float(scnScene.physicsWorld.timeStep)/(1.0/60.0)
gravity *= (1.0/60.0)/(1.0/Float(sceneView.preferredFramesPerSecond))
gravity *= 1.0/Float(scnScene.physicsWorld.speed)
let mass = (ballNode.physicsBody?.mass)!
let force = SCNVector3(gravity * Float(mass))
ballNode.physicsBody?.applyForce(force, asImpulse: false)
That's weird, I guess I missed something?
The risk is that if FPS changes dynamically due to GPU overload, the result will differ.
Post
Replies
Boosts
Views
Activity
Hi,When adding a settings bundle to an Independent watchOS app, is-it expected to see the App name in the Settings app?In other word, is-it possible to manage settings thru Settings App in watchOS?Thx.
Hi,Is there a way to be informed on Apple Watch side that the connection with the iPhone is lost?The idea is to notify User that he probably forgot to take his iPhone.Thx.