Post

Replies

Boosts

Views

Activity

Reply to version update in Vision Pro
Hi thanks for the reply! the problem I'm having is with the alignment of a model. I tap 2 times on a 3D model and then 2 times on a grid of spheres. after calculating the alignment the model should jump to it's new position on the grid of spheres and match the target points. I have an unknown visual offset after the alignment even though visually I can see the taps are in the correct place. I'll add a snippet of my alignment function and an image of the visual. the brute force offset you can see in the code was to try and move the alignment a meter to the left (which wasn't successful). func alignModel2Points() { guard let modelPointA = modelPointA, let modelPointB = modelPointB, let targetPointA = targetPointA, let targetPointB = targetPointB, let modelRootEntity = modelRootEntity, let modelAnchor = modelAnchor else { print("❌ Missing data for alignment") return } let offset = SIMD3(-1, 0, 0) let modelPointA_shifted = modelPointA + offset let modelPointB_shifted = modelPointB + offset let targetPointA_shifted = targetPointA + offset let targetPointB_shifted = targetPointB + offset modelRootEntity.position = .zero modelRootEntity.orientation = simd_quatf() modelRootEntity.scale = SIMD3<Float>(repeating: 1.0) pivotEntity?.position = .zero // 1) compute scale from the two segments let modelVec = modelPointB_shifted - modelPointA_shifted let targetVec = targetPointB_shifted - targetPointA_shifted let modelLen = length(modelVec) let targetLen = length(targetVec) guard modelLen > 1e-6 else { print("❌ model points coincide") return } let s = targetLen / modelLen // 2) compute rotation that aligns modelVec -> targetVec let modelDir = normalize(modelVec) let targetDir = normalize(targetVec) let crossProd = cross(modelDir, targetDir) let crossLen = length(crossProd) var rot: simd_quatf if crossLen < 1e-6 { // parallel or opposite if dot(modelDir, targetDir) > 0 { rot = simd_quatf(angle: 0, axis: [0,1,0]) } else { var tmp = cross(modelDir, [0,1,0]) if length(tmp) < 1e-6 { tmp = cross(modelDir, [1,0,0]) } rot = simd_quatf(angle: .pi, axis: normalize(tmp)) } } else { let dp = dot(modelDir, targetDir) let clamped = min(max(dp, -1.0), 1.0) let angle = acos(clamped) rot = simd_quatf(angle: angle, axis: normalize(crossProd)) } // 3) Compute world-space translation for the anchor: // We want: worldPoint = AnchorTransform * (rot * (s * modelPoint) + modelRootLocalPosition) // Since modelRootEntity is identity at origin, simplified: // translation = targetPointA - rot.act(modelPointA_shifted * s) let transformedModelA = rot.act(modelPointA_shifted * s) let translation = targetPointA - transformedModelA // 4) Build final Transform and set it on the modelAnchor (anchor is root — transform is world) var final = Transform() final.scale = SIMD3<Float>(repeating: s) final.rotation = rot final.translation = translation // Apply final transform to the anchor (this places the whole model in world space) modelAnchor.transform = final alignedModelPosition = modelAnchor.position alignmentDone = true // debug prints let modelA_world_after = modelRootEntity.convert(position: modelPointA_shifted, to: nil) let modelB_world_after = modelRootEntity.convert(position: modelPointB_shifted, to: nil) print(""" ✅ ALIGN: scale s = \(s) rotation = \(rot) translation = \(translation) modelA_world_after = \(modelA_world_after) targetA = \(targetPointA) modelB_world_after = \(modelB_world_after) targetB = \(targetPointB) finalAnchor = \(modelAnchor.position) """) // cleanup // removeAllMarkers() NotificationCenter.default.post(name: .alignmentDidComplete, object: nil) debugSpawnSpheres() printAlignmentOffsets() } func printAlignmentOffsets() { guard let mr = modelRootEntity, let mA = modelPointA, let mB = modelPointB, let tA = targetPointA, let tB = targetPointB else { return } let mA_world = mr.convert(position: mA, to: nil) let mB_world = mr.convert(position: mB, to: nil) let offsetA = tA - mA_world let offsetB = tB - mB_world print("DEBUG OFFSETS:") print(" mA_world = \(mA_world)") print(" tA = \(tA)") print(" offsetA = \(offsetA)") print(" mB_world = \(mB_world)") print(" tB = \(tB)") print(" offsetB = \(offsetB)") } func debugSpawnSpheres() { guard let c = content, let a = modelRootEntity, let A = modelPointA, let B = modelPointB, let tA = targetPointA, let tB = targetPointB else { return } let s = [(a.convert(position: A, to: nil), UIColor.red), (a.convert(position: B, to: nil), UIColor.orange), (tA, UIColor.green), (tB, UIColor.blue)] for (pos, color) in s { let e = ModelEntity(mesh: MeshResource.generateSphere(radius: 0.01), materials: [SimpleMaterial(color: color, isMetallic: false)]) e.position = pos c.add(e) allMarkers.append(e) } }
Oct ’25
Reply to Anchor an Reality scene on an image anchor
Hi ShanhaiLab, I'm encountering a similar issue with detecting my image and use it as an anchor. would love for your help in that matter as I see you succeeded! I'm trying to detect the image but the Vision Pro isn't detecting it. thanks!
Topic: Graphics & Games SubTopic: RealityKit Tags:
Replies
Boosts
Views
Activity
Sep ’25
Reply to Getting the world position of a QR code
Thanks for the reply! I'm in immersive space, my spheres are not showing up on the QR codes. what could be the problem? It might be in the way I upload my QR codes as a reference images? the script looks fine to you?
Replies
Boosts
Views
Activity
Oct ’25
Reply to version update in Vision Pro
Hi thanks for the reply! the problem I'm having is with the alignment of a model. I tap 2 times on a 3D model and then 2 times on a grid of spheres. after calculating the alignment the model should jump to it's new position on the grid of spheres and match the target points. I have an unknown visual offset after the alignment even though visually I can see the taps are in the correct place. I'll add a snippet of my alignment function and an image of the visual. the brute force offset you can see in the code was to try and move the alignment a meter to the left (which wasn't successful). func alignModel2Points() { guard let modelPointA = modelPointA, let modelPointB = modelPointB, let targetPointA = targetPointA, let targetPointB = targetPointB, let modelRootEntity = modelRootEntity, let modelAnchor = modelAnchor else { print("❌ Missing data for alignment") return } let offset = SIMD3(-1, 0, 0) let modelPointA_shifted = modelPointA + offset let modelPointB_shifted = modelPointB + offset let targetPointA_shifted = targetPointA + offset let targetPointB_shifted = targetPointB + offset modelRootEntity.position = .zero modelRootEntity.orientation = simd_quatf() modelRootEntity.scale = SIMD3<Float>(repeating: 1.0) pivotEntity?.position = .zero // 1) compute scale from the two segments let modelVec = modelPointB_shifted - modelPointA_shifted let targetVec = targetPointB_shifted - targetPointA_shifted let modelLen = length(modelVec) let targetLen = length(targetVec) guard modelLen > 1e-6 else { print("❌ model points coincide") return } let s = targetLen / modelLen // 2) compute rotation that aligns modelVec -> targetVec let modelDir = normalize(modelVec) let targetDir = normalize(targetVec) let crossProd = cross(modelDir, targetDir) let crossLen = length(crossProd) var rot: simd_quatf if crossLen < 1e-6 { // parallel or opposite if dot(modelDir, targetDir) > 0 { rot = simd_quatf(angle: 0, axis: [0,1,0]) } else { var tmp = cross(modelDir, [0,1,0]) if length(tmp) < 1e-6 { tmp = cross(modelDir, [1,0,0]) } rot = simd_quatf(angle: .pi, axis: normalize(tmp)) } } else { let dp = dot(modelDir, targetDir) let clamped = min(max(dp, -1.0), 1.0) let angle = acos(clamped) rot = simd_quatf(angle: angle, axis: normalize(crossProd)) } // 3) Compute world-space translation for the anchor: // We want: worldPoint = AnchorTransform * (rot * (s * modelPoint) + modelRootLocalPosition) // Since modelRootEntity is identity at origin, simplified: // translation = targetPointA - rot.act(modelPointA_shifted * s) let transformedModelA = rot.act(modelPointA_shifted * s) let translation = targetPointA - transformedModelA // 4) Build final Transform and set it on the modelAnchor (anchor is root — transform is world) var final = Transform() final.scale = SIMD3<Float>(repeating: s) final.rotation = rot final.translation = translation // Apply final transform to the anchor (this places the whole model in world space) modelAnchor.transform = final alignedModelPosition = modelAnchor.position alignmentDone = true // debug prints let modelA_world_after = modelRootEntity.convert(position: modelPointA_shifted, to: nil) let modelB_world_after = modelRootEntity.convert(position: modelPointB_shifted, to: nil) print(""" ✅ ALIGN: scale s = \(s) rotation = \(rot) translation = \(translation) modelA_world_after = \(modelA_world_after) targetA = \(targetPointA) modelB_world_after = \(modelB_world_after) targetB = \(targetPointB) finalAnchor = \(modelAnchor.position) """) // cleanup // removeAllMarkers() NotificationCenter.default.post(name: .alignmentDidComplete, object: nil) debugSpawnSpheres() printAlignmentOffsets() } func printAlignmentOffsets() { guard let mr = modelRootEntity, let mA = modelPointA, let mB = modelPointB, let tA = targetPointA, let tB = targetPointB else { return } let mA_world = mr.convert(position: mA, to: nil) let mB_world = mr.convert(position: mB, to: nil) let offsetA = tA - mA_world let offsetB = tB - mB_world print("DEBUG OFFSETS:") print(" mA_world = \(mA_world)") print(" tA = \(tA)") print(" offsetA = \(offsetA)") print(" mB_world = \(mB_world)") print(" tB = \(tB)") print(" offsetB = \(offsetB)") } func debugSpawnSpheres() { guard let c = content, let a = modelRootEntity, let A = modelPointA, let B = modelPointB, let tA = targetPointA, let tB = targetPointB else { return } let s = [(a.convert(position: A, to: nil), UIColor.red), (a.convert(position: B, to: nil), UIColor.orange), (tA, UIColor.green), (tB, UIColor.blue)] for (pos, color) in s { let e = ModelEntity(mesh: MeshResource.generateSphere(radius: 0.01), materials: [SimpleMaterial(color: color, isMetallic: false)]) e.position = pos c.add(e) allMarkers.append(e) } }
Replies
Boosts
Views
Activity
Oct ’25