HoloLite Posted January 16, 2018 Share Posted January 16, 2018 It seems to me that there is no direct way to create asset (light, camera, meshes etc) and add it into the asset container. What I am trying to do is the create the assets programmatically (not using load scene) into an container without polluting the scene object itself. The typical code fragment to create/add an asset into a container looks like the following: scene: BABYLON.Scene; assets: BABYLON.AssetContainer; ... let camera = new BABYLON.FreeCamera(... , scene); scene.removeCamera(camera); assets.cameras.push(camera); Basically it has to be done in 3 steps: 1. create/add the asset into scene (all existing api to create mesh takes the scene object) 2. remove asset from scene 3. add the asset to container This is true for all other asset types like light, meshes, animations etc. Is there an easier to do this (like doing in 1 step?) Please advise. Thanks Quote Link to comment Share on other sites More sharing options...
HoloLite Posted January 16, 2018 Author Share Posted January 16, 2018 I wonder if the following approach will work (not ideal, but a bit more manageable) 1. Create all the needed assets (meshes, cameras, lights) as usual into the scene object. 2. Enumerate all asset array properties of the scene object like scene.camera, scene.lights, scene.animations, etc) and manually copy them into the corresponding array properties in the asset container object. (Question: does the asset container has all of the asset array properties of the scene object ? if not this approach won't work) 3. call assetContainer.removeAllFromScene() I guess, this will cleanly 'move' all the assets from the scene object to the container object. Any comments ? Quote Link to comment Share on other sites More sharing options...
trevordev Posted January 16, 2018 Share Posted January 16, 2018 Yea, your approach seems reasonable. Currently all manual asset creation adds the asset to the scene. Previously there was some discussion about possibly making AssetContainer and scene inherit from a same base interface so either could be passed into an asset creating method but this was not implemented due to the somewhat unnatural complexity of the change. Question: does the asset container has all of the asset array properties of the scene object Yes, it should contain all the asset arrays the scene has. For now I would recommend manually adding your assets to the AssetContainer and then calling removeAllFromScene like you mentioned. See this http://www.babylonjs-playground.com/#5NFRVE#1 GameMonetize 1 Quote Link to comment Share on other sites More sharing options...
Wingnut Posted January 17, 2018 Share Posted January 17, 2018 Hi @trevordev, welcome to the forum, and thanks for being a forum helper. It's pretty cool when a user's first post... is helping another. (Wingnut shakes your hand vigorously.) trevordev, Capitaine Herlock and GameMonetize 3 Quote Link to comment Share on other sites More sharing options...
HoloLite Posted January 17, 2018 Author Share Posted January 17, 2018 @trevordev thanks for the input. In that case, then I think we should add into 3.2 release the helper method called something like AssetContainer.moveAllFromScene which does the steps I described. I think many users will benefit from this. In retrospect, perhaps the better approach is not to expose the AssetContainer at all. The root issue is that the current BABYLON.Scene and its vr helper object can only be used as singleton (even if you intend to create multiple scenes), otherwise you will see rendering problem inside the VR headset. A high-level abstraction of Scene concept that internally manages its assets as user switches scenes would be a cleaner approach, imo. Another approach is not to make vr helper associated with scene but rather make it explicitly global entity. Quote Link to comment Share on other sites More sharing options...
trevordev Posted January 18, 2018 Share Posted January 18, 2018 Adding an AssetContainer.moveAllFromScene method sounds possible. Could you expand more on your exact use case? After you create your assets in code, how are you planning to use them? Is your code already written with multiple scenes? Beyond the vrHelper issue you mentioned, the assetContainer can also be used to load assets to be used at a later time without being automatically added to the scene. It does seem like the AssetContainer will result in code that has been written with multiple scenes to need to be rewritten to use a single scene and multiple AssetContainers which isn't very obvious. Having the helper method you suggested could be good for alleviating that pain. Switching assets between scenes is rather complex due to how tightly coupled each asset is to the scene when created. Adding support for that would likely be good but the change would be large and difficult to avoid breakage. Having special cases for certain objects like the vrHelper to move between scenes automatically might also cause confusion to users not expecting that behavior. If you create a github issue for the moveAllFromScene I can take a look at implementing it when free. Quote Link to comment Share on other sites More sharing options...
HoloLite Posted January 18, 2018 Author Share Posted January 18, 2018 My codes are all in typescript as I know little javascript. Unfortunately the playground takes only javascript. That said though, @brianzinn has wrote nice sample code: http://playground.babylonjs.com/#JA1ND3#48 that illustrates similar situation. Notice how he created only a single object of scene and vr object and iterates each scene container and loads them into the scene object. If you are using VR headset, this is the only way to switch scenes afaik. Doing otherwise will result in the scene rendered incorrectly in the vr headset. What I am trying to do is similar to this except that I don't use screen loader, I programmatically create the assets. I agreed with your statements that switching scene is a complex op, that's why I'd rather avoid using AssetContainer, but currently this is the only options I can think of. So far the approach I describe above (to juggle the assets using the containers) seem to work. But there is this weird thing about how the .cameras properties not showing up in the scene - I am still trying to figure out the root cause. Quote Link to comment Share on other sites More sharing options...
trevordev Posted January 18, 2018 Share Posted January 18, 2018 I see, glad you have it working with your solution. Did you end up writing a method similar to the moveAllFromScene you described above or is it more manual juggling? Quote Link to comment Share on other sites More sharing options...
HoloLite Posted January 18, 2018 Author Share Posted January 18, 2018 I had to do both. Implementation of moveAllFromScene is the following. I prefer that this is implemented by the framework in the near future so that any internal changes in the scene object like addition or removal of assets properties will be taken care of as well. import 'babylonjs' export class AssetContainerEx extends BABYLON.AssetContainer { constructor(scene: BABYLON.Scene) { super(scene); } moveAllFromScene(): void { Array.prototype.push.apply(this.actionManagers, this.scene._actionManagers); Array.prototype.push.apply(this.animations, this.scene.animations); Array.prototype.push.apply(this.cameras, this.scene.cameras); Array.prototype.push.apply(this.geometries, this.scene.getGeometries()); Array.prototype.push.apply(this.lensFlareSystems, this.scene.lensFlareSystems); Array.prototype.push.apply(this.lights, this.scene.lights); Array.prototype.push.apply(this.materials, this.scene.materials); Array.prototype.push.apply(this.meshes, this.scene.meshes); Array.prototype.push.apply(this.morphTargetManagers, this.scene.morphTargetManagers); Array.prototype.push.apply(this.multiMaterials, this.scene.multiMaterials); Array.prototype.push.apply(this.skeletons, this.scene.skeletons); Array.prototype.push.apply(this.particleSystems, this.scene.particleSystems); Array.prototype.push.apply(this.sounds, this.scene.mainSoundTrack.soundCollection); Array.prototype.push.apply(this.transformNodes, this.scene.transformNodes); this.removeAllFromScene(); } } trevordev 1 Quote Link to comment Share on other sites More sharing options...
HoloLite Posted January 19, 2018 Author Share Posted January 19, 2018 @trevordev I figured out the issues with the missing camera stuff. Basically the call to scene.createDefaultVRExperience() will create several cameras (5 of them now) which are used for VR purpose. You do want to keep these cameras in the scene object as you shuffle assets in and out from the containers to the scene object. That said I have to modify the moveAllFromScene to take optional keepCameras for this very purpose. import 'babylonjs' export class AssetContainerEx extends BABYLON.AssetContainer { constructor(scene: BABYLON.Scene) { super(scene); } moveAllFromScene(keepCameras?: BABYLON.Camera[]): void { Array.prototype.push.apply(this.actionManagers, this.scene._actionManagers); Array.prototype.push.apply(this.animations, this.scene.animations); if (keepCameras === undefined) { keepCameras = []; } for (let camera of this.scene.cameras) { let moveCamera = true; for (let keepCamera of keepCameras) { if (camera === keepCamera) { moveCamera = false; break; } } if (moveCamera) { this.cameras.push(camera); } } Array.prototype.push.apply(this.geometries, this.scene.getGeometries()); Array.prototype.push.apply(this.lensFlareSystems, this.scene.lensFlareSystems); Array.prototype.push.apply(this.lights, this.scene.lights); Array.prototype.push.apply(this.materials, this.scene.materials); Array.prototype.push.apply(this.meshes, this.scene.meshes); Array.prototype.push.apply(this.morphTargetManagers, this.scene.morphTargetManagers); Array.prototype.push.apply(this.multiMaterials, this.scene.multiMaterials); Array.prototype.push.apply(this.skeletons, this.scene.skeletons); Array.prototype.push.apply(this.particleSystems, this.scene.particleSystems); Array.prototype.push.apply(this.sounds, this.scene.mainSoundTrack.soundCollection); Array.prototype.push.apply(this.transformNodes, this.scene.transformNodes); this.removeAllFromScene(); } } Quote Link to comment Share on other sites More sharing options...
trevordev Posted January 19, 2018 Share Posted January 19, 2018 Thanks! I created a PR with your code so hopefully it can get into version 3.2 See: https://github.com/BabylonJS/Babylon.js/pull/3590 Quote Link to comment Share on other sites More sharing options...
HoloLite Posted January 19, 2018 Author Share Posted January 19, 2018 I found more states that need to be saved. These are essentially artifacts of the VR helper during teleportation/interactions. Now my app can switch scenes and does the teleportation and interaction within each scene correctly as I switch scenes. The more complete codes look like the following: import 'babylonjs' export class KeepAssets { cameras: BABYLON.Camera[] = []; meshes: BABYLON.Mesh[] = []; geometries: BABYLON.Geometry[] = []; materials: BABYLON.Material[] = []; } export class AssetContainerEx extends BABYLON.AssetContainer { private moveAssets<T>(sourceAssets: T[], targetAssets: T[], keepAssets: T[]): void { for (let asset of sourceAssets) { let move = true; for (let keepAsset of keepAssets) { if (asset === keepAsset) { move = false; break; } } if (move) { targetAssets.push(asset); } } } constructor(scene: BABYLON.Scene) { super(scene); } moveAllFromScene(keepAssets?: KeepAssets): void { if (keepAssets === undefined) { keepAssets = new KeepAssets(); } this.moveAssets(this.scene.cameras, this.cameras, keepAssets.cameras); this.moveAssets(this.scene.meshes, this.meshes, keepAssets.meshes); this.moveAssets(this.scene.getGeometries(), this.geometries, keepAssets.geometries); this.moveAssets(this.scene.materials, this.materials, keepAssets.materials); Array.prototype.push.apply(this.actionManagers, this.scene._actionManagers); Array.prototype.push.apply(this.animations, this.scene.animations); Array.prototype.push.apply(this.lensFlareSystems, this.scene.lensFlareSystems); Array.prototype.push.apply(this.lights, this.scene.lights); Array.prototype.push.apply(this.morphTargetManagers, this.scene.morphTargetManagers); Array.prototype.push.apply(this.multiMaterials, this.scene.multiMaterials); Array.prototype.push.apply(this.skeletons, this.scene.skeletons); Array.prototype.push.apply(this.particleSystems, this.scene.particleSystems); Array.prototype.push.apply(this.sounds, this.scene.mainSoundTrack.soundCollection); Array.prototype.push.apply(this.transformNodes, this.scene.transformNodes); this.removeAllFromScene(); } } Quote Link to comment Share on other sites More sharing options...
trevordev Posted January 19, 2018 Share Posted January 19, 2018 Sweet, I can add that to the PR as well. Thank you! HoloLite 1 Quote Link to comment Share on other sites More sharing options...
HoloLite Posted January 19, 2018 Author Share Posted January 19, 2018 Here is a video capture of the scene switching. trevordev and brianzinn 2 Quote Link to comment Share on other sites More sharing options...
GameMonetize Posted January 19, 2018 Share Posted January 19, 2018 Cool music HoloLite 1 Quote Link to comment Share on other sites More sharing options...
brianzinn Posted January 20, 2018 Share Posted January 20, 2018 On 1/17/2018 at 7:56 PM, HoloLite said: That said though, @brianzinn has wrote nice sample code I can't take any credit for that. You were asking for examples and I found that on the github issue comment HoloLite, GameMonetize and trevordev 3 Quote Link to comment Share on other sites More sharing options...
HoloLite Posted January 29, 2018 Author Share Posted January 29, 2018 @trevordev I just synced to alpha6 and see the changes you made. Thank you! I have a suggestion for moveAllFromScene implementation: make the implementation more general to accommodate future additional keep assets. That said, the codes would look like the following: moveAllFromScene(keepAssets?: KeepAssets): void { if (keepAssets === undefined) { keepAssets = new KeepAssets(); } this.moveAssets(this.scene.cameras, this.cameras, keepAssets.cameras); this.moveAssets(this.scene.meshes, this.meshes, keepAssets.meshes); this.moveAssets(this.scene.getGeometries(), this.geometries, keepAssets.geometries); this.moveAssets(this.scene.materials, this.materials, keepAssets.materials); this.moveAssets(this.scene._actionManagers, this.actionManagers, keepAssets.actionManagers); this.moveAssets(this.scene.animations, this.animations, keepAssets.animations); ... // do this for all assets this.removeAllFromScene(); } I noticed you already made the KeepAssets class handling all assets which is good. This change will keep the logic intact as the caller is responsible to filling the correct keep assets prior to calling and the default assets in KeepAssets are just empty arrays. Quote Link to comment Share on other sites More sharing options...
trevordev Posted January 29, 2018 Share Posted January 29, 2018 Yup this was missed. Added it in PR here https://github.com/BabylonJS/Babylon.js/pull/3649/files. Thanks. 1glayfan 1 Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.