ARKit with multiple users
Now, after releasing ARKit 2.0 at WWDC 2018, it's possible to make games for 2....6 users.
For this, you need to use ARWorldMap
class. By saving world maps
and using them to start new sessions, your iOS application can now add new Augmented Reality capabilities: multiuser and persistent AR experiences.
AR Multiuser experiences. Now you may create a shared frame of a reference by sending archived ARWorldMap
objects to a nearby iPhone or iPad. With several devices simultaneously tracking the same world map
, you may build an experience where all users (up to 6) can share and see the same virtual 3D content (use Pixar's USDZ
file format for 3D in Xcode 10+ and iOS 12+).
session.getCurrentWorldMap { worldMap, error in
guard let worldMap = worldMap else {
showAlert(error)
return
}
}
let configuration = ARWorldTrackingConfiguration()
configuration.initialWorldMap = worldMap
session.run(configuration)
AR Persistent experiences. If you save a world map
and then your iOS application becomes inactive, you can easily restore it in the next launch of app and in the same physical environment. You can use ARAnchors
from the resumed world map
to place the same virtual 3D content (in USDZ or DAE format) at the same positions from the previous saved session.
AR Multi User Projectiles (Swift4)
If you are using the example provided by Apple, I was able to get your code work by doing the following.
Firstly when both devices where connected, I used the following function to send some test data:
/// Send A Movement Data Object To Our Peers
@IBAction func pressToSend(){
let shouldSend = MovementData(velocity: CGPoint.zero,
angular: Float(10),
position: "StackOverflow",
x:Float(10), y:Float(20),z:Float(30),
type:"BlackMirrorz")
guard let sendData = try? NSKeyedArchiver.archivedData(withRootObject: shouldSend, requiringSecureCoding: true) else { fatalError("can't encode movementData") }
cloudSession.sendDataToUsers(sendData)
}
With the cloudSession sendDataToUsers(_ data: Data)
function being called in the Multipeer Class
:
//--------------------------
// MARK: - MCSessionDelegate
//--------------------------
extension ARCloudShare: MCSessionDelegate {
func session(_ session: MCSession, peer peerID: MCPeerID, didChange state: MCSessionState) { }
func session(_ session: MCSession, didReceive data: Data, fromPeer peerID: MCPeerID) {
receivedDataHandler(data, peerID)
}
func session(_ session: MCSession, didReceive stream: InputStream, withName streamName: String, fromPeer peerID: MCPeerID) {
fatalError("This Service Does Not Send Or Receive Streams")
}
func session(_ session: MCSession, didStartReceivingResourceWithName resourceName: String, fromPeer peerID: MCPeerID, with progress: Progress) {
fatalError("This Service Does Not Send Or Receive Resources")
}
func session(_ session: MCSession, didFinishReceivingResourceWithName resourceName: String, fromPeer peerID: MCPeerID, at localURL: URL?, withError error: Error?) {
fatalError("This Service Does Not Send Or Receive Resources")
}
}
//---------------------------------------
// MARK: - MCNearbyServiceBrowserDelegate
//---------------------------------------
extension ARCloudShare: MCNearbyServiceBrowserDelegate {
public func browser(_ browser: MCNearbyServiceBrowser, foundPeer peerID: MCPeerID, withDiscoveryInfo info: [String: String]?) {
//Invite A New User To The Session
browser.invitePeer(peerID, to: session, withContext: nil, timeout: 10)
}
public func browser(_ browser: MCNearbyServiceBrowser, lostPeer peerID: MCPeerID) { }
}
//------------------------------------------
// MARK: - MCNearbyServiceAdvertiserDelegate
//------------------------------------------
extension ARCloudShare: MCNearbyServiceAdvertiserDelegate {
//----------------------------------------------------------
// MARK: - Allows The User To Accept The Invitation To Share
//----------------------------------------------------------
func advertiser(_ advertiser: MCNearbyServiceAdvertiser, didReceiveInvitationFromPeer peerID: MCPeerID, withContext context: Data?, invitationHandler: @escaping (Bool, MCSession?) -> Void) {
//Allow The User To Accept The Invitation & Join The Twunkl Session
invitationHandler(true, self.session)
}
}
class ARCloudShare: NSObject{
static let serviceType = "arcloud-share"
let myPeerID = MCPeerID(displayName: UIDevice.current.name)
var session: MCSession!
var serviceAdvertiser: MCNearbyServiceAdvertiser!
var serviceBrowser: MCNearbyServiceBrowser!
let receivedDataHandler: (Data, MCPeerID) -> Void
//-----------------------
// MARK: - Initialization
//-----------------------
init(receivedDataHandler: @escaping (Data, MCPeerID) -> Void ) {
self.receivedDataHandler = receivedDataHandler
super.init()
session = MCSession(peer: myPeerID, securityIdentity: nil, encryptionPreference: .required)
session.delegate = self
serviceAdvertiser = MCNearbyServiceAdvertiser(peer: myPeerID, discoveryInfo: nil, serviceType: ARCloudShare.serviceType)
serviceAdvertiser.delegate = self
serviceAdvertiser.startAdvertisingPeer()
serviceBrowser = MCNearbyServiceBrowser(peer: myPeerID, serviceType: ARCloudShare.serviceType)
serviceBrowser.delegate = self
serviceBrowser.startBrowsingForPeers()
}
//---------------------
// MARK: - Data Sending
//---------------------
func sendDataToUsers(_ data: Data) {
do {
try session.send(data, toPeers: session.connectedPeers, with: .reliable)
} catch {
print("Error Sending Data To Users: \(error.localizedDescription)")
}
}
//----------------------
// MARK: - Peer Tracking
//----------------------
var connectedPeers: [MCPeerID] { return session.connectedPeers }
}
Then in our main ViewController handling the data like so:
//----------------------
// MARK: - Data Handling
//----------------------
/// Handles The Data Received From Our ARMultipeer Session
///
/// - Parameters:
/// - data: Data
/// - peer: MCPeerID
func receivedData(_ data: Data, from peer: MCPeerID) {
if let unarchivedData = try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data){
if unarchivedData is MovementData, let data = unarchivedData as? MovementData{
print(data.orientation)
print(data.position)
}
else {
print("Unknown Data Recieved From = \(peer)")
}
}
}
Which yields something like this:
An example of sending multiple data types can be seen here: ARWorldMaps
Hope it points you in the right direction...
ARKit on different iPhones
Of course different iPhone models present different resolutions. There's a big difference between iPhone's screen size
and viewport size
. Look at this table. In some cases viewport size
is 1/9 of screen size
, sometimes – 1/4. Though, some models have identical screen size
and viewport size
.
Device | Screen Size | Viewport Size |
---|---|---|
iPhone 12 Pro Max | 1284 x 2778 | 428 x 926 |
iPhone X | 1125 x 2436 | 375 x 812 |
iPhone SE 2 | 750 x 1334 | 375 x 667 |
iPhone 8 Plus | 1080 x 1920 | 414 x 736 |
iPhone 6s | 750 x 1334 | 375 x 667 |
iOS ARKit saving map across multiple sessions
Nope.
There is no API for accessing the data ARKit uses internally for position/orientation tracking, nor for telling ARKit to save/restore such data itself.
Related Topics
Swift Xcode Index Freezing or Slow
Why .Pch File Not Available in Swift
Adding 3D Object to Argeoanchor
In Xcode 6.1. 'Uiimage' Does Not Have a Member Named 'Size' Error
Can Associated Values and Raw Values Coexist in Swift Enumeration
How to Use Generic Types to Get Object with Same Type
Swift Performsegue Going to Xcode
How to Save a Struct to Realm in Swift
How to Convert Uicolor to Swiftui's Color
Swiftui - Is There a Popviewcontroller Equivalent in Swiftui
Swift Cross Compile to Single Linux Binary
Swift 2.1 [Uint8] --Utf8--> String
Querying Below Autoid's in Firebase
Swift: Change the Cell's Uibutton Image with Tableview Didselect Method