XSceneManager.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448
  1. import XCameraComponent from "./XCameraComponent.js"
  2. import XStaticMeshComponent from "./XStaticMeshComponent.js"
  3. import XMaterialComponent from "./XMaterialComponent.js"
  4. import XStats from "./XStats.js"
  5. import XBreathPointManager from "./XBreathPointManager.js"
  6. import XDecalManager from "./XDecalManager.js"
  7. import XAvatarManager from "./XAvatarManager.js"
  8. import XBillboardManager from "./XBillboardManager.js"
  9. import XLightManager from "./XLightManager.js"
  10. import XEngineRunTimeStats from "./XEngineRunTimeStats.js"
  11. import EShaderMode from "./enum/EShaderMode.js"
  12. import defaultLog from "./defaultLog.js"
  13. import Logger from "./Logger.js"
  14. const logger = new Logger('XSceneManager')
  15. const getAlphaWidthMap = (i,e)=>{
  16. const t = new BABYLON.DynamicTexture("test",3,e)
  17. , r = new Map;
  18. for (let n = 32; n < 127; n++) {
  19. const o = String.fromCodePoint(n)
  20. , a = 2 + "px " + i;
  21. t.drawText(o, null, null, a, "#000000", "#ffffff", !0);
  22. const s = t.getContext();
  23. s.font = a;
  24. const l = s.measureText(o).width;
  25. r.set(n, l)
  26. }
  27. return t.dispose(),
  28. r
  29. }
  30. export default class XSceneManager {
  31. constructor(canvas, options) {
  32. this.cameraParam
  33. this.shaderMode
  34. this.panoInfo
  35. this._forceKeepVertical = !1
  36. this._currentShader
  37. this._renderStatusCheckCount = 0
  38. this._renderStatusNotChecktCount = 0
  39. this._nonlinearCanvasResize = !1
  40. this._bChangeEngineSize = !0
  41. this._skytv
  42. this._mv = []
  43. this._backgroundImg
  44. this.engine = new BABYLON.Engine(canvas, !0, {
  45. preserveDrawingBuffer: !0,
  46. stencil: !0,
  47. disableWebGL2Support: /iphone|ipad/gi.test(window.navigator.userAgent) || options.disableWebGL2
  48. }, !0),
  49. this.scene = new BABYLON.Scene(this.engine),
  50. this.canvas = canvas,
  51. this.scene.clearColor = new BABYLON.Color4(.7,.7,.7,1),
  52. this.engine.getCaps().parallelShaderCompile = void 0,
  53. this._initEngineScaleNumber = this.engine.getHardwareScalingLevel(),
  54. this.engine.enableOfflineSupport = !1,
  55. this.engine.doNotHandleContextLost = !0,
  56. this.scene.clearCachedVertexData(),
  57. this.scene.cleanCachedTextureBuffer(),
  58. this.scene.debugLayer.show({ embedMode: true, }), // BABYLON调试工具栏
  59. this.urlTransformer = options.urlTransformer || (s=>Promise.resolve(s)),
  60. options.logger && defaultLog.setLogger(options.logger),
  61. this.gl = canvas.getContext("webgl2", { preserveDrawingBuffer: !0 })
  62. || canvas.getContext("webgl", { preserveDrawingBuffer: !0 })
  63. || canvas.getContext("experimental-webgl", { preserveDrawingBuffer: !0 }),
  64. this.gl.pixelStorei(this.gl.UNPACK_ALIGNMENT, 1),
  65. this._currentPanoId = 0,
  66. options.forceKeepVertical && (this._forceKeepVertical = options.forceKeepVertical),
  67. options.panoInfo && (this.panoInfo = options.panoInfo),
  68. options.shaderMode && (this.shaderMode = options.shaderMode),
  69. options.yuvInfo ? this._yuvInfo = options.yuvInfo : this._yuvInfo = {
  70. width: options.videoResOriArray[0].width,
  71. height: options.videoResOriArray[0].height,
  72. fov: 50
  73. },
  74. options.cameraParam && (this.cameraParam = options.cameraParam),
  75. options.nonlinearCanvasResize && (this._nonlinearCanvasResize = options.nonlinearCanvasResize),
  76. this._cameraManager = new XCameraComponent(this.canvas,this.scene,{
  77. cameraParam: this.cameraParam,
  78. yuvInfo: this._yuvInfo,
  79. forceKeepVertical: this._forceKeepVertical
  80. }),
  81. this._lowpolyManager = new XStaticMeshComponent(this),
  82. this._materialManager = new XMaterialComponent(this,{
  83. videoResOriArray: options.videoResOriArray,
  84. yuvInfo: this._yuvInfo,
  85. panoInfo: this.panoInfo,
  86. shaderMode: this.shaderMode
  87. }),
  88. this._statisticManager = new XStats(this),
  89. this._breathPointManager = new XBreathPointManager(this),
  90. this._decalManager = new XDecalManager(this),
  91. this._avatarManager = new XAvatarManager(this),
  92. this._billboardManager = new XBillboardManager(this),
  93. this.billboardComponent.loadBackGroundTexToIDB(),
  94. this._lightManager = new XLightManager(this),
  95. this.postprocessing(),
  96. this.initSceneManager(),
  97. this.engineRunTimeStats = new XEngineRunTimeStats,
  98. /iphone/gi.test(window.navigator.userAgent)
  99. && window.devicePixelRatio
  100. && window.devicePixelRatio === 3
  101. && window.screen.width === 375
  102. && window.screen.height === 812
  103. ? this.engine.setHardwareScalingLevel(this._initEngineScaleNumber * 2)
  104. : this.engine.setHardwareScalingLevel(this._initEngineScaleNumber * 1.8),
  105. this.scene.registerBeforeRender(()=>{
  106. this._nonlinearCanvasResize && this._bChangeEngineSize && (this.setEngineSize(this._yuvInfo),
  107. this._bChangeEngineSize = !1)
  108. }),
  109. this.scene.registerAfterRender(()=>{
  110. this._nonlinearCanvasResize || this.registerAfterRender()
  111. }),
  112. window.addEventListener("resize", ()=>{
  113. this._nonlinearCanvasResize ? this._bChangeEngineSize = !0 : this.engine.resize()
  114. }),
  115. XBillboardManager.alphaWidthMap = getAlphaWidthMap("Arial", this.scene),
  116. this.uploadHardwareSystemInfo()
  117. }
  118. uploadHardwareSystemInfo = ()=>{
  119. const e = this.statisticComponent.getHardwareRenderInfo()
  120. , t = this.statisticComponent.getSystemInfo()
  121. , r = {
  122. driver: t.driver,
  123. vender: t.vender,
  124. webgl: t.version,
  125. os: t.os
  126. };
  127. logger.warn(JSON.stringify(e)),
  128. logger.warn(JSON.stringify(r))
  129. }
  130. addNewLowPolyMesh = async(e,t)=>(
  131. this._currentShader == null && await this.initSceneManager(),
  132. this._lowpolyManager.addNewLowPolyMesh(e, t, this._currentShader)
  133. )
  134. initSceneManager = async()=>(await this._materialManager.initMaterial(),this.applyShader())
  135. registerAfterRender = ()=>{
  136. var e;
  137. if (this._forceKeepVertical) {
  138. const t = this.canvas.width
  139. , r = this.canvas.height;
  140. let n = 0
  141. , o = [[0, 0, 0, 0], [0, 0, 0, 0]];
  142. if (((e = this._cameraManager.MainCamera) == null ? void 0 : e.fovMode) === BABYLON.Camera.FOVMODE_HORIZONTAL_FIXED ? (n = Math.ceil((r - this._yuvInfo.height * t / this._yuvInfo.width) / 2),
  143. o = [[0, 0, t, n], [0, r - n, t, n]]) : (n = Math.ceil((t - this._yuvInfo.width * r / this._yuvInfo.height) / 2),
  144. o = [[0, 0, n, r], [t - n, 0, n, r]]),
  145. n > 0) {
  146. this.gl.enable(this.gl.SCISSOR_TEST);
  147. for (let a = 0; a < o.length; ++a)
  148. this.gl.scissor(o[a][0], o[a][1], o[a][2], o[a][3]),
  149. this.gl.clearColor(0, 0, 0, 1),
  150. this.gl.clear(this.gl.COLOR_BUFFER_BIT);
  151. this.gl.disable(this.gl.SCISSOR_TEST)
  152. }
  153. }
  154. }
  155. resetRender = ()=>{
  156. this.scene.environmentTexture && (
  157. this.scene.environmentTexture._texture ? this.lightComponent.setIBL(this.scene.environmentTexture._texture.url)
  158. : this.scene.environmentTexture.url && this.lightComponent.setIBL(this.scene.environmentTexture.url)
  159. )
  160. }
  161. get yuvInfo() {
  162. return this.getCurrentShaderMode() == 1 ? this._yuvInfo : {
  163. width: -1,
  164. height: -1,
  165. fov: -1
  166. }
  167. }
  168. set yuvInfo(e) {
  169. this.getCurrentShaderMode() == 1 && (this._yuvInfo = e,
  170. this._cameraManager.cameraFovChange(e))
  171. }
  172. get mainScene() {
  173. return this.scene
  174. }
  175. get cameraComponent() {
  176. return this._cameraManager
  177. }
  178. get staticmeshComponent() {
  179. return this._lowpolyManager
  180. }
  181. get materialComponent() {
  182. return this._materialManager
  183. }
  184. get statisticComponent() {
  185. return this._statisticManager
  186. }
  187. get avatarComponent() {
  188. return this._avatarManager
  189. }
  190. get lightComponent() {
  191. return this._lightManager
  192. }
  193. get Engine() {
  194. return this.engine
  195. }
  196. get Scene() {
  197. return this.scene
  198. }
  199. get billboardComponent() {
  200. return this._billboardManager
  201. }
  202. get breathPointComponent() {
  203. return this._breathPointManager
  204. }
  205. get skytvComponent() {
  206. return this._skytv
  207. }
  208. get mvComponent() {
  209. return this._mv
  210. }
  211. get decalComponent() {
  212. return this._decalManager
  213. }
  214. get currentShader() {
  215. return this._currentShader
  216. }
  217. get initEngineScaleNumber() {
  218. return this._initEngineScaleNumber
  219. }
  220. setImageQuality(e) {
  221. e == 0 ? (this.engine.setHardwareScalingLevel(this._initEngineScaleNumber * 1.8),
  222. logger.info("[Engine] change image quality to low, [" + this._initEngineScaleNumber * 1.8 + "]")) : e == 1 ? (this.engine.setHardwareScalingLevel(this._initEngineScaleNumber * 1.5),
  223. logger.info("[Engine] change image quality to mid, [" + this._initEngineScaleNumber * 1.5 + "]")) : e == 2 && (this.engine.setHardwareScalingLevel(this._initEngineScaleNumber * 1),
  224. logger.info("[Engine] change image quality to high, [" + this._initEngineScaleNumber * 1 + "]"))
  225. }
  226. setNonlinearCanvasResize(e) {
  227. this._nonlinearCanvasResize = e,
  228. this._bChangeEngineSize = e,
  229. e || this.engine.resize()
  230. }
  231. setBackgroundColor(e) {
  232. this.scene.clearColor = new Color4(e.r,e.g,e.b,e.a)
  233. }
  234. setBackgroundImg(e) {
  235. return this._backgroundImg != null && this._backgroundImg.url == e ? Promise.resolve(!0) : new Promise((t,r)=>{
  236. this.urlTransformer(e).then(n=>{
  237. this._backgroundImg == null ? this._backgroundImg = {
  238. layer: new Layer("tex_background_" + Date.now(),n,this.Scene,!0),
  239. url: e
  240. } : this._backgroundImg.url != e && this._backgroundImg.layer != null && this._backgroundImg.layer.texture != null && (this._backgroundImg.layer.texture.updateURL(n),
  241. this._backgroundImg.layer.name = "tex_background_" + Date.now(),
  242. this._backgroundImg.url = e),
  243. t(!0)
  244. }
  245. ).catch(n=>{
  246. logger.error(`[Engine] set background image Error: ${n}`),
  247. r(`[Engine] set background image Error: ${n}`)
  248. }
  249. )
  250. }
  251. )
  252. }
  253. cleanTheWholeScene() {
  254. const e = this.scene.getFrameId();
  255. this.scene.onBeforeRenderObservable.clear(),
  256. this.scene.onAfterRenderObservable.clear(),
  257. this.scene.clearCachedVertexData(),
  258. this.scene.cleanCachedTextureBuffer(),
  259. this.scene.registerBeforeRender(()=>{
  260. this.scene.getFrameId() - e > 5 && this.scene.dispose()
  261. }
  262. )
  263. }
  264. getAreaAvatar(e, t) {
  265. const r = [];
  266. return this._avatarManager.getAvatarList().forEach(n=>{
  267. const o = e
  268. , a = n.position;
  269. a && o && calcDistance3D(o, a) < t && r.push(n.id)
  270. }
  271. ),
  272. r
  273. }
  274. setEngineSize(e) {
  275. const t = e.width
  276. , r = e.height
  277. , n = this.canvas.width;
  278. this.canvas.height,
  279. this.engine.setSize(Math.round(n), Math.round(n * (r / t)))
  280. }
  281. getCurrentShaderMode() {
  282. return this._currentShader === this._materialManager.getDefaultShader() ? 0 : this._currentShader === this._materialManager.getPureVideoShader() ? 1 : 2
  283. }
  284. addSkyTV(e, t) {
  285. return this._skytv = new XTelevision(this.scene,e,this,t),
  286. this._skytv
  287. }
  288. addMv(e, t) {
  289. this._mv.push(new XTelevision(this.scene,e,this,t))
  290. }
  291. addMeshInfo(e) {
  292. this._lowpolyManager.setMeshInfo(e)
  293. }
  294. applyShader() {
  295. return new Promise((e,t)=>{
  296. this.shaderMode == EShaderMode.videoAndPano || this.shaderMode == EShaderMode.video ? this.changeVideoShaderForLowModel() : this.shaderMode == EShaderMode.default && this.changeDefaultShaderForLowModel(),
  297. e(!0)
  298. }
  299. )
  300. }
  301. changeHardwareScaling(e) {
  302. e < 1 ? e = 1 : e > 2.5 && (e = 2.5),
  303. this._bChangeEngineSize = !0,
  304. this.engine.setHardwareScalingLevel(this._initEngineScaleNumber * e)
  305. }
  306. getCurrentUsedPanoId() {
  307. return this._currentPanoId
  308. }
  309. render() {
  310. try {
  311. this.scene.render()
  312. } catch (e) {
  313. throw logger.error(`[Engine] Render Error: ${e}`),
  314. e
  315. }
  316. }
  317. isReadyToRender(e) {
  318. const {checkMesh: t=!0, checkEffect: r=!1, checkPostProgress: n=!1, checkParticle: o=!1, checkAnimation: a=!1, materialNameWhiteLists: s=[]} = e;
  319. if (this.scene._isDisposed)
  320. return logger.error("[Engine] this.scene._isDisposed== false "),
  321. !1;
  322. let l;
  323. const u = this.scene.getEngine();
  324. if (r && !u.areAllEffectsReady())
  325. return logger.error("[Engine] engine.areAllEffectsReady == false"),
  326. !1;
  327. if (a && this.scene._pendingData.length > 0)
  328. return logger.error("[Engine] scene._pendingData.length > 0 && animation error"),
  329. !1;
  330. if (t) {
  331. for (l = 0; l < this.scene.meshes.length; l++) {
  332. const c = this.scene.meshes[l];
  333. if (!c.isEnabled() || !c.subMeshes || c.subMeshes.length === 0 || c != null && c.material != null && !(c.material.name.startsWith("Pure") || c.material.name.startsWith("Pano")))
  334. continue;
  335. if (!c.isReady(!0))
  336. return logger.error(`[Engine] scene. mesh isReady == false, mesh name:${c.name}, mesh xtype: ${c == null ? void 0 : c.xtype}, mesh xgroup: ${c == null ? void 0 : c.xgroup}, mesh xskinInfo: ${c == null ? void 0 : c.xskinInfo}`),
  337. !1;
  338. const h = c.hasThinInstances || c.getClassName() === "InstancedMesh" || c.getClassName() === "InstancedLinesMesh" || u.getCaps().instancedArrays && c.instances.length > 0;
  339. for (const f of this.scene._isReadyForMeshStage)
  340. if (!f.action(c, h))
  341. return logger.error(`[Engine] scene._isReadyForMeshStage == false, mesh name:${c.name}, mesh xtype: ${c == null ? void 0 : c.xtype}, mesh xgroup: ${c == null ? void 0 : c.xgroup}, mesh xskinInfo: ${c == null ? void 0 : c.xskinInfo}`),
  342. !1
  343. }
  344. for (l = 0; l < this.scene.geometries.length; l++)
  345. if (this.scene.geometries[l].delayLoadState === 2)
  346. return logger.error("[Engine] geometry.delayLoadState === 2"),
  347. !1
  348. }
  349. if (n) {
  350. if (this.scene.activeCameras && this.scene.activeCameras.length > 0) {
  351. for (const c of this.scene.activeCameras)
  352. if (!c.isReady(!0))
  353. return logger.error("[Engine] camera not ready === false, ", c.name),
  354. !1
  355. } else if (this.scene.activeCamera && !this.scene.activeCamera.isReady(!0))
  356. return logger.error("[Engine] activeCamera ready === false, ", this.scene.activeCamera.name),
  357. !1
  358. }
  359. if (o) {
  360. for (const c of this.scene.particleSystems)
  361. if (!c.isReady())
  362. return logger.error("[Engine] particleSystem ready === false, ", c.name),
  363. !1
  364. }
  365. return !0
  366. }
  367. changePanoShaderForLowModel(e) {
  368. return logger.info(`[Engine] changePanoShaderForLowModel: ${e}`),
  369. this._materialManager.allowYUVUpdate(),
  370. new Promise((t,r)=>{
  371. this._materialManager._isInDynamicRange(e) == !1 && r(!1),
  372. this._currentPanoId = e,
  373. this._currentShader = this._materialManager.getDynamicShader(e),
  374. this.changeShaderForLowModel().then(()=>{
  375. t(!0)
  376. }
  377. )
  378. }
  379. )
  380. }
  381. changeVideoShaderForLowModel() {
  382. return logger.info("[Engine] changeVideoShaderForLowModel"),
  383. this._currentShader = this._materialManager.getPureVideoShader(),
  384. this._materialManager.allowYUVUpdate(),
  385. this.changeShaderForLowModel()
  386. }
  387. changeDefaultShaderForLowModel() {
  388. return logger.info("[Engine] changeDefaultShaderForLowModel"),
  389. this._currentShader = this._materialManager.getDefaultShader(),
  390. this._materialManager.stopYUVUpdate(),
  391. this.changeShaderForLowModel()
  392. }
  393. changeShaderForLowModel() {
  394. return new Promise((e,t)=>{
  395. this._lowpolyManager.getMeshes().forEach(r=>{
  396. r.setMaterial(this._currentShader)
  397. }
  398. ),
  399. this._lowpolyManager.getCgMesh().mesh.material = this._currentShader,
  400. e(!0)
  401. }
  402. )
  403. }
  404. setIBL(e) {
  405. this._lightManager.setIBL(e)
  406. }
  407. // 后处理bloom
  408. postprocessing() {
  409. const e = new BABYLON.DefaultRenderingPipeline("default",!0,this.scene);
  410. e.imageProcessingEnabled = !1,
  411. // e.bloomEnabled = !0,
  412. e.bloomThreshold = 1,
  413. e.bloomWeight = 1,
  414. e.bloomKernel = 64,
  415. e.bloomScale = .1
  416. }
  417. // 查询name中包含SM_Stage和以ground开头的meshes
  418. getGround() {
  419. const t = this._lowpolyManager.getMeshes()
  420. , r = [];
  421. return t.forEach(n=>{
  422. n.mesh.name.indexOf("SM_Stage") >= 0 && r.push(n.mesh)
  423. }),
  424. t.forEach(n=>{
  425. n.mesh.name.indexOf("Level _L01") >= 0 && r.push(n.mesh)
  426. }),
  427. this.Scene.meshes.forEach(n=>{
  428. n.name.split("_")[0] === "ground" && r.push(n)
  429. }),
  430. r
  431. }
  432. }