sceneSerializer.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  1. import { Mesh } from "../Meshes/mesh.js";
  2. import { MultiMaterial } from "../Materials/multiMaterial.js";
  3. import { SerializationHelper } from "./decorators.serialization.js";
  4. import { Texture } from "../Materials/Textures/texture.js";
  5. import { Logger } from "./logger.js";
  6. let serializedGeometries = [];
  7. const SerializeGeometry = (geometry, serializationGeometries) => {
  8. if (geometry.doNotSerialize) {
  9. return;
  10. }
  11. serializationGeometries.vertexData.push(geometry.serializeVerticeData());
  12. serializedGeometries[geometry.id] = true;
  13. };
  14. const SerializeMesh = (mesh, serializationScene) => {
  15. const serializationObject = {};
  16. // Geometry
  17. const geometry = mesh._geometry;
  18. if (geometry) {
  19. if (!mesh.getScene().getGeometryById(geometry.id)) {
  20. // Geometry was in the memory but not added to the scene, nevertheless it's better to serialize to be able to reload the mesh with its geometry
  21. SerializeGeometry(geometry, serializationScene.geometries);
  22. }
  23. }
  24. // Custom
  25. if (mesh.serialize) {
  26. mesh.serialize(serializationObject);
  27. }
  28. return serializationObject;
  29. };
  30. const FinalizeSingleNode = (node, serializationObject) => {
  31. if (node._isMesh) {
  32. const mesh = node;
  33. //only works if the mesh is already loaded
  34. if (mesh.delayLoadState === 1 || mesh.delayLoadState === 0) {
  35. const serializeMaterial = (material) => {
  36. serializationObject.materials = serializationObject.materials || [];
  37. if (mesh.material && !serializationObject.materials.some((mat) => mat.id === mesh.material.id)) {
  38. serializationObject.materials.push(material.serialize());
  39. }
  40. };
  41. //serialize material
  42. if (mesh.material && !mesh.material.doNotSerialize) {
  43. if (mesh.material instanceof MultiMaterial) {
  44. serializationObject.multiMaterials = serializationObject.multiMaterials || [];
  45. if (!serializationObject.multiMaterials.some((mat) => mat.id === mesh.material.id)) {
  46. serializationObject.multiMaterials.push(mesh.material.serialize());
  47. for (const submaterial of mesh.material.subMaterials) {
  48. if (submaterial) {
  49. serializeMaterial(submaterial);
  50. }
  51. }
  52. }
  53. }
  54. else {
  55. serializeMaterial(mesh.material);
  56. }
  57. }
  58. else if (!mesh.material) {
  59. serializeMaterial(mesh.getScene().defaultMaterial);
  60. }
  61. //serialize geometry
  62. const geometry = mesh._geometry;
  63. if (geometry) {
  64. if (!serializationObject.geometries) {
  65. serializationObject.geometries = {};
  66. serializationObject.geometries.boxes = [];
  67. serializationObject.geometries.spheres = [];
  68. serializationObject.geometries.cylinders = [];
  69. serializationObject.geometries.toruses = [];
  70. serializationObject.geometries.grounds = [];
  71. serializationObject.geometries.planes = [];
  72. serializationObject.geometries.torusKnots = [];
  73. serializationObject.geometries.vertexData = [];
  74. }
  75. SerializeGeometry(geometry, serializationObject.geometries);
  76. }
  77. // Skeletons
  78. if (mesh.skeleton && !mesh.skeleton.doNotSerialize) {
  79. serializationObject.skeletons = serializationObject.skeletons || [];
  80. serializationObject.skeletons.push(mesh.skeleton.serialize());
  81. }
  82. //serialize the actual mesh
  83. serializationObject.meshes = serializationObject.meshes || [];
  84. serializationObject.meshes.push(SerializeMesh(mesh, serializationObject));
  85. }
  86. }
  87. else if (node.getClassName() === "TransformNode") {
  88. const transformNode = node;
  89. serializationObject.transformNodes.push(transformNode.serialize());
  90. }
  91. else if (node.getClassName().indexOf("Camera") !== -1) {
  92. const camera = node;
  93. serializationObject.cameras.push(camera.serialize());
  94. }
  95. else if (node.getClassName().indexOf("Light") !== -1) {
  96. const light = node;
  97. serializationObject.lights.push(light.serialize());
  98. }
  99. };
  100. /**
  101. * Class used to serialize a scene into a string
  102. */
  103. export class SceneSerializer {
  104. /**
  105. * Clear cache used by a previous serialization
  106. */
  107. static ClearCache() {
  108. serializedGeometries = [];
  109. }
  110. /**
  111. * Serialize a scene into a JSON compatible object
  112. * Note that if the current engine does not support synchronous texture reading (like WebGPU), you should use SerializeAsync instead
  113. * as else you may not retrieve the proper base64 encoded texture data (when using the Texture.ForceSerializeBuffers flag)
  114. * @param scene defines the scene to serialize
  115. * @returns a JSON compatible object
  116. */
  117. static Serialize(scene) {
  118. return SceneSerializer._Serialize(scene);
  119. }
  120. static _Serialize(scene, checkSyncReadSupported = true) {
  121. const serializationObject = {};
  122. if (checkSyncReadSupported && !scene.getEngine()._features.supportSyncTextureRead && Texture.ForceSerializeBuffers) {
  123. Logger.Warn("The serialization object may not contain the proper base64 encoded texture data! You should use the SerializeAsync method instead.");
  124. }
  125. SceneSerializer.ClearCache();
  126. // Scene
  127. serializationObject.useDelayedTextureLoading = scene.useDelayedTextureLoading;
  128. serializationObject.autoClear = scene.autoClear;
  129. serializationObject.clearColor = scene.clearColor.asArray();
  130. serializationObject.ambientColor = scene.ambientColor.asArray();
  131. serializationObject.gravity = scene.gravity.asArray();
  132. serializationObject.collisionsEnabled = scene.collisionsEnabled;
  133. serializationObject.useRightHandedSystem = scene.useRightHandedSystem;
  134. // Fog
  135. if (scene.fogMode && scene.fogMode !== 0) {
  136. serializationObject.fogMode = scene.fogMode;
  137. serializationObject.fogColor = scene.fogColor.asArray();
  138. serializationObject.fogStart = scene.fogStart;
  139. serializationObject.fogEnd = scene.fogEnd;
  140. serializationObject.fogDensity = scene.fogDensity;
  141. }
  142. //Physics
  143. if (scene.isPhysicsEnabled && scene.isPhysicsEnabled()) {
  144. const physicEngine = scene.getPhysicsEngine();
  145. if (physicEngine) {
  146. serializationObject.physicsEnabled = true;
  147. serializationObject.physicsGravity = physicEngine.gravity.asArray();
  148. serializationObject.physicsEngine = physicEngine.getPhysicsPluginName();
  149. }
  150. }
  151. // Metadata
  152. if (scene.metadata) {
  153. serializationObject.metadata = scene.metadata;
  154. }
  155. // Morph targets
  156. serializationObject.morphTargetManagers = [];
  157. for (const abstractMesh of scene.meshes) {
  158. const manager = abstractMesh.morphTargetManager;
  159. if (manager) {
  160. serializationObject.morphTargetManagers.push(manager.serialize());
  161. }
  162. }
  163. // Lights
  164. serializationObject.lights = [];
  165. let index;
  166. let light;
  167. for (index = 0; index < scene.lights.length; index++) {
  168. light = scene.lights[index];
  169. if (!light.doNotSerialize) {
  170. serializationObject.lights.push(light.serialize());
  171. }
  172. }
  173. // Cameras
  174. serializationObject.cameras = [];
  175. for (index = 0; index < scene.cameras.length; index++) {
  176. const camera = scene.cameras[index];
  177. if (!camera.doNotSerialize) {
  178. serializationObject.cameras.push(camera.serialize());
  179. }
  180. }
  181. if (scene.activeCamera) {
  182. serializationObject.activeCameraID = scene.activeCamera.id;
  183. }
  184. // Animations
  185. SerializationHelper.AppendSerializedAnimations(scene, serializationObject);
  186. // Animation Groups
  187. if (scene.animationGroups && scene.animationGroups.length > 0) {
  188. serializationObject.animationGroups = [];
  189. for (let animationGroupIndex = 0; animationGroupIndex < scene.animationGroups.length; animationGroupIndex++) {
  190. const animationGroup = scene.animationGroups[animationGroupIndex];
  191. serializationObject.animationGroups.push(animationGroup.serialize());
  192. }
  193. }
  194. // Reflection probes
  195. if (scene.reflectionProbes && scene.reflectionProbes.length > 0) {
  196. serializationObject.reflectionProbes = [];
  197. for (index = 0; index < scene.reflectionProbes.length; index++) {
  198. const reflectionProbe = scene.reflectionProbes[index];
  199. serializationObject.reflectionProbes.push(reflectionProbe.serialize());
  200. }
  201. }
  202. // Materials
  203. serializationObject.materials = [];
  204. serializationObject.multiMaterials = [];
  205. let material;
  206. for (index = 0; index < scene.materials.length; index++) {
  207. material = scene.materials[index];
  208. if (!material.doNotSerialize) {
  209. serializationObject.materials.push(material.serialize());
  210. }
  211. }
  212. // MultiMaterials
  213. serializationObject.multiMaterials = [];
  214. for (index = 0; index < scene.multiMaterials.length; index++) {
  215. const multiMaterial = scene.multiMaterials[index];
  216. serializationObject.multiMaterials.push(multiMaterial.serialize());
  217. }
  218. // Environment texture
  219. if (scene.environmentTexture) {
  220. if (scene.environmentTexture._files) {
  221. serializationObject.environmentTexture = scene.environmentTexture.serialize();
  222. }
  223. else {
  224. serializationObject.environmentTexture = scene.environmentTexture.name;
  225. serializationObject.environmentTextureRotationY = scene.environmentTexture.rotationY;
  226. }
  227. }
  228. // Environment Intensity
  229. serializationObject.environmentIntensity = scene.environmentIntensity;
  230. // Skeletons
  231. serializationObject.skeletons = [];
  232. for (index = 0; index < scene.skeletons.length; index++) {
  233. const skeleton = scene.skeletons[index];
  234. if (!skeleton.doNotSerialize) {
  235. serializationObject.skeletons.push(skeleton.serialize());
  236. }
  237. }
  238. // Transform nodes
  239. serializationObject.transformNodes = [];
  240. for (index = 0; index < scene.transformNodes.length; index++) {
  241. if (!scene.transformNodes[index].doNotSerialize) {
  242. serializationObject.transformNodes.push(scene.transformNodes[index].serialize());
  243. }
  244. }
  245. // Geometries
  246. serializationObject.geometries = {};
  247. serializationObject.geometries.boxes = [];
  248. serializationObject.geometries.spheres = [];
  249. serializationObject.geometries.cylinders = [];
  250. serializationObject.geometries.toruses = [];
  251. serializationObject.geometries.grounds = [];
  252. serializationObject.geometries.planes = [];
  253. serializationObject.geometries.torusKnots = [];
  254. serializationObject.geometries.vertexData = [];
  255. serializedGeometries = [];
  256. const geometries = scene.getGeometries();
  257. for (index = 0; index < geometries.length; index++) {
  258. const geometry = geometries[index];
  259. if (geometry.isReady()) {
  260. SerializeGeometry(geometry, serializationObject.geometries);
  261. }
  262. }
  263. // Meshes
  264. serializationObject.meshes = [];
  265. for (index = 0; index < scene.meshes.length; index++) {
  266. const abstractMesh = scene.meshes[index];
  267. if (abstractMesh instanceof Mesh) {
  268. const mesh = abstractMesh;
  269. if (!mesh.doNotSerialize) {
  270. if (mesh.delayLoadState === 1 || mesh.delayLoadState === 0) {
  271. serializationObject.meshes.push(SerializeMesh(mesh, serializationObject));
  272. }
  273. }
  274. }
  275. }
  276. // Particles Systems
  277. serializationObject.particleSystems = [];
  278. for (index = 0; index < scene.particleSystems.length; index++) {
  279. serializationObject.particleSystems.push(scene.particleSystems[index].serialize(false));
  280. }
  281. // Post processes
  282. serializationObject.postProcesses = [];
  283. for (index = 0; index < scene.postProcesses.length; index++) {
  284. serializationObject.postProcesses.push(scene.postProcesses[index].serialize());
  285. }
  286. // Action Manager
  287. if (scene.actionManager) {
  288. serializationObject.actions = scene.actionManager.serialize("scene");
  289. }
  290. // Components
  291. for (const component of scene._serializableComponents) {
  292. component.serialize(serializationObject);
  293. }
  294. // Sprites
  295. if (scene.spriteManagers) {
  296. serializationObject.spriteManagers = [];
  297. for (index = 0; index < scene.spriteManagers.length; index++) {
  298. serializationObject.spriteManagers.push(scene.spriteManagers[index].serialize(true));
  299. }
  300. }
  301. return serializationObject;
  302. }
  303. /**
  304. * Serialize a scene into a JSON compatible object
  305. * @param scene defines the scene to serialize
  306. * @returns a JSON promise compatible object
  307. */
  308. static SerializeAsync(scene) {
  309. const serializationObject = SceneSerializer._Serialize(scene, false);
  310. const promises = [];
  311. this._CollectPromises(serializationObject, promises);
  312. return Promise.all(promises).then(() => serializationObject);
  313. }
  314. static _CollectPromises(obj, promises) {
  315. if (Array.isArray(obj)) {
  316. for (let i = 0; i < obj.length; ++i) {
  317. const o = obj[i];
  318. if (o instanceof Promise) {
  319. promises.push(o.then((res) => (obj[i] = res)));
  320. }
  321. else if (o instanceof Object || Array.isArray(o)) {
  322. this._CollectPromises(o, promises);
  323. }
  324. }
  325. }
  326. else if (obj instanceof Object) {
  327. for (const name in obj) {
  328. if (Object.prototype.hasOwnProperty.call(obj, name)) {
  329. const o = obj[name];
  330. if (o instanceof Promise) {
  331. promises.push(o.then((res) => (obj[name] = res)));
  332. }
  333. else if (o instanceof Object || Array.isArray(o)) {
  334. this._CollectPromises(o, promises);
  335. }
  336. }
  337. }
  338. }
  339. }
  340. /**
  341. * Serialize a mesh into a JSON compatible object
  342. * @param toSerialize defines the mesh to serialize
  343. * @param withParents defines if parents must be serialized as well
  344. * @param withChildren defines if children must be serialized as well
  345. * @returns a JSON compatible object
  346. */
  347. static SerializeMesh(toSerialize /* Mesh || Mesh[] */, withParents = false, withChildren = false) {
  348. const serializationObject = {};
  349. serializationObject.meshes = [];
  350. serializationObject.transformNodes = [];
  351. serializationObject.cameras = [];
  352. serializationObject.lights = [];
  353. SceneSerializer.ClearCache();
  354. toSerialize = toSerialize instanceof Array ? toSerialize : [toSerialize];
  355. if (withParents || withChildren) {
  356. //deliberate for loop! not for each, appended should be processed as well.
  357. for (let i = 0; i < toSerialize.length; ++i) {
  358. if (withChildren) {
  359. toSerialize[i].getDescendants().forEach((node) => {
  360. if (toSerialize.indexOf(node) < 0 && !node.doNotSerialize) {
  361. toSerialize.push(node);
  362. }
  363. });
  364. }
  365. //make sure the array doesn't contain the object already
  366. if (withParents && toSerialize[i].parent && toSerialize.indexOf(toSerialize[i].parent) < 0 && !toSerialize[i].parent.doNotSerialize) {
  367. toSerialize.push(toSerialize[i].parent);
  368. }
  369. }
  370. }
  371. toSerialize.forEach((mesh) => {
  372. FinalizeSingleNode(mesh, serializationObject);
  373. });
  374. return serializationObject;
  375. }
  376. }
  377. //# sourceMappingURL=sceneSerializer.js.map