distance calculation:I want to implement the same code functionality for distance calculation in Unity using SwiftUI. visionos

I use this piece of code in Unity to get the distance length of my model entering another model. I have set collision markers at the tip and end of the model and performed raycasting, but Unity currently does not support object tracking in VisionOS. Therefore, I plan to use SwiftUI for native development. In Reality Composer Pro, I haven't seen a collision editing feature like in Unity; I can only set the size of the collision body but cannot manually adjust or visualize the shape and size of my collision body.

I want to achieve similar functionality using SwiftUI, to be able to calculate and display the distance that my model A, like a needle or ruler, penetrates into another model or a physical object's interior. Is there a similar functionality available, or other coding methods to achieve this?

void CalculateLengthInsideOrgan()
{
    // Direction from the base of the probe to the tip
    Vector3 direction = probeTip.position - probeBase.position;
    float probeLength = direction.magnitude;

    // Raycasting
    RaycastHit[] hits = Physics.RaycastAll(probeBase.position, direction, probeLength, organLayerMask);
    if (hits.Length > 0)
    {
        // Calculate the length entering the organ
        float distanceToFirstHit = hits[0].distance;
        lengthInsideOrgan = probeLength - distanceToFirstHit;
    }
    else
    {
        lengthInsideOrgan = 0f;
    }
}

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!

distance calculation:I want to implement the same code functionality for distance calculation in Unity using SwiftUI. visionos
 
 
Q