Hi @YuThomas
RealityKit provides a raycast
method which should allow you to achieve a similar setup. For example, you can translate that bit of code into Swift as follows:
func calculateLengthInsideOrgan(scene: RealityKit.Scene,
probeBasePosition: SIMD3<Float>,
probeTipPosition: SIMD3<Float>,
organCollisionGroup: CollisionGroup) -> Float {
// Raycast against the organ collision group.
let hits = scene.raycast(from: probeBasePosition, to: probeTipPosition, mask: organCollisionGroup)
// Return the length entering the organ if the raycast hit an object in the organ collision group,
// otherwise return zero.
if let firstHit = hits.first {
let distanceToFirstHit = firstHit.distance
return distance(probeTipPosition, probeBasePosition) - distanceToFirstHit
} else {
return 0
}
}
Additionally, here's some sample code that demonstrates one way you could integrate this function into a RealityKit project with the behavior you're describing:
@State var probeBaseEntity: Entity = Entity()
@State var lengthInsideOrgan: Float = 0
var body: some View {
RealityView { content, attachments in
// Create an "organ" entity with sphere mesh.
let organEntity = Entity()
organEntity.components.set(ModelComponent(mesh: .generateSphere(radius: 0.25), materials: [SimpleMaterial()]))
// Optionally, create a custom collision group for this entity.
// This is similar to Unity's notion of a LayerMask.
let organCollisionGroup = CollisionGroup(rawValue: 1 << 1)
let organCollisionFilter = CollisionFilter(group: organCollisionGroup, mask: .all)
// Add the collision component to the entity so that it can be the target of raycasts.
let collisionComponent = CollisionComponent(shapes: [.generateSphere(radius: 0.25)], filter: organCollisionFilter)
organEntity.components.set(collisionComponent)
// Create the base of the probe entity.
let probeLength = Float(0.25)
let probeMaterial = SimpleMaterial(color: .gray, isMetallic: true)
probeBaseEntity = ModelEntity(mesh: .generateSphere(radius: 0.02), materials: [probeMaterial])
// Add a collision component and an input target component so that it can be the target of a drag gesture.
probeBaseEntity.generateCollisionShapes(recursive: false)
probeBaseEntity.components.set(InputTargetComponent())
// Create the body of the probe
let probeBodyEntity = Entity()
probeBodyEntity.components.set(ModelComponent(mesh: .generateBox(width: probeLength, height: 0.01, depth: 0.01), materials: [probeMaterial]))
probeBaseEntity.addChild(probeBodyEntity)
probeBodyEntity.position = [probeLength / 2, 0, 0]
// Create a subentity at the tip of the probe.
let probeTipEntity = Entity()
probeBaseEntity.addChild(probeTipEntity)
probeTipEntity.position = [probeLength, 0, 0]
// Position the root entities and add them to the scene.
organEntity.position = [0, 1, -1]
content.add(organEntity)
probeBaseEntity.position = [-0.6, 1, -1]
content.add(probeBaseEntity)
// Add the text attachment as a child of the probe base entity.
if let textAttachmentEntity = attachments.entity(for: "TextAttachment") {
probeBaseEntity.addChild(textAttachmentEntity)
textAttachmentEntity.position = [-0.1, 0, 0]
}
// Subscribe to the scene update event.
_ = content.subscribe(to: SceneEvents.Update.self) { event in
// Get the world position of the probe base and probe tip.
let probeBaseWorldPosition = probeBaseEntity.position(relativeTo: nil)
let probeTipWorldPosition = probeTipEntity.position(relativeTo: nil)
// Calculate the length of the probe that is inside any organs.
lengthInsideOrgan = calculateLengthInsideOrgan(scene: event.scene,
probeBasePosition: probeBaseWorldPosition,
probeTipPosition: probeTipWorldPosition,
organCollisionGroup: organCollisionGroup)
}
} attachments: {
// Create an attachment that displays the length inside the organ.
Attachment(id: "TextAttachment") {
Text("Length: \(lengthInsideOrgan)")
.padding()
.glassBackgroundEffect()
}
}.gesture(
// Allow the base of the probe to be moved with a drag gesture.
DragGesture()
.targetedToEntity(probeBaseEntity)
.onChanged({ value in
probeBaseEntity.position = value.convert(value.location3D,
from: .local,
to: .scene)
})
)
}
This code creates a sphere model with a CollisionComponent
to act as an "organ," along with a needle-like entity to act as a "probe." The probe can be dragged around, and it displays the output of the calculateLengthInsideOrgan()
method with an attachment that floats in space next to the probe.
Hope this helps, and let me know if you have any question!