How could I create AnchorEntity in RealityKit without .image?

Hi, everybody !

For example one of the possible option to create AnchorEntity for RealityKit is provided below:
Code Block
let imageAnchor = AnchorEntity(.image(group:"group_name", name:"image_name"))
self.arView.scene.anchors.append(imageAnchor)

But, is it possible to create AnchorEntity, for example, from ARReferenceImage? Something like that:
Code Block
let referenceImage = ARReferenceImage(self.image.cgImage!, orientation: self.getCGOrientationFromUIImage(self.image), physicalWidth: width)
let imageAnchor = AnchorEntity(.image(referenceImage))

I want to download image from the internet and use it for creating AnchorEntity. Is there any way for solving such problem?


Answered by brandonK212 in 622241022
As far as I understand your inquiry, this should be possible to do. There are a few steps and considerations you will need to take, but as a whole, you should be able to download reference images (and some relevant metadata) from a web-based resource, instantiate a set of ARReferenceImages, and use those ARReferenceImages as anchors for your AR session. In my mind, you would need to take these steps;

  • Begin an ARWorldTrackingConfiguration or ARImageTrackingConfiguration so your users have a responsive experience and see the camera feed immediately.

  • Create an empty set of ARReferenceImages, which will be used to hold your downloaded images.

  • Download the necessary images from your web-based resource, using a common URLSession (or any optimal method for downloading images).

  • Instantiate an ARReferenceImage for each of your downloaded images. Note that you will also need to have awareness of the image's orientation, as well as the image's physical width in the real world (you may want to have some data, such as a JSON file, that contains the URLs of each image, alongside their real-world size, in meters).

  • Insert each of your new ARReferenceImages to the empty ARReferenceImages set.

  • Reset your session and configure a new ARWorldTrackingConfiguration or ARImageTrackingConfiguration, setting your newly created ARReferenceImages set to the configuration's detectionImages or trackingImages property, respectively.

  • Instantiate an AnchorEntity from the ARImageAnchor, which you should receive in a delegate method whenever a tracked image is found.

If I were to build an app trying to achieve this, I'd go step by step.

Set Up A Session For A Responsive Experience
Assuming you already have a RealityKit project going, you could add this in your viewDidLoad method.

Code Block
let configuration = ARWorldTrackingConfiguration()
sceneView.session.run(configuration)


Create An Empty Set of ARReferenceImages
You could add this to a local function or as a property accessible to your entire ViewController or class.

Code Block
var newReferenceImages: Set<ARReferenceImage> = Set<ARReferenceImage>()


Download the Images
You can use an asynchronous URLSession to download your images (and any relevant metadata). This should return each image as a UIImage. As your question focuses more on ARKit/RealityKit, this is being skipped, but you should be able to find plenty of resources with regards to downloading images online.

Instantiate a New ARReferenceImage from Each Downloaded Image
For each downloaded image, you could create a new ARReferenceImage.

Code Block
let myImage = ARReferenceImage(downloadedImage.cgImage!, orientation: CGImagePropertyOrientation.up, physicalWidth: width)


In your case, you will want to consider how you are acquiring the CGImagePropertyOrientation (whether that is being determined by a function you already have in your app, as your sample in the question shows, setting to .up as a default, or some other methodology). The same with the physical width of the image; you'll want to acquire that from somewhere prior to this step.

Insert Each ARReferenceImage Into the Empty ARReferenceImages Set
Code Block
newReferenceImages.insert(myImage)


Reset Session and Re-Configure
Once you have added each ARReferenceImage to the ARReferenceImages set, you can reset your session and apply this set to the configuration. I would recommend a function like such;

Code Block
func resetSession() {
let configuration = ARWorldTrackingConfiguration()
configuration.detectionImages = newReferenceImages
configuration.maximumNumberOfTrackedImages = 1
session.run(configuration, options: [.resetTracking, .removeExistingAnchors])
}


Your choice of maximumNumberOfTrackedImages should be a number suitable for your app's experience.

Create AnchorEntity from Each ARImageAnchor
Presumably, you will have already set an ARSessionDelegate somewhere in your setup. This should allow your delegate to receive a call each time new anchors are added, which will be provided as the more general ARAnchor. Therefore, I would use that delegate function like such;

Code Block
func session(_ session: ARSession, didAdd anchors: [ARAnchor]) {
for anchor in anchors {
if let myAnchor = anchor as? ARImageAnchor {
let imageAnchor = AnchorEntity(anchor: myAnchor)
/* Do something with the anchor here if necessary, such as adding an Entity to the model. For example;
let model = try! Entity.load(named: "myModel")
model.position = imageAnchor.position
imageAnchor.addChild(model)
*/
self.scene.addAnchor(imageAnchor)
}
}
}


