SceneKit custom physics fields using wrong position?

In the simplest case I can come up with, I create a scene (either fully or partially in code) with a single dynamic body, located slightly away from the origin.

I give the body a charge as well as adding an electric field to the node. Body does nothing (as to be expected, since it's the source of the field).

However if I replace that field with a custom field (does nothing except reports back the passed in position value) the position shown is the location of the body in the local space of its parent (in this case, the root node) rather than the node the field is attached to (i.e. itself).

I've attached the code customising the SwiftUI app template. Hopefully someone can tell me what I'm doing wrong?

ContentView customisation…

struct ContentView: View
{
	var body: some View
	{
		SceneView(scene: ElectricScene(), options: [.allowsCameraControl, .autoenablesDefaultLighting])
	}
}

And the code to create the scene…

import Foundation
import SceneKit

class ElectricScene: SCNScene
{
	override init()
	{
		super.init()
		physicsWorld.gravity = SCNVector3(0, 0, 0)

		let cameraNode = SCNNode()
		cameraNode.camera = SCNCamera()
		cameraNode.position = SCNVector3(0, 0, 10)
		rootNode.addChildNode(cameraNode)

		let ballNode = SCNNode(geometry: SCNSphere(radius: 0.5))
		ballNode.position = SCNVector3(2, 0, 0)
		ballNode.physicsBody = SCNPhysicsBody(type: .dynamic, shape: nil)
		ballNode.physicsBody?.charge = -1
		rootNode.addChildNode(ballNode)

//		ballNode.physicsField = SCNPhysicsField.electric()
		ballNode.physicsField = SCNPhysicsField
			.customField {position, _, _, _, _ in
				print(position)
				return SCNVector3Zero
		}
}

	@available(*, unavailable)
	required init?(coder: NSCoder)
	{
		fatalError("init(coder:) has not been implemented")
	}
}

This (repeatedly) prints out the following…

SCNVector3(x: 2.0, y: 0.0, z: 0.0)

…which is the position of the node relative to the root node, rather than relative to the source of the field (itself).

Answered by DTS Engineer in 813110022

Hello @reflexx,

Thanks for posting this question!

The behavior I'm observing is that the position is given to you in world space. This contradicts the documentation, so you should file a bug report using Feedback Assistant.

You can convert the world space position to the local space you were expecting with the following code:

ballNode.physicsField = SCNPhysicsField
	.customField {position, _, _, _, _ in
	    print(position)
        let localPosition = ballNode.convertPosition(position, from: nil)
        print(localPosition)
	    return SCNVector3Zero
}

Best regards,

Greg

Hello @reflexx,

Thanks for posting this question!

The behavior I'm observing is that the position is given to you in world space. This contradicts the documentation, so you should file a bug report using Feedback Assistant.

You can convert the world space position to the local space you were expecting with the following code:

ballNode.physicsField = SCNPhysicsField
	.customField {position, _, _, _, _ in
	    print(position)
        let localPosition = ballNode.convertPosition(position, from: nil)
        print(localPosition)
	    return SCNVector3Zero
}

Best regards,

Greg

SceneKit custom physics fields using wrong position?
 
 
Q