XAvatarLoader.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384
  1. import Logger from "./Logger.js"
  2. const logger = new Logger('CharacterLoader')
  3. export default class XAvatarLoader {
  4. constructor() {
  5. this.containers = new Map,
  6. this.meshes = new Map,
  7. this.animations = new Map,
  8. this.aniPath = new Map,
  9. this.binPath = new Map,
  10. this.texPath = new Map,
  11. this.matPath = new Map,
  12. this.mshPath = new Map,
  13. this.rootPath = new Map,
  14. this.meshTexList = new Map,
  15. this._enableIdb = !0,
  16. this._mappings = new Map,
  17. this._sharedTex = new Map,
  18. this.avaliableAnimation = new Map,
  19. this.enableShareTexture = !0,
  20. this.enableShareAnimation = !0,
  21. this.fillEmptyLod = !0,
  22. this.pendantMap = new Map;
  23. const e = new BABYLON.GLTFFileLoader;
  24. BABYLON.SceneLoader.RegisterPlugin(e),
  25. e.preprocessUrlAsync = function(i) {
  26. const o = avatarLoader._mappings.get(i);
  27. return o ? Promise.resolve(o) : Promise.resolve(i)
  28. }
  29. }
  30. _parsePendant(e, i) {
  31. if (!e || !i) {
  32. logger.error("[Engine] invalid id or url when loading pendant");
  33. return
  34. }
  35. const o = ".zip"
  36. , s = i.replace(o, "/");
  37. this.pendantMap.set(e, s)
  38. }
  39. pullAndLoadXObject(e, i) {
  40. const o = avatarLoader.pendantMap.get(i);
  41. return Tools.LoadFileAsync(o + `${i}.json`, !1).then(s=>{
  42. if (!(s instanceof ArrayBuffer))
  43. return LoadXObject(o, s).then(c=>c)
  44. }
  45. )
  46. }
  47. getParsedUrl(e, i, o, s="") {
  48. return new Promise((c,d)=>{
  49. if (!o || o.indexOf(".zip") === -1)
  50. return c(o);
  51. const _ = this.rootPath.get(o);
  52. if (_)
  53. return c(_);
  54. {
  55. const b = ".zip"
  56. , k = o.replace(b, "") + COMPONENT_LIST_PREFIX;
  57. e.urlTransformer(k, !0).then(j=>{
  58. if (!j)
  59. return d("Loading Failed");
  60. new Response(j).json().then($=>{
  61. var tt, rt, it, nt, ot, at, st;
  62. const _e = o.replace(b, "")
  63. , et = _e + ((tt = $ == null ? void 0 : $.components) == null ? void 0 : tt.url.replace("./", ""));
  64. if (this.rootPath.set(o, et),
  65. $.components ? ($.components.url && this.mshPath.set(i, _e + "/" + ((rt = $ == null ? void 0 : $.components) == null ? void 0 : rt.url.replace("./", ""))),
  66. $.components.url_lod2 && this.mshPath.set(i + "_" + avatarSetting.lod[1].level, _e + "/" + ((it = $ == null ? void 0 : $.components) == null ? void 0 : it.url_lod2.replace("./", ""))),
  67. $.components.url_lod4 && this.mshPath.set(i + "_" + avatarSetting.lod[2].level, _e + "/" + ((nt = $ == null ? void 0 : $.components) == null ? void 0 : nt.url_lod4.replace("./", "")))) : ($.meshes.url && this.mshPath.set(i, _e + "/" + ((ot = $ == null ? void 0 : $.meshes) == null ? void 0 : ot.url.replace("./", ""))),
  68. $.meshes.url_lod2 && this.mshPath.set(i + "_" + avatarSetting.lod[1].level, _e + "/" + ((at = $ == null ? void 0 : $.meshes) == null ? void 0 : at.url_lod2.replace("./", ""))),
  69. $.meshes.url_lod4 && this.mshPath.set(i + "_" + avatarSetting.lod[2].level, _e + "/" + ((st = $ == null ? void 0 : $.meshes) == null ? void 0 : st.url_lod4.replace("./", "")))),
  70. $.materials && $.materials.forEach(ut=>{
  71. const ct = _e + "/" + ut.url;
  72. this.matPath.set(ut.name, ct)
  73. }
  74. ),
  75. $.bin) {
  76. const ut = _e + "/" + $.bin.url;
  77. this.binPath.set(i, ut);
  78. const ct = _e + "/" + $.bin.url_lod2;
  79. this.binPath.set(i + "_" + avatarSetting.lod[1].level, ct);
  80. const lt = _e + "/" + $.bin.url_lod4;
  81. this.binPath.set(i + "_" + avatarSetting.lod[2].level, lt)
  82. }
  83. return $.textures && $.textures.forEach(ut=>{
  84. const ct = _e + "/" + ut.url;
  85. this.texPath.set(ut.url, ct);
  86. const lt = this.meshTexList.get($.components.url);
  87. ut.type === "png" && (lt ? lt.find(ft=>ft === ut.name) || lt.push(ut.url) : this.meshTexList.set(i, [ut.name]))
  88. }
  89. ),
  90. c(et)
  91. }
  92. ).catch($=>{
  93. d(`[Engine] parse json file error,${$}`)
  94. }
  95. )
  96. }
  97. ).catch(j=>{
  98. d(`[Engine] ulrtransform error, cannot find resource in db,${j}`)
  99. }
  100. )
  101. }
  102. }
  103. )
  104. }
  105. async parse(e, i) {
  106. const o = [];
  107. i.forEach(s=>{
  108. this._setAnimationList(s.id, s.animations),
  109. o.push(this.getParsedUrl(e, s.id, s.url)),
  110. s.components.forEach(c=>{
  111. c.name === "pendant" ? c.units.forEach(d=>{
  112. this._parsePendant(d.id, d.url)
  113. }
  114. ) : c.units.forEach(d=>{
  115. o.push(this.getParsedUrl(e, d.name, d.url))
  116. }
  117. )
  118. }
  119. )
  120. }
  121. ),
  122. await Promise.all(o)
  123. }
  124. _setAnimationList(e, i) {
  125. i ? i.forEach(o=>{
  126. this.aniPath.set(e + "_" + o.name, o.url)
  127. }
  128. ) : logger.error("[Engine] no animation list exist, please check config for details")
  129. }
  130. disposeContainer() {
  131. const e = [];
  132. this.containers.forEach((i,o)=>{
  133. if (i.xReferenceCount < 1) {
  134. if (this.enableShareTexture && i.textures.length > 0) {
  135. for (let s = 0; s < i.textures.length; ++s)
  136. i.textures[s].xReferenceCount != null ? i.textures[s].xReferenceCount-- : i.textures[s].xReferenceCount = 0,
  137. i.textures[s]._parentContainer = null;
  138. i.textures = []
  139. }
  140. e.push(o)
  141. }
  142. }
  143. ),
  144. e.forEach(i=>{
  145. var o, s;
  146. (o = this.containers.get(i)) == null || o.removeAllFromScene(),
  147. (s = this.containers.get(i)) == null || s.dispose(),
  148. this.containers.delete(i)
  149. }
  150. ),
  151. this._sharedTex.forEach((i,o)=>{
  152. i.xReferenceCount == 0 && (i.dispose(),
  153. this._sharedTex.delete(o))
  154. }
  155. )
  156. }
  157. set enableIdb(e) {
  158. this._enableIdb = e
  159. }
  160. getGlbPath(e) {
  161. return this.aniPath.get(e + ".glb")
  162. }
  163. getGltfPath(e) {
  164. return this.mshPath.get(e + ".gltf")
  165. }
  166. getPngUrl(e) {
  167. return this.texPath.get(e + ".png")
  168. }
  169. getMeshUrl(e) {
  170. return this.mshPath.get(e)
  171. }
  172. _getSourceKey(e, i) {
  173. return i && avatarSetting.lod[i] ? e + avatarSetting.lod[i].fileName.split(".")[0] : e
  174. }
  175. _getAnimPath(animationName, avatarType) {
  176. let o = this.aniPath.get(avatarType + "_animations_" + avatarType.split("_")[1]);
  177. return o || (o = this.aniPath.get(avatarType + "_" + animationName)),
  178. o
  179. }
  180. load(e, i, o, s) {
  181. return this.loadGlb(e, i, o).then(c=>c || Promise.reject("[Engine] container load failed")).catch(()=>Promise.reject("[Engine] container load failed"))
  182. }
  183. _searchAnimation(e, i) {
  184. let o;
  185. return this.containers.forEach((s,c)=>{
  186. const d = i.split("_")[0];
  187. c.indexOf(d) != -1 && c.indexOf(e) != -1 && (o = s)
  188. }
  189. ),
  190. o
  191. }
  192. loadAnimRes(sceneManager, animationName, avatarType) {
  193. const aniModelPath = this._getAnimPath(animationName, avatarType)
  194. , aniKey = getAnimationKey(animationName, avatarType);
  195. return aniModelPath && this.containers.get(aniModelPath)
  196. ? Promise.resolve(this.containers.get(aniModelPath))
  197. : aniModelPath
  198. ? this._loadGlbFromBlob(sceneManager, aniKey, aniModelPath).then(d=>
  199. d.animationGroups.length == 0
  200. ? (
  201. this.containers.delete(aniKey),
  202. d.dispose(),
  203. Promise.reject("container does not contains animation data")
  204. )
  205. : d)
  206. : Promise.reject("no such url")
  207. }
  208. loadGlb(e, i, o) {
  209. let s = this.getMeshUrl(this._getSourceKey(i, o));
  210. !s && this.fillEmptyLod && (
  211. o = 0,
  212. s = this.getMeshUrl(this._getSourceKey(i, o))
  213. )
  214. return s && this.containers.get(s)
  215. ? Promise.resolve(this.containers.get(s))
  216. : s
  217. ? this._enableIdb
  218. ? this._loadGlbFromBlob(e, this._getSourceKey(i, o), s)
  219. : this._loadGlbFromUrl(e, this._getSourceKey(i, o), s)
  220. : Promise.reject("no such url")
  221. }
  222. loadGltf(e, i, o, s) {
  223. const c = this._getSourceKey(i, o || 0);
  224. let d = this.getGltfPath(c);
  225. !d && this.fillEmptyLod && (d = this.getGltfPath(i))
  226. return d && this.containers.get(d)
  227. ? Promise.resolve(this.containers.get(d))
  228. : this._enableIdb
  229. ? this._loadGltfFromBlob(e, i, o, s)
  230. : d
  231. ? this._loadGltfFromUrl(e, i, d.replace(i + ".gltf", ""))
  232. : Promise.reject()
  233. }
  234. loadSubsequence() {}
  235. loadVAT() {}
  236. getResourceName(e) {
  237. return this.meshTexList.get(e)
  238. }
  239. _loadGltfFromUrl(e, i, o) {
  240. return BABYLON.SceneLoader.LoadAssetContainerAsync(o, i + ".gltf", e.Scene, null, ".gltf")
  241. }
  242. _loadGlbFromBlob(sceneManager, i, aniModelPath) {
  243. return sceneManager.urlTransformer(aniModelPath)
  244. .then(path=>BABYLON.SceneLoader.LoadAssetContainerAsync("", path, sceneManager.Scene, null, ".glb").then(model => {
  245. if (model) {
  246. if (this.containers.get(aniModelPath))
  247. return model.dispose(),
  248. this.containers.get(aniModelPath);
  249. model.addAllToScene()
  250. if (this.enableShareTexture && model.textures.length > 0) {
  251. const d = [];
  252. let hasSameTex = false;
  253. model.meshes.forEach(mesh=>{
  254. if (mesh.material) {
  255. const albedoTexture = mesh.material._albedoTexture;
  256. if (albedoTexture) {
  257. let albedoTexName = albedoTexture.name;
  258. albedoTexName = albedoTexName.replace(" (Base Color)", "").split(".")[0];
  259. const oldTex = this._sharedTex.get(albedoTexName);
  260. oldTex ? (
  261. hasSameTex = true,
  262. mesh.material._albedoTexture = oldTex,
  263. d.push(oldTex),
  264. oldTex._parentContainer = model,
  265. oldTex.xReferenceCount++
  266. ) : (
  267. this._sharedTex.set(albedoTexName, albedoTexture),
  268. model.textures[0].xReferenceCount = 1
  269. )
  270. }
  271. }
  272. })
  273. hasSameTex && (
  274. model.textures.forEach(tex=>{
  275. sceneManager.Scene.removeTexture(tex)
  276. // tex.dispose() // zeg 这个加上会导致贴图丢失
  277. }),
  278. model.textures = d
  279. )
  280. }
  281. model.xReferenceCount = 0
  282. model.meshes.forEach(mesh=>{
  283. mesh.setEnabled(false)
  284. })
  285. this.containers.set(aniModelPath, model)
  286. return Promise.resolve(model)
  287. } else
  288. return Promise.reject("glb file load failed")
  289. }
  290. ))
  291. }
  292. _loadGlbFromUrl(e, i, o) {
  293. return BABYLON.SceneLoader.LoadAssetContainerAsync("", o, e.Scene, null, ".glb").then(s=>s ? (s.addAllToScene(),
  294. s.meshes.forEach(c=>{
  295. c.setEnabled(!1)
  296. }
  297. ),
  298. this.enableShareTexture && s.textures.length > 0 ? (s.meshes.forEach(c=>{
  299. if (c.material) {
  300. const d = c.material._albedoTexture;
  301. if (d) {
  302. let _ = d.name;
  303. _ = _.replace(" (Base Color)", "").split(".")[0];
  304. const b = this._sharedTex.get(_);
  305. b ? (c.material._albedoTexture = b,
  306. b.xReferenceCount++) : (this._sharedTex.set(_, d),
  307. s.textures[0].xReferenceCount = 1)
  308. }
  309. }
  310. }
  311. ),
  312. s.xReferenceCount = 0,
  313. this.containers.set(o, s),
  314. Promise.resolve(s)) : Promise.reject("glb file load failed"),
  315. s.xReferenceCount = 0,
  316. this.containers.set(o, s),
  317. Promise.resolve(s)) : Promise.reject("glb file load failed"))
  318. }
  319. _loadGltfFromBlob(e, i, o, s) {
  320. return new Promise((c,d)=>{
  321. const _ = [];
  322. let b = this._getSourceKey(i, o)
  323. , k = this.getGltfPath(b);
  324. if (!k && this.fillEmptyLod && (o = 0,
  325. b = this._getSourceKey(i, o),
  326. k = this.getGltfPath(b)),
  327. !k)
  328. return d(`[Engine] gltf path incorrect ${b},cancel.`);
  329. const j = this.mshPath.get(b + ".gltf");
  330. if (!j)
  331. return d("cannot find asset mshPath");
  332. const $ = this.binPath.get(b + ".bin");
  333. if (!$)
  334. return d("cannot find asset binPath");
  335. if (!s) {
  336. const tt = this.meshTexList.get(i);
  337. if (!tt || tt.length == 0)
  338. return d("cannot find texture");
  339. s = tt[0]
  340. }
  341. const _e = this.texPath.get(s + ".png");
  342. if (!_e)
  343. return d();
  344. const et = this.texPath.get(s + "-astc.ktx");
  345. if (!et)
  346. return d();
  347. _.push(this._blobMapping(e, j)),
  348. _.push(this._blobMapping(e, $)),
  349. _.push(this._blobMapping(e, _e)),
  350. _.push(this._blobMapping(e, et)),
  351. Promise.all(_).then(()=>{
  352. const tt = k.replace(b + ".gltf", "");
  353. BABYLON.SceneLoader.LoadAssetContainerAsync(tt, b + ".gltf", e.Scene, null, ".gltf").then(rt=>{
  354. var nt;
  355. this.containers.set(k, rt),
  356. rt.addAllToScene(),
  357. rt.meshes.forEach(ot=>{
  358. ot.setEnabled(!1)
  359. }
  360. );
  361. const it = this._sharedTex.get(i);
  362. it ? ((nt = rt.meshes[1].material._albedoTexture) == null || nt.dispose(),
  363. rt.meshes[1].material._albedoTexture = it) : this._sharedTex.set(i, rt.meshes[1].material._albedoTexture),
  364. c(rt)
  365. }
  366. )
  367. }
  368. )
  369. }
  370. )
  371. }
  372. _blobMapping(e, i) {
  373. return new Promise((o,s)=>{
  374. e.urlTransformer(i).then(c=>c ? (this._mappings.set(i, c),
  375. o(i)) : s(`[Engine] url urlTransformer parse error ${i}`))
  376. }
  377. )
  378. }
  379. }
  380. const avatarLoader = new XAvatarLoader();
  381. export { avatarLoader };