59b7958b47eec6168615a6469581f8f48e26cb00.js 62 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282
  1. System.register(["__unresolved_0", "cc", "cc/env", "__unresolved_1"], function (_export, _context) {
  2. "use strict";
  3. var _reporterNs, _cclegacy, __checkObsolete__, __checkObsoleteInNamespace__, DEBUG, EDITOR, assert, clamp, geometry, gfx, Layers, Material, pipeline, renderer, rendering, sys, Vec2, Vec3, Vec4, cclegacy, PipelineEventType, warn, makePipelineSettings, PipelineConfigs, CameraConfigs, _crd, AABB, Sphere, intersect, ClearFlagBit, Color, Format, FormatFeatureBit, LoadOp, StoreOp, TextureType, Viewport, scene, CameraUsage, CSMLevel, LightType, defaultSettings, QueueHint, SceneFlags, ResourceFlags, ResourceResidency;
  4. function forwardNeedClearColor(camera) {
  5. return !!(camera.clearFlag & (ClearFlagBit.COLOR | ClearFlagBit.STENCIL << 1));
  6. }
  7. function getCsmMainLightViewport(light, w, h, level, vp, screenSpaceSignY) {
  8. if (light.shadowFixedArea || light.csmLevel === CSMLevel.LEVEL_1) {
  9. vp.left = 0;
  10. vp.top = 0;
  11. vp.width = Math.trunc(w);
  12. vp.height = Math.trunc(h);
  13. } else {
  14. vp.left = Math.trunc(level % 2 * 0.5 * w);
  15. if (screenSpaceSignY > 0) {
  16. vp.top = Math.trunc((1 - Math.floor(level / 2)) * 0.5 * h);
  17. } else {
  18. vp.top = Math.trunc(Math.floor(level / 2) * 0.5 * h);
  19. }
  20. vp.width = Math.trunc(0.5 * w);
  21. vp.height = Math.trunc(0.5 * h);
  22. }
  23. vp.left = Math.max(0, vp.left);
  24. vp.top = Math.max(0, vp.top);
  25. vp.width = Math.max(1, vp.width);
  26. vp.height = Math.max(1, vp.height);
  27. }
  28. function setupPipelineConfigs(ppl, configs) {
  29. const sampleFeature = FormatFeatureBit.SAMPLED_TEXTURE | FormatFeatureBit.LINEAR_FILTER;
  30. const device = ppl.device; // Platform
  31. configs.isWeb = !sys.isNative;
  32. configs.isWebGL1 = device.gfxAPI === gfx.API.WEBGL;
  33. configs.isWebGPU = device.gfxAPI === gfx.API.WEBGPU;
  34. configs.isMobile = sys.isMobile; // Rendering
  35. configs.isHDR = ppl.pipelineSceneData.isHDR; // Has tone mapping
  36. configs.useFloatOutput = ppl.getMacroBool('CC_USE_FLOAT_OUTPUT');
  37. configs.toneMappingType = ppl.pipelineSceneData.postSettings.toneMappingType; // Shadow
  38. const shadowInfo = ppl.pipelineSceneData.shadows;
  39. configs.shadowEnabled = shadowInfo.enabled;
  40. configs.shadowMapFormat = pipeline.supportsR32FloatTexture(ppl.device) ? Format.R32F : Format.RGBA8;
  41. configs.shadowMapSize.set(shadowInfo.size);
  42. configs.usePlanarShadow = shadowInfo.enabled && shadowInfo.type === renderer.scene.ShadowType.Planar; // Device
  43. configs.screenSpaceSignY = ppl.device.capabilities.screenSpaceSignY;
  44. configs.supportDepthSample = (ppl.device.getFormatFeatures(Format.DEPTH_STENCIL) & sampleFeature) === sampleFeature; // Constants
  45. const screenSpaceSignY = device.capabilities.screenSpaceSignY;
  46. configs.platform.x = configs.isMobile ? 1.0 : 0.0;
  47. configs.platform.w = screenSpaceSignY * 0.5 + 0.5 << 1 | device.capabilities.clipSpaceSignY * 0.5 + 0.5;
  48. }
  49. function setupPostProcessConfigs(pipelineConfigs, settings, cameraConfigs) {
  50. cameraConfigs.enableDOF = pipelineConfigs.supportDepthSample && settings.depthOfField.enabled && !!settings.depthOfField.material;
  51. cameraConfigs.enableBloom = settings.bloom.enabled && !!settings.bloom.material;
  52. cameraConfigs.enableColorGrading = settings.colorGrading.enabled && !!settings.colorGrading.material && !!settings.colorGrading.colorGradingMap;
  53. cameraConfigs.enableFXAA = settings.fxaa.enabled && !!settings.fxaa.material;
  54. cameraConfigs.enablePostProcess = cameraConfigs.enableDOF || cameraConfigs.enableBloom || cameraConfigs.enableColorGrading || cameraConfigs.enableFXAA;
  55. }
  56. function setupCameraConfigs(camera, pipelineConfigs, cameraConfigs) {
  57. const window = camera.window;
  58. const isMainGameWindow = camera.cameraUsage === CameraUsage.GAME && !!window.swapchain;
  59. const isEditorView = camera.cameraUsage === CameraUsage.SCENE_VIEW || camera.cameraUsage === CameraUsage.PREVIEW;
  60. cameraConfigs.colorName = window.colorName;
  61. cameraConfigs.depthStencilName = window.depthStencilName;
  62. cameraConfigs.useFullPipeline = (camera.visibility & Layers.Enum.DEFAULT) !== 0;
  63. cameraConfigs.enableMainLightShadowMap = pipelineConfigs.shadowEnabled && !pipelineConfigs.usePlanarShadow && !!camera.scene && !!camera.scene.mainLight && camera.scene.mainLight.shadowEnabled;
  64. cameraConfigs.enableMainLightPlanarShadowMap = pipelineConfigs.shadowEnabled && pipelineConfigs.usePlanarShadow && !!camera.scene && !!camera.scene.mainLight && camera.scene.mainLight.shadowEnabled;
  65. cameraConfigs.enablePlanarReflectionProbe = isMainGameWindow || camera.cameraUsage === CameraUsage.SCENE_VIEW;
  66. cameraConfigs.enableProfiler = DEBUG && isMainGameWindow;
  67. cameraConfigs.settings = camera.pipelineSettings ? camera.pipelineSettings : defaultSettings;
  68. setupPostProcessConfigs(pipelineConfigs, cameraConfigs.settings, cameraConfigs);
  69. if (isEditorView) {
  70. const editorSettings = rendering.getEditorPipelineSettings();
  71. if (editorSettings) {
  72. cameraConfigs.settings = editorSettings;
  73. setupPostProcessConfigs(pipelineConfigs, cameraConfigs.settings, cameraConfigs);
  74. }
  75. } // MSAA
  76. cameraConfigs.enableMSAA = cameraConfigs.settings.msaa.enabled && !pipelineConfigs.isWeb // TODO(zhouzhenglong): remove this constraint
  77. && !pipelineConfigs.isWebGL1; // Shading scale
  78. cameraConfigs.shadingScale = cameraConfigs.settings.shadingScale;
  79. cameraConfigs.enableShadingScale = cameraConfigs.settings.enableShadingScale && cameraConfigs.shadingScale !== 1.0; // FSR (Depend on Shading scale)
  80. cameraConfigs.enableFSR = cameraConfigs.settings.fsr.enabled && !!cameraConfigs.settings.fsr.material && cameraConfigs.enableShadingScale && cameraConfigs.shadingScale < 1.0; // Forward rendering (Depend on MSAA and TBR)
  81. cameraConfigs.singleForwardRadiancePass = pipelineConfigs.isMobile || cameraConfigs.enableMSAA;
  82. cameraConfigs.enableHDR = cameraConfigs.useFullPipeline && pipelineConfigs.useFloatOutput;
  83. cameraConfigs.radianceFormat = cameraConfigs.enableHDR ? gfx.Format.RGBA16F : gfx.Format.RGBA8;
  84. }
  85. function _reportPossibleCrUseOfPipelineSettings(extras) {
  86. _reporterNs.report("PipelineSettings", "./builtin-pipeline-types", _context.meta, extras);
  87. }
  88. function _reportPossibleCrUseOfmakePipelineSettings(extras) {
  89. _reporterNs.report("makePipelineSettings", "./builtin-pipeline-types", _context.meta, extras);
  90. }
  91. return {
  92. setters: [function (_unresolved_) {
  93. _reporterNs = _unresolved_;
  94. }, function (_cc) {
  95. _cclegacy = _cc.cclegacy;
  96. __checkObsolete__ = _cc.__checkObsolete__;
  97. __checkObsoleteInNamespace__ = _cc.__checkObsoleteInNamespace__;
  98. assert = _cc.assert;
  99. clamp = _cc.clamp;
  100. geometry = _cc.geometry;
  101. gfx = _cc.gfx;
  102. Layers = _cc.Layers;
  103. Material = _cc.Material;
  104. pipeline = _cc.pipeline;
  105. renderer = _cc.renderer;
  106. rendering = _cc.rendering;
  107. sys = _cc.sys;
  108. Vec2 = _cc.Vec2;
  109. Vec3 = _cc.Vec3;
  110. Vec4 = _cc.Vec4;
  111. cclegacy = _cc.cclegacy;
  112. PipelineEventType = _cc.PipelineEventType;
  113. warn = _cc.warn;
  114. }, function (_ccEnv) {
  115. DEBUG = _ccEnv.DEBUG;
  116. EDITOR = _ccEnv.EDITOR;
  117. }, function (_unresolved_2) {
  118. makePipelineSettings = _unresolved_2.makePipelineSettings;
  119. }],
  120. execute: function () {
  121. _crd = true;
  122. _cclegacy._RF.push({}, "ff9b0GZzgRM/obMbHGfCNbk", "builtin-pipeline", undefined);
  123. /*
  124. Copyright (c) 2021-2024 Xiamen Yaji Software Co., Ltd.
  125. https://www.cocos.com/
  126. Permission is hereby granted, free of charge, to any person obtaining a copy
  127. of this software and associated documentation files (the "Software"), to deal
  128. in the Software without restriction, including without limitation the rights to
  129. use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
  130. of the Software, and to permit persons to whom the Software is furnished to do so,
  131. subject to the following conditions:
  132. The above copyright notice and this permission notice shall be included in
  133. all copies or substantial portions of the Software.
  134. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  135. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  136. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  137. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  138. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  139. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  140. THE SOFTWARE.
  141. */
  142. __checkObsolete__(['assert', 'clamp', 'geometry', 'gfx', 'Layers', 'Material', 'pipeline', 'renderer', 'rendering', 'sys', 'Vec2', 'Vec3', 'Vec4', 'cclegacy', 'PipelineEventType', 'PipelineEventProcessor', 'ReflectionProbeManager', 'warn']);
  143. ({
  144. AABB,
  145. Sphere,
  146. intersect
  147. } = geometry);
  148. ({
  149. ClearFlagBit,
  150. Color,
  151. Format,
  152. FormatFeatureBit,
  153. LoadOp,
  154. StoreOp,
  155. TextureType,
  156. Viewport
  157. } = gfx);
  158. ({
  159. scene
  160. } = renderer);
  161. ({
  162. CameraUsage,
  163. CSMLevel,
  164. LightType
  165. } = scene);
  166. PipelineConfigs = class PipelineConfigs {
  167. constructor() {
  168. this.isWeb = false;
  169. this.isWebGL1 = false;
  170. this.isWebGPU = false;
  171. this.isMobile = false;
  172. this.isHDR = false;
  173. this.useFloatOutput = false;
  174. this.toneMappingType = 0;
  175. // 0: ACES, 1: None
  176. this.shadowEnabled = false;
  177. this.shadowMapFormat = Format.R32F;
  178. this.shadowMapSize = new Vec2(1, 1);
  179. this.usePlanarShadow = false;
  180. this.screenSpaceSignY = 1;
  181. this.supportDepthSample = false;
  182. this.mobileMaxSpotLightShadowMaps = 1;
  183. this.platform = new Vec4(0, 0, 0, 0);
  184. }
  185. };
  186. defaultSettings = (_crd && makePipelineSettings === void 0 ? (_reportPossibleCrUseOfmakePipelineSettings({
  187. error: Error()
  188. }), makePipelineSettings) : makePipelineSettings)();
  189. CameraConfigs = class CameraConfigs {
  190. constructor() {
  191. this.colorName = '';
  192. this.depthStencilName = '';
  193. this.enableMainLightShadowMap = false;
  194. this.enableMainLightPlanarShadowMap = false;
  195. this.enablePostProcess = false;
  196. this.enableProfiler = false;
  197. this.enableShadingScale = false;
  198. this.enableMSAA = false;
  199. this.enableDOF = false;
  200. this.enableBloom = false;
  201. this.enableColorGrading = false;
  202. this.enableFXAA = false;
  203. this.enableFSR = false;
  204. this.enableHDR = false;
  205. this.enablePlanarReflectionProbe = false;
  206. this.useFullPipeline = false;
  207. this.singleForwardRadiancePass = false;
  208. this.radianceFormat = gfx.Format.RGBA8;
  209. this.shadingScale = 0.5;
  210. this.settings = defaultSettings;
  211. }
  212. };
  213. if (rendering) {
  214. ({
  215. QueueHint,
  216. SceneFlags,
  217. ResourceFlags,
  218. ResourceResidency
  219. } = rendering);
  220. class ForwardLighting {
  221. constructor() {
  222. // Active lights
  223. this.lights = [];
  224. // Active spot lights with shadows (Mutually exclusive with `lights`)
  225. this.shadowEnabledSpotLights = [];
  226. // Internal cached resources
  227. this._sphere = Sphere.create(0, 0, 0, 1);
  228. this._boundingBox = new AABB();
  229. this._rangedDirLightBoundingBox = new AABB(0.0, 0.0, 0.0, 0.5, 0.5, 0.5);
  230. }
  231. // ----------------------------------------------------------------
  232. // Interface
  233. // ----------------------------------------------------------------
  234. cullLights(scene, frustum, cameraPos) {
  235. // TODO(zhouzhenglong): Make light culling native
  236. this.lights.length = 0;
  237. this.shadowEnabledSpotLights.length = 0; // spot lights
  238. for (const light of scene.spotLights) {
  239. if (light.baked) {
  240. continue;
  241. }
  242. Sphere.set(this._sphere, light.position.x, light.position.y, light.position.z, light.range);
  243. if (intersect.sphereFrustum(this._sphere, frustum)) {
  244. if (light.shadowEnabled) {
  245. this.shadowEnabledSpotLights.push(light);
  246. } else {
  247. this.lights.push(light);
  248. }
  249. }
  250. } // sphere lights
  251. for (const light of scene.sphereLights) {
  252. if (light.baked) {
  253. continue;
  254. }
  255. Sphere.set(this._sphere, light.position.x, light.position.y, light.position.z, light.range);
  256. if (intersect.sphereFrustum(this._sphere, frustum)) {
  257. this.lights.push(light);
  258. }
  259. } // point lights
  260. for (const light of scene.pointLights) {
  261. if (light.baked) {
  262. continue;
  263. }
  264. Sphere.set(this._sphere, light.position.x, light.position.y, light.position.z, light.range);
  265. if (intersect.sphereFrustum(this._sphere, frustum)) {
  266. this.lights.push(light);
  267. }
  268. } // ranged dir lights
  269. for (const light of scene.rangedDirLights) {
  270. AABB.transform(this._boundingBox, this._rangedDirLightBoundingBox, light.node.getWorldMatrix());
  271. if (intersect.aabbFrustum(this._boundingBox, frustum)) {
  272. this.lights.push(light);
  273. }
  274. }
  275. if (cameraPos) {
  276. this.shadowEnabledSpotLights.sort((lhs, rhs) => Vec3.squaredDistance(cameraPos, lhs.position) - Vec3.squaredDistance(cameraPos, rhs.position));
  277. }
  278. }
  279. _addLightQueues(camera, pass) {
  280. for (const light of this.lights) {
  281. const queue = pass.addQueue(QueueHint.BLEND, 'forward-add');
  282. switch (light.type) {
  283. case LightType.SPHERE:
  284. queue.name = 'sphere-light';
  285. break;
  286. case LightType.SPOT:
  287. queue.name = 'spot-light';
  288. break;
  289. case LightType.POINT:
  290. queue.name = 'point-light';
  291. break;
  292. case LightType.RANGED_DIRECTIONAL:
  293. queue.name = 'ranged-directional-light';
  294. break;
  295. default:
  296. queue.name = 'unknown-light';
  297. }
  298. queue.addScene(camera, SceneFlags.BLEND, light);
  299. }
  300. }
  301. addSpotlightShadowPasses(ppl, camera, maxNumShadowMaps) {
  302. let i = 0;
  303. for (const light of this.shadowEnabledSpotLights) {
  304. const shadowMapSize = ppl.pipelineSceneData.shadows.size;
  305. const shadowPass = ppl.addRenderPass(shadowMapSize.x, shadowMapSize.y, 'default');
  306. shadowPass.name = `SpotLightShadowPass${i}`;
  307. shadowPass.addRenderTarget(`SpotShadowMap${i}`, LoadOp.CLEAR, StoreOp.STORE, new Color(1, 1, 1, 1));
  308. shadowPass.addDepthStencil(`SpotShadowDepth${i}`, LoadOp.CLEAR, StoreOp.DISCARD);
  309. shadowPass.addQueue(QueueHint.NONE, 'shadow-caster').addScene(camera, SceneFlags.OPAQUE | SceneFlags.MASK | SceneFlags.SHADOW_CASTER).useLightFrustum(light);
  310. ++i;
  311. if (i >= maxNumShadowMaps) {
  312. break;
  313. }
  314. }
  315. }
  316. addLightQueues(pass, camera, maxNumShadowMaps) {
  317. this._addLightQueues(camera, pass);
  318. let i = 0;
  319. for (const light of this.shadowEnabledSpotLights) {
  320. // Add spot-light pass
  321. // Save last RenderPass to the `pass` variable
  322. // TODO(zhouzhenglong): Fix per queue addTexture
  323. pass.addTexture(`SpotShadowMap${i}`, 'cc_spotShadowMap');
  324. const queue = pass.addQueue(QueueHint.BLEND, 'forward-add');
  325. queue.addScene(camera, SceneFlags.BLEND, light);
  326. ++i;
  327. if (i >= maxNumShadowMaps) {
  328. break;
  329. }
  330. }
  331. } // Notice: ForwardLighting cannot handle a lot of lights.
  332. // If there are too many lights, the performance will be very poor.
  333. // If many lights are needed, please implement a forward+ or deferred rendering pipeline.
  334. addLightPasses(colorName, depthStencilName, depthStencilStoreOp, id, // window id
  335. width, height, camera, viewport, ppl, pass) {
  336. this._addLightQueues(camera, pass);
  337. let count = 0;
  338. const shadowMapSize = ppl.pipelineSceneData.shadows.size;
  339. for (const light of this.shadowEnabledSpotLights) {
  340. const shadowPass = ppl.addRenderPass(shadowMapSize.x, shadowMapSize.y, 'default');
  341. shadowPass.name = 'SpotlightShadowPass'; // Reuse csm shadow map
  342. shadowPass.addRenderTarget(`ShadowMap${id}`, LoadOp.CLEAR, StoreOp.STORE, new Color(1, 1, 1, 1));
  343. shadowPass.addDepthStencil(`ShadowDepth${id}`, LoadOp.CLEAR, StoreOp.DISCARD);
  344. shadowPass.addQueue(QueueHint.NONE, 'shadow-caster').addScene(camera, SceneFlags.OPAQUE | SceneFlags.MASK | SceneFlags.SHADOW_CASTER).useLightFrustum(light); // Add spot-light pass
  345. // Save last RenderPass to the `pass` variable
  346. ++count;
  347. const storeOp = count === this.shadowEnabledSpotLights.length ? depthStencilStoreOp : StoreOp.STORE;
  348. pass = ppl.addRenderPass(width, height, 'default');
  349. pass.name = 'SpotlightWithShadowMap';
  350. pass.setViewport(viewport);
  351. pass.addRenderTarget(colorName, LoadOp.LOAD);
  352. pass.addDepthStencil(depthStencilName, LoadOp.LOAD, storeOp);
  353. pass.addTexture(`ShadowMap${id}`, 'cc_spotShadowMap');
  354. const queue = pass.addQueue(QueueHint.BLEND, 'forward-add');
  355. queue.addScene(camera, SceneFlags.BLEND, light);
  356. }
  357. return pass;
  358. }
  359. isMultipleLightPassesNeeded() {
  360. return this.shadowEnabledSpotLights.length > 0;
  361. }
  362. }
  363. class BuiltinPipelineBuilder {
  364. constructor() {
  365. this._pipelineEvent = cclegacy.director.root.pipelineEvent;
  366. // Internal cached resources
  367. this._clearColor = new Color(0, 0, 0, 1);
  368. this._clearColorTransparentBlack = new Color(0, 0, 0, 0);
  369. this._reflectionProbeClearColor = new Vec3(0, 0, 0);
  370. this._viewport = new Viewport();
  371. this._configs = new PipelineConfigs();
  372. this._cameraConfigs = new CameraConfigs();
  373. // DepthOfField
  374. this._cocParams = new Vec4(0, 0, 0, 0);
  375. this._cocTexSize = new Vec4(0, 0, 0, 0);
  376. // Bloom
  377. this._bloomParams = new Vec4(0, 0, 0, 0);
  378. this._bloomTexSize = new Vec4(0, 0, 0, 0);
  379. this._bloomWidths = [];
  380. this._bloomHeights = [];
  381. this._bloomTexNames = [];
  382. // Color Grading
  383. this._colorGradingTexSize = new Vec2(0, 0);
  384. // FXAA
  385. this._fxaaParams = new Vec4(0, 0, 0, 0);
  386. // FSR
  387. this._fsrParams = new Vec4(0, 0, 0, 0);
  388. this._fsrTexSize = new Vec4(0, 0, 0, 0);
  389. // Materials
  390. this._copyAndTonemapMaterial = new Material();
  391. // Internal States
  392. this._initialized = false;
  393. // TODO(zhouzhenglong): Make default effect asset loading earlier and remove this flag
  394. // Forward lighting
  395. this.forwardLighting = new ForwardLighting();
  396. }
  397. // ----------------------------------------------------------------
  398. // Interface
  399. // ----------------------------------------------------------------
  400. windowResize(ppl, window, camera, nativeWidth, nativeHeight) {
  401. setupPipelineConfigs(ppl, this._configs);
  402. setupCameraConfigs(camera, this._configs, this._cameraConfigs);
  403. const settings = this._cameraConfigs.settings;
  404. const id = window.renderWindowId;
  405. const width = this._cameraConfigs.enableShadingScale ? Math.max(Math.floor(nativeWidth * this._cameraConfigs.shadingScale), 1) : nativeWidth;
  406. const height = this._cameraConfigs.enableShadingScale ? Math.max(Math.floor(nativeHeight * this._cameraConfigs.shadingScale), 1) : nativeHeight; // Render Window (UI)
  407. ppl.addRenderWindow(this._cameraConfigs.colorName, Format.RGBA8, nativeWidth, nativeHeight, window, this._cameraConfigs.depthStencilName);
  408. if (this._cameraConfigs.enableShadingScale) {
  409. ppl.addDepthStencil(`ScaledSceneDepth${id}`, Format.DEPTH_STENCIL, width, height);
  410. ppl.addRenderTarget(`ScaledRadiance${id}`, this._cameraConfigs.radianceFormat, width, height);
  411. ppl.addRenderTarget(`ScaledLdrColor${id}`, Format.RGBA8, width, height);
  412. } else {
  413. ppl.addDepthStencil(`SceneDepth${id}`, Format.DEPTH_STENCIL, width, height);
  414. ppl.addRenderTarget(`Radiance${id}`, this._cameraConfigs.radianceFormat, width, height);
  415. ppl.addRenderTarget(`LdrColor${id}`, Format.RGBA8, width, height);
  416. }
  417. if (this._cameraConfigs.enableFSR) {
  418. ppl.addRenderTarget(`FsrColor${id}`, Format.RGBA8, nativeWidth, nativeHeight);
  419. } // MsaaRadiance
  420. if (this._cameraConfigs.enableMSAA) {
  421. // Notice: We never store multisample results.
  422. // These samples are always resolved and discarded at the end of the render pass.
  423. // So the ResourceResidency should be MEMORYLESS.
  424. if (this._cameraConfigs.enableHDR) {
  425. ppl.addTexture(`MsaaRadiance${id}`, TextureType.TEX2D, this._cameraConfigs.radianceFormat, width, height, 1, 1, 1, settings.msaa.sampleCount, ResourceFlags.COLOR_ATTACHMENT, ResourceResidency.MEMORYLESS);
  426. } else {
  427. ppl.addTexture(`MsaaRadiance${id}`, TextureType.TEX2D, Format.RGBA8, width, height, 1, 1, 1, settings.msaa.sampleCount, ResourceFlags.COLOR_ATTACHMENT, ResourceResidency.MEMORYLESS);
  428. }
  429. ppl.addTexture(`MsaaDepthStencil${id}`, TextureType.TEX2D, Format.DEPTH_STENCIL, width, height, 1, 1, 1, settings.msaa.sampleCount, ResourceFlags.DEPTH_STENCIL_ATTACHMENT, ResourceResidency.MEMORYLESS);
  430. } // Mainlight ShadowMap
  431. ppl.addRenderTarget(`ShadowMap${id}`, this._configs.shadowMapFormat, this._configs.shadowMapSize.x, this._configs.shadowMapSize.y);
  432. ppl.addDepthStencil(`ShadowDepth${id}`, Format.DEPTH_STENCIL, this._configs.shadowMapSize.x, this._configs.shadowMapSize.y); // Spot-light shadow maps
  433. if (this._cameraConfigs.singleForwardRadiancePass) {
  434. const count = this._configs.mobileMaxSpotLightShadowMaps;
  435. for (let i = 0; i !== count; ++i) {
  436. ppl.addRenderTarget(`SpotShadowMap${i}`, this._configs.shadowMapFormat, this._configs.shadowMapSize.x, this._configs.shadowMapSize.y);
  437. ppl.addDepthStencil(`SpotShadowDepth${i}`, Format.DEPTH_STENCIL, this._configs.shadowMapSize.x, this._configs.shadowMapSize.y);
  438. }
  439. } // ---------------------------------------------------------
  440. // Post Process
  441. // ---------------------------------------------------------
  442. // DepthOfField
  443. if (this._cameraConfigs.enableDOF) {
  444. const halfWidth = Math.max(Math.floor(width / 2), 1);
  445. const halfHeight = Math.max(Math.floor(height / 2), 1); // `DofCoc${id}` texture will reuse ldrColorName
  446. ppl.addRenderTarget(`DofRadiance${id}`, this._cameraConfigs.radianceFormat, width, height);
  447. ppl.addRenderTarget(`DofPrefilter${id}`, this._cameraConfigs.radianceFormat, halfWidth, halfHeight);
  448. ppl.addRenderTarget(`DofBokeh${id}`, this._cameraConfigs.radianceFormat, halfWidth, halfHeight);
  449. ppl.addRenderTarget(`DofFilter${id}`, this._cameraConfigs.radianceFormat, halfWidth, halfHeight);
  450. } // Bloom (Kawase Dual Filter)
  451. if (this._cameraConfigs.enableBloom) {
  452. let bloomWidth = width;
  453. let bloomHeight = height;
  454. for (let i = 0; i !== settings.bloom.iterations + 1; ++i) {
  455. bloomWidth = Math.max(Math.floor(bloomWidth / 2), 1);
  456. bloomHeight = Math.max(Math.floor(bloomHeight / 2), 1);
  457. ppl.addRenderTarget(`BloomTex${id}_${i}`, this._cameraConfigs.radianceFormat, bloomWidth, bloomHeight);
  458. }
  459. } // Color Grading
  460. if (this._cameraConfigs.enableColorGrading && settings.colorGrading.material && settings.colorGrading.colorGradingMap) {
  461. settings.colorGrading.material.setProperty('colorGradingMap', settings.colorGrading.colorGradingMap);
  462. } // FXAA
  463. if (this._cameraConfigs.enableFXAA && this._cameraConfigs.enableShadingScale) {
  464. ppl.addRenderTarget(`AaColor${id}`, Format.RGBA8, width, height);
  465. }
  466. }
  467. setup(cameras, ppl) {
  468. // TODO(zhouzhenglong): Make default effect asset loading earlier and remove _initMaterials
  469. if (this._initMaterials(ppl)) {
  470. return;
  471. } // Render cameras
  472. // log(`==================== One Frame ====================`);
  473. for (const camera of cameras) {
  474. // Skip invalid camera
  475. if (!camera.scene || !camera.window) {
  476. continue;
  477. } // Setup camera configs
  478. setupCameraConfigs(camera, this._configs, this._cameraConfigs); // log(`Setup camera: ${camera.node!.name}, window: ${camera.window.renderWindowId}, isFull: ${this._cameraConfigs.useFullPipeline}, `
  479. // + `size: ${camera.window.width}x${camera.window.height}`);
  480. this._pipelineEvent.emit(PipelineEventType.RENDER_CAMERA_BEGIN, camera); // Build pipeline
  481. if (this._cameraConfigs.useFullPipeline) {
  482. this._buildForwardPipeline(ppl, camera, camera.scene);
  483. } else {
  484. this._buildSimplePipeline(ppl, camera);
  485. }
  486. this._pipelineEvent.emit(PipelineEventType.RENDER_CAMERA_END, camera);
  487. }
  488. } // ----------------------------------------------------------------
  489. // Pipelines
  490. // ----------------------------------------------------------------
  491. _buildSimplePipeline(ppl, camera) {
  492. const width = Math.max(Math.floor(camera.window.width), 1);
  493. const height = Math.max(Math.floor(camera.window.height), 1);
  494. const colorName = this._cameraConfigs.colorName;
  495. const depthStencilName = this._cameraConfigs.depthStencilName;
  496. const viewport = camera.viewport; // Reduce C++/TS interop
  497. this._viewport.left = Math.round(viewport.x * width);
  498. this._viewport.top = Math.round(viewport.y * height); // Here we must use camera.viewport.width instead of camera.viewport.z, which
  499. // is undefined on native platform. The same as camera.viewport.height.
  500. this._viewport.width = Math.max(Math.round(viewport.width * width), 1);
  501. this._viewport.height = Math.max(Math.round(viewport.height * height), 1);
  502. const clearColor = camera.clearColor; // Reduce C++/TS interop
  503. this._clearColor.x = clearColor.x;
  504. this._clearColor.y = clearColor.y;
  505. this._clearColor.z = clearColor.z;
  506. this._clearColor.w = clearColor.w;
  507. const pass = ppl.addRenderPass(width, height, 'default'); // bind output render target
  508. if (forwardNeedClearColor(camera)) {
  509. pass.addRenderTarget(colorName, LoadOp.CLEAR, StoreOp.STORE, this._clearColor);
  510. } else {
  511. pass.addRenderTarget(colorName, LoadOp.LOAD, StoreOp.STORE);
  512. } // bind depth stencil buffer
  513. if (camera.clearFlag & ClearFlagBit.DEPTH_STENCIL) {
  514. pass.addDepthStencil(depthStencilName, LoadOp.CLEAR, StoreOp.DISCARD, camera.clearDepth, camera.clearStencil, camera.clearFlag & ClearFlagBit.DEPTH_STENCIL);
  515. } else {
  516. pass.addDepthStencil(depthStencilName, LoadOp.LOAD, StoreOp.DISCARD);
  517. }
  518. pass.setViewport(this._viewport); // The opaque queue is used for Reflection probe preview
  519. pass.addQueue(QueueHint.OPAQUE).addScene(camera, SceneFlags.OPAQUE); // The blend queue is used for UI and Gizmos
  520. let flags = SceneFlags.BLEND | SceneFlags.UI;
  521. if (this._cameraConfigs.enableProfiler) {
  522. flags |= SceneFlags.PROFILER;
  523. pass.showStatistics = true;
  524. }
  525. pass.addQueue(QueueHint.BLEND).addScene(camera, flags);
  526. }
  527. _buildForwardPipeline(ppl, camera, scene) {
  528. // Init
  529. const settings = this._cameraConfigs.settings;
  530. const nativeWidth = Math.max(Math.floor(camera.window.width), 1);
  531. const nativeHeight = Math.max(Math.floor(camera.window.height), 1);
  532. const width = this._cameraConfigs.enableShadingScale ? Math.max(Math.floor(nativeWidth * this._cameraConfigs.shadingScale), 1) : nativeWidth;
  533. const height = this._cameraConfigs.enableShadingScale ? Math.max(Math.floor(nativeHeight * this._cameraConfigs.shadingScale), 1) : nativeHeight;
  534. const id = camera.window.renderWindowId;
  535. const colorName = this._cameraConfigs.colorName;
  536. const sceneDepth = this._cameraConfigs.enableShadingScale ? `ScaledSceneDepth${id}` : `SceneDepth${id}`;
  537. const radianceName = this._cameraConfigs.enableShadingScale ? `ScaledRadiance${id}` : `Radiance${id}`;
  538. const ldrColorName = this._cameraConfigs.enableShadingScale ? `ScaledLdrColor${id}` : `LdrColor${id}`;
  539. const mainLight = scene.mainLight; // Forward Lighting (Light Culling)
  540. this.forwardLighting.cullLights(scene, camera.frustum); // Main Directional light CSM Shadow Map
  541. if (this._cameraConfigs.enableMainLightShadowMap) {
  542. assert(!!mainLight);
  543. this._addCascadedShadowMapPass(ppl, id, mainLight, camera);
  544. } // Spot light shadow maps (Mobile or MSAA)
  545. if (this._cameraConfigs.singleForwardRadiancePass) {
  546. // Currently, only support 1 spot light with shadow map on mobile platform.
  547. // TODO(zhouzhenglong): Relex this limitation.
  548. this.forwardLighting.addSpotlightShadowPasses(ppl, camera, this._configs.mobileMaxSpotLightShadowMaps);
  549. }
  550. this._tryAddReflectionProbePasses(ppl, id, mainLight, camera.scene); // Forward Lighting
  551. let lastPass;
  552. if (this._cameraConfigs.enablePostProcess) {
  553. // Post Process
  554. // Radiance and DoF
  555. if (this._cameraConfigs.enableDOF) {
  556. assert(!!settings.depthOfField.material);
  557. const dofRadianceName = `DofRadiance${id}`; // Disable MSAA, depth stencil cannot be resolved cross-platformly
  558. this._addForwardRadiancePasses(ppl, id, camera, width, height, mainLight, dofRadianceName, sceneDepth, true, StoreOp.STORE);
  559. this._addDepthOfFieldPasses(ppl, settings, settings.depthOfField.material, id, camera, width, height, dofRadianceName, sceneDepth, radianceName, ldrColorName);
  560. } else {
  561. this._addForwardRadiancePasses(ppl, id, camera, width, height, mainLight, radianceName, sceneDepth);
  562. } // Bloom
  563. if (this._cameraConfigs.enableBloom) {
  564. assert(!!settings.bloom.material);
  565. this._addKawaseDualFilterBloomPasses(ppl, settings, settings.bloom.material, id, width, height, radianceName);
  566. } // Tone Mapping and FXAA
  567. if (this._cameraConfigs.enableFXAA) {
  568. assert(!!settings.fxaa.material);
  569. const copyAndTonemapPassNeeded = this._cameraConfigs.enableHDR || this._cameraConfigs.enableColorGrading;
  570. const ldrColorBufferName = copyAndTonemapPassNeeded ? ldrColorName : radianceName; // FXAA is applied after tone mapping
  571. if (copyAndTonemapPassNeeded) {
  572. this._addCopyAndTonemapPass(ppl, settings, width, height, radianceName, ldrColorBufferName);
  573. } // Apply FXAA
  574. if (this._cameraConfigs.enableShadingScale) {
  575. const aaColorName = `AaColor${id}`; // Apply FXAA on scaled image
  576. this._addFxaaPass(ppl, settings.fxaa.material, width, height, ldrColorBufferName, aaColorName); // Copy FXAA result to screen
  577. if (this._cameraConfigs.enableFSR && settings.fsr.material) {
  578. // Apply FSR
  579. lastPass = this._addFsrPass(ppl, settings, settings.fsr.material, id, width, height, aaColorName, nativeWidth, nativeHeight, colorName);
  580. } else {
  581. // Scale FXAA result to screen
  582. lastPass = this._addCopyPass(ppl, nativeWidth, nativeHeight, aaColorName, colorName);
  583. }
  584. } else {
  585. // Image not scaled, output FXAA result to screen directly
  586. lastPass = this._addFxaaPass(ppl, settings.fxaa.material, nativeWidth, nativeHeight, ldrColorBufferName, colorName);
  587. }
  588. } else {
  589. // No FXAA (Size might be scaled)
  590. lastPass = this._addTonemapResizeOrSuperResolutionPasses(ppl, settings, id, width, height, radianceName, ldrColorName, nativeWidth, nativeHeight, colorName);
  591. }
  592. } else if (this._cameraConfigs.enableHDR || this._cameraConfigs.enableShadingScale) {
  593. // HDR or Scaled LDR
  594. this._addForwardRadiancePasses(ppl, id, camera, width, height, mainLight, radianceName, sceneDepth);
  595. lastPass = this._addTonemapResizeOrSuperResolutionPasses(ppl, settings, id, width, height, radianceName, ldrColorName, nativeWidth, nativeHeight, colorName);
  596. } else {
  597. // LDR (Size is not scaled)
  598. lastPass = this._addForwardRadiancePasses(ppl, id, camera, nativeWidth, nativeHeight, mainLight, colorName, this._cameraConfigs.depthStencilName);
  599. } // UI size is not scaled, does not have AA
  600. this._addUIQueue(camera, lastPass);
  601. } // ----------------------------------------------------------------
  602. // Common Passes
  603. // ----------------------------------------------------------------
  604. _addTonemapResizeOrSuperResolutionPasses(ppl, settings, id, width, height, radianceName, ldrColorName, nativeWidth, nativeHeight, colorName) {
  605. let lastPass;
  606. if (this._cameraConfigs.enableFSR && settings.fsr.material) {
  607. // Apply FSR
  608. this._addCopyAndTonemapPass(ppl, settings, width, height, radianceName, ldrColorName);
  609. lastPass = this._addFsrPass(ppl, settings, settings.fsr.material, id, width, height, ldrColorName, nativeWidth, nativeHeight, colorName);
  610. } else {
  611. // Output HDR/LDR result to screen directly (Size might be scaled)
  612. lastPass = this._addCopyAndTonemapPass(ppl, settings, nativeWidth, nativeHeight, radianceName, colorName);
  613. }
  614. return lastPass;
  615. }
  616. _addCascadedShadowMapPass(ppl, id, light, camera) {
  617. // ----------------------------------------------------------------
  618. // Dynamic states
  619. // ----------------------------------------------------------------
  620. const width = ppl.pipelineSceneData.shadows.size.x;
  621. const height = ppl.pipelineSceneData.shadows.size.y;
  622. this._viewport.left = 0;
  623. this._viewport.top = 0;
  624. this._viewport.width = width;
  625. this._viewport.height = height; // ----------------------------------------------------------------
  626. // CSM Shadow Map
  627. // ----------------------------------------------------------------
  628. const pass = ppl.addRenderPass(width, height, 'default');
  629. pass.name = 'CascadedShadowMap';
  630. pass.addRenderTarget(`ShadowMap${id}`, LoadOp.CLEAR, StoreOp.STORE, new Color(1, 1, 1, 1));
  631. pass.addDepthStencil(`ShadowDepth${id}`, LoadOp.CLEAR, StoreOp.DISCARD);
  632. const csmLevel = ppl.pipelineSceneData.csmSupported ? light.csmLevel : 1; // Add shadow map viewports
  633. for (let level = 0; level !== csmLevel; ++level) {
  634. getCsmMainLightViewport(light, width, height, level, this._viewport, this._configs.screenSpaceSignY);
  635. const queue = pass.addQueue(QueueHint.NONE, 'shadow-caster');
  636. if (!this._configs.isWebGPU) {
  637. // Temporary workaround for WebGPU
  638. queue.setViewport(this._viewport);
  639. }
  640. queue.addScene(camera, SceneFlags.OPAQUE | SceneFlags.MASK | SceneFlags.SHADOW_CASTER).useLightFrustum(light, level);
  641. }
  642. }
  643. _addCopyPass(ppl, width, height, input, output) {
  644. const pass = ppl.addRenderPass(width, height, 'cc-tone-mapping');
  645. pass.addRenderTarget(output, LoadOp.CLEAR, StoreOp.STORE, this._clearColorTransparentBlack);
  646. pass.addTexture(input, 'inputTexture');
  647. pass.setVec4('g_platform', this._configs.platform);
  648. pass.addQueue(QueueHint.OPAQUE).addFullscreenQuad(this._copyAndTonemapMaterial, 1);
  649. return pass;
  650. }
  651. _addCopyAndTonemapPass(ppl, settings, width, height, radianceName, colorName) {
  652. let pass;
  653. if (this._cameraConfigs.enableColorGrading && settings.colorGrading.material && settings.colorGrading.colorGradingMap) {
  654. const lutTex = settings.colorGrading.colorGradingMap;
  655. this._colorGradingTexSize.x = lutTex.width;
  656. this._colorGradingTexSize.y = lutTex.height;
  657. const isSquareMap = lutTex.width === lutTex.height;
  658. if (isSquareMap) {
  659. pass = ppl.addRenderPass(width, height, 'cc-color-grading-8x8');
  660. } else {
  661. pass = ppl.addRenderPass(width, height, 'cc-color-grading-nx1');
  662. }
  663. pass.addRenderTarget(colorName, LoadOp.CLEAR, StoreOp.STORE, this._clearColorTransparentBlack);
  664. pass.addTexture(radianceName, 'sceneColorMap');
  665. pass.setVec4('g_platform', this._configs.platform);
  666. pass.setVec2('lutTextureSize', this._colorGradingTexSize);
  667. pass.setFloat('contribute', settings.colorGrading.contribute);
  668. pass.addQueue(QueueHint.OPAQUE).addFullscreenQuad(settings.colorGrading.material, isSquareMap ? 1 : 0);
  669. } else {
  670. pass = ppl.addRenderPass(width, height, 'cc-tone-mapping');
  671. pass.addRenderTarget(colorName, LoadOp.CLEAR, StoreOp.STORE, this._clearColorTransparentBlack);
  672. pass.addTexture(radianceName, 'inputTexture');
  673. pass.setVec4('g_platform', this._configs.platform);
  674. if (settings.toneMapping.material) {
  675. pass.addQueue(QueueHint.OPAQUE).addFullscreenQuad(settings.toneMapping.material, 0);
  676. } else {
  677. pass.addQueue(QueueHint.OPAQUE).addFullscreenQuad(this._copyAndTonemapMaterial, 0);
  678. }
  679. }
  680. return pass;
  681. }
  682. _buildForwardMainLightPass(pass, id, camera, colorName, depthStencilName, depthStencilStoreOp, mainLight, scene = null) {
  683. // set viewport
  684. pass.setViewport(this._viewport);
  685. const colorStoreOp = this._cameraConfigs.enableMSAA ? StoreOp.DISCARD : StoreOp.STORE; // bind output render target
  686. if (forwardNeedClearColor(camera)) {
  687. pass.addRenderTarget(colorName, LoadOp.CLEAR, colorStoreOp, this._clearColor);
  688. } else {
  689. pass.addRenderTarget(colorName, LoadOp.LOAD, colorStoreOp);
  690. } // bind depth stencil buffer
  691. if (DEBUG) {
  692. if (colorName === this._cameraConfigs.colorName && depthStencilName !== this._cameraConfigs.depthStencilName) {
  693. warn('Default framebuffer cannot use custom depth stencil buffer');
  694. }
  695. }
  696. if (camera.clearFlag & ClearFlagBit.DEPTH_STENCIL) {
  697. pass.addDepthStencil(depthStencilName, LoadOp.CLEAR, depthStencilStoreOp, camera.clearDepth, camera.clearStencil, camera.clearFlag & ClearFlagBit.DEPTH_STENCIL);
  698. } else {
  699. pass.addDepthStencil(depthStencilName, LoadOp.LOAD, depthStencilStoreOp);
  700. } // Set shadow map if enabled
  701. if (this._cameraConfigs.enableMainLightShadowMap) {
  702. pass.addTexture(`ShadowMap${id}`, 'cc_shadowMap');
  703. } // TODO(zhouzhenglong): Separate OPAQUE and MASK queue
  704. // add opaque and mask queue
  705. pass.addQueue(QueueHint.NONE) // Currently we put OPAQUE and MASK into one queue, so QueueHint is NONE
  706. .addScene(camera, SceneFlags.OPAQUE | SceneFlags.MASK, mainLight || undefined, scene ? scene : undefined);
  707. }
  708. _addDepthOfFieldPasses(ppl, settings, dofMaterial, id, camera, width, height, dofRadianceName, depthStencil, radianceName, ldrColorName) {
  709. // https://catlikecoding.com/unity/tutorials/advanced-rendering/depth-of-field/
  710. this._cocParams.x = settings.depthOfField.focusDistance;
  711. this._cocParams.y = settings.depthOfField.focusRange;
  712. this._cocParams.z = settings.depthOfField.bokehRadius;
  713. this._cocParams.w = 0.0;
  714. this._cocTexSize.x = 1.0 / width;
  715. this._cocTexSize.y = 1.0 / height;
  716. this._cocTexSize.z = width;
  717. this._cocTexSize.w = height;
  718. const halfWidth = Math.max(Math.floor(width / 2), 1);
  719. const halfHeight = Math.max(Math.floor(height / 2), 1);
  720. const cocName = ldrColorName;
  721. const prefilterName = `DofPrefilter${id}`;
  722. const bokehName = `DofBokeh${id}`;
  723. const filterName = `DofFilter${id}`; // CoC
  724. const cocPass = ppl.addRenderPass(width, height, 'cc-dof-coc');
  725. cocPass.addRenderTarget(cocName, LoadOp.CLEAR, StoreOp.STORE, this._clearColorTransparentBlack);
  726. cocPass.addTexture(depthStencil, 'DepthTex');
  727. cocPass.setVec4('g_platform', this._configs.platform);
  728. cocPass.setMat4('proj', camera.matProj);
  729. cocPass.setVec4('cocParams', this._cocParams);
  730. cocPass.addQueue(QueueHint.OPAQUE).addCameraQuad(camera, dofMaterial, 0); // addCameraQuad will set camera related UBOs
  731. // Downsample and Prefilter
  732. const prefilterPass = ppl.addRenderPass(halfWidth, halfHeight, 'cc-dof-prefilter');
  733. prefilterPass.addRenderTarget(prefilterName, LoadOp.CLEAR, StoreOp.STORE, this._clearColorTransparentBlack);
  734. prefilterPass.addTexture(dofRadianceName, 'colorTex');
  735. prefilterPass.addTexture(cocName, 'cocTex');
  736. prefilterPass.setVec4('g_platform', this._configs.platform);
  737. prefilterPass.setVec4('mainTexTexelSize', this._cocTexSize);
  738. prefilterPass.addQueue(QueueHint.OPAQUE).addFullscreenQuad(dofMaterial, 1); // Bokeh blur
  739. const bokehPass = ppl.addRenderPass(halfWidth, halfHeight, 'cc-dof-bokeh');
  740. bokehPass.addRenderTarget(bokehName, LoadOp.CLEAR, StoreOp.STORE, this._clearColorTransparentBlack);
  741. bokehPass.addTexture(prefilterName, 'prefilterTex');
  742. bokehPass.setVec4('g_platform', this._configs.platform);
  743. bokehPass.setVec4('mainTexTexelSize', this._cocTexSize);
  744. bokehPass.setVec4('cocParams', this._cocParams);
  745. bokehPass.addQueue(QueueHint.OPAQUE).addFullscreenQuad(dofMaterial, 2); // Filtering
  746. const filterPass = ppl.addRenderPass(halfWidth, halfHeight, 'cc-dof-filter');
  747. filterPass.addRenderTarget(filterName, LoadOp.CLEAR, StoreOp.STORE, this._clearColorTransparentBlack);
  748. filterPass.addTexture(bokehName, 'bokehTex');
  749. filterPass.setVec4('g_platform', this._configs.platform);
  750. filterPass.setVec4('mainTexTexelSize', this._cocTexSize);
  751. filterPass.addQueue(QueueHint.OPAQUE).addFullscreenQuad(dofMaterial, 3); // Combine
  752. const combinePass = ppl.addRenderPass(width, height, 'cc-dof-combine');
  753. combinePass.addRenderTarget(radianceName, LoadOp.CLEAR, StoreOp.STORE, this._clearColorTransparentBlack);
  754. combinePass.addTexture(dofRadianceName, 'colorTex');
  755. combinePass.addTexture(cocName, 'cocTex');
  756. combinePass.addTexture(filterName, 'filterTex');
  757. combinePass.setVec4('g_platform', this._configs.platform);
  758. combinePass.setVec4('cocParams', this._cocParams);
  759. combinePass.addQueue(QueueHint.OPAQUE).addFullscreenQuad(dofMaterial, 4);
  760. }
  761. _addKawaseDualFilterBloomPasses(ppl, settings, bloomMaterial, id, width, height, radianceName) {
  762. // Based on Kawase Dual Filter Blur. Saves bandwidth on mobile devices.
  763. // eslint-disable-next-line max-len
  764. // https://community.arm.com/cfs-file/__key/communityserver-blogs-components-weblogfiles/00-00-00-20-66/siggraph2015_2D00_mmg_2D00_marius_2D00_slides.pdf
  765. // Size: [prefilter(1/2), downsample(1/4), downsample(1/8), downsample(1/16), ...]
  766. const iterations = settings.bloom.iterations;
  767. const sizeCount = iterations + 1;
  768. this._bloomWidths.length = sizeCount;
  769. this._bloomHeights.length = sizeCount;
  770. this._bloomWidths[0] = Math.max(Math.floor(width / 2), 1);
  771. this._bloomHeights[0] = Math.max(Math.floor(height / 2), 1);
  772. for (let i = 1; i !== sizeCount; ++i) {
  773. this._bloomWidths[i] = Math.max(Math.floor(this._bloomWidths[i - 1] / 2), 1);
  774. this._bloomHeights[i] = Math.max(Math.floor(this._bloomHeights[i - 1] / 2), 1);
  775. } // Bloom texture names
  776. this._bloomTexNames.length = sizeCount;
  777. for (let i = 0; i !== sizeCount; ++i) {
  778. this._bloomTexNames[i] = `BloomTex${id}_${i}`;
  779. } // Setup bloom parameters
  780. this._bloomParams.x = this._configs.useFloatOutput ? 1 : 0;
  781. this._bloomParams.x = 0; // unused
  782. this._bloomParams.z = settings.bloom.threshold;
  783. this._bloomParams.w = settings.bloom.enableAlphaMask ? 1 : 0; // Prefilter pass
  784. const prefilterPass = ppl.addRenderPass(this._bloomWidths[0], this._bloomHeights[0], 'cc-bloom-prefilter');
  785. prefilterPass.addRenderTarget(this._bloomTexNames[0], LoadOp.CLEAR, StoreOp.STORE, this._clearColorTransparentBlack);
  786. prefilterPass.addTexture(radianceName, 'inputTexture');
  787. prefilterPass.setVec4('g_platform', this._configs.platform);
  788. prefilterPass.setVec4('bloomParams', this._bloomParams);
  789. prefilterPass.addQueue(QueueHint.OPAQUE).addFullscreenQuad(bloomMaterial, 0); // Downsample passes
  790. for (let i = 1; i !== sizeCount; ++i) {
  791. const downPass = ppl.addRenderPass(this._bloomWidths[i], this._bloomHeights[i], 'cc-bloom-downsample');
  792. downPass.addRenderTarget(this._bloomTexNames[i], LoadOp.CLEAR, StoreOp.STORE, this._clearColorTransparentBlack);
  793. downPass.addTexture(this._bloomTexNames[i - 1], 'bloomTexture');
  794. this._bloomTexSize.x = this._bloomWidths[i - 1];
  795. this._bloomTexSize.y = this._bloomHeights[i - 1];
  796. downPass.setVec4('g_platform', this._configs.platform);
  797. downPass.setVec4('bloomTexSize', this._bloomTexSize);
  798. downPass.addQueue(QueueHint.OPAQUE).addFullscreenQuad(bloomMaterial, 1);
  799. } // Upsample passes
  800. for (let i = iterations; i-- > 0;) {
  801. const upPass = ppl.addRenderPass(this._bloomWidths[i], this._bloomHeights[i], 'cc-bloom-upsample');
  802. upPass.addRenderTarget(this._bloomTexNames[i], LoadOp.CLEAR, StoreOp.STORE, this._clearColorTransparentBlack);
  803. upPass.addTexture(this._bloomTexNames[i + 1], 'bloomTexture');
  804. this._bloomTexSize.x = this._bloomWidths[i + 1];
  805. this._bloomTexSize.y = this._bloomHeights[i + 1];
  806. upPass.setVec4('g_platform', this._configs.platform);
  807. upPass.setVec4('bloomTexSize', this._bloomTexSize);
  808. upPass.addQueue(QueueHint.OPAQUE).addFullscreenQuad(bloomMaterial, 2);
  809. } // Combine pass
  810. const combinePass = ppl.addRenderPass(width, height, 'cc-bloom-combine');
  811. combinePass.addRenderTarget(radianceName, LoadOp.LOAD, StoreOp.STORE);
  812. combinePass.addTexture(this._bloomTexNames[0], 'bloomTexture');
  813. combinePass.setVec4('g_platform', this._configs.platform);
  814. combinePass.setVec4('bloomParams', this._bloomParams);
  815. combinePass.addQueue(QueueHint.BLEND).addFullscreenQuad(bloomMaterial, 3);
  816. }
  817. _addFsrPass(ppl, settings, fsrMaterial, id, width, height, ldrColorName, nativeWidth, nativeHeight, colorName) {
  818. this._fsrTexSize.x = width;
  819. this._fsrTexSize.y = height;
  820. this._fsrTexSize.z = nativeWidth;
  821. this._fsrTexSize.w = nativeHeight;
  822. this._fsrParams.x = clamp(1.0 - settings.fsr.sharpness, 0.02, 0.98);
  823. const fsrColorName = `FsrColor${id}`;
  824. const easuPass = ppl.addRenderPass(nativeWidth, nativeHeight, 'cc-fsr-easu');
  825. easuPass.addRenderTarget(fsrColorName, LoadOp.CLEAR, StoreOp.STORE, this._clearColorTransparentBlack);
  826. easuPass.addTexture(ldrColorName, 'outputResultMap');
  827. easuPass.setVec4('g_platform', this._configs.platform);
  828. easuPass.setVec4('fsrTexSize', this._fsrTexSize);
  829. easuPass.addQueue(QueueHint.OPAQUE).addFullscreenQuad(fsrMaterial, 0);
  830. const rcasPass = ppl.addRenderPass(nativeWidth, nativeHeight, 'cc-fsr-rcas');
  831. rcasPass.addRenderTarget(colorName, LoadOp.CLEAR, StoreOp.STORE, this._clearColorTransparentBlack);
  832. rcasPass.addTexture(fsrColorName, 'outputResultMap');
  833. rcasPass.setVec4('g_platform', this._configs.platform);
  834. rcasPass.setVec4('fsrTexSize', this._fsrTexSize);
  835. rcasPass.setVec4('fsrParams', this._fsrParams);
  836. rcasPass.addQueue(QueueHint.OPAQUE).addFullscreenQuad(fsrMaterial, 1);
  837. return rcasPass;
  838. }
  839. _addFxaaPass(ppl, fxaaMaterial, width, height, ldrColorName, colorName) {
  840. this._fxaaParams.x = width;
  841. this._fxaaParams.y = height;
  842. this._fxaaParams.z = 1 / width;
  843. this._fxaaParams.w = 1 / height;
  844. const pass = ppl.addRenderPass(width, height, 'cc-fxaa');
  845. pass.addRenderTarget(colorName, LoadOp.CLEAR, StoreOp.STORE, this._clearColorTransparentBlack);
  846. pass.addTexture(ldrColorName, 'sceneColorMap');
  847. pass.setVec4('g_platform', this._configs.platform);
  848. pass.setVec4('texSize', this._fxaaParams);
  849. pass.addQueue(QueueHint.OPAQUE).addFullscreenQuad(fxaaMaterial, 0);
  850. return pass;
  851. }
  852. _addUIQueue(camera, pass) {
  853. let flags = SceneFlags.UI;
  854. if (this._cameraConfigs.enableProfiler) {
  855. flags |= SceneFlags.PROFILER;
  856. pass.showStatistics = true;
  857. }
  858. pass.addQueue(QueueHint.BLEND, 'default', 'default').addScene(camera, flags);
  859. } // ----------------------------------------------------------------
  860. // Forward
  861. // ----------------------------------------------------------------
  862. _addForwardRadiancePasses(ppl, id, camera, width, height, mainLight, colorName, depthStencilName, disableMSAA = false, depthStencilStoreOp = StoreOp.DISCARD) {
  863. // ----------------------------------------------------------------
  864. // Dynamic states
  865. // ----------------------------------------------------------------
  866. // Prepare camera clear color
  867. const clearColor = camera.clearColor; // Reduce C++/TS interop
  868. this._clearColor.x = clearColor.x;
  869. this._clearColor.y = clearColor.y;
  870. this._clearColor.z = clearColor.z;
  871. this._clearColor.w = clearColor.w; // Prepare camera viewport
  872. const viewport = camera.viewport; // Reduce C++/TS interop
  873. this._viewport.left = Math.round(viewport.x * width);
  874. this._viewport.top = Math.round(viewport.y * height); // Here we must use camera.viewport.width instead of camera.viewport.z, which
  875. // is undefined on native platform. The same as camera.viewport.height.
  876. this._viewport.width = Math.max(Math.round(viewport.width * width), 1);
  877. this._viewport.height = Math.max(Math.round(viewport.height * height), 1); // MSAA
  878. const enableMSAA = !disableMSAA && this._cameraConfigs.enableMSAA;
  879. assert(!enableMSAA || this._cameraConfigs.singleForwardRadiancePass); // ----------------------------------------------------------------
  880. // Forward Lighting (Main Directional Light)
  881. // ----------------------------------------------------------------
  882. const pass = this._cameraConfigs.singleForwardRadiancePass ? this._addForwardSingleRadiancePass(ppl, id, camera, enableMSAA, width, height, mainLight, colorName, depthStencilName, depthStencilStoreOp) : this._addForwardMultipleRadiancePasses(ppl, id, camera, width, height, mainLight, colorName, depthStencilName, depthStencilStoreOp); // Planar Shadow
  883. if (this._cameraConfigs.enableMainLightPlanarShadowMap) {
  884. this.addPlanarShadowQueue(camera, mainLight, pass);
  885. } // ----------------------------------------------------------------
  886. // Forward Lighting (Blend)
  887. // ----------------------------------------------------------------
  888. // Add transparent queue
  889. const sceneFlags = SceneFlags.BLEND | (camera.geometryRenderer ? SceneFlags.GEOMETRY : SceneFlags.NONE);
  890. pass.addQueue(QueueHint.BLEND).addScene(camera, sceneFlags, mainLight || undefined);
  891. return pass;
  892. }
  893. _addForwardSingleRadiancePass(ppl, id, camera, enableMSAA, width, height, mainLight, colorName, depthStencilName, depthStencilStoreOp) {
  894. assert(this._cameraConfigs.singleForwardRadiancePass); // ----------------------------------------------------------------
  895. // Forward Lighting (Main Directional Light)
  896. // ----------------------------------------------------------------
  897. let pass;
  898. if (enableMSAA) {
  899. const msaaRadianceName = `MsaaRadiance${id}`;
  900. const msaaDepthStencilName = `MsaaDepthStencil${id}`;
  901. const sampleCount = this._cameraConfigs.settings.msaa.sampleCount;
  902. const msPass = ppl.addMultisampleRenderPass(width, height, sampleCount, 0, 'default');
  903. msPass.name = 'MsaaForwardPass'; // MSAA always discards depth stencil
  904. this._buildForwardMainLightPass(msPass, id, camera, msaaRadianceName, msaaDepthStencilName, StoreOp.DISCARD, mainLight);
  905. msPass.resolveRenderTarget(msaaRadianceName, colorName);
  906. pass = msPass;
  907. } else {
  908. pass = ppl.addRenderPass(width, height, 'default');
  909. pass.name = 'ForwardPass';
  910. this._buildForwardMainLightPass(pass, id, camera, colorName, depthStencilName, depthStencilStoreOp, mainLight);
  911. }
  912. assert(pass !== undefined); // Forward Lighting (Additive Lights)
  913. this.forwardLighting.addLightQueues(pass, camera, this._configs.mobileMaxSpotLightShadowMaps);
  914. return pass;
  915. }
  916. addPlanarShadowQueue(camera, mainLight, pass) {
  917. pass.addQueue(QueueHint.BLEND, 'planar-shadow').addScene(camera, SceneFlags.SHADOW_CASTER | SceneFlags.PLANAR_SHADOW | SceneFlags.BLEND, mainLight || undefined);
  918. }
  919. _addForwardMultipleRadiancePasses(ppl, id, camera, width, height, mainLight, colorName, depthStencilName, depthStencilStoreOp) {
  920. assert(!this._cameraConfigs.singleForwardRadiancePass); // Forward Lighting (Main Directional Light)
  921. let pass = ppl.addRenderPass(width, height, 'default');
  922. pass.name = 'ForwardPass';
  923. const firstStoreOp = this.forwardLighting.isMultipleLightPassesNeeded() ? StoreOp.STORE : depthStencilStoreOp;
  924. this._buildForwardMainLightPass(pass, id, camera, colorName, depthStencilName, firstStoreOp, mainLight); // Forward Lighting (Additive Lights)
  925. pass = this.forwardLighting.addLightPasses(colorName, depthStencilName, depthStencilStoreOp, id, width, height, camera, this._viewport, ppl, pass);
  926. return pass;
  927. }
  928. _buildReflectionProbePass(pass, id, camera, colorName, depthStencilName, mainLight, scene = null) {
  929. // set viewport
  930. const colorStoreOp = this._cameraConfigs.enableMSAA ? StoreOp.DISCARD : StoreOp.STORE; // bind output render target
  931. if (forwardNeedClearColor(camera)) {
  932. this._reflectionProbeClearColor.x = camera.clearColor.x;
  933. this._reflectionProbeClearColor.y = camera.clearColor.y;
  934. this._reflectionProbeClearColor.z = camera.clearColor.z;
  935. const clearColor = rendering.packRGBE(this._reflectionProbeClearColor);
  936. this._clearColor.x = clearColor.x;
  937. this._clearColor.y = clearColor.y;
  938. this._clearColor.z = clearColor.z;
  939. this._clearColor.w = clearColor.w;
  940. pass.addRenderTarget(colorName, LoadOp.CLEAR, colorStoreOp, this._clearColor);
  941. } else {
  942. pass.addRenderTarget(colorName, LoadOp.LOAD, colorStoreOp);
  943. } // bind depth stencil buffer
  944. if (camera.clearFlag & ClearFlagBit.DEPTH_STENCIL) {
  945. pass.addDepthStencil(depthStencilName, LoadOp.CLEAR, StoreOp.DISCARD, camera.clearDepth, camera.clearStencil, camera.clearFlag & ClearFlagBit.DEPTH_STENCIL);
  946. } else {
  947. pass.addDepthStencil(depthStencilName, LoadOp.LOAD, StoreOp.DISCARD);
  948. } // Set shadow map if enabled
  949. if (this._cameraConfigs.enableMainLightShadowMap) {
  950. pass.addTexture(`ShadowMap${id}`, 'cc_shadowMap');
  951. } // TODO(zhouzhenglong): Separate OPAQUE and MASK queue
  952. // add opaque and mask queue
  953. pass.addQueue(QueueHint.NONE, 'reflect-map') // Currently we put OPAQUE and MASK into one queue, so QueueHint is NONE
  954. .addScene(camera, SceneFlags.OPAQUE | SceneFlags.MASK | SceneFlags.REFLECTION_PROBE, mainLight || undefined, scene ? scene : undefined);
  955. }
  956. _tryAddReflectionProbePasses(ppl, id, mainLight, scene) {
  957. const reflectionProbeManager = cclegacy.internal.reflectionProbeManager;
  958. if (!reflectionProbeManager) {
  959. return;
  960. }
  961. const probes = reflectionProbeManager.getProbes();
  962. const maxProbeCount = 4;
  963. let probeID = 0;
  964. for (const probe of probes) {
  965. if (!probe.needRender) {
  966. continue;
  967. }
  968. const area = probe.renderArea();
  969. const width = Math.max(Math.floor(area.x), 1);
  970. const height = Math.max(Math.floor(area.y), 1);
  971. if (probe.probeType === renderer.scene.ProbeType.PLANAR) {
  972. if (!this._cameraConfigs.enablePlanarReflectionProbe) {
  973. continue;
  974. }
  975. const window = probe.realtimePlanarTexture.window;
  976. const colorName = `PlanarProbeRT${probeID}`;
  977. const depthStencilName = `PlanarProbeDS${probeID}`; // ProbeResource
  978. ppl.addRenderWindow(colorName, this._cameraConfigs.radianceFormat, width, height, window);
  979. ppl.addDepthStencil(depthStencilName, gfx.Format.DEPTH_STENCIL, width, height, ResourceResidency.MEMORYLESS); // Rendering
  980. const probePass = ppl.addRenderPass(width, height, 'default');
  981. probePass.name = `PlanarReflectionProbe${probeID}`;
  982. this._buildReflectionProbePass(probePass, id, probe.camera, colorName, depthStencilName, mainLight, scene);
  983. } else if (EDITOR) {
  984. for (let faceIdx = 0; faceIdx < probe.bakedCubeTextures.length; faceIdx++) {
  985. probe.updateCameraDir(faceIdx);
  986. const window = probe.bakedCubeTextures[faceIdx].window;
  987. const colorName = `CubeProbeRT${probeID}${faceIdx}`;
  988. const depthStencilName = `CubeProbeDS${probeID}${faceIdx}`; // ProbeResource
  989. ppl.addRenderWindow(colorName, this._cameraConfigs.radianceFormat, width, height, window);
  990. ppl.addDepthStencil(depthStencilName, gfx.Format.DEPTH_STENCIL, width, height, ResourceResidency.MEMORYLESS); // Rendering
  991. const probePass = ppl.addRenderPass(width, height, 'default');
  992. probePass.name = `CubeProbe${probeID}${faceIdx}`;
  993. this._buildReflectionProbePass(probePass, id, probe.camera, colorName, depthStencilName, mainLight, scene);
  994. }
  995. probe.needRender = false;
  996. }
  997. ++probeID;
  998. if (probeID === maxProbeCount) {
  999. break;
  1000. }
  1001. }
  1002. }
  1003. _initMaterials(ppl) {
  1004. if (this._initialized) {
  1005. return 0;
  1006. }
  1007. setupPipelineConfigs(ppl, this._configs); // When add new effect asset, please add its uuid to the dependentAssets in cc.config.json.
  1008. this._copyAndTonemapMaterial._uuid = `builtin-pipeline-tone-mapping-material`;
  1009. this._copyAndTonemapMaterial.initialize({
  1010. effectName: 'pipeline/post-process/tone-mapping'
  1011. });
  1012. if (this._copyAndTonemapMaterial.effectAsset) {
  1013. this._initialized = true;
  1014. }
  1015. return this._initialized ? 0 : 1;
  1016. }
  1017. }
  1018. rendering.setCustomPipeline('Builtin', new BuiltinPipelineBuilder());
  1019. } // if (rendering)
  1020. _cclegacy._RF.pop();
  1021. _crd = false;
  1022. }
  1023. };
  1024. });
  1025. //# sourceMappingURL=59b7958b47eec6168615a6469581f8f48e26cb00.js.map