Is it possible to sync a model that I loaded through url in a collaborative room?
Yes, it is possible to sync a model that you loaded through a URL in a collaborative room using Needle Engine. You can achieve this by utilizing the PlayerSync
class, which is designed for synchronizing assets across users in a networked setup.
Here’s a brief overview of the steps you could follow:
-
Load the Model: Use the
PlayerSync.setupFrom
method to load your 3D model from a URL. This method will handle the fetching and instantiation of the model in the scene. -
Sync the Model: Once the model is loaded, you can add it to the scene with a networking component that will automatically handle synchronization among users in the same room.
-
Listen for Events: You can listen for events related to room state changes, such as users joining and leaving, which
PlayerSync
will handle for you.
Here’s a code example for how this might look:
const url = "https://example.com/model.glb"; // Replace with your model URL
const playerSync = await PlayerSync.setupFrom(url);
if (playerSync) {
// The model is now loaded and synced in the collaborative room
scene.add(playerSync.asset?.asset);
}
Notes:
- Ensure that the necessary networking components (like
SyncedRoom
andSyncedTransform
) are also added to your entity to manage the collaborative aspect. - You may want to customize the model loading to take into account user-specific configurations or visual representations.
For further details, you can explore more in the relevant documentation on the PlayerSync
class and networking events in the provided resources (see the documentation) (see networking).
If you have any specific scenarios or additional questions, feel free to ask!
3 replies left
thread_9fIpTcbW9XivJvr0r1b1XnZQ
Reply to this message to continue the conversation
this solution loads the object in single browser, the sync doesn’t work for the other person
To sync a model loaded from a URL across clients in a collaborative room using Needle Engine, you need to ensure that the model is appropriately instantiated using networked synchronization features. Below are the steps you should follow:
-
Use
SyncedRoom
andPlayerSync
:- First, ensure you have a
SyncedRoom
component set up for your object, which will handle room joining and networking. - When you load the model, use the
PlayerSync
component, ensuring the model is synchronized when a player joins.
- First, ensure you have a
-
Instantiate the Model:
- Use the
instantiateSynced
method when adding your model to make sure it is instantiated across all clients in the room.
- Use the
-
Accept Ownership and Sync:
- Make sure to handle ownership properly using the
requestOwnership()
method from theSyncedTransform
component if you want to manipulate the model. This ensures that the changes made to the model are synced in real-time for all connected users.
- Make sure to handle ownership properly using the
Here’s an example of how you might implement this:
// Create a new Room
const roomObject = new Object3D();
roomObject.addComponent(SyncedRoom, { roomName: "MyCollabRoom" });
// Load and sync the model when a player joins
const modelUrl = "https://example.com/model.glb"; // URL of your model
const playerSync = await PlayerSync.setupFrom(modelUrl);
playerSync.autoSync = true; // Enable automatic synchronization
// Add transform sync to the model
const syncedTransform = new SyncedTransform();
modelObject.addComponent(syncedTransform);
syncedTransform.requestOwnership(); // Handle ownership
// Add to scene
scene.add(playerSync.asset?.asset);
Notes:
- Ensure that both
PlayerSync
andSyncedTransform
are added to your model for synchronization across all clients. - Depending on your setup, you may need to manage events when users join or leave the room to ensure models are loaded and destroyed correctly.
For additional information and best practices, consider visiting the Needle Engine documentation (see the documentation) (see the documentation). If you need more specific guidance or help with a particular aspect, feel free to ask!
2 replies left
thread_9fIpTcbW9XivJvr0r1b1XnZQ
Reply to this message to continue the conversation
I removed instantiate and its still spawning the object, which appears and disappears immediately.
It seems that the object you’re experiencing issues with is being instantiated but then immediately disappearing. This could be due to a few possible reasons:
-
Ownership and Synchronization: Ensure that the object is properly synchronized with the networking context, which might involve managing ownership correctly. If the client does not have ownership, the object may not persist.
-
Network Disconnect Handling: If the object is set to delete upon disconnection, it may be that the networking context is treating it as disconnected after instantiation, thereby triggering a deletion.
-
Visibility: Check the visibility state of the model when it is instantiated. If it is not explicitly set to be visible or if another part of the code is setting it to be invisible, that could result in the model disappearing.
To fix these issues, you can try implementing enhanced visibility checks or force setting the model visible right after instantiation. Here’s a potential solution:
const modelUrl = "https://example.com/model.glb"; // your model URL
const modelObject = await PlayerSync.setupFrom(modelUrl);
if (modelObject) {
// Ensure the object's visibility
modelObject.visible = true; // or use setActive if it is managed
scene.add(modelObject.asset?.asset);
// Manage ownership
const syncedTransform = new SyncedTransform();
modelObject.addComponent(syncedTransform);
syncedTransform.requestOwnership();
}
Additional Tips:
- Implement debugging logs to track the object’s state; logging when it is added and removed from the scene may help isolate the issue.
- Ensure that the necessary network components are initialized properly and that the model is being preserved on all clients.
If the issue persists, please provide more specific details about how your network rooms are structured or any relevant code snippets, so I can assist you further!
3 replies left
thread_9fIpTcbW9XivJvr0r1b1XnZQ
Reply to this message to continue the conversation
Hi, use the instantiateSynced
method.
Do i have to do this part too?
const playerSync = await PlayerSync.setupFrom(modelUrl);
scene.add(playerSync.asset?.asset);
I tried using instantiateSyned yesterday, it didn’t work though. I’ll give it a try again.
Is your model loaded from a remote url? Or part of the needle scene already?
from remote url. I’m using the url provided in the sample.
Ok, because then you need to network the url and load it on your clients individually. You can use a syncField for that (see our documentation).and just listen to the change event for the url to load your model
We will add support for this usecase in a future update.
I tried using intantiateSyned with SyncField(). It doesn’t show the object to other clients. There was a glitch too that made the object appear for everyone but disappeared right away for the first few attempts.
This is how im trying to do.
@syncField(htmlConnection.prototype.downloadmodel)
private downloadmodel(){
this.syncRoom();
}
private async syncRoom() {
const imageUrl = “https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Models/master/2.0/DamagedHelmet/glTF-Embedded/DamagedHelmet.gltf”;
const assetReference = AssetReference.getOrCreateFromUrl(imageUrl);
const modelObject = await assetReference.instantiateSynced(this.parent, true) as GameObject;
}
Also after spawning the object, on re-entering the room I dont see the model anymore and there’s this warning in the console.
You need to decorate a property or field (!) with the @syncField decorator. In your code example you put it above a method it seems, which wouldnt work / do nothing. The decorator synchronizes the value of a field to all connected users in the same room - e.g. a url: string = "https://...
and when that string is changed by anyone user it will be networked to all other users.
So to make it work change your code to:
@serializable() // to make it editable from unity/blender
@syncField(htmlConnection.prototype.downloadmodel)
url: string
private downloadModel() {
const imageUrl = this.url;
// the rest of your code
}
I omitted the syncRoom method since you dont need this extra indirection (maybe you do, feel free to add it again then)
Here’s a small demo Needle Engine: SyncField URL switch demo - StackBlitz (you can open it in two windows and click the change url button. You can technically copy paste the component at the top of the file in your project. i utilized the sceneswitcher as well since it makes it handles loading and unloading the model for me)
I added indirection due to “await” Or else SyncField decorator is giving error.
const assetReference = AssetReference.getOrCreateFromUrl(modelUrl);
const modelObject = await assetReference.instantiateSynced(this.parent, true) as GameObject;
the example you shared works but I think its not spawning a model in the same scene which isnt my case but it helps.
I see, i noticed this too (it will work either way and the typescript error will be fixed in the next version)
The model is being spawned as a child of the object with the component on all clients. It’s part of the same scene hierarchy. Im not sure what you mean, maybe you can rephrase?
using your demo from stackBiltz, I dont understand how to add component to the object just added. e.g dragControls OR instantiate more than 1 of the same object.
Im trying to achieve spawning multiple models through url with dragControls and syncTransform component attached to them.
They should be synced with other clients in the room.
Right now i’m able to spawn single model across clients but on changing the url the model replaces instead of spawning another object.
Using sceneswitcher example I’m not able to add components to it.
@saad_baig here is an example with DragControls and SyncedTransform. You can copy line 17-60 into your scripts folder and attach it to multiple empty GameObjects in Unity for example (if you want to load multiple objects)
The solution works but doesn’t solve my issue. I’m starting to think that it isn’t possible.
I can try to explain again, I don’t know how many object I would need so can’t create empty gameObjects before in the unity.
I want to instantiate objects through url in the scene with these components synced with everyone in the room. ( THIS WORKS).
If one leaves the room and join again should see all those previously spawned objects. (THIS DOESN’T WORK). Only the last loaded object is visible.
I think its because i haven’t created empty gameObjects before in unity. So I tried spawning a prefab and using that as the empty game object to do the task. But it doesnt work either.
Hi, it’s definitely possibly - sorry but I didn’t have the full context of what you’re trying to build in the beginning.
I think what’s missing for this particular case is that your SyncedURL component (or whatever component is runtime generated with the @syncField decorator) does not have a deterministic guid (which is used to store the state in the networking room).
With this new information I would also change the code slightly so that there’s one @syncField field with the whole URL state and seeds (so containing a list of URLs that should be displayed + a seed for the GUIDs and components)
Something along the line of
@syncField()
myState: { urls: Array<{url:string, seed:string}> }
Not sure how you add your URLs to the scene (drag drop? paste? backend request?)