google-ar / arcore-unity-sdk

ARCore SDK for Unity
https://developers.google.com/ar
Other
1.4k stars 402 forks source link

Application Crash when hosting multiple anchors #227

Closed nydej2 closed 6 years ago

nydej2 commented 6 years ago

I am currently working with the CloudAnchors example. Right now I'm trying to host multiple Anchors/instantiate multiple prefabs. Shortly after the the "Cloud Anchor was created and saved" message, the application crashes. If I only add one GameObject before hosting, the Application runs as excepted. .

sbrundage commented 6 years ago

Same issue. Keeping an eye in hopes for a response

pablisho commented 6 years ago

Hi, Thanks for the report. Could you explain a little better what you are trying to do? Are you basing your app from the Cloud Anchor example? Could you provide a logcat of the crash? The "Device disconnect" sentence doesn't seem to cause the app to crash.

nydej2 commented 6 years ago

Yes my app is basing on the code from the cloud anchor example. what I changed is the used prefab(own instead of andy) and at the end of Update(), I set the variable m_LastPlacedAnchor to null. Here is a logcat of the errors from start till crash: errorLogCloudAnchors.txt I am Currently working with a Google Pixel2(Android 8.1.0)

pablisho commented 6 years ago

Hi, the error seems to be:

05-25 08:51:46.887: E/mono(18359): Unhandled Exception: System.ArgumentException: An element with the same key already exists in the dictionary. 05-25 08:51:46.887: E/mono(18359): at System.Collections.Generic.Dictionary`2[System.Int32,GoogleARCore.CrossPlatform.XPAnchor].Add (Int32 key, GoogleARCore.CrossPlatform.XPAnchor value) [0x00000] in :0 05-25 08:51:46.887: E/mono(18359): at GoogleARCore.Examples.CloudAnchor.RoomSharingServer.SaveCloudAnchorToRoom (Int32 room, GoogleARCore.CrossPlatform.XPAnchor anchor) [0x00000] in :0 05-25 08:51:46.887: E/mono(18359): at GoogleARCore.Examples.CloudAnchor.CloudAnchorController.<_HostLastPlacedAnchor>m__1 (CloudAnchorResult result) [0x00000] in :0

which is an app error and not a SDK error. In particular the error means you are trying to add the same object to a dictionary, which makes me think that you are not adding multiple anchors, but you are actually adding the same anchor multiple times. Adding the same anchor multiple times is supported by Cloud Anchors API, but you'll have to modify the example code to properly support it. Does it help?

nydej2 commented 6 years ago

Hi,

But the creation of a Anchor is done with this line right?

"m_LastPlacedAnchor = hit.Trackable.CreateAnchor(hit.Pose);"

I do see that the called "_HostLastPlacedAnchor()" method creates a new XPAnchor object. I also understand that it is saved inside a dictionary.

As far as I see, the dicitonary consist of <roomNr, XPAnchor> tuples.

What i don't understand is how to create different Anchors if we can only give the pose during instantiation process?

EricBatlle commented 6 years ago

In my case the app gets stuck with the message "Attempting to host anchor..."

sbrundage commented 6 years ago

But from the Pose Struct, it looks like it contains a Vector3 position. So in my mind, I thought every-time we reset m_LastPlacedAnchor to null and sent a new Pose, it would create a new Anchor point. I also get stuck with "Attempting to host anchor..." Log gets errors such as: "libc++abi.dylib: terminating with uncaught exception of type Il2CppExceptionWrapper"

peteradvr commented 6 years ago

I was able to create a test app that supported multiple anchors. So this is not an issue for me.

EricBatlle commented 6 years ago

@peteradvr could you provide any info about how to do it?

sbrundage commented 6 years ago

@peteradvr Yeah this thread isn't about who can and cannot do it, it's about us trying to figure out how to get it working. So if you have already got it up and working, it would be awesome for you to share your code and thought process. Otherwise, your comment is irrelevant. Google's "Just a Line" app uses cloud anchors apparently to create a multi user drawing experience, I'll be searching through the code in attempt to see if they create multiple cloud anchors. Here is the link for those interested: https://github.com/googlecreativelab/justaline-android

EricBatlle commented 6 years ago

@sbrundage @nydej2 did you achieve something?

sbrundage commented 6 years ago

I believe it might be because we are attempting to use the same CloudAnchorID a second time. So if we can figure out how to generate a unique anchorID every-time, I think it will work

nydej2 commented 6 years ago

@sbrundage my toughs too. But i didn't find any way to set my own ID.

pablisho commented 6 years ago

Hi, this issue is happening because you are not hosting multiple anchors, you are hosting the same anchor multiple times. I would first make sure if that is the case. To create multiple anchors, call hit.Trackable.CreateAnchor(hit.Pose); with different hits. Calling XPSession.CreateCloudAnchor with the same Anchor multiple times is ok. That doesn't host the Anchor multiple times though. It will update the same Anchor. This issue seems to be happening in the Example (because it was not prepared to update the existing anchors), what you should avoid is calling RoomSharingServer.SaveCloudAnchorToRoom with the same anchor multiple times, because this Anchor was already associated to a room. Let me know if it helps.

EricBatlle commented 6 years ago

@pablisho but, as far as I know, every time that we touch the screen, we are already creating a new anchor, isn't it?

TrackableHit hit;
                if (Frame.Raycast(touch.position.x, touch.position.y,
                        TrackableHitFlags.PlaneWithinPolygon, out hit))
                {
                    m_LastPlacedAnchor = hit.Trackable.CreateAnchor(hit.Pose);
                }

The problem is not to update the same anchor, is to create new anchors on the same room, to share more than one to the same client. And _HostLastPlacedAnchor() works with the m_LastPlacedAnchor, so I don't know why it doesn't works.

pablisho commented 6 years ago

@nydej2 @ls29322 @sbrundage Sorry for having been misleading with this. The problem is not trying to host the same anchor multiple times, I take it back, but trying to use the same "room code" multiple times with more than one Anchor is an issue (to the example, the SDK is ok because it doesn't know about "rooms"). In our example we use a Dictionary to map "room codes" to "Cloud Anchors" this implicitly means that each room can only have one Anchor. You can modify our example to instead map each room to list of anchors and share that accordingly to other devices (This would increase the complexity to share the anchors to other devices), or to generate a new room code before calling SaveCloudAnchorToRoom and associate the anchor with it. Does this help?

EricBatlle commented 6 years ago

@pablisho No problem and thanks for keep answering!

So as you said, I convert the Dictionary stored in the class RoomSharingServer to that kind of Dictionary: private Dictionary<int, List<XPAnchor>> m_RoomAnchorsDict = new Dictionary<int, List<XPAnchor>>();

With this change comes another changes to the same class, such as the way to SaveCloudAnchorToRoom acts, to something like:

public void SaveCloudAnchorToRoom(int room, XPAnchor anchor)
        {
            if (!m_RoomAnchorsDict.ContainsKey(room))
            {
                List<XPAnchor> anchorList = new List<XPAnchor>();
                anchorList.Add(anchor);
                m_RoomAnchorsDict.Add(room, anchorList);
            }
            else
            {
                m_RoomAnchorsDict[room].Add(anchor);
            }
        }

And the way to found the room in the OnGetAnchorIdFromRoomRequest now has to be: bool found = m_RoomAnchorsDict.ContainsKey(roomMessage.RoomId) ? true : false; (maybe there is a way to keep using TryGetValue but I don't know how)

So everything is fine so far, and the app do not crash when I set the second cloud anchor, BUUUUUT, now the client (obviusly) got an error when trying to resolves and join to the room.

I supouse that the CloudAnchorController now has to resolves each cloudAnchor, and seems to be resolving the anchors on the OnResolveRoomClick function, so now I had to do the RoomSharingClient.GetAnchorIdFromRoom for each cloudAnchor.

(AND NOW WE ARRIVE TO THE TROUBLE!) But on RoomSharingClient I don't get how to change the class to retrieve the response as it should, as it seems to be something related to the networkMessages (specifically with the AnchorIdFromRoomResponseMessage).

Could you help me with that? Many thanks!

sbrundage commented 6 years ago

Appreciate all the answers...definitely have come a long way and I'm starting to understand the code more. Will having X anchor points with X rooms open hurt the experience? (X being greater than 1) My thought process was that it would improve the overall world tracking considering there are more anchor points to reference. Also, building onto the example project more...essentially with Firebase, after successfully hosting an anchor between two phones, I should be able to place a 3D object and have it appear on both phones simultaneously, correct?

pablisho commented 6 years ago

@ls29322 What you say looks right. You'll need to modify the network messages to share all the anchorIds of the room. Regarding how to do it I think it exceeds ARCore and it's a regular network problem. I think the solution will be different depending on your use case, you could either modify the existing solution or think something that could scale better like uploading the anchorIds of each room to a database instead of sharing them through the local network. @sbrundage The "room" concept does not exist in ARCore (so it will not hurt the experience at all). The room concept was introduced at the Example level so there's an easy way to share the AnchorId with another device. You can host multiple CloudAnchors and if you are able to share each of the AnchorIds everything will be fine. You can use "multiple rooms" to do that, it's just more annoying to the user to enter each of the codes.

sbrundage commented 6 years ago

@pablisho Gotcha, appreciate it. Not sure if you have any idea, but how is it possible to create real time updates within the scene between two devices once they are both in the same room. Is it as simple as adding an object to the scene if Firebase is enabled? For example, one user places a cube on a horizontal plane, if it is set as a child of the anchor, will it sync and appear on the other phone?

pablisho commented 6 years ago

@sbrundage If you want to sync objects among multiple devices you'll have to use Unity's solution for that which is https://docs.unity3d.com/Manual/UNet.html. Once you sync your objects, CloudAnchors will help you to position them in the right place in the scene. You should place your objects relative to the cloud anchor. I'm closing this issue as I believe the questions about this example were solved. Feel free to reopen if you have more questions about it.

raj244u commented 6 years ago

hi i making a tic-tak toe game by using Arcore cloud anchor.I replace the andy with game board prefab is done but when i use Raycasting and instantiate prefab as cross or nought on a board then i cant able to save prefab on cloud anchor.When i use same room on other device,it show only Game board which i replace with Andy.So please help me out . // use this code below
class CloudAnchorController { Ray raycast = ARKitFirstPersonCamera.ScreenPointToRay(touch.position); RaycastHit raycastHit; if (Physics.Raycast(raycast, out raycastHit)) { Debug.Log("Inside ray");

                if ((raycastHit.transform.tag == "f1" || raycastHit.transform.tag == "f2" || raycastHit.transform.tag == "f3" || raycastHit.transform.tag == "f4" || raycastHit.transform.tag == "f5" || raycastHit.transform.tag == "f6" || raycastHit.transform.tag == "f7" || raycastHit.transform.tag == "f8" || raycastHit.transform.tag == "f9"))
                {

                    if (count == 0)
                    {
                        Debug.Log("hit  count = " + count);
                        var andyObject = Instantiate(cross, raycastHit.transform.position, Quaternion.identity);
                        andyObject.transform.SetParent(raycastHit.collider.transform);

} else if (count == 1) { Debug.Log("hit count = " + count); var andyObject = Instantiate(nought, raycastHit.transform.position, Quaternion.identity); andyObject.transform.SetParent(raycastHit.collider.transform);

                    }
                    else if (count == 2)
                    {
                        Debug.Log("hit  count = " + count);
                        var andyObject = Instantiate(cross, raycastHit.transform.position, Quaternion.identity);
                        andyObject.transform.SetParent(raycastHit.collider.transform);

                    }
abudriaz commented 5 years ago

i want to have multiple cloud anchors in app can some one help or share the code or tutorial of it please