Note that this example does not take into account efficiency (I.E. instantiating the should probably happen somewhere earlier in your app's lifecycle), but as a whole, this should point you in the general direction of each step necessary to download, build, and set your ARReferenceImages.
Accepted Answer
As far as I understand your inquiry, this should be possible to do. There are a few steps and considerations you will need to take, but as a whole, you should be able to download reference images (and some relevant metadata) from a web-based resource, instantiate a set of ARReferenceImages, and use those ARReferenceImages as anchors for your AR session. In my mind, you would need to take these steps;

  • Begin an ARWorldTrackingConfiguration or ARImageTrackingConfiguration so your users have a responsive experience and see the camera feed immediately.

  • Create an empty set of ARReferenceImages, which will be used to hold your downloaded images.

  • Download the necessary images from your web-based resource, using a common URLSession (or any optimal method for downloading images).

  • Instantiate an ARReferenceImage for each of your downloaded images. Note that you will also need to have awareness of the image's orientation, as well as the image's physical width in the real world (you may want to have some data, such as a JSON file, that contains the URLs of each image, alongside their real-world size, in meters).

  • Insert each of your new ARReferenceImages to the empty ARReferenceImages set.

  • Reset your session and configure a new ARWorldTrackingConfiguration or ARImageTrackingConfiguration, setting your newly created ARReferenceImages set to the configuration's detectionImages or trackingImages property, respectively.

  • Instantiate an AnchorEntity from the ARImageAnchor, which you should receive in a delegate method whenever a tracked image is found.

If I were to build an app trying to achieve this, I'd go step by step.

Set Up A Session For A Responsive Experience
Assuming you already have a RealityKit project going, you could add this in your viewDidLoad method.

Code Block
let configuration = ARWorldTrackingConfiguration()
sceneView.session.run(configuration)


Create An Empty Set of ARReferenceImages
You could add this to a local function or as a property accessible to your entire ViewController or class.

Code Block
var newReferenceImages: Set<ARReferenceImage> = Set<ARReferenceImage>()


Download the Images
You can use an asynchronous URLSession to download your images (and any relevant metadata). This should return each image as a UIImage. As your question focuses more on ARKit/RealityKit, this is being skipped, but you should be able to find plenty of resources with regards to downloading images online.

Instantiate a New ARReferenceImage from Each Downloaded Image
For each downloaded image, you could create a new ARReferenceImage.

Code Block
let myImage = ARReferenceImage(downloadedImage.cgImage!, orientation: CGImagePropertyOrientation.up, physicalWidth: width)


In your case, you will want to consider how you are acquiring the CGImagePropertyOrientation (whether that is being determined by a function you already have in your app, as your sample in the question shows, setting to .up as a default, or some other methodology). The same with the physical width of the image; you'll want to acquire that from somewhere prior to this step.

Insert Each ARReferenceImage Into the Empty ARReferenceImages Set
Code Block
newReferenceImages.insert(myImage)


Reset Session and Re-Configure
Once you have added each ARReferenceImage to the ARReferenceImages set, you can reset your session and apply this set to the configuration. I would recommend a function like such;

Code Block
func resetSession() {
let configuration = ARWorldTrackingConfiguration()
configuration.detectionImages = newReferenceImages
configuration.maximumNumberOfTrackedImages = 1
session.run(configuration, options: [.resetTracking, .removeExistingAnchors])
}


Your choice of maximumNumberOfTrackedImages should be a number suitable for your app's experience.

Create AnchorEntity from Each ARImageAnchor
Presumably, you will have already set an ARSessionDelegate somewhere in your setup. This should allow your delegate to receive a call each time new anchors are added, which will be provided as the more general ARAnchor. Therefore, I would use that delegate function like such;

Code Block
func session(_ session: ARSession, didAdd anchors: [ARAnchor]) {
for anchor in anchors {
if let myAnchor = anchor as? ARImageAnchor {
let imageAnchor = AnchorEntity(anchor: myAnchor)
/* Do something with the anchor here if necessary, such as adding an Entity to the model. For example;
let model = try! Entity.load(named: "myModel")
model.position = imageAnchor.position
imageAnchor.addChild(model)
*/
self.scene.addAnchor(imageAnchor)
}
}
}


Note that this example does not take into account efficiency (I.E. instantiating the should probably happen somewhere earlier in your app's lifecycle), but as a whole, this should point you in the general direction of each step necessary to download, build, and set your ARReferenceImages.
Hello,

One approach would be to create your ARReferenceImage, then create a new ARImageTrackingConfiguration with your updated ARReferenceImage set, and run this new configuration using the ARView's session. You should also make sure that automaticallyConfigureSession is false, since you will be configuring the session manually.

Once you have done this, you should use the ARSessionDelegate session(_:didAdd:) method, and whenever an ARImageAnchor is added, you should create an AnchorEntity from that image anchor using init(anchor:). Then add the new AnchorEntity to your scene.

brandonK212's answer is quite thorough, one thing to note though is that you do not *have* to reset tracking and remove anchors when you update your reference image set.


Thank you for clarifying that, gchiste. If the session does not have to be reset, does that mean that the ARImageTrackingConfiguration could be run when the app launches (to keep it responsive for the user), and the trackingImages property could be set after the fact? Or would it make more sense to wait to begin the session until all of the reference images have been downloaded/created?
Hey brandonK212,

That is correct, you can start your session before you actually have your trackingImages, which may make sense depending on your application. It probably makes the most sense for setting the detectionImages of an ARWorldTrackingConfiguration. In that case, you can establish world tracking and place things in the world before you have your detectionImages downloaded.
Thank you for your reply, @gchiste. This is very helpful information!
@gchiste , @brandonK212
Thank you so much ! You helped a lot, I did it according to your advice - everything works great, no lagging.
How could I create AnchorEntity in RealityKit without .image?
 
 
Q