XSceneManager.js 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525
  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. import { http1 } from "./Http1.js"
  15. import util from "./util.js"
  16. const logger = new Logger('XSceneManager')
  17. const getAlphaWidthMap = (i,e)=>{
  18. const t = new BABYLON.DynamicTexture("test",3,e)
  19. , r = new Map;
  20. for (let n = 32; n < 127; n++) {
  21. const o = String.fromCodePoint(n)
  22. , a = 2 + "px " + i;
  23. t.drawText(o, null, null, a, "#000000", "#ffffff", !0);
  24. const s = t.getContext();
  25. s.font = a;
  26. const l = s.measureText(o).width;
  27. r.set(n, l)
  28. }
  29. return t.dispose(),
  30. r
  31. }
  32. export default class XSceneManager {
  33. constructor(e, t) {
  34. E(this, "scene");
  35. E(this, "engine");
  36. E(this, "canvas");
  37. E(this, "gl");
  38. E(this, "_yuvInfo");
  39. E(this, "cameraParam");
  40. E(this, "shaderMode");
  41. E(this, "panoInfo");
  42. E(this, "_initEngineScaleNumber");
  43. E(this, "_forceKeepVertical", !1);
  44. E(this, "_currentShader");
  45. E(this, "_currentPanoId");
  46. E(this, "_renderStatusCheckCount", 0);
  47. E(this, "_renderStatusNotChecktCount", 0);
  48. E(this, "_nonlinearCanvasResize", !1);
  49. E(this, "_bChangeEngineSize", !0);
  50. E(this, "_cameraManager");
  51. E(this, "_lowpolyManager");
  52. E(this, "_materialManager");
  53. E(this, "_statisticManager");
  54. E(this, "_breathPointManager");
  55. E(this, "_skytv");
  56. E(this, "_mv", []);
  57. E(this, "_decalManager");
  58. E(this, "_lightManager");
  59. E(this, "_avatarManager");
  60. E(this, "urlTransformer");
  61. E(this, "_billboardManager");
  62. E(this, "_backgroundImg");
  63. E(this, "engineRunTimeStats");
  64. E(this, "uploadHardwareSystemInfo", ()=>{
  65. const e = this.statisticComponent.getHardwareRenderInfo()
  66. , t = this.statisticComponent.getSystemInfo()
  67. , r = {
  68. driver: t.driver,
  69. vender: t.vender,
  70. webgl: t.version,
  71. os: t.os
  72. };
  73. logger.warn(JSON.stringify(e)),
  74. logger.warn(JSON.stringify(r))
  75. }
  76. );
  77. E(this, "addNewLowPolyMesh", async(e,t)=>(this._currentShader == null && await this.initSceneManager(),
  78. this._lowpolyManager.addNewLowPolyMesh(e, t, this._currentShader)));
  79. E(this, "initSceneManager", async()=>(
  80. await this._materialManager.initMaterial(),
  81. this.applyShader()
  82. ));
  83. E(this, "registerAfterRender", ()=>{
  84. var e;
  85. if (this._forceKeepVertical) {
  86. const t = this.canvas.width
  87. , r = this.canvas.height;
  88. let n = 0
  89. , o = [[0, 0, 0, 0], [0, 0, 0, 0]];
  90. 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),
  91. o = [[0, 0, t, n], [0, r - n, t, n]]) : (n = Math.ceil((t - this._yuvInfo.width * r / this._yuvInfo.height) / 2),
  92. o = [[0, 0, n, r], [t - n, 0, n, r]]),
  93. n > 0) {
  94. this.gl.enable(this.gl.SCISSOR_TEST);
  95. for (let a = 0; a < o.length; ++a)
  96. this.gl.scissor(o[a][0], o[a][1], o[a][2], o[a][3]),
  97. this.gl.clearColor(0, 0, 0, 1),
  98. this.gl.clear(this.gl.COLOR_BUFFER_BIT);
  99. this.gl.disable(this.gl.SCISSOR_TEST)
  100. }
  101. }
  102. }
  103. );
  104. E(this, "resetRender", ()=>{
  105. this.scene.environmentTexture && (this.scene.environmentTexture._texture ? this.lightComponent.setIBL(this.scene.environmentTexture._texture.url) : this.scene.environmentTexture.url && this.lightComponent.setIBL(this.scene.environmentTexture.url))
  106. }
  107. );
  108. const r = /iphone|ipad/gi.test(window.navigator.userAgent) || t.disableWebGL2
  109. , n = new BABYLON.Engine(e,!0,{
  110. preserveDrawingBuffer: !0,
  111. stencil: !0,
  112. disableWebGL2Support: r
  113. },!0)
  114. , o = new BABYLON.Scene(n);
  115. this.scene = o,
  116. this.engine = n,
  117. this.canvas = e,
  118. this.scene.clearColor = new BABYLON.Color4(.7,.7,.7,1),
  119. this.engine.getCaps().parallelShaderCompile = void 0,
  120. this._initEngineScaleNumber = this.engine.getHardwareScalingLevel(),
  121. this.engine.enableOfflineSupport = !1,
  122. this.engine.doNotHandleContextLost = !0,
  123. this.scene.clearCachedVertexData(),
  124. this.scene.cleanCachedTextureBuffer(),
  125. // 周恩光加 调试用工具栏
  126. // this.scene.debugLayer.show({
  127. // embedMode: true,
  128. // })
  129. this.urlTransformer = t.urlTransformer || (s=>Promise.resolve(s)),
  130. t.logger && defaultLog.setLogger(t.logger),
  131. this.gl = e.getContext("webgl2", {
  132. preserveDrawingBuffer: !0
  133. }) || e.getContext("webgl", {
  134. preserveDrawingBuffer: !0
  135. }) || e.getContext("experimental-webgl", {
  136. preserveDrawingBuffer: !0
  137. }),
  138. this.gl.pixelStorei(this.gl.UNPACK_ALIGNMENT, 1),
  139. this._currentPanoId = 0,
  140. t.forceKeepVertical != null && (this._forceKeepVertical = t.forceKeepVertical),
  141. t.panoInfo != null && (this.panoInfo = t.panoInfo),
  142. t.shaderMode != null && (this.shaderMode = t.shaderMode),
  143. t.yuvInfo != null ? this._yuvInfo = t.yuvInfo : this._yuvInfo = {
  144. width: t.videoResOriArray[0].width,
  145. height: t.videoResOriArray[0].height,
  146. fov: 50
  147. },
  148. t.cameraParam != null && (this.cameraParam = t.cameraParam),
  149. t.nonlinearCanvasResize != null && (this._nonlinearCanvasResize = t.nonlinearCanvasResize),
  150. this._cameraManager = new XCameraComponent(this.canvas,this.scene,{
  151. cameraParam: this.cameraParam,
  152. yuvInfo: this._yuvInfo,
  153. forceKeepVertical: this._forceKeepVertical
  154. }),
  155. this._lowpolyManager = new XStaticMeshComponent(this),
  156. this._materialManager = new XMaterialComponent(this,{
  157. videoResOriArray: t.videoResOriArray,
  158. yuvInfo: this._yuvInfo,
  159. panoInfo: this.panoInfo,
  160. shaderMode: this.shaderMode
  161. }),
  162. this._statisticManager = new XStats(this),
  163. this._breathPointManager = new XBreathPointManager(this),
  164. this._decalManager = new XDecalManager(this),
  165. this._avatarManager = new XAvatarManager(this),
  166. this._billboardManager = new XBillboardManager(this),
  167. this.billboardComponent.loadBackGroundTexToIDB(),
  168. this._lightManager = new XLightManager(this),
  169. // this.readPointData(),
  170. this.postprocessing(),
  171. this.initSceneManager(),
  172. this.engineRunTimeStats = new XEngineRunTimeStats,
  173. /iphone/gi.test(window.navigator.userAgent) && window.devicePixelRatio && window.devicePixelRatio === 3 && window.screen.width === 375 && window.screen.height === 812 ? this.engine.setHardwareScalingLevel(this._initEngineScaleNumber * 2) : this.engine.setHardwareScalingLevel(this._initEngineScaleNumber * 1.8),
  174. this.scene.registerBeforeRender(()=>{
  175. this._nonlinearCanvasResize && this._bChangeEngineSize && (this.setEngineSize(this._yuvInfo),
  176. this._bChangeEngineSize = !1)
  177. }
  178. ),
  179. this.scene.registerAfterRender(()=>{
  180. this._nonlinearCanvasResize || this.registerAfterRender()
  181. }
  182. ),
  183. window.addEventListener("resize", ()=>{
  184. this._nonlinearCanvasResize ? this._bChangeEngineSize = !0 : this.engine.resize()
  185. }
  186. ),
  187. XBillboardManager.alphaWidthMap = getAlphaWidthMap("Arial", this.scene),
  188. this.uploadHardwareSystemInfo()
  189. }
  190. get yuvInfo() {
  191. return this.getCurrentShaderMode() == 1 ? this._yuvInfo : {
  192. width: -1,
  193. height: -1,
  194. fov: -1
  195. }
  196. }
  197. set yuvInfo(e) {
  198. this.getCurrentShaderMode() == 1 && (this._yuvInfo = e,
  199. this._cameraManager.cameraFovChange(e))
  200. }
  201. get mainScene() {
  202. return this.scene
  203. }
  204. get cameraComponent() {
  205. return this._cameraManager
  206. }
  207. get staticmeshComponent() {
  208. return this._lowpolyManager
  209. }
  210. get materialComponent() {
  211. return this._materialManager
  212. }
  213. get statisticComponent() {
  214. return this._statisticManager
  215. }
  216. get avatarComponent() {
  217. return this._avatarManager
  218. }
  219. get lightComponent() {
  220. return this._lightManager
  221. }
  222. get Engine() {
  223. return this.engine
  224. }
  225. get Scene() {
  226. return this.scene
  227. }
  228. get billboardComponent() {
  229. return this._billboardManager
  230. }
  231. get breathPointComponent() {
  232. return this._breathPointManager
  233. }
  234. get skytvComponent() {
  235. return this._skytv
  236. }
  237. get mvComponent() {
  238. return this._mv
  239. }
  240. get decalComponent() {
  241. return this._decalManager
  242. }
  243. get currentShader() {
  244. return this._currentShader
  245. }
  246. get initEngineScaleNumber() {
  247. return this._initEngineScaleNumber
  248. }
  249. setImageQuality(e) {
  250. e == 0 ? (this.engine.setHardwareScalingLevel(this._initEngineScaleNumber * 1.8),
  251. logger.info("[Engine] change image quality to low, [" + this._initEngineScaleNumber * 1.8 + "]")) : e == 1 ? (this.engine.setHardwareScalingLevel(this._initEngineScaleNumber * 1.5),
  252. logger.info("[Engine] change image quality to mid, [" + this._initEngineScaleNumber * 1.5 + "]")) : e == 2 && (this.engine.setHardwareScalingLevel(this._initEngineScaleNumber * 1),
  253. logger.info("[Engine] change image quality to high, [" + this._initEngineScaleNumber * 1 + "]"))
  254. }
  255. setNonlinearCanvasResize(e) {
  256. this._nonlinearCanvasResize = e,
  257. this._bChangeEngineSize = e,
  258. e || this.engine.resize()
  259. }
  260. setBackgroundColor(e) {
  261. this.scene.clearColor = new Color4(e.r,e.g,e.b,e.a)
  262. }
  263. setBackgroundImg(e) {
  264. return this._backgroundImg != null && this._backgroundImg.url == e ? Promise.resolve(!0) : new Promise((t,r)=>{
  265. this.urlTransformer(e).then(n=>{
  266. this._backgroundImg == null ? this._backgroundImg = {
  267. layer: new Layer("tex_background_" + Date.now(),n,this.Scene,!0),
  268. url: e
  269. } : this._backgroundImg.url != e && this._backgroundImg.layer != null && this._backgroundImg.layer.texture != null && (this._backgroundImg.layer.texture.updateURL(n),
  270. this._backgroundImg.layer.name = "tex_background_" + Date.now(),
  271. this._backgroundImg.url = e),
  272. t(!0)
  273. }
  274. ).catch(n=>{
  275. logger.error(`[Engine] set background image Error: ${n}`),
  276. r(`[Engine] set background image Error: ${n}`)
  277. }
  278. )
  279. }
  280. )
  281. }
  282. cleanTheWholeScene() {
  283. const e = this.scene.getFrameId();
  284. this.scene.onBeforeRenderObservable.clear(),
  285. this.scene.onAfterRenderObservable.clear(),
  286. this.scene.clearCachedVertexData(),
  287. this.scene.cleanCachedTextureBuffer(),
  288. this.scene.registerBeforeRender(()=>{
  289. this.scene.getFrameId() - e > 5 && this.scene.dispose()
  290. }
  291. )
  292. }
  293. getAreaAvatar(e, t) {
  294. const r = [];
  295. return this._avatarManager.getAvatarList().forEach(n=>{
  296. const o = e
  297. , a = n.position;
  298. a && o && calcDistance3D(o, a) < t && r.push(n.id)
  299. }
  300. ),
  301. r
  302. }
  303. setEngineSize(e) {
  304. const t = e.width
  305. , r = e.height
  306. , n = this.canvas.width;
  307. this.canvas.height,
  308. this.engine.setSize(Math.round(n), Math.round(n * (r / t)))
  309. }
  310. getCurrentShaderMode() {
  311. return this._currentShader === this._materialManager.getDefaultShader() ? 0 : this._currentShader === this._materialManager.getPureVideoShader() ? 1 : 2
  312. }
  313. addSkyTV(e, t) {
  314. return this._skytv = new XTelevision(this.scene,e,this,t),
  315. this._skytv
  316. }
  317. addMv(e, t) {
  318. this._mv.push(new XTelevision(this.scene,e,this,t))
  319. }
  320. addMeshInfo(e) {
  321. this._lowpolyManager.setMeshInfo(e)
  322. }
  323. applyShader() {
  324. return new Promise((e,t)=>{
  325. this.shaderMode == EShaderMode.videoAndPano || this.shaderMode == EShaderMode.video ? this.changeVideoShaderForLowModel() : this.shaderMode == EShaderMode.default && this.changeDefaultShaderForLowModel(),
  326. e(!0)
  327. }
  328. )
  329. }
  330. changeHardwareScaling(e) {
  331. e < 1 ? e = 1 : e > 2.5 && (e = 2.5),
  332. this._bChangeEngineSize = !0,
  333. this.engine.setHardwareScalingLevel(this._initEngineScaleNumber * e)
  334. }
  335. getCurrentUsedPanoId() {
  336. return this._currentPanoId
  337. }
  338. render() {
  339. try {
  340. this.scene.render()
  341. } catch (e) {
  342. throw logger.error(`[Engine] Render Error: ${e}`),
  343. e
  344. }
  345. }
  346. isReadyToRender(e) {
  347. const {checkMesh: t=!0, checkEffect: r=!1, checkPostProgress: n=!1, checkParticle: o=!1, checkAnimation: a=!1, materialNameWhiteLists: s=[]} = e;
  348. if (this.scene._isDisposed)
  349. return logger.error("[Engine] this.scene._isDisposed== false "),
  350. !1;
  351. let l;
  352. const u = this.scene.getEngine();
  353. if (r && !u.areAllEffectsReady())
  354. return logger.error("[Engine] engine.areAllEffectsReady == false"),
  355. !1;
  356. if (a && this.scene._pendingData.length > 0)
  357. return logger.error("[Engine] scene._pendingData.length > 0 && animation error"),
  358. !1;
  359. if (t) {
  360. for (l = 0; l < this.scene.meshes.length; l++) {
  361. const c = this.scene.meshes[l];
  362. if (!c.isEnabled() || !c.subMeshes || c.subMeshes.length === 0 || c != null && c.material != null && !(c.material.name.startsWith("Pure") || c.material.name.startsWith("Pano")))
  363. continue;
  364. if (!c.isReady(!0))
  365. 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}`),
  366. !1;
  367. const h = c.hasThinInstances || c.getClassName() === "InstancedMesh" || c.getClassName() === "InstancedLinesMesh" || u.getCaps().instancedArrays && c.instances.length > 0;
  368. for (const f of this.scene._isReadyForMeshStage)
  369. if (!f.action(c, h))
  370. 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}`),
  371. !1
  372. }
  373. for (l = 0; l < this.scene.geometries.length; l++)
  374. if (this.scene.geometries[l].delayLoadState === 2)
  375. return logger.error("[Engine] geometry.delayLoadState === 2"),
  376. !1
  377. }
  378. if (n) {
  379. if (this.scene.activeCameras && this.scene.activeCameras.length > 0) {
  380. for (const c of this.scene.activeCameras)
  381. if (!c.isReady(!0))
  382. return logger.error("[Engine] camera not ready === false, ", c.name),
  383. !1
  384. } else if (this.scene.activeCamera && !this.scene.activeCamera.isReady(!0))
  385. return logger.error("[Engine] activeCamera ready === false, ", this.scene.activeCamera.name),
  386. !1
  387. }
  388. if (o) {
  389. for (const c of this.scene.particleSystems)
  390. if (!c.isReady())
  391. return logger.error("[Engine] particleSystem ready === false, ", c.name),
  392. !1
  393. }
  394. return !0
  395. }
  396. changePanoShaderForLowModel(e) {
  397. return logger.info(`[Engine] changePanoShaderForLowModel: ${e}`),
  398. this._materialManager.allowYUVUpdate(),
  399. new Promise((t,r)=>{
  400. this._materialManager._isInDynamicRange(e) == !1 && r(!1),
  401. this._currentPanoId = e,
  402. this._currentShader = this._materialManager.getDynamicShader(e),
  403. this.changeShaderForLowModel().then(()=>{
  404. t(!0)
  405. }
  406. )
  407. }
  408. )
  409. }
  410. changeVideoShaderForLowModel() {
  411. return logger.info("[Engine] changeVideoShaderForLowModel"),
  412. this._currentShader = this._materialManager.getPureVideoShader(),
  413. this._materialManager.allowYUVUpdate(),
  414. this.changeShaderForLowModel()
  415. }
  416. changeDefaultShaderForLowModel() {
  417. return logger.info("[Engine] changeDefaultShaderForLowModel"),
  418. this._currentShader = this._materialManager.getDefaultShader(),
  419. this._materialManager.stopYUVUpdate(),
  420. this.changeShaderForLowModel()
  421. }
  422. changeShaderForLowModel() {
  423. return new Promise((e,t)=>{
  424. this._lowpolyManager.getMeshes().forEach(r=>{
  425. r.setMaterial(this._currentShader)
  426. }
  427. ),
  428. this._lowpolyManager.getCgMesh().mesh.material = this._currentShader,
  429. e(!0)
  430. }
  431. )
  432. }
  433. setIBL(e) {
  434. this._lightManager.setIBL(e)
  435. }
  436. postprocessing() {
  437. const e = new BABYLON.DefaultRenderingPipeline("default",!0,this.scene);
  438. e.imageProcessingEnabled = !1,
  439. e.bloomEnabled = !0,
  440. e.bloomThreshold = 1,
  441. e.bloomWeight = 1,
  442. e.bloomKernel = 64,
  443. e.bloomScale = .1
  444. }
  445. getGround(e) {
  446. const t = this._lowpolyManager.getMeshes()
  447. , r = [];
  448. return t.forEach(n=>{
  449. n.mesh.name.indexOf("SM_Stage") >= 0 && r.push(n.mesh)
  450. }
  451. ),
  452. this.Scene.meshes.forEach(n=>{
  453. n.name.split("_")[0] === "ground" && r.push(n)
  454. }
  455. ),
  456. r
  457. }
  458. // // zeg
  459. // readPointData() {
  460. // return fetch("./assets/points.json", {
  461. // headers: {
  462. // 'content-type': 'application/json'
  463. // },
  464. // method: 'GET',
  465. // })
  466. // .then(response => response.json())
  467. // .then(response => {
  468. // this.texture = new BABYLON.Texture("https://4dkk.4dage.com/v3/img/marker.png", this.scene);
  469. // response.forEach(data => {
  470. // var plane = new BABYLON.Mesh.CreatePlane("TextPlane", 0.2, this.scene, true);
  471. // plane.material = new BABYLON.StandardMaterial("TextPlaneMaterial", this.scene);
  472. // plane.material.alpha = 1,
  473. // plane.material.emissiveTexture = this.texture,
  474. // plane.material.backFaceCulling = true,
  475. // plane.material.diffuseTexture = this.texture,
  476. // plane.material.diffuseTexture.hasAlpha = !0,
  477. // plane.material.useAlphaFromDiffuseTexture = !0
  478. // plane.rotation.x = Math.PI / 2
  479. // plane.position.x = -data.position.x;
  480. // plane.position.y = data.position.y+0.01;
  481. // plane.position.z = data.position.z;
  482. // // todo 矫正
  483. // let ue4Pos = util.xversePosition2Ue4({x: -data.position.x, y: data.position.y, z: data.position.z})
  484. // // console.error(data.position, ue4Pos)
  485. // data.position0 = data.position
  486. // data.position = new BABYLON.Vector3(ue4Pos.x, ue4Pos.y, ue4Pos.z)
  487. // })
  488. // window.points = response
  489. // })
  490. // }
  491. getClosestPointData(vec) {
  492. vec = new BABYLON.Vector3(vec.x, vec.y, vec.z)
  493. let closestPoint = { data: null, length: 99999 }
  494. window.points.forEach( data => {
  495. let length = vec.clone().subtract(data.position).length()
  496. if(length < closestPoint.length) {
  497. closestPoint.data = data
  498. closestPoint.length = length
  499. }
  500. })
  501. return closestPoint.data
  502. }
  503. correctCameraDirec() {
  504. // 视频逆时针旋转
  505. let num = Math.round((this._cameraManager.mainCamera.rotation.y + Math.PI/2*5) / (Math.PI/4)) // 矫正
  506. let angle = num * (Math.PI/4) - (this._cameraManager.mainCamera.rotation.y + Math.PI/2*5)
  507. return {
  508. anglePlus: angle,
  509. dircNum: num <= 0 ? -num%8 : num%8
  510. }
  511. }
  512. }