Realitykit - Add Force to Entity at Specific Point

RealityKit – Add force to Entity at specific point

I think you need the following approach.

First of all, apply generateCollisionShapes(...) instance method that activates collisions for given entities.

func generateCollisionShapes(recursive: Bool)

Secondly, use ray(...) method returning an optional tuple:

@MainActor func ray(through screenPoint: CGPoint) -> (origin: SIMD3<Float>, 
direction: SIMD3<Float>)?

Thirdly, use arView.scene.raycast(...) method that returns CollisionCastHit collection:

       func raycast(origin: SIMD3<Float>, 
direction: SIMD3<Float>,
length: Float = 100,
query: CollisionCastQueryType = .all,
mask: CollisionGroup = .all,
relativeTo referenceEntity: Entity? = nil) -> [CollisionCastHit]

Instance of CollisionCastHit can give you 4 subproperties:

CollisionCastHit().position
CollisionCastHit().entity
CollisionCastHit().distance
CollisionCastHit().normal

And at last, you already know the vector of force...

entity.physicsMotion?.linearVelocity = SIMD3<Float>()

Optionally, you might use an angular velocity of the body around the center of its mass.

entity.physicsMotion?.angularVelocity = SIMD3<Float>()

Move the centre of the force within Reality Composer scene

Physics forces are applied to the model's pivot position. At the moment, neither RealityKit nor Reality Composer has the ability to change the location of an object's pivot point.

In addition to the above, you've applied Add Force behavior that pushes an object along a specific vector with the definite velocity, however, user's taps occur along the local -Z axis of the screen. Do these vectors match?

And one more note: within the Reality-family, only rigid body dynamics is possible, not soft body.

Applying downward force to an object using RealityKit

Ollie trick

In real life, if you shift your entire body's weight to the nose of the skateboard's deck (like doing the Ollie Maneuver), the skateboard's center of mass shifts from the middle towards the point where the force is being applied. In RealityKit, if you need to tear the rear (front) wheels of the skateboard off the floor, move the model's center of mass towards the slope.

Sample Image

The repositioning of the center of mass occurs in a local coordinate system.

import SwiftUI
import RealityKit

struct ContentView : View {
var body: some View {
ARViewContainer().ignoresSafeArea()
}
}

struct ARViewContainer: UIViewRepresentable {

func makeUIView(context: Context) -> ARView {

let arView = ARView(frame: .zero)
arView.debugOptions = .showPhysics // shape visualization

let scene = try! Experience.loadScene()
let name = "skateboard_01_base_stylized_lod0"
typealias ModelPack = ModelEntity & HasPhysicsBody & HasCollision

let model = scene.findEntity(named: name) as! ModelPack
model.physicsBody = .init()
model.generateCollisionShapes(recursive: true)
model.physicsBody?.massProperties.centerOfMass.position = [0, 0,-27]

arView.scene.anchors.append(scene)
return arView
}

func updateUIView(_ uiView: ARView, context: Context) { }
}

Physics shape

The second problem that you need to solve is to replace the model's box shape of the physical body (RealityKit and Reality Composer generate this type of shape by default). Its shape cannot be in the form of a monolithic box, it's quite obvious, because the box-shaped form does not allow the force to be applied appropriately. You need a shape similar to the outline of the model.

Sample Image

So, you can use the following code to create a custom shape:

(four spheres for wheels and box for deck)

let shapes: [ShapeResource] = [ 
.generateBox(size: [ 20, 4, 78])
.offsetBy(translation: [ 0.0, 11, 0.0]),
.generateSphere(radius: 3.1)
.offsetBy(translation: [ 7.5, 3, 21.4]),
.generateSphere(radius: 3.1)
.offsetBy(translation: [ 7.5, 3,-21.4]),
.generateSphere(radius: 3.1)
.offsetBy(translation: [-7.5, 3, 21.4]),
.generateSphere(radius: 3.1)
.offsetBy(translation: [-7.5, 3,-21.4])
]

// model.physicsBody = PhysicsBodyComponent(shapes: shapes, mass: 4.5)

model.collision = CollisionComponent(shapes: shapes)

Sample Image

Sample Image

Sample Image

P.S.

Reality Composer model's settings (I used Xcode 14.0 RC 1).

Sample Image

Adding a Point Light in RealityKit

There's a couple of things here, the most noticeable is that your material is set to .blue, and you're trying to light it using a .red light. The material's made from the colour contains zero red (in rgb form), so the light will have no effect on it. If you're using glasses with a red filter on them, green and blue will just appear black, only the reds will shine through.

Even if you change it to a .white light, it won't look much different though. This is just what it looks like with the default SimpleMaterial with isMetallic set to true; all you'll see is reflections of light, rather than see a light hitting it.

This is because the roughness of the material is set to 0, increase it just a tiny bit you'll see the cube light up with your point light.

var material = SimpleMaterial(color: .blue, isMetallic: true)
material.roughness = 0.1

Also worth noting, your light intensity is quite high, I assume this is just because you weren't seeing an effect before!



Related Topics



Leave a reply



Submit