EngineProxy.js 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696
  1. import CircularArray from "./CircularArray.js"
  2. import AssetTypeName from "./enum/AssetTypeName.js"
  3. import AssetClassName from "./enum/AssetClassName.js"
  4. import LoggerLevels from "./enum/LoggerLevels.js"
  5. import EShaderMode from "./enum/EShaderMode.js"
  6. import EFitMode from "./enum/EFitMode.js"
  7. import Http from "./Http.js"
  8. import XSceneManager from "./XSceneManager.js"
  9. import XBillboardManager from "./XBillboardManager.js"
  10. import ModelManager from "./ModelManager.js"
  11. import InitEngineTimeoutError from "./error/InitEngineTimeoutError.js"
  12. import Logger from "./Logger.js"
  13. const logger = new Logger('xverse-bus')
  14. const http = new Http
  15. const blobToDataURI = async i=>new Promise((resolve,reject)=>{
  16. const fileReader = new FileReader;
  17. fileReader.readAsDataURL(i),
  18. fileReader.onload = function(n) {
  19. var o;
  20. resolve((o = n.target) == null ? void 0 : o.result)
  21. }
  22. ,
  23. fileReader.onerror = function(n) {
  24. reject(n)
  25. }
  26. }
  27. )
  28. const urlMap = new Map
  29. , urlTransformer = async(i,e=!1)=>typeof i != "string" ? (console.warn("url transformer error", i),
  30. i) : i.startsWith("blob:") ? i : e ? http.get({
  31. url: i,
  32. useIndexedDb: !0,
  33. key: "url",
  34. isOutPutObjectURL: !1
  35. }) : urlMap.has(i) ? urlMap.get(i) : http.get({
  36. url: i,
  37. useIndexedDb: !0,
  38. key: "url"
  39. }).then(t=>(urlMap.set(i, t),
  40. t));
  41. let sceneManager;
  42. function getSceneManager(i, e) {
  43. return sceneManager || (sceneManager = new XSceneManager(i,e)),
  44. sceneManager
  45. }
  46. export default class EngineProxy{
  47. constructor(xverseRoom) {
  48. this._tvs = []
  49. this.isRenderFirstFrame = !1
  50. this._idleTime = 0
  51. this.renderTimer
  52. this.lightManager
  53. this._checkSceneNotReadyCount = 0
  54. this._checkSceneDurationFrameNum = 0
  55. this._checkSceneFrameCount = 0
  56. this.timeoutCircularArray = new CircularArray(120, !1, [])
  57. this.frameCircularArray = new CircularArray(120, !1, [])
  58. this.interFrameCircularArray = new CircularArray(120, !1, [])
  59. this.drawCallCntCircularArray = new CircularArray(120, !1, [])
  60. this.activeFacesCircularArray = new CircularArray(120, !1, [])
  61. this.renderTimeCircularArray = new CircularArray(120, !1, [])
  62. this.drawCallTimeCircularArray = new CircularArray(120, !1, [])
  63. this.animationCircularArray = new CircularArray(120, !1, [])
  64. this.meshSelectCircularArray = new CircularArray(120, !1, [])
  65. this.renderTargetCircularArray = new CircularArray(120, !1, [])
  66. this.regBeforeRenderCircularArray = new CircularArray(120, !1, [])
  67. this.regAfterRenderCircularArray = new CircularArray(120, !1, [])
  68. this.renderCnt = 0
  69. this.renderErrorCount = 0
  70. this.engineSloppyCnt = 0
  71. this.systemStuckCnt = 0
  72. this.frameRenderNumber = 0
  73. this.room = xverseRoom
  74. this.updateStats = ()=>{
  75. this.room.stats && this.room.stats.assign({
  76. renderFrameTime: this.renderTimeCircularArray.getAvg(),
  77. maxRenderFrameTime: this.renderTimeCircularArray.getMax(),
  78. interFrameTime: this.interFrameCircularArray.getAvg(),
  79. animationTime: this.animationCircularArray.getAvg(),
  80. meshSelectTime: this.meshSelectCircularArray.getAvg(),
  81. drawcallTime: this.drawCallTimeCircularArray.getAvg(),
  82. idleTime: this._idleTime,
  83. registerBeforeRenderTime: this.regBeforeRenderCircularArray.getAvg(),
  84. registerAfterRenderTime: this.regAfterRenderCircularArray.getAvg(),
  85. renderTargetRenderTime: this.renderTargetCircularArray.getAvg(),
  86. fps: (1e3 / (this.renderTimeCircularArray.getAvg() + this.interFrameCircularArray.getAvg())).toFixed(2),
  87. drawcall: this.drawCallCntCircularArray.getAvg(),
  88. engineSloppyCnt: this.engineSloppyCnt,
  89. maxInterFrameTime: this.interFrameCircularArray.getMax(),
  90. maxDrawcallTime: this.drawCallTimeCircularArray.getMax(),
  91. maxMeshSelectTime: this.meshSelectCircularArray.getMax(),
  92. maxAnimationTime: this.animationCircularArray.getMax(),
  93. maxRegisterBeforeRenderTime: this.regBeforeRenderCircularArray.getMax(),
  94. maxRegisterAfterRenderTime: this.regAfterRenderCircularArray.getMax(),
  95. maxRenderTargetRenderTime: this.renderTargetCircularArray.getMax(),
  96. avgFrameTime: this.frameCircularArray.getAvg(),
  97. avgTimeoutTime: this.timeoutCircularArray.getAvg(),
  98. maxFrameTime: this.frameCircularArray.getMax(),
  99. maxTimeoutTime: this.timeoutCircularArray.getMax()
  100. })
  101. }
  102. }
  103. _setFPS(sceneManager, fps=25) {
  104. logger.info("Set fps to", fps);
  105. const protectFps = fps > 60 ? 60 : fps < 24 ? 24 : fps;
  106. const mspf = 1e3 / protectFps; //毫秒每帧
  107. let o = Date.now()
  108. , a = Date.now()
  109. , lastGap = mspf
  110. , ratio = 1;
  111. sceneManager.Engine.stopRenderLoop();
  112. const updatePerGap = ()=>{
  113. const c = Date.now()
  114. , h = c - o
  115. , f = c - a;
  116. a = c
  117. this.frameCircularArray.add(f)
  118. h - lastGap > mspf && (this.systemStuckCnt += 1)
  119. const d = h / lastGap;
  120. ratio = .9 * ratio + .1 * d;
  121. const _ = Date.now();
  122. let cpuRenderTime = 0, cpuUpdateYUVTime = 0;
  123. if (this.room.isUpdatedRawYUVData || this.room.isPano) {
  124. this.isRenderFirstFrame = !0
  125. if (this._checkSceneDurationFrameNum > 0)
  126. {
  127. this._checkSceneFrameCount++,
  128. this.room.sceneManager.isReadyToRender({}) && this._checkSceneDurationFrameNum--,
  129. this._checkSceneFrameCount > EngineProxy._CHECK_DURATION &&
  130. (
  131. this._checkSceneDurationFrameNum = EngineProxy._CHECK_DURATION,
  132. this._checkSceneFrameCount = 0,
  133. this._checkSceneNotReadyCount++,
  134. (this._checkSceneNotReadyCount == 1 || this._checkSceneNotReadyCount % 100 == 0)
  135. && logger.error(`[SDK] Scene not ready, skip render. loop: ${this._checkSceneNotReadyCount}`),
  136. this._checkSceneNotReadyCount > 10 && (
  137. logger.error("[SDK] Scene not ready, reload later"),
  138. this.room.proxyEvents("renderError", {
  139. error: new Error("[SDK] Scene not ready, skip render and reload.")
  140. })
  141. ),
  142. this.room.stats.assign({
  143. renderErrorCount: this._checkSceneNotReadyCount
  144. }),
  145. logger.infoAndReportMeasurement({
  146. value: 0,
  147. startTime: Date.now(),
  148. metric: "renderError",
  149. error: new Error("[SDK] Scene not ready, skip render and reload."),
  150. reportOptions: {
  151. sampleRate: .1
  152. }
  153. })
  154. );
  155. } else {
  156. try {
  157. sceneManager.render()
  158. }
  159. catch (error) {
  160. this.renderErrorCount++,
  161. this.renderErrorCount > 10 && this.room.proxyEvents("renderError", { error }),
  162. this.room.stats.assign({
  163. renderErrorCount: this.renderErrorCount
  164. }),
  165. logger.infoAndReportMeasurement({
  166. value: 0,
  167. startTime: Date.now(),
  168. metric: "renderError",
  169. error,
  170. reportOptions: {
  171. sampleRate: .1
  172. }
  173. })
  174. }
  175. }
  176. cpuRenderTime = Date.now() - _,
  177. this.frameRenderNumber < 1e3 && this.frameRenderNumber++,
  178. this.room.networkController.rtcp.workers.UpdateYUV(),
  179. cpuUpdateYUVTime = Date.now() - _ - cpuRenderTime
  180. }
  181. this.isRenderFirstFrame || this.room.networkController.rtcp.workers.UpdateYUV();
  182. const usedTimeMs = Date.now() - _;
  183. o = c + usedTimeMs,
  184. lastGap = Math.min(Math.max((mspf - usedTimeMs) / ratio, 5), 200),
  185. usedTimeMs > mspf && (
  186. lastGap = 10,
  187. this.engineSloppyCnt += 1
  188. ),
  189. this._idleTime = lastGap;
  190. lastGap > 150 && console.log("lastGap is ", lastGap, ", ratio is ", ratio, ", usedTimeMs is ", usedTimeMs,
  191. ", cpuRenderTime is ", cpuRenderTime, ", cpuUpdateYUVTime is ", cpuUpdateYUVTime)
  192. const b = lastGap;
  193. this.timeoutCircularArray.add(b)
  194. if (this.renderCnt % 25 == 0) {
  195. this.room.stats && this.room.stats.assign({
  196. avgFrameTime: this.frameCircularArray.getAvg(),
  197. avgTimeoutTime: this.frameCircularArray.getMax(),
  198. maxFrameTime: this.frameCircularArray.getMax(),
  199. maxTimeoutTime: this.timeoutCircularArray.getMax(),
  200. systemStuckCnt: this.systemStuckCnt
  201. })
  202. }
  203. this.renderTimer = window.setTimeout(updatePerGap, lastGap)
  204. }
  205. this.renderTimer = window.setTimeout(updatePerGap, mspf / ratio)
  206. }
  207. async initEngine(e) {
  208. await this.updateBillboard();
  209. logger.info("engine version:", VERSION$1);
  210. logger.setLevel(LoggerLevels.Warn);
  211. const videoPanoInfo = {
  212. videoResOriArray: [{
  213. width: 720,
  214. height: 1280
  215. }, {
  216. width: 1280,
  217. height: 720
  218. }, {
  219. width: 480,
  220. height: 654
  221. }, {
  222. width: 654,
  223. height: 480
  224. }, {
  225. width: 1920,
  226. height: 1080
  227. }, {
  228. width: 1080,
  229. height: 1920
  230. }, {
  231. width: 414,
  232. height: 896
  233. }],
  234. forceKeepVertical: this.room.options.objectFit !== "cover",
  235. panoInfo: {
  236. dynamicRange: 1,
  237. width: 4096,
  238. height: 2048
  239. },
  240. shaderMode: EShaderMode.videoAndPano,
  241. yuvInfo: {
  242. width: 1280,
  243. height: 720,
  244. fov: e.fov || DEFAULT_MAIN_CAMERA_FOV
  245. },
  246. cameraParam: {
  247. maxZ: 1e4
  248. },
  249. urlTransformer,
  250. logger: logger,
  251. disableWebGL2: this.room.options.disableWebGL2 || !1
  252. };
  253. const resolution = this.room.options.resolution;
  254. if(resolution){
  255. videoPanoInfo.videoResOriArray.some(l=>l.width === resolution.width && l.height === resolution.height) ||
  256. videoPanoInfo.videoResOriArray.push(resolution)
  257. }
  258. const sceneManager = this.room.sceneManager = getSceneManager(this.room.canvas, videoPanoInfo);
  259. this.room.setPictureQualityLevel(this.room.options.pictureQualityLevel || "high");
  260. this.room.sceneManager.staticmeshComponent.setRegionLodRule([2, 2, -1, -1, -1]);
  261. this.room.scene = sceneManager.Scene;
  262. this.room.breathPointManager = sceneManager.breathPointComponent;
  263. this.lightManager = sceneManager.lightComponent;
  264. this.registerStats();
  265. this.setEnv(e);
  266. await this.room.avatarManager.init();
  267. const a = this._createAssetList(e);
  268. await this.loadAssets(a, "");
  269. this._setFPS(sceneManager);
  270. }
  271. pause() {
  272. clearTimeout(this.renderTimer),
  273. logger.info("Invoke room.pause to pause render");
  274. const e = {
  275. roomId: this.room.id,
  276. effects: [],
  277. lowPolyModels: [],
  278. breathPointsConfig: [],
  279. skinId: this.room.skinId
  280. };
  281. return this.loadAssets(e, this.room.skinId)
  282. }
  283. async resume() {
  284. this._setFPS(this.room.sceneManager),
  285. this.room.sceneManager.cameraComponent.cameraFovChange(this.room.sceneManager.yuvInfo),
  286. logger.info("Invoke room.resume to render");
  287. const e = this._createAssetList(this.room.skin);
  288. await this.loadAssets(e, "")
  289. }
  290. setEnv(e) {
  291. var r;
  292. this.lightManager || (this.lightManager = this.room.sceneManager.lightComponent),
  293. e = e || this.room.skin;
  294. const t = ModelManager.findModel(e.models, AssetTypeName.Config, AssetClassName.Env);
  295. return t ? (r = this.lightManager) == null ? void 0 : r.setIBL(t.modelUrl) : (logger.error("env file not found"),
  296. Promise.resolve())
  297. }
  298. async _parseModelsAndLoad(e, t, r) {
  299. logger.info("Invoke _parseModelsAndLoad start", t);
  300. const n = ["airship", "balloon", "default", "ground_feiting", "ground_reqiqiu"]
  301. , o = new Map;
  302. r == null && (r = "xxxx");
  303. let a = !0;
  304. for (let u = 0; u < e.length; ++u) {
  305. a = !0;
  306. for (let c = 0; c < n.length; ++c)
  307. if (e[u].modelUrl.toLowerCase().indexOf(n[c]) >= 0) {
  308. const h = o.get(n[c]);
  309. h ? (h.push(e[u]),
  310. o.set(n[c], h)) : o.set(n[c], [e[u]]),
  311. a = !1;
  312. break
  313. }
  314. if (a) {
  315. const c = o.get("default");
  316. c ? (c.push(e[u]),
  317. o.set("default", c)) : o.set("default", [e[u]])
  318. }
  319. }
  320. let s = o.get(t) || [];
  321. if (this.room.viewMode === "simple" && (s = s.filter(u=>!u.modelUrl.endsWith("zip"))),
  322. !s)
  323. return Promise.reject(`no invalid scene model with group name: ${t}`);
  324. const l = [];
  325. for (let u = 0; u < s.length; ++u) {
  326. const c = s[u];
  327. if (c.modelUrl.toLowerCase().endsWith("zip"))
  328. c.modelUrl.toLowerCase().endsWith("zip") && l.push(this.room.sceneManager.addNewLowPolyMesh({
  329. url: c.modelUrl,
  330. skinInfo: r
  331. }));
  332. else {
  333. const h = t;
  334. l.push(this.room.sceneManager.addNewLowPolyMesh({
  335. url: c.modelUrl,
  336. group: h,
  337. pick: !0,
  338. skinInfo: r
  339. }))
  340. }
  341. }
  342. return Promise.all(l)
  343. }
  344. async _deleteAssetsLowpolyModel(e) {
  345. this.room.sceneManager.staticmeshComponent.deleteMeshesBySkinInfo(e),
  346. this.room.sceneManager.breathPointComponent.clearBreathPointsBySkinInfo(e),
  347. this.room.sceneManager.decalComponent.deleteDecalBySkinInfo(e);
  348. const t = [];
  349. this.room.sceneManager.Scene.meshes.forEach(r=>{
  350. r.xskinInfo == e && t.push(r)
  351. }
  352. ),
  353. t.forEach(r=>{
  354. r.dispose(!1, !1)
  355. }
  356. )
  357. }
  358. async loadLandAssets() {
  359. const e = this._createAssetList(this.room.skin);
  360. return this.loadAssets(e, this.room.skinId).catch(()=>this.loadAssets(e, this.room.skinId))
  361. }
  362. async loadAssets(e, t="", r=8e3) {
  363. const startTime = Date.now();
  364. return this._loadAssets(e, t)._timeout(r, new InitEngineTimeoutError(`loadAssets timeout(${r}ms)`)).then(o=>(logger.infoAndReportMeasurement({
  365. tag: "loadAssets",
  366. startTime: startTime,
  367. metric: "loadAssets"
  368. }),o)).catch(err=>(logger.infoAndReportMeasurement({
  369. tag: "loadAssets",
  370. startTime: startTime,
  371. metric: "loadAssets",
  372. error: err
  373. }),
  374. Promise.reject(err)))
  375. }
  376. async _loadAssets(e, t="") {
  377. try {
  378. const r = [];
  379. r.push(this._loadAssetsLowpolyModel(e, t));
  380. await Promise.all(r);
  381. await this.setEnv();
  382. this._checkSceneDurationFrameNum = EngineProxy._CHECK_DURATION;
  383. this._checkSceneNotReadyCount = 0;
  384. this._checkSceneFrameCount = 0;
  385. this.updateAnimationList();
  386. this.room.loadAssetsHook();
  387. } catch (r) {
  388. return Promise.reject(r)
  389. }
  390. }
  391. updateAnimationList() {
  392. if (this.room.avatarManager && this.room.avatarManager.xAvatarManager) {
  393. const animationList = this.room.skin.animationList;
  394. if (!animationList)
  395. {
  396. return;
  397. }
  398. animationList.forEach(t=>{
  399. this.room.avatarManager.xAvatarManager.updateAnimationLists(t.animations, t.avatarId)
  400. })
  401. }
  402. }
  403. async _loadAssetsLowpolyModel(e, t="") {
  404. const r = []
  405. , n = []
  406. , o = [];
  407. e.lowPolyModels.forEach(f=>{
  408. f.group === "TV" ? n.push({
  409. id: "",
  410. name: "",
  411. thumbnailUrl: "",
  412. typeName: AssetTypeName.Model,
  413. className: AssetClassName.Tv,
  414. modelUrl: f.url
  415. }) : f.group === "\u544A\u767D\u5899" ? o.push({ //告白墙
  416. id: "",
  417. name: "",
  418. thumbnailUrl: "",
  419. typeName: AssetTypeName.Model,
  420. className: AssetClassName.Lpm,
  421. modelUrl: f.url
  422. }) : r.push({
  423. id: "",
  424. name: "",
  425. thumbnailUrl: "",
  426. typeName: AssetTypeName.Model,
  427. className: AssetClassName.Lpm,
  428. modelUrl: f.url
  429. })
  430. });
  431. t != "" && t != null && this._deleteAssetsLowpolyModel(t);
  432. const skinId = e.skinId;
  433. logger.info("====> from ", t, " to ", skinId),
  434. this._tvs.forEach(f=>f.clean()),
  435. this._tvs = [];
  436. let s = EFitMode.cover;
  437. skinId == "10048" && (s = EFitMode.contain)
  438. Array.isArray(n) && n.forEach((f,d)=>{
  439. this._tvs.push(new TV("squareTv" + d,f.modelUrl,this.room,{
  440. fitMode: s
  441. }))
  442. }
  443. ),
  444. e.breathPointsConfig.forEach(async breathPoint=>{
  445. let d;
  446. try {
  447. d = await urlTransformer(breathPoint.imageUrl)
  448. } catch (_) {
  449. d = breathPoint.imageUrl,
  450. logger.error("urlTransformer error", _)
  451. }
  452. this.room.breathPointManager.addBreathPoint({
  453. id: breathPoint.id,
  454. position: breathPoint.position,
  455. spriteSheet: d,
  456. rotation: breathPoint.rotation || {
  457. pitch: 0,
  458. yaw: 270,
  459. roll: 0
  460. },
  461. billboardMode: !0,
  462. type: breathPoint.type || "no_type",
  463. spriteWidthNumber: breathPoint.spriteWidthNum || 1,
  464. spriteHeightNumber: breathPoint.spriteHeightNum || 1,
  465. maxVisibleRegion: breathPoint.maxVisibleRegion || 150,
  466. width: breathPoint.width,
  467. height: breathPoint.height,
  468. skinInfo: breathPoint.skinId
  469. })
  470. }
  471. ),
  472. o.forEach(f=>{
  473. this.room.sceneManager.decalComponent.addDecal({
  474. id: f.id || "gbq",
  475. meshPath: f.modelUrl,
  476. skinInfo: skinId
  477. })
  478. }
  479. );
  480. const u = this.room.sceneManager.staticmeshComponent.lowModel_group
  481. , c = Array.from(u.keys()).filter(f=>!f.startsWith("region_"))
  482. , h = ["airship", "balloon", "ground_feiting", "ground_reqiqiu", "default"];
  483. return new Promise((f,d)=>{
  484. Promise.all(h.map(_=>this._parseModelsAndLoad(r, _, skinId))).then(()=>{
  485. let _ = !1;
  486. r.forEach(v=>{
  487. v.modelUrl.endsWith("zip") && (_ = !0)
  488. }
  489. ),
  490. _ == !1 && this.room.sceneManager.staticmeshComponent.deleteLastRegionMesh(),
  491. this.room.sceneManager.staticmeshComponent.lowModel_group;
  492. const g = Array.from(u.keys()).filter(v=>!v.startsWith("region_"))
  493. , m = c.filter(v=>g.indexOf(v) < 0);
  494. m.length > 0 && m.forEach(v=>{
  495. this.room.sceneManager.staticmeshComponent.deleteMeshesByGroup(v)
  496. }
  497. ),
  498. f(!0)
  499. }
  500. ).catch(_=>{
  501. d(_)
  502. }
  503. )
  504. }
  505. )
  506. }
  507. async _updateSkinAssets(e) {
  508. const t = this.room.lastSkinId
  509. , r = await this.room.getSkin(e)
  510. , n = this._createAssetList(r);
  511. try {
  512. await this.loadAssets(n, t),
  513. this.room.updateCurrentState({
  514. versionId: r.versionId,
  515. skinId: r.id,
  516. skin: r
  517. })
  518. } catch {
  519. await this.loadAssets(n, t),
  520. this.room.updateCurrentState({
  521. versionId: r.versionId,
  522. skinId: r.id,
  523. skin: r
  524. })
  525. }
  526. this.setEnv(r)
  527. }
  528. _createAssetList(e) {
  529. const t = []
  530. , r = []
  531. , n = [];
  532. let o = e.models;
  533. const a = this.room.modelManager.config.preload;
  534. return this.room.viewMode === "simple" ? a && (o = a.baseUrls.map(l=>(l.modelUrl = l.url,
  535. l))) : this.room.viewMode,
  536. ModelManager.findModels(o, AssetTypeName.Effects, AssetClassName.Effects).forEach(l=>{
  537. t.push({
  538. url: l.modelUrl,
  539. group: l.className,
  540. name: l.name
  541. })
  542. }
  543. ),
  544. ModelManager.findModels(o, AssetTypeName.Model, AssetClassName.Lpm).forEach(l=>{
  545. r.push({
  546. url: l.modelUrl,
  547. group: l.className
  548. })
  549. }
  550. ),
  551. ModelManager.findModels(o, AssetTypeName.Model, AssetClassName.Gbq).forEach(l=>{
  552. r.push({
  553. url: l.modelUrl,
  554. group: l.className
  555. })
  556. }
  557. ),
  558. ModelManager.findModels(o, AssetTypeName.Model, AssetClassName.Tv).forEach(l=>{
  559. r.push({
  560. url: l.modelUrl,
  561. group: l.className
  562. })
  563. }
  564. ),
  565. [].forEach(l=>{
  566. l.skinId == e.id && n.push(l)
  567. }
  568. ),
  569. {
  570. roomId: this.room.id,
  571. effects: t,
  572. lowPolyModels: r,
  573. breathPointsConfig: n,
  574. skinId: e.id
  575. }
  576. }
  577. //sceneManager.statisticComponent是XStats对象
  578. registerStats() {
  579. const sceneManager = this.room.sceneManager;
  580. this.room.scene.registerAfterRender(()=>{
  581. const interFrameTimeCounterCurrent = sceneManager.statisticComponent.getInterFrameTimeCounter()
  582. const drawCallsCounterCurrent = sceneManager.statisticComponent.getDrawCall()
  583. const activeTriangle = sceneManager.statisticComponent.getActiveFaces()
  584. const frameTimeCounterCurrent = sceneManager.statisticComponent.getFrameTimeCounter()
  585. const renderTimeCounterCurrent = sceneManager.statisticComponent.getDrawCallTime()
  586. const animationsTimeCounterCurrent = sceneManager.statisticComponent.getAnimationTime()
  587. const activeMeshesEvaluationTimeCounterCurrent = sceneManager.statisticComponent.getActiveMeshEvaluationTime()
  588. const renderTargetRenderTime = sceneManager.statisticComponent.getRenderTargetRenderTime()
  589. const registerBeforeTimeCounterCurrent = sceneManager.statisticComponent.getRegisterBeforeRenderTime()
  590. const registerAfterTimeCounterCurrent = sceneManager.statisticComponent.getRegisterAfterRenderTime()
  591. const _activeParticlesCurrent = sceneManager.statisticComponent.getActiveParticles()
  592. const _activeBonesCurrent = sceneManager.statisticComponent.getActiveBones()
  593. const activeAnimatablesLength = sceneManager.Scene._activeAnimatables.length
  594. const rootNodesLength = sceneManager.statisticComponent.getTotalRootNodes()
  595. const geometriesLength = sceneManager.Scene.geometries.length
  596. const beforeRenderObservableLength = sceneManager.Scene.onBeforeRenderObservable.observers.length
  597. const afterRenderObservableLength = sceneManager.Scene.onAfterRenderObservable.observers.length
  598. const meshesLength = sceneManager.statisticComponent.getTotalMeshes()
  599. const texturesLength = sceneManager.statisticComponent.getTotalTextures()
  600. const materialsLength = sceneManager.statisticComponent.getTotalMaterials()
  601. const systemInfo = sceneManager.statisticComponent.getSystemInfo()
  602. const resolution = systemInfo.resolution
  603. const driver = systemInfo.driver;
  604. systemInfo.vender;
  605. const version = systemInfo.version
  606. const hardwareScalingLevel = systemInfo.hardwareScalingLevel
  607. const hardwareInfo = resolution + "_" + driver + "_" + version + "_" + hardwareScalingLevel;
  608. this.interFrameCircularArray.add(interFrameTimeCounterCurrent);
  609. this.renderTimeCircularArray.add(frameTimeCounterCurrent);
  610. this.animationCircularArray.add(animationsTimeCounterCurrent);
  611. this.meshSelectCircularArray.add(activeMeshesEvaluationTimeCounterCurrent);
  612. this.drawCallTimeCircularArray.add(renderTimeCounterCurrent);
  613. this.regAfterRenderCircularArray.add(registerAfterTimeCounterCurrent);
  614. this.regBeforeRenderCircularArray.add(registerBeforeTimeCounterCurrent);
  615. this.renderTargetCircularArray.add(renderTargetRenderTime);
  616. this.drawCallCntCircularArray.add(drawCallsCounterCurrent);
  617. this.renderCnt += 1;
  618. if(this.renderCnt % 25 == 0){
  619. let stats = this.room.stats
  620. if(stats != null){
  621. stats.assign({
  622. renderFrameTime: this.renderTimeCircularArray.getAvg(),
  623. maxRenderFrameTime: this.renderTimeCircularArray.getMax(),
  624. interFrameTime: this.interFrameCircularArray.getAvg(),
  625. animationTime: this.animationCircularArray.getAvg(),
  626. meshSelectTime: this.meshSelectCircularArray.getAvg(),
  627. drawcallTime: this.drawCallTimeCircularArray.getAvg(),
  628. idleTime: this._idleTime,
  629. registerBeforeRenderTime: this.regBeforeRenderCircularArray.getAvg(),
  630. registerAfterRenderTime: this.regAfterRenderCircularArray.getAvg(),
  631. renderTargetRenderTime: this.renderTargetCircularArray.getAvg(),
  632. fps: (1e3 / (this.renderTimeCircularArray.getAvg() + this.interFrameCircularArray.getAvg())).toFixed(2),
  633. drawcall: this.drawCallCntCircularArray.getAvg(),
  634. triangle: activeTriangle.toString(),
  635. engineSloppyCnt: this.engineSloppyCnt,
  636. maxInterFrameTime: this.interFrameCircularArray.getMax(),
  637. maxDrawcallTime: this.drawCallTimeCircularArray.getMax(),
  638. maxMeshSelectTime: this.meshSelectCircularArray.getMax(),
  639. maxAnimationTime: this.animationCircularArray.getMax(),
  640. maxRegisterBeforeRenderTime: this.regBeforeRenderCircularArray.getMax(),
  641. maxRegisterAfterRenderTime: this.regAfterRenderCircularArray.getMax(),
  642. maxRenderTargetRenderTime: this.renderTargetCircularArray.getMax(),
  643. activeParticles: _activeParticlesCurrent,
  644. activeBones: _activeBonesCurrent,
  645. activeAnimation: activeAnimatablesLength,
  646. totalMeshes: meshesLength,
  647. totalRootNodes: rootNodesLength,
  648. totalGeometries: geometriesLength,
  649. totalTextures: texturesLength,
  650. totalMaterials: materialsLength,
  651. registerBeforeCount: beforeRenderObservableLength,
  652. registerAfterCount: afterRenderObservableLength,
  653. hardwareInfo: hardwareInfo
  654. })
  655. }
  656. }
  657. }
  658. )
  659. }
  660. async updateBillboard() {
  661. const {options: {skinId: skinId}} = this.room
  662. , r = (await this.room.modelManager.findAssetList(skinId)).filter(a=>a.typeName === AssetTypeName.Textures && a.className === AssetClassName.SayBubble)
  663. , n = ["bubble01", "bubble02", "bubble03"]
  664. , o = ["bubble01_npc", "bubble02_npc", "bubble03_npc"];
  665. if (r.length) {
  666. const a = r.filter(l=>n.includes(l.name)).map(l=>l.url)
  667. , s = r.filter(l=>o.includes(l.name)).map(l=>l.url);
  668. a.length && (XBillboardManager.userBubbleUrls = a),
  669. s.length && (XBillboardManager.npcBubbleUrls = s)
  670. }
  671. }
  672. }
  673. ;