diff --git a/docs/en/graphics/material/examples/shader-05-advance.mdx b/docs/en/graphics/material/examples/shader-05-advance.mdx index fc36f9c64e..3fb24dfb22 100644 --- a/docs/en/graphics/material/examples/shader-05-advance.mdx +++ b/docs/en/graphics/material/examples/shader-05-advance.mdx @@ -190,7 +190,6 @@ gl_FragColor = vec4(lighting, 1.0); The engine provides a rich set of built-in variables that can be used directly, such as transformation matrix variables: ```glsl -mat4 renderer_LocalMat; // Local transformation matrix mat4 renderer_ModelMat; // Model matrix mat4 renderer_MVMat; // Model-view matrix mat4 renderer_MVPMat; // MVP matrix diff --git a/docs/en/graphics/material/shaderAPI.mdx b/docs/en/graphics/material/shaderAPI.mdx index 72b39ef686..3193dcd374 100644 --- a/docs/en/graphics/material/shaderAPI.mdx +++ b/docs/en/graphics/material/shaderAPI.mdx @@ -27,7 +27,6 @@ vec4 fog(vec4 color, vec3 positionVS); Provides system variables for model space, view space, world space, and camera coordinates: ```glsl -mat4 renderer_LocalMat; mat4 renderer_ModelMat; mat4 camera_ViewMat; mat4 camera_ProjMat; diff --git a/docs/en/graphics/material/variables.mdx b/docs/en/graphics/material/variables.mdx index f64f02b3a3..779f86130b 100644 --- a/docs/en/graphics/material/variables.mdx +++ b/docs/en/graphics/material/variables.mdx @@ -25,7 +25,6 @@ Below are the engine's built-in variables for reference when writing Shaders: | Name | Type | Description | | :---------------- | :--- | :--------------------------- | -| renderer_LocalMat | mat4 | Model local coordinate matrix | | renderer_ModelMat | mat4 | Model world coordinate matrix | | renderer_MVMat | mat4 | Model view matrix | | renderer_MVPMat | mat4 | Model view projection matrix | diff --git a/docs/zh/graphics/material/examples/shader-05-advance.mdx b/docs/zh/graphics/material/examples/shader-05-advance.mdx index 1040966a93..baa1e900e3 100644 --- a/docs/zh/graphics/material/examples/shader-05-advance.mdx +++ b/docs/zh/graphics/material/examples/shader-05-advance.mdx @@ -193,7 +193,6 @@ void frag() { 引擎提供了丰富的内置变量,直接声明使用即可,比如变换矩阵相关变量: ```glsl -mat4 renderer_LocalMat; // 本地变换矩阵 mat4 renderer_ModelMat; // 模型矩阵 mat4 renderer_MVMat; // 模型视图矩阵 mat4 renderer_MVPMat; // MVP矩阵 diff --git a/docs/zh/graphics/material/shaderAPI.mdx b/docs/zh/graphics/material/shaderAPI.mdx index bc0dbd8ce2..522a393f0c 100644 --- a/docs/zh/graphics/material/shaderAPI.mdx +++ b/docs/zh/graphics/material/shaderAPI.mdx @@ -29,7 +29,6 @@ vec4 fog(vec4 color, vec3 positionVS); 提供了模型空间、视图空间、世界空间、相机坐标等[系统变量](/docs/graphics/material/variables/): ```glsl -mat4 renderer_LocalMat; mat4 renderer_ModelMat; mat4 camera_ViewMat; mat4 camera_ProjMat; diff --git a/docs/zh/graphics/material/variables.mdx b/docs/zh/graphics/material/variables.mdx index 6059e0d0e1..48deab814b 100644 --- a/docs/zh/graphics/material/variables.mdx +++ b/docs/zh/graphics/material/variables.mdx @@ -25,7 +25,6 @@ Shader 代码中会经常用到内置变量,一种是**逐顶点**的 `attribu | 名字 | 类型 | 解释 | | :----------------- | :--- | ------------------ | -| renderer_LocalMat | mat4 | 模型本地坐标系矩阵 | | renderer_ModelMat | mat4 | 模型世界坐标系矩阵 | | renderer_MVMat | mat4 | 模型视口矩阵 | | renderer_MVPMat | mat4 | 模型视口投影矩阵 | diff --git a/e2e/case/animator-customBlendShape.ts b/e2e/case/animator-customBlendShape.ts index 83c809de66..673a56b487 100644 --- a/e2e/case/animator-customBlendShape.ts +++ b/e2e/case/animator-customBlendShape.ts @@ -32,7 +32,6 @@ WebGLEngine.create({ canvas: "canvas" }).then((engine) => { cameraEntity.transform.position = new Vector3(0, 0, 5); const camera = cameraEntity.addComponent(Camera); - const meshEntity = rootEntity.createChild("meshEntity"); const skinnedMeshRenderer = meshEntity.addComponent(SkinnedMeshRenderer); const modelMesh = new ModelMesh(engine); diff --git a/e2e/case/gltf-blendshape.ts b/e2e/case/gltf-blendshape.ts index 85f3c72b72..21a239adc9 100644 --- a/e2e/case/gltf-blendshape.ts +++ b/e2e/case/gltf-blendshape.ts @@ -54,4 +54,4 @@ WebGLEngine.create({ canvas: "canvas" }).then((engine) => { initScreenshot(engine, camera); }); -}); \ No newline at end of file +}); diff --git a/e2e/case/gpu-instancing-auto-batch.ts b/e2e/case/gpu-instancing-auto-batch.ts new file mode 100644 index 0000000000..e9f80e35ab --- /dev/null +++ b/e2e/case/gpu-instancing-auto-batch.ts @@ -0,0 +1,68 @@ +/** + * @title GPU Instancing Auto Batch + * @category Mesh + */ +import { + AmbientLight, + AssetType, + Camera, + Color, + DirectLight, + GLTFResource, + Logger, + Vector3, + WebGLEngine +} from "@galacean/engine"; +import { initScreenshot, updateForE2E } from "./.mockForE2E"; + +Logger.enable(); +WebGLEngine.create({ canvas: "canvas" }).then(async (engine) => { + engine.canvas.resizeByClientSize(2); + + const scene = engine.sceneManager.activeScene; + const rootEntity = scene.createRootEntity("Root"); + + // Camera + const cameraEntity = rootEntity.createChild("Camera"); + cameraEntity.transform.setPosition(0, 10, 80); + cameraEntity.transform.lookAt(new Vector3(0, 0, 0)); + const camera = cameraEntity.addComponent(Camera); + camera.farClipPlane = 300; + + // Light + const lightEntity = rootEntity.createChild("Light"); + lightEntity.transform.setRotation(-45, -45, 0); + lightEntity.addComponent(DirectLight).color = new Color(1, 1, 1, 1); + + // Load Duck model and ambient light + const [glTF, ambientLight] = await Promise.all([ + engine.resourceManager.load({ + url: "https://gw.alipayobjects.com/os/bmw-prod/6cb8f543-285c-491a-8cfd-57a1160dc9ab.glb", + type: AssetType.GLTF + }), + engine.resourceManager.load({ + url: "https://mdn.alipayobjects.com/oasis_be/afts/file/A*eRJ8QKzf5zAAAAAAgBAAAAgAekp5AQ/ambient.ambLight", + type: AssetType.AmbientLight + }) + ]); + scene.ambientLight = ambientLight; + + // Clone ducks with fixed seed positions for deterministic output + const count = 500; + const spread = 50; + for (let i = 0; i < count; i++) { + const duck = glTF.instantiateSceneRoot(); + // Use deterministic positions based on index + const t = i / count; + duck.transform.setPosition( + Math.sin(t * 137.5) * spread * 0.5, + Math.cos(t * 97.3) * spread * 0.5, + Math.sin(t * 59.1) * spread * 0.5 + ); + duck.transform.setRotation(t * 360, t * 720, t * 1080); + rootEntity.addChild(duck); + } + + updateForE2E(engine); + initScreenshot(engine, camera); +}); diff --git a/e2e/case/gpu-instancing-custom-data.ts b/e2e/case/gpu-instancing-custom-data.ts new file mode 100644 index 0000000000..1c6f1755dd --- /dev/null +++ b/e2e/case/gpu-instancing-custom-data.ts @@ -0,0 +1,112 @@ +/** + * @title GPU Instancing Custom Data + * @category Mesh + */ +import { + Camera, + Color, + DirectLight, + Logger, + Material, + MeshRenderer, + PrimitiveMesh, + Shader, + ShaderProperty, + Vector3, + Vector4, + WebGLEngine +} from "@galacean/engine"; +import { ShaderCompiler } from "@galacean/engine-shader-compiler"; +import { initScreenshot, updateForE2E } from "./.mockForE2E"; + +Logger.enable(); + +const shaderCompiler = new ShaderCompiler(); + +// Custom shader: uses renderer_CustomColor (per-instance) for fragment output +const customInstanceShaderSource = `Shader "CustomInstanceShader" { + SubShader "Default" { + Pass "Forward" { + struct Attributes { + vec3 POSITION; + vec3 NORMAL; + }; + + struct Varyings { + vec3 v_normal; + }; + + mat4 renderer_MVPMat; + mat4 renderer_NormalMat; + vec4 renderer_CustomColor; + + VertexShader = vert; + FragmentShader = frag; + + Varyings vert(Attributes attr) { + Varyings v; + gl_Position = renderer_MVPMat * vec4(attr.POSITION, 1.0); + v.v_normal = normalize((renderer_NormalMat * vec4(attr.NORMAL, 0.0)).xyz); + return v; + } + + vec4 frag(Varyings v) { + vec3 lightDir = normalize(vec3(1.0, 1.0, 1.0)); + float NdotL = max(dot(v.v_normal, lightDir), 0.2); + return vec4(renderer_CustomColor.rgb * NdotL, 1.0); + } + } + } +}`; + +WebGLEngine.create({ canvas: "canvas", shaderCompiler }).then((engine) => { + Shader.create(customInstanceShaderSource); + engine.canvas.resizeByClientSize(2); + + const scene = engine.sceneManager.activeScene; + const rootEntity = scene.createRootEntity("Root"); + + // Camera + const cameraEntity = rootEntity.createChild("Camera"); + cameraEntity.transform.setPosition(0, 10, 80); + cameraEntity.transform.lookAt(new Vector3(0, 0, 0)); + const camera = cameraEntity.addComponent(Camera); + camera.farClipPlane = 300; + + // Light + const lightEntity = rootEntity.createChild("Light"); + lightEntity.transform.setRotation(-45, -45, 0); + lightEntity.addComponent(DirectLight).color = new Color(1, 1, 1, 1); + + // Shared mesh and material + const mesh = PrimitiveMesh.createCuboid(engine, 1, 1, 1); + const material = new Material(engine, Shader.find("CustomInstanceShader")); + const customColorProperty = ShaderProperty.getByName("renderer_CustomColor"); + + // Create cubes with deterministic positions and colors + const count = 500; + const spread = 50; + for (let i = 0; i < count; i++) { + const entity = rootEntity.createChild("Cube" + i); + const t = i / count; + entity.transform.setPosition( + Math.sin(t * 137.5) * spread * 0.5, + Math.cos(t * 97.3) * spread * 0.5, + Math.sin(t * 59.1) * spread * 0.5 + ); + entity.transform.setRotation(t * 360, t * 720, t * 1080); + + const renderer = entity.addComponent(MeshRenderer); + renderer.mesh = mesh; + renderer.setMaterial(material); + + // Deterministic colors based on index + renderer.shaderData.setVector4( + customColorProperty, + new Vector4(Math.sin(t * 6.28) * 0.5 + 0.5, Math.cos(t * 4.71) * 0.5 + 0.5, Math.sin(t * 3.14) * 0.5 + 0.5, 1.0) + ); + } + + updateForE2E(engine); + initScreenshot(engine, camera); +}); diff --git a/e2e/case/spriteMask-customStencil.ts b/e2e/case/spriteMask-customStencil.ts index 9eb08589c8..2056ae66f2 100644 --- a/e2e/case/spriteMask-customStencil.ts +++ b/e2e/case/spriteMask-customStencil.ts @@ -151,7 +151,15 @@ WebGLEngine.create({ canvas: "canvas", shaderCompiler: new ShaderCompiler() }).t // Create a sprite renderer that writes stencil. pos.set(0, 0, 0); scale.set(5, 5, 5); - const writeStencilSR = addSpriteRenderer(pos, scale, sprite, SpriteMaskInteraction.None, Layer.Layer0, Layer.Layer0, 0); + const writeStencilSR = addSpriteRenderer( + pos, + scale, + sprite, + SpriteMaskInteraction.None, + Layer.Layer0, + Layer.Layer0, + 0 + ); const writeStencilMaterial = writeStencilSR.getInstanceMaterial(); writeStencilMaterial.shader = customStencilShader; const writeStencilData = writeStencilMaterial.shaderData; @@ -161,7 +169,15 @@ WebGLEngine.create({ canvas: "canvas", shaderCompiler: new ShaderCompiler() }).t // Create a sprite renderer that reads stencil. pos.set(3, 3, 0); - const readStencilSR = addSpriteRenderer(pos, scale, sprite, SpriteMaskInteraction.None, Layer.Layer0, Layer.Layer0, 1); + const readStencilSR = addSpriteRenderer( + pos, + scale, + sprite, + SpriteMaskInteraction.None, + Layer.Layer0, + Layer.Layer0, + 1 + ); readStencilSR.color.set(1, 0, 0, 1); const readStencilMaterial = readStencilSR.getInstanceMaterial(); readStencilMaterial.shader = customStencilShader; @@ -173,7 +189,15 @@ WebGLEngine.create({ canvas: "canvas", shaderCompiler: new ShaderCompiler() }).t // Create a sprite renderer with mask interaction (does not need custom stencil). pos.set(5, -3, 0); - const maskSR = addSpriteRenderer(pos, scale, sprite, SpriteMaskInteraction.VisibleOutsideMask, Layer.Layer0, Layer.Layer0, 2); + const maskSR = addSpriteRenderer( + pos, + scale, + sprite, + SpriteMaskInteraction.VisibleOutsideMask, + Layer.Layer0, + Layer.Layer0, + 2 + ); maskSR.color.set(0, 1, 0, 1); // Create a sprite mask. @@ -183,7 +207,15 @@ WebGLEngine.create({ canvas: "canvas", shaderCompiler: new ShaderCompiler() }).t // Create another sprite renderer that reads stencil with a different comparison. pos.set(20, 10, 0); scale.set(3, 3, 3); - const readStencilSR2 = addSpriteRenderer(pos, scale, sprite, SpriteMaskInteraction.None, Layer.Layer0, Layer.Layer0, 4); + const readStencilSR2 = addSpriteRenderer( + pos, + scale, + sprite, + SpriteMaskInteraction.None, + Layer.Layer0, + Layer.Layer0, + 4 + ); readStencilSR2.color.set(1, 0.5, 0.8, 1); const readStencilMaterial2 = readStencilSR2.getInstanceMaterial(); readStencilMaterial2.shader = customStencilShader; diff --git a/e2e/case/ui-batch-order.ts b/e2e/case/ui-batch-order.ts new file mode 100644 index 0000000000..a0d234004f --- /dev/null +++ b/e2e/case/ui-batch-order.ts @@ -0,0 +1,92 @@ +/** + * @title UI Batch Order + * @category UI + * @description Regression guard for the canvas hierarchy-order bug introduced when + * SubRenderElement was flattened into RenderElement: canvas sub-elements entered + * the main transparent queue directly and could be shuffled by unstable quicksort + * under equal (priority, distance), making `text` render below `bg` on some buttons. + * Fixed by canvas-internal batching + subDistancePriority tiebreaker. + * This case lays out a 4×3 grid of (bg + text) buttons; if hierarchy order ever + * breaks again, the green text would be hidden behind red bg in the screenshot. + */ +import { Camera, Color, Sprite, Texture2D, TextureFormat, WebGLEngine } from "@galacean/engine"; +import { CanvasRenderMode, Image, registerGUI, UICanvas, UITransform } from "@galacean/engine-ui"; +import { initScreenshot, updateForE2E } from "./.mockForE2E"; + +registerGUI(); + +WebGLEngine.create({ canvas: "canvas" }).then((engine) => { + engine.canvas.resizeByClientSize(2); + + const scene = engine.sceneManager.activeScene; + const root = scene.createRootEntity("root"); + + // Camera (ScreenSpaceCamera mode is required: ScreenSpaceOverlay UI renders in a + // separate overlay pass that bypasses camera.render(), so initScreenshot's + // off-screen render-target won't capture it.) + const cameraEntity = root.createChild("camera"); + cameraEntity.transform.setPosition(0, 0, 50); + const camera = cameraEntity.addComponent(Camera); + + // Canvas + const canvasEntity = root.createChild("canvas"); + const canvas = canvasEntity.addComponent(UICanvas); + canvas.renderMode = CanvasRenderMode.ScreenSpaceCamera; + canvas.renderCamera = camera; + canvas.referenceResolution.set(1280, 720); + + // Two solid-color textures → distinct materials, so bg/text are batch-incompatible + const bgTex = createSolidTexture(engine, 64, 64, [255, 80, 80, 255]); // red + const textTex = createSolidTexture(engine, 64, 64, [80, 255, 80, 255]); // green + const bgSprite = new Sprite(engine, bgTex); + const textSprite = new Sprite(engine, textTex); + + // Build a 4×3 grid of buttons; each button = bg (red) + text (green) overlapping. + // Hierarchy creation order: bg0, text0, bg1, text1, ... — text must paint over bg. + // If sort breaks per-button order, green will be hidden under red somewhere. + const cols = 4; + const rows = 3; + const cellW = 180; + const cellH = 100; + const startX = -((cols - 1) * cellW) / 2; + const startY = -((rows - 1) * cellH) / 2; + + for (let r = 0; r < rows; r++) { + for (let c = 0; c < cols; c++) { + const x = startX + c * cellW; + const y = startY + r * cellH; + + const bgEntity = canvasEntity.createChild(`bg-${r}-${c}`); + const bgTransform = bgEntity.transform as UITransform; + bgTransform.position.set(x, y, 0); + bgTransform.size.set(140, 60); + const bgImage = bgEntity.addComponent(Image); + bgImage.sprite = bgSprite; + bgImage.color = new Color(1, 1, 1, 1); + + const textEntity = canvasEntity.createChild(`text-${r}-${c}`); + const textTransform = textEntity.transform as UITransform; + textTransform.position.set(x, y, 0); + textTransform.size.set(80, 30); + const textImage = textEntity.addComponent(Image); + textImage.sprite = textSprite; + textImage.color = new Color(1, 1, 1, 1); + } + } + + updateForE2E(engine); + initScreenshot(engine, camera); +}); + +function createSolidTexture(engine: WebGLEngine, w: number, h: number, rgba: number[]): Texture2D { + const tex = new Texture2D(engine, w, h, TextureFormat.R8G8B8A8, false); + const data = new Uint8Array(w * h * 4); + for (let i = 0; i < w * h; i++) { + data[i * 4] = rgba[0]; + data[i * 4 + 1] = rgba[1]; + data[i * 4 + 2] = rgba[2]; + data[i * 4 + 3] = rgba[3]; + } + tex.setPixelBuffer(data); + return tex; +} diff --git a/e2e/config.ts b/e2e/config.ts index 0140328de4..780baae28d 100644 --- a/e2e/config.ts +++ b/e2e/config.ts @@ -135,7 +135,7 @@ export const E2E_CONFIG = { category: "Material", caseFileName: "material-pbr", threshold: 0, - diffPercentage: 0.0080 + diffPercentage: 0.008 }, shader: { category: "Material", @@ -476,6 +476,20 @@ export const E2E_CONFIG = { diffPercentage: 0.03 } }, + GPUInstancing: { + autoBatch: { + category: "GPUInstancing", + caseFileName: "gpu-instancing-auto-batch", + threshold: 0, + diffPercentage: 0.00126 + }, + customData: { + category: "GPUInstancing", + caseFileName: "gpu-instancing-custom-data", + threshold: 0, + diffPercentage: 0 + } + }, SpriteMask: { CustomStencil: { category: "SpriteMask", @@ -532,5 +546,13 @@ export const E2E_CONFIG = { threshold: 0, diffPercentage: 0.044 } + }, + UI: { + batchOrder: { + category: "UI", + caseFileName: "ui-batch-order", + threshold: 0, + diffPercentage: 0 + } } }; diff --git a/e2e/fixtures/originImage/Animator_animator-crossfade.jpg b/e2e/fixtures/originImage/Animator_animator-crossfade.jpg index ab638de414..c71cd431c8 100644 --- a/e2e/fixtures/originImage/Animator_animator-crossfade.jpg +++ b/e2e/fixtures/originImage/Animator_animator-crossfade.jpg @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e18021c1e0a3b682259046e812eba199c907ffd9a634dda12379f1f0c3b8b43a -size 45710 +oid sha256:a1dfa2435f26222617b08ce2830ca28d8d84e083678dde1a9d945479c7b6d019 +size 45716 diff --git a/e2e/fixtures/originImage/Animator_animator-play.jpg b/e2e/fixtures/originImage/Animator_animator-play.jpg index 79170b806b..ddfb02c4e7 100644 --- a/e2e/fixtures/originImage/Animator_animator-play.jpg +++ b/e2e/fixtures/originImage/Animator_animator-play.jpg @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4910985a371b9022e73d2a7efbd71ca6754bcc7bf4c25edc2a41391f1bb1533b -size 46499 +oid sha256:82d8ba4776b6b27b923d0f1f0094d48d0d4c59e61e8666275690fec70c39e854 +size 46527 diff --git a/e2e/fixtures/originImage/Camera_camera-opaque-texture.jpg b/e2e/fixtures/originImage/Camera_camera-opaque-texture.jpg index bcc2d5f331..1d409ae544 100644 --- a/e2e/fixtures/originImage/Camera_camera-opaque-texture.jpg +++ b/e2e/fixtures/originImage/Camera_camera-opaque-texture.jpg @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fdde03beb8ead802b61a14e8649102c18ccfe6b9e1e176d3b9f8bc0dfe7f9c76 -size 47500 +oid sha256:a2068be8d0b35c94ec1ddaed9da63494f1a93294ea6128e2036563df1947e854 +size 47482 diff --git a/e2e/fixtures/originImage/GPUInstancing_gpu-instancing-auto-batch.jpg b/e2e/fixtures/originImage/GPUInstancing_gpu-instancing-auto-batch.jpg new file mode 100644 index 0000000000..ecec018d8c --- /dev/null +++ b/e2e/fixtures/originImage/GPUInstancing_gpu-instancing-auto-batch.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:dc2a26d0ad06c2dfa722484b2e914b43c4c6671c76ec31d18715dc4a89ec1d88 +size 590047 diff --git a/e2e/fixtures/originImage/GPUInstancing_gpu-instancing-custom-data.jpg b/e2e/fixtures/originImage/GPUInstancing_gpu-instancing-custom-data.jpg new file mode 100644 index 0000000000..79399c097c --- /dev/null +++ b/e2e/fixtures/originImage/GPUInstancing_gpu-instancing-custom-data.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:baece2c4437803e1474699eb4e99214b38caa05393f747fe0f7e47bd6469a693 +size 427005 diff --git a/e2e/fixtures/originImage/Physics_physx-collision.jpg b/e2e/fixtures/originImage/Physics_physx-collision.jpg index d32e92214d..5716d22a3f 100644 --- a/e2e/fixtures/originImage/Physics_physx-collision.jpg +++ b/e2e/fixtures/originImage/Physics_physx-collision.jpg @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7ae9760712d39077cdfe8355be063186096d4ae0132de697fc8278bd6ebc42db -size 36026 +oid sha256:2426a2b92ad4d62b28f5c54c255c6e072d7b02e4b79eff839ea8f75f16c34061 +size 36011 diff --git a/e2e/fixtures/originImage/Physics_physx-customUrl.jpg b/e2e/fixtures/originImage/Physics_physx-customUrl.jpg index d32e92214d..5716d22a3f 100644 --- a/e2e/fixtures/originImage/Physics_physx-customUrl.jpg +++ b/e2e/fixtures/originImage/Physics_physx-customUrl.jpg @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7ae9760712d39077cdfe8355be063186096d4ae0132de697fc8278bd6ebc42db -size 36026 +oid sha256:2426a2b92ad4d62b28f5c54c255c6e072d7b02e4b79eff839ea8f75f16c34061 +size 36011 diff --git a/e2e/fixtures/originImage/Physics_physx-mesh-collider-data.jpg b/e2e/fixtures/originImage/Physics_physx-mesh-collider-data.jpg index b179343be2..b18cb45c89 100644 --- a/e2e/fixtures/originImage/Physics_physx-mesh-collider-data.jpg +++ b/e2e/fixtures/originImage/Physics_physx-mesh-collider-data.jpg @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a1e13bb7569d857bbf63e2f2fe9ab43d738d12c1fa5689b3d9659912930989df -size 143176 +oid sha256:0fd92c9589df7c7cd9474a0b5b14315bedda98f5984858308756dffe3dad8689 +size 143304 diff --git a/e2e/fixtures/originImage/UI_ui-batch-order.jpg b/e2e/fixtures/originImage/UI_ui-batch-order.jpg new file mode 100644 index 0000000000..f0085f7116 --- /dev/null +++ b/e2e/fixtures/originImage/UI_ui-batch-order.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fa01567d7e322a9491b0e3381c6cbce620417395c4e51ec63b022e111bc028ce +size 39022 diff --git a/e2e/package.json b/e2e/package.json index 7787e36773..a56c88c28c 100644 --- a/e2e/package.json +++ b/e2e/package.json @@ -19,6 +19,7 @@ "@galacean/engine-rhi-webgl": "workspace:*", "@galacean/engine-physics-lite": "workspace:*", "@galacean/engine-physics-physx": "workspace:*", + "@galacean/engine-ui": "workspace:*", "dat.gui": "^0.7.9", "vite": "3.1.6", "sass": "^1.55.0" diff --git a/examples/package.json b/examples/package.json index e53aabc690..b7010641f3 100644 --- a/examples/package.json +++ b/examples/package.json @@ -22,6 +22,7 @@ "@galacean/engine-shader": "workspace:*", "@galacean/engine-shader-compiler": "workspace:*", "@galacean/engine-toolkit": "latest", + "@galacean/engine-toolkit-stats": "latest", "@galacean/engine-ui": "workspace:*" }, "devDependencies": { diff --git a/examples/src/gpu-instancing-auto-batch.ts b/examples/src/gpu-instancing-auto-batch.ts new file mode 100644 index 0000000000..3bf57fc429 --- /dev/null +++ b/examples/src/gpu-instancing-auto-batch.ts @@ -0,0 +1,207 @@ +/** + * @title GPU Instancing Auto Batch + * @category Mesh + * @thumbnail https://mdn.alipayobjects.com/merchant_appfe/afts/img/A*jjZMTrp-vU8AAAAAAAAAAAAADiR2AQ/original + */ +import { Stats } from "@galacean/engine-toolkit-stats"; +import { + AmbientLight, + AssetType, + Camera, + Color, + DirectLight, + GLTFResource, + Logger, + Material, + MeshRenderer, + PrimitiveMesh, + Script, + Shader, + ShaderProperty, + Vector3, + Vector4, + WebGLEngine, + WebGLMode +} from "@galacean/engine"; +import { ShaderCompiler } from "@galacean/engine-shader-compiler"; + +const shaderCompiler = new ShaderCompiler(); +const _customColorProperty = ShaderProperty.getByName("renderer_CustomColor"); + +class SpiralAnimate extends Script { + radius: number = 0; + radiusSpeed: number = 0; + theta: number = 0; + thetaSpeed: number = 0; + phi: number = 0; + phiSpeed: number = 0; + rotateSpeed: Vector3 = new Vector3(); + scaleBase: number = 1; + scaleFreq: number = 0; + colorPhase: number = 0; + colorSpeed: number = 0; + private _time: number = 0; + private _color: Vector4 = new Vector4(); + private _hasColor: boolean = false; + + onUpdate(deltaTime: number): void { + this._time += deltaTime; + const t = this._time; + const transform = this.entity.transform; + + // Spiral breathing motion + const r = this.radius * (0.6 + 0.4 * Math.sin(t * this.radiusSpeed)); + const theta = this.theta + t * this.thetaSpeed; + const phi = this.phi + t * this.phiSpeed; + + const sinTheta = Math.sin(theta); + transform.setPosition(r * sinTheta * Math.cos(phi), r * Math.cos(theta), r * sinTheta * Math.sin(phi)); + + // Rotation + const { rotateSpeed } = this; + transform.rotate(rotateSpeed.x * deltaTime, rotateSpeed.y * deltaTime, rotateSpeed.z * deltaTime); + + // Scale pulse + const s = this.scaleBase * (0.7 + 0.3 * Math.sin(t * this.scaleFreq)); + transform.setScale(s, s, s); + + // Color animation (cubes only) + if (this._hasColor) { + const ct = t * this.colorSpeed + this.colorPhase; + this._color.set( + 0.5 + 0.5 * Math.sin(ct), + 0.5 + 0.5 * Math.sin(ct + 2.094), + 0.5 + 0.5 * Math.sin(ct + 4.189), + 1.0 + ); + this.entity.getComponent(MeshRenderer).shaderData.setVector4(_customColorProperty, this._color); + } + } + + enableColor(): void { + this._hasColor = true; + } +} + +// Custom shader for cubes +const customInstanceShaderSource = `Shader "CustomInstanceShader" { + SubShader "Default" { + Pass "Forward" { + struct Attributes { + vec3 POSITION; + vec3 NORMAL; + }; + + struct Varyings { + vec3 v_normal; + }; + + mat4 renderer_MVPMat; + mat4 renderer_NormalMat; + vec4 renderer_CustomColor; + + VertexShader = vert; + FragmentShader = frag; + + Varyings vert(Attributes attr) { + Varyings v; + gl_Position = renderer_MVPMat * vec4(attr.POSITION, 1.0); + v.v_normal = normalize((renderer_NormalMat * vec4(attr.NORMAL, 0.0)).xyz); + return v; + } + + vec4 frag(Varyings v) { + vec3 lightDir = normalize(vec3(1.0, 1.0, 1.0)); + float NdotL = max(dot(v.v_normal, lightDir), 0.2); + return vec4(renderer_CustomColor.rgb * NdotL, 1.0); + } + } + } +}`; + +Logger.enable(); +WebGLEngine.create({ + canvas: "canvas", + graphicDeviceOptions: { webGLMode: WebGLMode.WebGL2 }, + shaderCompiler +}).then(async (engine) => { + Shader.create(customInstanceShaderSource); + engine.canvas.resizeByClientSize(); + + const scene = engine.sceneManager.activeScene; + const rootEntity = scene.createRootEntity("Root"); + + // Camera + const cameraEntity = rootEntity.createChild("Camera"); + cameraEntity.transform.setPosition(0, 0, 100); + cameraEntity.transform.lookAt(new Vector3(0, 0, 0)); + const camera = cameraEntity.addComponent(Camera); + camera.farClipPlane = 500; + cameraEntity.addComponent(Stats); + + // Light + const lightEntity = rootEntity.createChild("Light"); + lightEntity.transform.setRotation(-45, -45, 0); + lightEntity.addComponent(DirectLight).color = new Color(1, 1, 1, 1); + + // Load Duck model and ambient light + const [glTF, ambientLight] = await Promise.all([ + engine.resourceManager.load({ + url: "https://mdn.alipayobjects.com/rms/afts/file/A*9R-_TY9K_6oAAAAAgIAAAAgAehQnAQ/Avocado.glb", + type: AssetType.GLTF + }), + engine.resourceManager.load({ + url: "https://mdn.alipayobjects.com/oasis_be/afts/file/A*eRJ8QKzf5zAAAAAAgBAAAAgAekp5AQ/ambient.ambLight", + type: AssetType.AmbientLight + }) + ]); + scene.ambientLight = ambientLight; + + // Cube resources + const cubeMesh = PrimitiveMesh.createCuboid(engine, 1, 1, 1); + const cubeMaterial = new Material(engine, Shader.find("CustomInstanceShader")); + const customColorProperty = ShaderProperty.getByName("renderer_CustomColor"); + + // Interleave ducks and cubes to break batching — instancing shines here + const duckCount = 2500; + const cubeCount = 2500; + const totalCount = duckCount + cubeCount; + + for (let i = 0; i < totalCount; i++) { + const ti = i / totalCount; + const isDuck = i % 2 === 0 && i / 2 < duckCount; + const isCube = !isDuck; + + let entity; + if (isDuck) { + entity = glTF.instantiateSceneRoot(); + rootEntity.addChild(entity); + } else { + entity = rootEntity.createChild("Cube" + i); + const renderer = entity.addComponent(MeshRenderer); + renderer.mesh = cubeMesh; + renderer.setMaterial(cubeMaterial); + const initColor = new Vector4(Math.random(), Math.random(), Math.random(), 1.0); + renderer.shaderData.setVector4(customColorProperty, initColor); + } + + const anim = entity.addComponent(SpiralAnimate); + anim.radius = 10 + Math.random() * 40; + anim.radiusSpeed = 0.3 + Math.random() * 0.6; + anim.theta = ti * Math.PI * 2 * 13.7; + anim.phi = ti * Math.PI * 2 * 7.3; + anim.thetaSpeed = (0.2 + Math.random() * 0.4) * (Math.random() > 0.5 ? 1 : -1); + anim.phiSpeed = (0.3 + Math.random() * 0.5) * (Math.random() > 0.5 ? 1 : -1); + anim.rotateSpeed = new Vector3((Math.random() - 0.5) * 60, (Math.random() - 0.5) * 60, (Math.random() - 0.5) * 60); + anim.scaleBase = (isDuck ? 20 : 1) * (0.6 + Math.random() * 0.8); + anim.scaleFreq = 0.5 + Math.random() * 2; + + if (isCube) { + anim.colorPhase = Math.random() * Math.PI * 2; + anim.colorSpeed = 0.5 + Math.random() * 2; + anim.enableColor(); + } + } + + engine.run(); +}); diff --git a/examples/src/gpu-instancing-custom-data.ts b/examples/src/gpu-instancing-custom-data.ts new file mode 100644 index 0000000000..eb7c9e8917 --- /dev/null +++ b/examples/src/gpu-instancing-custom-data.ts @@ -0,0 +1,163 @@ +/** + * @title GPU Instancing Custom Data + * @category Mesh + * @thumbnail https://mdn.alipayobjects.com/merchant_appfe/afts/img/A*jjZMTrp-vU8AAAAAAAAAAAAADiR2AQ/original + */ +import { Stats } from "@galacean/engine-toolkit-stats"; +import { + Camera, + Color, + DirectLight, + Logger, + Material, + MeshRenderer, + PrimitiveMesh, + Script, + Shader, + ShaderProperty, + Vector3, + Vector4, + WebGLEngine, + WebGLMode +} from "@galacean/engine"; +import { ShaderCompiler } from "@galacean/engine-shader-compiler"; + +const shaderCompiler = new ShaderCompiler(); +const _customColorProperty = ShaderProperty.getByName("renderer_CustomColor"); + +class SpiralFlash extends Script { + radius: number = 0; + radiusSpeed: number = 0; + theta: number = 0; + thetaSpeed: number = 0; + phi: number = 0; + phiSpeed: number = 0; + rotateSpeed: Vector3 = new Vector3(); + scaleBase: number = 1; + scaleFreq: number = 0; + colorPhase: number = 0; + colorSpeed: number = 1; + private _time: number = 0; + private _color: Vector4 = new Vector4(); + + onUpdate(deltaTime: number): void { + this._time += deltaTime; + const t = this._time; + const transform = this.entity.transform; + + // Spiral breathing motion + const r = this.radius * (0.6 + 0.4 * Math.sin(t * this.radiusSpeed)); + const theta = this.theta + t * this.thetaSpeed; + const phi = this.phi + t * this.phiSpeed; + + const sinTheta = Math.sin(theta); + transform.setPosition(r * sinTheta * Math.cos(phi), r * Math.cos(theta), r * sinTheta * Math.sin(phi)); + + // Rotation + const { rotateSpeed } = this; + transform.rotate(rotateSpeed.x * deltaTime, rotateSpeed.y * deltaTime, rotateSpeed.z * deltaTime); + + // Scale pulse + const s = this.scaleBase * (0.7 + 0.3 * Math.sin(t * this.scaleFreq)); + transform.setScale(s, s, s); + + // Color cycles through hue based on time + unique phase + const ct = t * this.colorSpeed + this.colorPhase; + this._color.set(0.5 + 0.5 * Math.sin(ct), 0.5 + 0.5 * Math.sin(ct + 2.094), 0.5 + 0.5 * Math.sin(ct + 4.189), 1.0); + this.entity.getComponent(MeshRenderer).shaderData.setVector4(_customColorProperty, this._color); + } +} + +Logger.enable(); + +const customInstanceShaderSource = `Shader "CustomInstanceShader" { + SubShader "Default" { + Pass "Forward" { + struct Attributes { + vec3 POSITION; + vec3 NORMAL; + }; + + struct Varyings { + vec3 v_normal; + }; + + mat4 renderer_MVPMat; + mat4 renderer_NormalMat; + vec4 renderer_CustomColor; + + VertexShader = vert; + FragmentShader = frag; + + Varyings vert(Attributes attr) { + Varyings v; + gl_Position = renderer_MVPMat * vec4(attr.POSITION, 1.0); + v.v_normal = normalize((renderer_NormalMat * vec4(attr.NORMAL, 0.0)).xyz); + return v; + } + + vec4 frag(Varyings v) { + vec3 lightDir = normalize(vec3(1.0, 1.0, 1.0)); + float NdotL = max(dot(v.v_normal, lightDir), 0.2); + return vec4(renderer_CustomColor.rgb * NdotL, 1.0); + } + } + } +}`; + +WebGLEngine.create({ + canvas: "canvas", + graphicDeviceOptions: { webGLMode: WebGLMode.WebGL2 }, + shaderCompiler +}).then((engine) => { + Shader.create(customInstanceShaderSource); + engine.canvas.resizeByClientSize(); + + const scene = engine.sceneManager.activeScene; + const rootEntity = scene.createRootEntity("Root"); + + // Camera + const cameraEntity = rootEntity.createChild("Camera"); + cameraEntity.transform.setPosition(0, 0, 100); + cameraEntity.transform.lookAt(new Vector3(0, 0, 0)); + const camera = cameraEntity.addComponent(Camera); + camera.farClipPlane = 500; + cameraEntity.addComponent(Stats); + + // Light + const lightEntity = rootEntity.createChild("Light"); + lightEntity.transform.setRotation(-45, -45, 0); + lightEntity.addComponent(DirectLight).color = new Color(1, 1, 1, 1); + + const mesh = PrimitiveMesh.createCuboid(engine, 1, 1, 1); + const material = new Material(engine, Shader.find("CustomInstanceShader")); + const customColorProperty = ShaderProperty.getByName("renderer_CustomColor"); + + const count = 5000; + for (let i = 0; i < count; i++) { + const entity = rootEntity.createChild("Cube" + i); + const ti = i / count; + + const renderer = entity.addComponent(MeshRenderer); + renderer.mesh = mesh; + renderer.setMaterial(material); + + const initColor = new Vector4(Math.random(), Math.random(), Math.random(), 1.0); + renderer.shaderData.setVector4(customColorProperty, initColor); + + const anim = entity.addComponent(SpiralFlash); + anim.radius = 10 + Math.random() * 40; + anim.radiusSpeed = 0.3 + Math.random() * 0.6; + anim.theta = ti * Math.PI * 2 * 13.7; + anim.phi = ti * Math.PI * 2 * 7.3; + anim.thetaSpeed = (0.2 + Math.random() * 0.4) * (Math.random() > 0.5 ? 1 : -1); + anim.phiSpeed = (0.3 + Math.random() * 0.5) * (Math.random() > 0.5 ? 1 : -1); + anim.rotateSpeed = new Vector3((Math.random() - 0.5) * 60, (Math.random() - 0.5) * 60, (Math.random() - 0.5) * 60); + anim.scaleBase = 0.6 + Math.random() * 0.8; + anim.scaleFreq = 0.5 + Math.random() * 2; + anim.colorPhase = Math.random() * Math.PI * 2; + anim.colorSpeed = 0.5 + Math.random() * 2; + } + + engine.run(); +}); diff --git a/examples/src/ui-batch-massive.ts b/examples/src/ui-batch-massive.ts new file mode 100644 index 0000000000..62d3a5c2b2 --- /dev/null +++ b/examples/src/ui-batch-massive.ts @@ -0,0 +1,239 @@ +/** + * @title UI Batch Massive Buttons + * @category UI + * @thumbnail https://mdn.alipayobjects.com/merchant_appfe/afts/img/A*jjZMTrp-vU8AAAAAAAAAAAAADiR2AQ/original + * + * Stress test: 6000 buttons (12000 sub-elements) on a single canvas. + * Each button = bg sprite (gradient panel) + icon sprite (atlas-sampled). + * Watch the Stats panel — DrawCall reflects current batching strategy. + */ +import { Stats } from "@galacean/engine-toolkit-stats"; +import { Camera, Color, Sprite, Texture2D, TextureFormat, WebGLEngine, Rect } from "@galacean/engine"; +import { + CanvasRenderMode, + Image, + registerGUI, + ResolutionAdaptationMode, + UICanvas, + UITransform +} from "@galacean/engine-ui"; + +registerGUI(); + +WebGLEngine.create({ canvas: "canvas" }).then((engine) => { + engine.canvas.resizeByClientSize(); + + const scene = engine.sceneManager.activeScene; + const root = scene.createRootEntity("root"); + + // Camera + const cameraEntity = root.createChild("camera"); + cameraEntity.transform.setPosition(0, 0, 50); + const camera = cameraEntity.addComponent(Camera); + cameraEntity.addComponent(Stats); + + // Canvas + const canvasEntity = root.createChild("canvas"); + const canvas = canvasEntity.addComponent(UICanvas); + canvas.renderMode = CanvasRenderMode.ScreenSpaceCamera; + canvas.renderCamera = camera; + canvas.referenceResolution.set(1280, 720); + canvas.resolutionAdaptationMode = ResolutionAdaptationMode.BothAdaptation; + + // Two textures: a gradient bg panel and an icon atlas (4 icons in 2×2) + // All buttons share these two textures, so all bg-sprites are batchable, and + // all icon-sprites (using different atlas regions) are also batchable — + // demonstrating cluster-by-(material, texture). + const bgSprite = new Sprite(engine, makeGradientPanel(engine)); + const iconAtlasTexture = makeIconAtlas(engine); + + // 4 sub-sprites of the same atlas, rotating per button + const iconSprites = [ + new Sprite(engine, iconAtlasTexture, new Rect(0, 0, 0.5, 0.5)), // sword + new Sprite(engine, iconAtlasTexture, new Rect(0.5, 0, 0.5, 0.5)), // heart + new Sprite(engine, iconAtlasTexture, new Rect(0, 0.5, 0.5, 0.5)), // bolt + new Sprite(engine, iconAtlasTexture, new Rect(0.5, 0.5, 0.5, 0.5)) // gem + ]; + + // 128×72 = 9216 buttons → 18432 sub-elements + const cols = 128; + const rows = 72; + const buttonW = 7; + const buttonH = 6; + const gapX = 9; + const gapY = 8; + const startX = -((cols - 1) * gapX) / 2; + const startY = -((rows - 1) * gapY) / 2; + + for (let r = 0; r < rows; r++) { + for (let c = 0; c < cols; c++) { + const x = startX + c * gapX; + const y = startY + r * gapY; + + const bg = canvasEntity.createChild(`bg-${r}-${c}`); + bg.transform.setPosition(x, y, 0); + const bgT = bg.transform as UITransform; + bgT.size.set(buttonW, buttonH); + const bgImg = bg.addComponent(Image); + bgImg.sprite = bgSprite; + bgImg.color = new Color(1, 1, 1, 1); + + const icon = canvasEntity.createChild(`icon-${r}-${c}`); + icon.transform.setPosition(x, y, 0); + const iconT = icon.transform as UITransform; + iconT.size.set(buttonW * 0.55, buttonH * 0.55); + const iconImg = icon.addComponent(Image); + iconImg.sprite = iconSprites[(r + c) % 4]; + iconImg.color = new Color(1, 1, 1, 1); + } + } + + engine.run(); +}); + +// Vertical gradient panel with double border (atlas-style game button background) +function makeGradientPanel(engine: WebGLEngine): Texture2D { + const size = 64; + const tex = new Texture2D(engine, size, size, TextureFormat.R8G8B8A8, false); + const data = new Uint8Array(size * size * 4); + // Base palette: deep navy → electric blue gradient + const top = [70, 130, 240]; + const bottom = [25, 55, 130]; + const outerBorder = [12, 25, 60]; + const innerHighlight = [180, 220, 255]; + + for (let y = 0; y < size; y++) { + for (let x = 0; x < size; x++) { + const i = (y * size + x) * 4; + const t = y / (size - 1); + // Vertical gradient + let r = top[0] * (1 - t) + bottom[0] * t; + let g = top[1] * (1 - t) + bottom[1] * t; + let b = top[2] * (1 - t) + bottom[2] * t; + + // Outer 2px border + if (x < 2 || x >= size - 2 || y < 2 || y >= size - 2) { + r = outerBorder[0]; + g = outerBorder[1]; + b = outerBorder[2]; + } + // Inner 1px highlight on top edge + else if (y < 4 && x >= 2 && x < size - 2) { + r = (r + innerHighlight[0]) * 0.5; + g = (g + innerHighlight[1]) * 0.5; + b = (b + innerHighlight[2]) * 0.5; + } + + data[i] = r | 0; + data[i + 1] = g | 0; + data[i + 2] = b | 0; + data[i + 3] = 255; + } + } + tex.setPixelBuffer(data); + return tex; +} + +// 64×64 atlas with 4 icons in 2×2 grid (32×32 each), transparent background +function makeIconAtlas(engine: WebGLEngine): Texture2D { + const cellSize = 32; + const atlasSize = cellSize * 2; + const tex = new Texture2D(engine, atlasSize, atlasSize, TextureFormat.R8G8B8A8, false); + const data = new Uint8Array(atlasSize * atlasSize * 4); + + const writePixel = (cx: number, cy: number, lx: number, ly: number, r: number, g: number, b: number, a: number) => { + const x = cx * cellSize + lx; + const y = cy * cellSize + ly; + if (x < 0 || x >= atlasSize || y < 0 || y >= atlasSize) return; + const i = (y * atlasSize + x) * 4; + data[i] = r; + data[i + 1] = g; + data[i + 2] = b; + data[i + 3] = a; + }; + + // Cell (0, 0): sword icon (silver blade + gold hilt) + for (let y = 0; y < cellSize; y++) { + for (let x = 0; x < cellSize; x++) { + const cx = cellSize / 2 - 0.5; + const cy = cellSize / 2; + const dx = x - cx; + const dy = y - cy; + // diagonal blade strip + const along = (dx + dy) * 0.7071; + const across = (dx - dy) * 0.7071; + const inBlade = Math.abs(across) < 2 && along > -10 && along < 8; + const inHilt = Math.abs(across) < 5 && along >= 8 && along < 11; + const inGuard = Math.abs(across) < 7 && Math.abs(along - 7.5) < 1; + if (inBlade) writePixel(0, 0, x, y, 220, 230, 240, 255); + else if (inHilt) writePixel(0, 0, x, y, 200, 150, 50, 255); + else if (inGuard) writePixel(0, 0, x, y, 150, 110, 30, 255); + } + } + + // Cell (1, 0): heart icon + for (let y = 0; y < cellSize; y++) { + for (let x = 0; x < cellSize; x++) { + // Heart equation: ((x²+y²-1)³ - x²y³) <= 0, with proper scaling + const nx = (x - cellSize / 2) / (cellSize / 2.5); + const ny = -(y - cellSize / 2.2) / (cellSize / 2.5); + const v = Math.pow(nx * nx + ny * ny - 1, 3) - nx * nx * Math.pow(ny, 3); + if (v <= 0) { + // Soft red gradient + const t = (ny + 0.5) * 0.5; + const r = (235 - t * 30) | 0; + const g = (50 + t * 30) | 0; + const b = (70 + t * 20) | 0; + writePixel(1, 0, x, y, r, g, b, 255); + } + } + } + + // Cell (0, 1): lightning bolt (zigzag) + const boltPath: [number, number][] = [ + [16, 4], + [10, 16], + [14, 16], + [11, 28], + [22, 14], + [17, 14], + [21, 4] + ]; + for (let y = 0; y < cellSize; y++) { + for (let x = 0; x < cellSize; x++) { + // Point-in-polygon + let inside = false; + for (let i = 0, j = boltPath.length - 1; i < boltPath.length; j = i++) { + const [xi, yi] = boltPath[i]; + const [xj, yj] = boltPath[j]; + if (yi > y !== yj > y && x < ((xj - xi) * (y - yi)) / (yj - yi) + xi) inside = !inside; + } + if (inside) writePixel(0, 1, x, y, 255, 215, 60, 255); + } + } + + // Cell (1, 1): gem (diamond shape with highlight) + for (let y = 0; y < cellSize; y++) { + for (let x = 0; x < cellSize; x++) { + const cx = cellSize / 2; + const cy = cellSize / 2; + const dx = Math.abs(x - cx); + const dy = Math.abs(y - cy); + // Diamond: |dx| + |dy| < r + if (dx + dy < cellSize * 0.4) { + // Cyan with white highlight at top-left + const high = Math.max(0, 1 - ((x - cx + 6) ** 2 + (y - cy + 6) ** 2) / 50); + const baseR = 80; + const baseG = 220; + const baseB = 230; + const r = (baseR + (255 - baseR) * high) | 0; + const g = (baseG + (255 - baseG) * high) | 0; + const b = (baseB + (255 - baseB) * high) | 0; + writePixel(1, 1, x, y, r, g, b, 255); + } + } + } + + tex.setPixelBuffer(data); + return tex; +} diff --git a/package.json b/package.json index 8ed1e3793a..9c8324fbeb 100644 --- a/package.json +++ b/package.json @@ -44,18 +44,18 @@ "@types/dom-webcodecs": "^0.1.13", "@types/node": "^18.7.16", "@types/webxr": "latest", - "@typescript-eslint/eslint-plugin": "^6.1.0", - "@typescript-eslint/parser": "^6.1.0", + "@typescript-eslint/eslint-plugin": "^8.58.1", + "@typescript-eslint/parser": "^8.58.1", "@vitest/coverage-v8": "2.1.3", "bumpp": "^9.5.2", "cross-env": "^5.2.0", "electron": "^13", - "eslint": "^8.44.0", + "eslint": "^8.57.1", "eslint-config-prettier": "^8.8.0", "eslint-plugin-prettier": "^5.0.0", "fs-extra": "^10.1.0", "husky": "^8.0.0", - "lint-staged": "^10.5.3", + "lint-staged": "^16.4.0", "nyc": "^15.1.0", "odiff-bin": "^2.5.0", "prettier": "^3.0.0", @@ -68,9 +68,8 @@ "vitest": "2.1.3" }, "lint-staged": { - "*.{ts}": [ - "eslint --fix", - "git add" + "**/*.ts": [ + "eslint --fix" ] }, "repository": "git@github.com:galacean/runtime.git" diff --git a/packages/core/src/2d/sprite/SpriteMask.ts b/packages/core/src/2d/sprite/SpriteMask.ts index 141f352d35..1f740081f9 100644 --- a/packages/core/src/2d/sprite/SpriteMask.ts +++ b/packages/core/src/2d/sprite/SpriteMask.ts @@ -1,12 +1,10 @@ import { BoundingBox } from "@galacean/engine-math"; import { Entity } from "../../Entity"; -import { RenderQueueFlags } from "../../RenderPipeline/BasicRenderPipeline"; -import { BatchUtils } from "../../RenderPipeline/BatchUtils"; +import { VertexMergeBatcher } from "../../RenderPipeline/VertexMergeBatcher"; import { PrimitiveChunkManager } from "../../RenderPipeline/PrimitiveChunkManager"; import { RenderContext } from "../../RenderPipeline/RenderContext"; -import { RenderElement } from "../../RenderPipeline/RenderElement"; import { SubPrimitiveChunk } from "../../RenderPipeline/SubPrimitiveChunk"; -import { SubRenderElement } from "../../RenderPipeline/SubRenderElement"; +import { RenderElement } from "../../RenderPipeline/RenderElement"; import { Renderer, RendererUpdateFlags } from "../../Renderer"; import { assignmentClone, ignoreClone } from "../../clone/CloneManager"; import { SpriteMaskLayer } from "../../enums/SpriteMaskLayer"; @@ -181,16 +179,15 @@ export class SpriteMask extends Renderer implements ISpriteRenderer { this.setMaterial(this._engine._basicResources.spriteMaskDefaultMaterial); this.shaderData.setFloat(SpriteMask._alphaCutoffProperty, this._alphaCutoff); this._renderElement = new RenderElement(); - this._renderElement.addSubRenderElement(new SubRenderElement()); this._onSpriteChange = this._onSpriteChange.bind(this); } /** * @internal */ - override _updateTransformShaderData(context: RenderContext, onlyMVP: boolean, batched: boolean): void { + override _updateTransformShaderData(context: RenderContext, onlyMVP: boolean): void { //@todo: Always update world positions to buffer, should opt - super._updateTransformShaderData(context, onlyMVP, true); + this._updateWorldSpaceTransformShaderData(context, onlyMVP); } /** @@ -204,15 +201,15 @@ export class SpriteMask extends Renderer implements ISpriteRenderer { /** * @internal */ - override _canBatch(elementA: SubRenderElement, elementB: SubRenderElement): boolean { - return BatchUtils.canBatchSpriteMask(elementA, elementB); + override _canBatch(preElement: RenderElement, curElement: RenderElement): boolean { + return VertexMergeBatcher.canBatchSpriteMask(preElement, curElement); } /** * @internal */ - override _batch(elementA: SubRenderElement, elementB?: SubRenderElement): void { - BatchUtils.batchFor2D(elementA, elementB); + override _batch(preElement: RenderElement | null, curElement: RenderElement): void { + VertexMergeBatcher.batch(preElement, curElement); } /** @@ -297,14 +294,11 @@ export class SpriteMask extends Renderer implements ISpriteRenderer { } const renderElement = this._renderElement; - const subRenderElement = renderElement.subRenderElements[0]; - renderElement.set(this.priority, this._distanceForSort); - const subChunk = this._subChunk; - subRenderElement.set(this, material, subChunk.chunk.primitive, subChunk.subMesh, this.sprite.texture, subChunk); - subRenderElement.shaderPasses = material.shader.subShaders[0].passes; - subRenderElement.renderQueueFlags = RenderQueueFlags.All; - renderElement.addSubRenderElement(subRenderElement); + renderElement.set(this, material, subChunk.chunk.primitive, subChunk.subMesh, this.sprite.texture, subChunk); + renderElement.priority = this.priority; + renderElement.distanceForSort = this._distanceForSort; + renderElement.subShader = material.shader.subShaders[0]; } /** diff --git a/packages/core/src/2d/sprite/SpriteRenderer.ts b/packages/core/src/2d/sprite/SpriteRenderer.ts index c1b183ee7a..2a6986af6a 100644 --- a/packages/core/src/2d/sprite/SpriteRenderer.ts +++ b/packages/core/src/2d/sprite/SpriteRenderer.ts @@ -1,10 +1,10 @@ import { BoundingBox, Color, MathUtil } from "@galacean/engine-math"; import { Entity } from "../../Entity"; -import { BatchUtils } from "../../RenderPipeline/BatchUtils"; +import { VertexMergeBatcher } from "../../RenderPipeline/VertexMergeBatcher"; import { PrimitiveChunkManager } from "../../RenderPipeline/PrimitiveChunkManager"; import { RenderContext } from "../../RenderPipeline/RenderContext"; import { SubPrimitiveChunk } from "../../RenderPipeline/SubPrimitiveChunk"; -import { SubRenderElement } from "../../RenderPipeline/SubRenderElement"; +import { RenderElement } from "../../RenderPipeline/RenderElement"; import { Renderer, RendererUpdateFlags } from "../../Renderer"; import { assignmentClone, deepClone, ignoreClone } from "../../clone/CloneManager"; import { ShaderProperty } from "../../shader/ShaderProperty"; @@ -278,9 +278,9 @@ export class SpriteRenderer extends Renderer implements ISpriteRenderer { /** * @internal */ - override _updateTransformShaderData(context: RenderContext, onlyMVP: boolean, batched: boolean): void { + override _updateTransformShaderData(context: RenderContext, onlyMVP: boolean): void { //@todo: Always update world positions to buffer, should opt - super._updateTransformShaderData(context, onlyMVP, true); + this._updateWorldSpaceTransformShaderData(context, onlyMVP); } /** @@ -295,15 +295,15 @@ export class SpriteRenderer extends Renderer implements ISpriteRenderer { /** * @internal */ - override _canBatch(elementA: SubRenderElement, elementB: SubRenderElement): boolean { - return BatchUtils.canBatchSprite(elementA, elementB); + override _canBatch(preElement: RenderElement, curElement: RenderElement): boolean { + return VertexMergeBatcher.canBatchSprite(preElement, curElement); } /** * @internal */ - override _batch(elementA: SubRenderElement, elementB?: SubRenderElement): void { - BatchUtils.batchFor2D(elementA, elementB); + override _batch(preElement: RenderElement | null, curElement: RenderElement): void { + VertexMergeBatcher.batch(preElement, curElement); } /** @@ -377,11 +377,10 @@ export class SpriteRenderer extends Renderer implements ISpriteRenderer { const camera = context.camera; const engine = camera.engine; const renderElement = engine._renderElementPool.get(); - renderElement.set(this.priority, this._distanceForSort); - const subRenderElement = engine._subRenderElementPool.get(); const subChunk = this._subChunk; - subRenderElement.set(this, material, subChunk.chunk.primitive, subChunk.subMesh, this.sprite.texture, subChunk); - renderElement.addSubRenderElement(subRenderElement); + renderElement.set(this, material, subChunk.chunk.primitive, subChunk.subMesh, this.sprite.texture, subChunk); + renderElement.priority = this.priority; + renderElement.distanceForSort = this._distanceForSort; camera._renderPipeline.pushRenderElement(context, renderElement); } diff --git a/packages/core/src/2d/text/TextRenderer.ts b/packages/core/src/2d/text/TextRenderer.ts index 143e46a7da..3649180c79 100644 --- a/packages/core/src/2d/text/TextRenderer.ts +++ b/packages/core/src/2d/text/TextRenderer.ts @@ -1,11 +1,11 @@ import { BoundingBox, Color, Vector3 } from "@galacean/engine-math"; import { Engine } from "../../Engine"; import { Entity } from "../../Entity"; -import { BatchUtils } from "../../RenderPipeline/BatchUtils"; +import { VertexMergeBatcher } from "../../RenderPipeline/VertexMergeBatcher"; import { PrimitiveChunkManager } from "../../RenderPipeline/PrimitiveChunkManager"; import { RenderContext } from "../../RenderPipeline/RenderContext"; import { SubPrimitiveChunk } from "../../RenderPipeline/SubPrimitiveChunk"; -import { SubRenderElement } from "../../RenderPipeline/SubRenderElement"; +import { RenderElement } from "../../RenderPipeline/RenderElement"; import { Renderer } from "../../Renderer"; import { TransformModifyFlags } from "../../Transform"; import { assignmentClone, deepClone, ignoreClone } from "../../clone/CloneManager"; @@ -373,23 +373,23 @@ export class TextRenderer extends Renderer implements ITextRenderer { /** * @internal */ - override _updateTransformShaderData(context: RenderContext, onlyMVP: boolean, batched: boolean): void { + override _updateTransformShaderData(context: RenderContext, onlyMVP: boolean): void { //@todo: Always update world positions to buffer, should opt - super._updateTransformShaderData(context, onlyMVP, true); + this._updateWorldSpaceTransformShaderData(context, onlyMVP); } /** * @internal */ - override _canBatch(elementA: SubRenderElement, elementB: SubRenderElement): boolean { - return BatchUtils.canBatchSprite(elementA, elementB); + override _canBatch(preElement: RenderElement, curElement: RenderElement): boolean { + return VertexMergeBatcher.canBatchSprite(preElement, curElement); } /** * @internal */ - override _batch(elementA: SubRenderElement, elementB?: SubRenderElement): void { - BatchUtils.batchFor2D(elementA, elementB); + override _batch(preElement: RenderElement | null, curElement: RenderElement): void { + VertexMergeBatcher.batch(preElement, curElement); } /** @@ -430,20 +430,22 @@ export class TextRenderer extends Renderer implements ITextRenderer { const camera = context.camera; const engine = camera.engine; - const textSubRenderElementPool = engine._textSubRenderElementPool; + const textRenderElementPool = engine._textRenderElementPool; const material = this.getMaterial(); - const renderElement = engine._renderElementPool.get(); - renderElement.set(this.priority, this._distanceForSort); + const priority = this.priority; + const distanceForSort = this._distanceForSort; + const renderPipeline = camera._renderPipeline; const textChunks = this._textChunks; for (let i = 0, n = textChunks.length; i < n; ++i) { const { subChunk, texture } = textChunks[i]; - const subRenderElement = textSubRenderElementPool.get(); - subRenderElement.set(this, material, subChunk.chunk.primitive, subChunk.subMesh, texture, subChunk); - subRenderElement.shaderData ||= new ShaderData(ShaderDataGroup.RenderElement); - subRenderElement.shaderData.setTexture(TextRenderer._textureProperty, texture); - renderElement.addSubRenderElement(subRenderElement); + const renderElement = textRenderElementPool.get(); + renderElement.set(this, material, subChunk.chunk.primitive, subChunk.subMesh, texture, subChunk); + renderElement.shaderData ||= new ShaderData(ShaderDataGroup.RenderElement); + renderElement.shaderData.setTexture(TextRenderer._textureProperty, texture); + renderElement.priority = priority; + renderElement.distanceForSort = distanceForSort; + renderPipeline.pushRenderElement(context, renderElement); } - camera._renderPipeline.pushRenderElement(context, renderElement); } private _resetSubFont(): void { diff --git a/packages/core/src/Engine.ts b/packages/core/src/Engine.ts index c909e49093..d55a7798ee 100644 --- a/packages/core/src/Engine.ts +++ b/packages/core/src/Engine.ts @@ -15,9 +15,8 @@ import { EngineSettings } from "./EngineSettings"; import { Entity } from "./Entity"; import { BatcherManager } from "./RenderPipeline/BatcherManager"; import { RenderContext } from "./RenderPipeline/RenderContext"; -import { RenderElement } from "./RenderPipeline/RenderElement"; import { RenderTargetPool } from "./RenderPipeline/RenderTargetPool"; -import { SubRenderElement } from "./RenderPipeline/SubRenderElement"; +import { RenderElement } from "./RenderPipeline/RenderElement"; import { Scene } from "./Scene"; import { SceneManager } from "./SceneManager"; import { RenderingStatistics } from "./asset/RenderingStatistics"; @@ -32,7 +31,8 @@ import { PostProcessUberPass } from "./postProcess/PostProcessUberPass"; import { Shader } from "./shader/Shader"; import { ShaderMacro } from "./shader/ShaderMacro"; import { ShaderMacroCollection } from "./shader/ShaderMacroCollection"; -import { ShaderProgramPool } from "./shader/ShaderProgramPool"; +import { ShaderProgramMap } from "./shader/ShaderProgramMap"; +import { ShaderProgram } from "./shader/ShaderProgram"; import { ShaderFactory } from "./shader/ShaderFactory"; import { RenderState } from "./shader/state/RenderState"; import { Texture2D, TextureFormat } from "./texture"; @@ -91,9 +91,7 @@ export class Engine extends EventDispatcher { /* @internal */ _renderElementPool = new ClearableObjectPool(RenderElement); /* @internal */ - _subRenderElementPool = new ClearableObjectPool(SubRenderElement); - /* @internal */ - _textSubRenderElementPool = new ClearableObjectPool(SubRenderElement); + _textRenderElementPool = new ClearableObjectPool(RenderElement); /* @internal */ _charRenderInfoPool = new ReturnableObjectPool(CharRenderInfo, 50); @@ -110,7 +108,7 @@ export class Engine extends EventDispatcher { /* @internal */ _renderCount: number = 0; /* @internal */ - _shaderProgramPools: ShaderProgramPool[] = []; + _shaderProgramMaps: ShaderProgramMap[] = []; /** @internal */ _fontMap: Record = {}; /** @internal */ @@ -327,9 +325,8 @@ export class Engine extends EventDispatcher { const deltaTime = time.deltaTime; this._frameInProcess = true; - this._subRenderElementPool.clear(); - this._textSubRenderElementPool.clear(); this._renderElementPool.clear(); + this._textRenderElementPool.clear(); this.xrManager?._update(); const { inputManager, _physicsInitialized: physicsInitialized } = this; @@ -539,18 +536,18 @@ export class Engine extends EventDispatcher { /** * @internal */ - _getShaderProgramPool(index: number, trackPools?: ShaderProgramPool[]): ShaderProgramPool { - const shaderProgramPools = this._shaderProgramPools; - let pool = shaderProgramPools[index]; - if (!pool) { + _getShaderProgramMap(index: number, trackMaps?: ShaderProgramMap[]): ShaderProgramMap { + const shaderProgramMaps = this._shaderProgramMaps; + let map = shaderProgramMaps[index]; + if (!map) { const length = index + 1; - if (length > shaderProgramPools.length) { - shaderProgramPools.length = length; + if (length > shaderProgramMaps.length) { + shaderProgramMaps.length = length; } - shaderProgramPools[index] = pool = new ShaderProgramPool(this); - trackPools?.push(pool); + shaderProgramMaps[index] = map = new ShaderProgramMap(this); + trackMaps?.push(map); } - return pool; + return map; } /** @@ -680,9 +677,9 @@ export class Engine extends EventDispatcher { private _onDeviceRestored(): void { this._hardwareRenderer.resetState(); this._lastRenderState = new RenderState(); - // Clear shader pools + // Clear shader program maps Shader._clear(this); - this._shaderProgramPools.length = 0; + this._shaderProgramMaps.length = 0; const { resourceManager } = this; // Restore graphic resources @@ -703,9 +700,8 @@ export class Engine extends EventDispatcher { } private _gc(): void { - this._subRenderElementPool.garbageCollection(); - this._textSubRenderElementPool.garbageCollection(); this._renderElementPool.garbageCollection(); + this._textRenderElementPool.garbageCollection(); this._renderContext.garbageCollection(); const scenes = this._sceneManager._scenes.getLoopArray(); for (let i = 0, n = scenes.length; i < n; i++) { diff --git a/packages/core/src/RenderPipeline/BasicRenderPipeline.ts b/packages/core/src/RenderPipeline/BasicRenderPipeline.ts index 5fc651c131..6baf9069d8 100644 --- a/packages/core/src/RenderPipeline/BasicRenderPipeline.ts +++ b/packages/core/src/RenderPipeline/BasicRenderPipeline.ts @@ -10,9 +10,8 @@ import { ScalableAmbientObscurancePass } from "../lighting/ambientOcclusion/Scal import { FinalPass } from "../postProcess"; import { Shader } from "../shader/Shader"; import { ShaderMacroCollection } from "../shader/ShaderMacroCollection"; -import { ShaderPass } from "../shader/ShaderPass"; +import { SubShader } from "../shader/SubShader"; import { RenderQueueType } from "../shader/enums/RenderQueueType"; -import { RenderState } from "../shader/state/RenderState"; import { CascadedShadowCasterPass } from "../shadow/CascadedShadowCasterPass"; import { ShadowType } from "../shadow/enum/ShadowType"; import { @@ -30,7 +29,6 @@ import { OpaqueTexturePass } from "./OpaqueTexturePass"; import { PipelineUtils } from "./PipelineUtils"; import { ContextRendererUpdateFlag, RenderContext } from "./RenderContext"; import { RenderElement } from "./RenderElement"; -import { SubRenderElement } from "./SubRenderElement"; import { PipelineStage } from "./enums/PipelineStage"; /** * Basic render pipeline. @@ -132,7 +130,6 @@ export class BasicRenderPipeline { this._cascadedShadowCasterPass.onRender(context); } - const batcherManager = engine._batcherManager; cullingResults.reset(); // Depth use camera's view and projection matrix @@ -140,6 +137,7 @@ export class BasicRenderPipeline { context.applyVirtualCamera(camera._virtualCamera, depthPassEnabled); this._prepareRender(context); + const batcherManager = engine._batcherManager; cullingResults.sortBatch(batcherManager); batcherManager.uploadBuffer(); @@ -369,62 +367,53 @@ export class BasicRenderPipeline { * @param renderElement - Render element */ pushRenderElement(context: RenderContext, renderElement: RenderElement): void { - renderElement.renderQueueFlags = RenderQueueFlags.None; - const subRenderElements = renderElement.subRenderElements; - for (let i = 0, n = subRenderElements.length; i < n; ++i) { - const subRenderElement = subRenderElements[i]; - const { material } = subRenderElement; - const materialSubShader = material.shader.subShaders[0]; - const replacementShader = context.replacementShader; - if (replacementShader) { - const replacementSubShaders = replacementShader.subShaders; - const { replacementTag } = context; - if (replacementTag) { - let replacementSuccess = false; - for (let j = 0, m = replacementSubShaders.length; j < m; j++) { - const subShader = replacementSubShaders[j]; - if (subShader.getTagValue(replacementTag) === materialSubShader.getTagValue(replacementTag)) { - this.pushRenderElementByType(renderElement, subRenderElement, subShader.passes); - replacementSuccess = true; - } + const { material } = renderElement; + const materialSubShader = material.shader.subShaders[0]; + const replacementShader = context.replacementShader; + if (replacementShader) { + const replacementSubShaders = replacementShader.subShaders; + const { replacementTag } = context; + if (replacementTag) { + let replacementSuccess = false; + for (let j = 0, m = replacementSubShaders.length; j < m; j++) { + const subShader = replacementSubShaders[j]; + if (subShader.getTagValue(replacementTag) === materialSubShader.getTagValue(replacementTag)) { + this._pushRenderElementByType(renderElement, subShader); + replacementSuccess = true; } + } - if ( - !replacementSuccess && - context.replacementFailureStrategy === ReplacementFailureStrategy.KeepOriginalShader - ) { - this.pushRenderElementByType(renderElement, subRenderElement, materialSubShader.passes); - } - } else { - this.pushRenderElementByType(renderElement, subRenderElement, replacementSubShaders[0].passes); + if ( + !replacementSuccess && + context.replacementFailureStrategy === ReplacementFailureStrategy.KeepOriginalShader + ) { + this._pushRenderElementByType(renderElement, materialSubShader); } } else { - this.pushRenderElementByType(renderElement, subRenderElement, materialSubShader.passes); + this._pushRenderElementByType(renderElement, replacementSubShaders[0]); } + } else { + this._pushRenderElementByType(renderElement, materialSubShader); } } - private pushRenderElementByType( - renderElement: RenderElement, - subRenderElement: SubRenderElement, - shaderPasses: ReadonlyArray - ): void { + private _pushRenderElementByType(renderElement: RenderElement, subShader: SubShader): void { + const shaderPasses = subShader.passes; const cullingResults = this._cullingResults; + let pushedQueueFlags = RenderQueueFlags.None; for (let i = 0, n = shaderPasses.length; i < n; i++) { - // Get render queue type const shaderPass = shaderPasses[i]; const renderState = shaderPass._renderState; const renderQueueType = renderState._getRenderQueueByShaderData( shaderPass._renderStateDataMap, - subRenderElement.material.shaderData + renderElement.material.shaderData ); const flag = 1 << renderQueueType; - subRenderElement.shaderPasses = shaderPasses; - subRenderElement.renderQueueFlags |= flag; + renderElement.subShader = subShader; - if (renderElement.renderQueueFlags & flag) { + if (pushedQueueFlags & flag) { continue; } @@ -439,7 +428,7 @@ export class BasicRenderPipeline { cullingResults.transparentQueue.pushRenderElement(renderElement); break; } - renderElement.renderQueueFlags |= flag; + pushedQueueFlags |= flag; } } @@ -505,7 +494,10 @@ export class BasicRenderPipeline { continue; } canvas._prepareRender(context); - this.pushRenderElement(context, canvas._renderElement); + const canvasElements = canvas._batchedRenderElements; + for (let j = 0, m = canvasElements.length; j < m; j++) { + this.pushRenderElement(context, canvasElements[j]); + } } } } diff --git a/packages/core/src/RenderPipeline/BatchUtils.ts b/packages/core/src/RenderPipeline/BatchUtils.ts deleted file mode 100644 index 387c951f93..0000000000 --- a/packages/core/src/RenderPipeline/BatchUtils.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { SpriteMask, SpriteMaskInteraction, SpriteRenderer } from "../2d"; -import { ShaderTagKey } from "../shader"; -import { SubRenderElement } from "./SubRenderElement"; - -/** - * @internal - */ -export class BatchUtils { - protected static _disableBatchTag: ShaderTagKey = ShaderTagKey.getByName("spriteDisableBatching"); - - static canBatchSprite(elementA: SubRenderElement, elementB: SubRenderElement): boolean { - if (elementB.shaderPasses[0].getTagValue(BatchUtils._disableBatchTag) === true) { - return false; - } - if (elementA.subChunk.chunk !== elementB.subChunk.chunk) { - return false; - } - - const rendererA = elementA.component; - const rendererB = elementB.component; - const maskInteractionA = rendererA.maskInteraction; - - // Compare mask, texture and material - return ( - maskInteractionA === rendererB.maskInteraction && - (maskInteractionA === SpriteMaskInteraction.None || rendererA.maskLayer === rendererB.maskLayer) && - elementA.texture === elementB.texture && - elementA.material === elementB.material - ); - } - - static canBatchSpriteMask(elementA: SubRenderElement, elementB: SubRenderElement): boolean { - if (elementA.subChunk.chunk !== elementB.subChunk.chunk) { - return false; - } - - const alphaCutoffProperty = SpriteMask._alphaCutoffProperty; - - // Compare renderer property - return ( - elementA.texture === elementB.texture && - (elementA.component).shaderData.getFloat(alphaCutoffProperty) === - (elementB.component).shaderData.getFloat(alphaCutoffProperty) - ); - } - - static batchFor2D(elementA: SubRenderElement, elementB?: SubRenderElement): void { - const subChunk = elementB ? elementB.subChunk : elementA.subChunk; - const { chunk, indices: subChunkIndices } = subChunk; - - const length = subChunkIndices.length; - let startIndex = chunk.updateIndexLength; - if (elementB) { - elementA.subChunk.subMesh.count += length; - } else { - // Reset subMesh - const subMesh = subChunk.subMesh; - subMesh.start = startIndex; - subMesh.count = length; - } - - const { start, size } = subChunk.vertexArea; - const vertexOffset = start / 9; - const indices = chunk.indices; - for (let i = 0; i < length; ++i) { - indices[startIndex++] = vertexOffset + subChunkIndices[i]; - } - chunk.updateIndexLength += length; - chunk.updateVertexStart = Math.min(chunk.updateVertexStart, start); - chunk.updateVertexEnd = Math.max(chunk.updateVertexEnd, start + size); - } -} diff --git a/packages/core/src/RenderPipeline/BatcherManager.ts b/packages/core/src/RenderPipeline/BatcherManager.ts index 702a4a01e8..923c258071 100644 --- a/packages/core/src/RenderPipeline/BatcherManager.ts +++ b/packages/core/src/RenderPipeline/BatcherManager.ts @@ -1,8 +1,8 @@ import { Engine } from "../Engine"; import { Renderer } from "../Renderer"; +import { InstanceBuffer } from "./InstanceBuffer"; import { PrimitiveChunkManager } from "./PrimitiveChunkManager"; -import { RenderQueue } from "./RenderQueue"; -import { SubRenderElement } from "./SubRenderElement"; +import { RenderElement } from "./RenderElement"; /** * @internal @@ -11,9 +11,14 @@ export class BatcherManager { private _primitiveChunkManager2D: PrimitiveChunkManager; private _primitiveChunkManagerMask: PrimitiveChunkManager; private _primitiveChunkManagerUI: PrimitiveChunkManager; + private _instanceBuffer: InstanceBuffer; constructor(public engine: Engine) {} + get instanceBuffer(): InstanceBuffer { + return (this._instanceBuffer ||= new InstanceBuffer(this.engine)); + } + get primitiveChunkManager2D(): PrimitiveChunkManager { return (this._primitiveChunkManager2D ||= new PrimitiveChunkManager(this.engine)); } @@ -39,47 +44,46 @@ export class BatcherManager { this._primitiveChunkManagerUI.destroy(); this._primitiveChunkManagerUI = null; } + if (this._instanceBuffer) { + this._instanceBuffer.destroy(); + this._instanceBuffer = null; + } } - batch(renderQueue: RenderQueue): void { - const { elements, batchedSubElements, renderQueueType } = renderQueue; - let preSubElement: SubRenderElement; + batch(input: RenderElement[], output: RenderElement[]): void { + let preElement: RenderElement; let preRenderer: Renderer; let preConstructor: Function; - for (let i = 0, n = elements.length; i < n; ++i) { - const subElements = elements[i].subRenderElements; - for (let j = 0, m = subElements.length; j < m; ++j) { - const subElement = subElements[j]; + for (let i = 0, n = input.length; i < n; ++i) { + const curElement = input[i]; - // Some sub render elements may not belong to the current render queue - if (!(subElement.renderQueueFlags & (1 << renderQueueType))) { - continue; - } + // Already-batched leaders (e.g. produced by UICanvas pre-batching) are terminal — + // each carries an opaque, self-contained draw range that must not be merged again. + // Flush any pending pre and pass the leader straight through + if (curElement._isBatched) { + preElement && (BatcherManager._flush(output, preElement), (preElement = null)); + output.push(curElement); + continue; + } - const renderer = subElement.component; - const constructor = renderer.constructor; - if (preSubElement) { - if (preConstructor === constructor && preRenderer._canBatch(preSubElement, subElement)) { - preRenderer._batch(preSubElement, subElement); - preSubElement.batched = true; - } else { - batchedSubElements.push(preSubElement); - preSubElement = subElement; - preRenderer = renderer; - preConstructor = constructor; - renderer._batch(subElement); - subElement.batched = false; - } - } else { - preSubElement = subElement; - preRenderer = renderer; - preConstructor = constructor; - renderer._batch(subElement); - subElement.batched = false; - } + const renderer = curElement.component; + const constructor = renderer.constructor; + if (preElement && preConstructor === constructor && preRenderer._canBatch(preElement, curElement)) { + preRenderer._batch(preElement, curElement); + } else { + preElement && BatcherManager._flush(output, preElement); + preElement = curElement; + preRenderer = renderer; + preConstructor = constructor; + renderer._batch(null, curElement); } } - preSubElement && batchedSubElements.push(preSubElement); + preElement && BatcherManager._flush(output, preElement); + } + + private static _flush(output: RenderElement[], element: RenderElement): void { + element._isBatched = true; + output.push(element); } uploadBuffer() { diff --git a/packages/core/src/RenderPipeline/InstanceBuffer.ts b/packages/core/src/RenderPipeline/InstanceBuffer.ts new file mode 100644 index 0000000000..5d0d4368c2 --- /dev/null +++ b/packages/core/src/RenderPipeline/InstanceBuffer.ts @@ -0,0 +1,86 @@ +import { Engine } from "../Engine"; +import { Buffer } from "../graphic/Buffer"; +import { BufferBindFlag } from "../graphic/enums/BufferBindFlag"; +import { BufferUsage } from "../graphic/enums/BufferUsage"; +import { SetDataOptions } from "../graphic/enums/SetDataOptions"; +import { Renderer } from "../Renderer"; +import { ShaderMacro } from "../shader/ShaderMacro"; +import { InstanceBufferLayout } from "../shader/ShaderFactory"; + +/** + * @internal + * Manages a UBO for GPU instancing, packing per-instance renderer data (ModelMat, Layer, etc.). + */ +export class InstanceBuffer { + static gpuInstanceMacro = ShaderMacro.getByName("RENDERER_GPU_INSTANCE"); + + buffer: Buffer; + + private _engine: Engine; + private _layout: InstanceBufferLayout; + private _data: ArrayBuffer; + private _floatView: Float32Array; + private _intView: Int32Array; + + constructor(engine: Engine) { + this._engine = engine; + } + + /** + * Set UBO layout and allocate buffer if needed. + */ + setLayout(layout: InstanceBufferLayout): void { + this._layout = layout; + const totalBytes = layout.instanceMaxCount * layout.structSize; + // Only reallocate when buffer is too small + if (!this.buffer || totalBytes > this.buffer.byteLength) { + this._data = new ArrayBuffer(totalBytes); + this._floatView = new Float32Array(this._data); + this._intView = new Int32Array(this._data); + this.buffer?.destroy(); + this.buffer = new Buffer(this._engine, BufferBindFlag.ConstantBuffer, totalBytes, BufferUsage.Dynamic); + } + } + + /** + * Pack renderer data into UBO and upload to GPU. + */ + upload(renderers: Renderer[], start: number, count: number): void { + const { instanceFields, structSize } = this._layout; + const elementsPerInstance = structSize / 4; + const { _floatView: floatView, _intView: intView } = this; + const modelMatId = Renderer._worldMatrixProperty._uniqueId; + + for (let i = 0; i < count; i++) { + const renderer = renderers[start + i]; + const propertyValueMap = renderer.shaderData._propertyValueMap; + const baseOffset = i * elementsPerInstance; + + for (let j = 0, n = instanceFields.length; j < n; j++) { + const field = instanceFields[j]; + const fieldOffset = baseOffset + field.offsetInElements; + const propertyId = field.property._uniqueId; + + if (propertyId === modelMatId) { + // Instancing skips _updateTransformShaderData; mirror its transform source + // @ts-ignore — _transformEntity is protected + field.pack(floatView, fieldOffset, renderer._transformEntity.transform.worldMatrix); + } else { + const value = propertyValueMap[propertyId]; + if (value != null) { + field.pack(field.useIntView ? intView : floatView, fieldOffset, value); + } + } + } + } + + this.buffer.setData(floatView, 0, 0, count * elementsPerInstance, SetDataOptions.Discard); + } + + destroy(): void { + this.buffer?.destroy(); + this._data = null; + this._floatView = null; + this._intView = null; + } +} diff --git a/packages/core/src/RenderPipeline/RenderElement.ts b/packages/core/src/RenderPipeline/RenderElement.ts index 582e72f47d..fe2f86936c 100644 --- a/packages/core/src/RenderPipeline/RenderElement.ts +++ b/packages/core/src/RenderPipeline/RenderElement.ts @@ -1,24 +1,58 @@ +import { Renderer } from "../Renderer"; +import { Primitive, SubMesh } from "../graphic"; +import { Material } from "../material"; +import { ShaderData, SubShader } from "../shader"; +import { Texture2D } from "../texture"; import { IPoolElement } from "../utils/ObjectPool"; -import { RenderQueueFlags } from "./BasicRenderPipeline"; -import { SubRenderElement } from "./SubRenderElement"; +import { SubPrimitiveChunk } from "./SubPrimitiveChunk"; export class RenderElement implements IPoolElement { priority: number; distanceForSort: number; - subRenderElements = Array(); - renderQueueFlags: RenderQueueFlags; + component: Renderer; + primitive: Primitive; + material: Material; + subPrimitive: SubMesh; + subShader: SubShader; + shaderData?: ShaderData; + instancedRenderers: Renderer[] = []; + subDistancePriority: number = 0; + /** @internal Marks a batch leader — a self-contained draw range that must not be merged again downstream */ + _isBatched: boolean = false; - set(priority: number, distanceForSort: number): void { - this.priority = priority; - this.distanceForSort = distanceForSort; - this.subRenderElements.length = 0; - } + // @todo: maybe should remove later + texture?: Texture2D; + subChunk?: SubPrimitiveChunk; - addSubRenderElement(element: SubRenderElement): void { - this.subRenderElements.push(element); + set( + component: Renderer, + material: Material, + primitive: Primitive, + subPrimitive: SubMesh, + texture?: Texture2D, + subChunk?: SubPrimitiveChunk + ): void { + this.component = component; + this.material = material; + this.primitive = primitive; + this.subPrimitive = subPrimitive; + this.texture = texture; + this.subChunk = subChunk; + this.instancedRenderers.length = 0; + this.subDistancePriority = 0; + this._isBatched = false; } dispose(): void { - this.subRenderElements.length = 0; + this.component = null; + this.material = null; + this.primitive = null; + this.subPrimitive = null; + this.subShader = null; + this.shaderData && (this.shaderData = null); + this.instancedRenderers = null; + + this.texture && (this.texture = null); + this.subChunk && (this.subChunk = null); } } diff --git a/packages/core/src/RenderPipeline/RenderQueue.ts b/packages/core/src/RenderPipeline/RenderQueue.ts index b2993ebecc..40801c3d6a 100644 --- a/packages/core/src/RenderPipeline/RenderQueue.ts +++ b/packages/core/src/RenderPipeline/RenderQueue.ts @@ -2,11 +2,12 @@ import { SpriteMaskInteraction } from "../2d/enums/SpriteMaskInteraction"; import { BasicResources, RenderStateElementMap } from "../BasicResources"; import { Utils } from "../Utils"; import { RenderQueueType, Shader } from "../shader"; +import { ConstantBufferBindingPoint } from "../shader/enums/ConstantBufferBindingPoint"; import { ShaderMacroCollection } from "../shader/ShaderMacroCollection"; import { BatcherManager } from "./BatcherManager"; +import { InstanceBuffer } from "./InstanceBuffer"; import { ContextRendererUpdateFlag, RenderContext } from "./RenderContext"; import { RenderElement } from "./RenderElement"; -import { SubRenderElement } from "./SubRenderElement"; import { RenderQueueMaskType } from "./enums/RenderQueueMaskType"; /** @@ -14,15 +15,21 @@ import { RenderQueueMaskType } from "./enums/RenderQueueMaskType"; */ export class RenderQueue { static compareForOpaque(a: RenderElement, b: RenderElement): number { - return a.priority - b.priority || a.distanceForSort - b.distanceForSort; + return ( + a.priority - b.priority || + a.material.instanceId - b.material.instanceId || + a.primitive.instanceId - b.primitive.instanceId + ); } static compareForTransparent(a: RenderElement, b: RenderElement): number { - return a.priority - b.priority || b.distanceForSort - a.distanceForSort; + return ( + a.priority - b.priority || b.distanceForSort - a.distanceForSort || a.subDistancePriority - b.subDistancePriority + ); } readonly elements = new Array(); - readonly batchedSubElements = new Array(); + readonly batchedElements = new Array(); rendererUpdateFlag = ContextRendererUpdateFlag.None; constructor(public renderQueueType: RenderQueueType) {} @@ -37,7 +44,7 @@ export class RenderQueue { } batch(batcherManager: BatcherManager): void { - batcherManager.batch(this); + batcherManager.batch(this.elements, this.batchedElements); } render( @@ -45,8 +52,8 @@ export class RenderQueue { pipelineStageTagValue: string, maskType: RenderQueueMaskType = RenderQueueMaskType.No ): void { - const batchedSubElements = this.batchedSubElements; - const length = batchedSubElements.length; + const batchedElements = this.batchedElements; + const length = batchedElements.length; if (length === 0) { return; } @@ -57,34 +64,33 @@ export class RenderQueue { const rhi = engine._hardwareRenderer; const pipelineStageKey = RenderContext.pipelineStageKey; const renderQueueType = this.renderQueueType; + const needMaskType = maskType !== RenderQueueMaskType.No; for (let i = 0; i < length; i++) { - const subElement = batchedSubElements[i]; - const { component: renderer, batched, material } = subElement; - - // @todo: Can optimize update view projection matrix updated - if ( - this.rendererUpdateFlag & ContextRendererUpdateFlag.WorldViewMatrix || - renderer._batchedTransformShaderData != batched - ) { - // Update world matrix and view matrix and model matrix - renderer._updateTransformShaderData(context, false, batched); - renderer._batchedTransformShaderData = batched; - } else if (this.rendererUpdateFlag & ContextRendererUpdateFlag.ProjectionMatrix) { - // Only projection matrix need updated - renderer._updateTransformShaderData(context, true, batched); + const curElement = batchedElements[i]; + const { component, material } = curElement; + const isInstanced = curElement.instancedRenderers.length > 0; + + // Update transform shader data + // Instancing packs per-renderer transforms into the instance UBO at draw time, so skip here + if (!isInstanced) { + if (this.rendererUpdateFlag & ContextRendererUpdateFlag.WorldViewMatrix) { + component._updateTransformShaderData(context, false); + } else if (this.rendererUpdateFlag & ContextRendererUpdateFlag.ProjectionMatrix) { + component._updateTransformShaderData(context, true); + } } - const maskInteraction = renderer._maskInteraction; + // Resolve mask render states + const maskInteraction = component._maskInteraction; const needMaskInteraction = maskInteraction !== SpriteMaskInteraction.None; - const needMaskType = maskType !== RenderQueueMaskType.No; let customStates: RenderStateElementMap = null; if (needMaskType) { customStates = BasicResources.getMaskTypeRenderStates(maskType); } else { if (needMaskInteraction) { - maskManager.drawMask(context, pipelineStageTagValue, subElement.component._maskLayer); + maskManager.drawMask(context, pipelineStageTagValue, component._maskLayer); customStates = BasicResources.getMaskInteractionRenderStates(maskInteraction); } else { maskManager.isReadStencil(material) && maskManager.clearMask(context, pipelineStageTagValue); @@ -92,15 +98,20 @@ export class RenderQueue { maskManager.isStencilWritten(material) && (maskManager.hasStencilWritten = true); } - const compileMacros = Shader._compileMacros; - const { primitive, shaderPasses, shaderData: renderElementShaderData } = subElement; - const { shaderData: rendererData, instanceId: rendererId } = renderer; + const { shaderData: renderElementShaderData } = curElement; + const shaderPasses = curElement.subShader.passes; + const { shaderData: rendererData, instanceId: rendererId } = component; const { shaderData: materialData, instanceId: materialId } = material; - // Union render global macro and material self macro - ShaderMacroCollection.unionCollection(renderer._globalShaderMacro, materialData._macroCollection, compileMacros); + // Build compile macros + const compileMacros = Shader._compileMacros; + ShaderMacroCollection.unionCollection(component._globalShaderMacro, materialData._macroCollection, compileMacros); ShaderMacroCollection.unionCollection(compileMacros, engine._macroCollection, compileMacros); + if (isInstanced) { + compileMacros.enable(InstanceBuffer.gpuInstanceMacro); + } + for (let j = 0, m = shaderPasses.length; j < m; j++) { const shaderPass = shaderPasses[j]; if (shaderPass.getTagValue(pipelineStageKey) !== pipelineStageTagValue) { @@ -123,18 +134,23 @@ export class RenderQueue { const switchProgram = program.bind(); const switchRenderCount = renderCount !== program._uploadRenderCount; + // Upload uniforms (cache-aware per block) if (switchRenderCount) { program.groupingOtherUniformBlock(); program.uploadAll(program.sceneUniformBlock, sceneData); program.uploadAll(program.cameraUniformBlock, cameraData); - program.uploadAll(program.rendererUniformBlock, rendererData); + if (isInstanced) { + program._uploadRendererId = -1; + } else { + program.uploadAll(program.rendererUniformBlock, rendererData); + program._uploadRendererId = rendererId; + } program.uploadAll(program.materialUniformBlock, materialData); renderElementShaderData && program.uploadAll(program.renderElementUniformBlock, renderElementShaderData); - // UnGroup textures should upload default value, texture uint maybe change by logic of texture bind. + // UnGroup textures should upload default value, texture uint maybe change by logic of texture bind program.uploadUnGroupTextures(); program._uploadSceneId = sceneId; program._uploadCameraId = cameraId; - program._uploadRendererId = rendererId; program._uploadMaterialId = materialId; program._uploadRenderCount = renderCount; } else { @@ -152,11 +168,13 @@ export class RenderQueue { program.uploadTextures(program.cameraUniformBlock, cameraData); } - if (program._uploadRendererId !== rendererId) { - program.uploadAll(program.rendererUniformBlock, rendererData); - program._uploadRendererId = rendererId; - } else if (switchProgram) { - program.uploadTextures(program.rendererUniformBlock, rendererData); + if (!isInstanced) { + if (program._uploadRendererId !== rendererId) { + program.uploadAll(program.rendererUniformBlock, rendererData); + program._uploadRendererId = rendererId; + } else if (switchProgram) { + program.uploadTextures(program.rendererUniformBlock, rendererData); + } } if (program._uploadMaterialId !== materialId) { @@ -168,20 +186,41 @@ export class RenderQueue { renderElementShaderData && program.uploadAll(program.renderElementUniformBlock, renderElementShaderData); - // We only consider switchProgram case, because UnGroup texture's value is always default. + // We only consider switchProgram case, because UnGroup texture's value is always default if (switchProgram) { program.uploadUnGroupTextures(); } } + // Apply render state renderState._applyStates( engine, - renderer._isFrontFaceInvert(), + component._isFrontFaceInvert(), shaderPass._renderStateDataMap, material.shaderData, customStates ); - rhi.drawPrimitive(primitive, subElement.subPrimitive, program); + + // Draw + const layout = program._instanceLayout; + if (isInstanced && layout) { + const { primitive, subPrimitive, instancedRenderers } = curElement; + const totalCount = instancedRenderers.length; + const maxCount = layout.instanceMaxCount; + const instanceBuffer = engine._batcherManager.instanceBuffer; + + instanceBuffer.setLayout(layout); + rhi.bindUniformBufferBase(ConstantBufferBindingPoint.RendererInstance, instanceBuffer.buffer._platformBuffer); + for (let start = 0; start < totalCount; start += maxCount) { + const count = Math.min(maxCount, totalCount - start); + instanceBuffer.upload(instancedRenderers, start, count); + primitive.instanceCount = count; + rhi.drawPrimitive(primitive, subPrimitive, program); + } + primitive.instanceCount = 0; + } else { + rhi.drawPrimitive(curElement.primitive, curElement.subPrimitive, program); + } } } @@ -190,7 +229,7 @@ export class RenderQueue { clear(): void { this.elements.length = 0; - this.batchedSubElements.length = 0; + this.batchedElements.length = 0; } destroy(): void {} diff --git a/packages/core/src/RenderPipeline/SubRenderElement.ts b/packages/core/src/RenderPipeline/SubRenderElement.ts deleted file mode 100644 index f8c86c114d..0000000000 --- a/packages/core/src/RenderPipeline/SubRenderElement.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { Renderer } from "../Renderer"; -import { Primitive, SubMesh } from "../graphic"; -import { Material } from "../material"; -import { ShaderData, ShaderPass } from "../shader"; -import { Texture2D } from "../texture"; -import { IPoolElement } from "../utils/ObjectPool"; -import { RenderQueueFlags } from "./BasicRenderPipeline"; -import { SubPrimitiveChunk } from "./SubPrimitiveChunk"; - -export class SubRenderElement implements IPoolElement { - component: Renderer; - primitive: Primitive; - material: Material; - subPrimitive: SubMesh; - shaderPasses: ReadonlyArray; - shaderData?: ShaderData; - batched: boolean; - renderQueueFlags: RenderQueueFlags; - - // @todo: maybe should remove later - texture?: Texture2D; - subChunk?: SubPrimitiveChunk; - - set( - component: Renderer, - material: Material, - primitive: Primitive, - subPrimitive: SubMesh, - texture?: Texture2D, - subChunk?: SubPrimitiveChunk - ): void { - this.component = component; - this.material = material; - this.primitive = primitive; - this.subPrimitive = subPrimitive; - this.texture = texture; - this.subChunk = subChunk; - } - - dispose(): void { - this.component = null; - this.material = null; - this.primitive = null; - this.subPrimitive = null; - this.shaderPasses = null; - this.shaderData && (this.shaderData = null); - - this.texture && (this.texture = null); - this.subChunk && (this.subChunk = null); - } -} diff --git a/packages/core/src/RenderPipeline/VertexMergeBatcher.ts b/packages/core/src/RenderPipeline/VertexMergeBatcher.ts new file mode 100644 index 0000000000..9bf7777b62 --- /dev/null +++ b/packages/core/src/RenderPipeline/VertexMergeBatcher.ts @@ -0,0 +1,67 @@ +import { SpriteMask, SpriteMaskInteraction, SpriteRenderer } from "../2d"; +import { ShaderTagKey } from "../shader"; +import { RenderElement } from "./RenderElement"; + +/** + * @internal + */ +export class VertexMergeBatcher { + protected static _disableBatchTag: ShaderTagKey = ShaderTagKey.getByName("spriteDisableBatching"); + + static canBatchSprite(preElement: RenderElement, curElement: RenderElement): boolean { + const preRenderer = preElement.component; + const renderer = curElement.component; + const maskInteraction = preRenderer.maskInteraction; + + // Order: cheap reference checks → mask state → tag lookup (rare opt-out) + return ( + preElement.subChunk.chunk === curElement.subChunk.chunk && + preElement.texture === curElement.texture && + preElement.material === curElement.material && + maskInteraction === renderer.maskInteraction && + (maskInteraction === SpriteMaskInteraction.None || preRenderer.maskLayer === renderer.maskLayer) && + curElement.subShader.passes[0].getTagValue(VertexMergeBatcher._disableBatchTag) !== true + ); + } + + static canBatchSpriteMask(preElement: RenderElement, curElement: RenderElement): boolean { + if (preElement.subChunk.chunk !== curElement.subChunk.chunk) { + return false; + } + + const alphaCutoffProperty = SpriteMask._alphaCutoffProperty; + + // Compare renderer property + return ( + preElement.texture === curElement.texture && + (preElement.component).shaderData.getFloat(alphaCutoffProperty) === + (curElement.component).shaderData.getFloat(alphaCutoffProperty) + ); + } + + static batch(preElement: RenderElement | null, curElement: RenderElement): void { + const subChunk = curElement.subChunk; + const { chunk, indices: localIndices } = subChunk; + + const length = localIndices.length; + if (preElement) { + preElement.subChunk.subMesh.count += length; + } else { + // First write this frame — init subMesh range + subChunk.subMesh.start = chunk.updateIndexLength; + subChunk.subMesh.count = length; + } + + let startIndex = chunk.updateIndexLength; + const { start, size } = subChunk.vertexArea; + // PrimitiveChunk vertex layout: pos(3) + uv(2) + color(4) = 9 floats per vertex + const vertexOffset = start / 9; + const indices = chunk.indices; + for (let i = 0; i < length; ++i) { + indices[startIndex++] = vertexOffset + localIndices[i]; + } + chunk.updateIndexLength += length; + chunk.updateVertexStart = Math.min(chunk.updateVertexStart, start); + chunk.updateVertexEnd = Math.max(chunk.updateVertexEnd, start + size); + } +} diff --git a/packages/core/src/RenderPipeline/index.ts b/packages/core/src/RenderPipeline/index.ts index 7161b57757..61855cbaee 100644 --- a/packages/core/src/RenderPipeline/index.ts +++ b/packages/core/src/RenderPipeline/index.ts @@ -1,5 +1,6 @@ export { BasicRenderPipeline, RenderQueueFlags } from "./BasicRenderPipeline"; -export { BatchUtils } from "./BatchUtils"; +export { VertexMergeBatcher } from "./VertexMergeBatcher"; export { Blitter } from "./Blitter"; +export { RenderElement } from "./RenderElement"; export { RenderQueue } from "./RenderQueue"; export { PipelineStage } from "./enums/PipelineStage"; diff --git a/packages/core/src/Renderer.ts b/packages/core/src/Renderer.ts index ab9f743c0c..5af1e71750 100644 --- a/packages/core/src/Renderer.ts +++ b/packages/core/src/Renderer.ts @@ -5,7 +5,7 @@ import { Component } from "./Component"; import { DependentMode, dependentComponents } from "./ComponentsDependencies"; import { Entity } from "./Entity"; import { RenderContext } from "./RenderPipeline/RenderContext"; -import { SubRenderElement } from "./RenderPipeline/SubRenderElement"; +import { RenderElement } from "./RenderPipeline/RenderElement"; import { Transform, TransformModifyFlags } from "./Transform"; import { assignmentClone, deepClone, ignoreClone } from "./clone/CloneManager"; import { SpriteMaskLayer } from "./enums/SpriteMaskLayer"; @@ -23,14 +23,15 @@ import { ShaderDataGroup } from "./shader/enums/ShaderDataGroup"; export class Renderer extends Component { private static _tempVector0 = new Vector3(); + /** @internal */ + static _worldMatrixProperty = ShaderProperty.getByName("renderer_ModelMat"); + /** @internal */ + static _rendererLayerProperty = ShaderProperty.getByName("renderer_Layer"); + private static _receiveShadowMacro = ShaderMacro.getByName("RENDERER_IS_RECEIVE_SHADOWS"); - private static _localMatrixProperty = ShaderProperty.getByName("renderer_LocalMat"); - private static _worldMatrixProperty = ShaderProperty.getByName("renderer_ModelMat"); private static _mvMatrixProperty = ShaderProperty.getByName("renderer_MVMat"); private static _mvpMatrixProperty = ShaderProperty.getByName("renderer_MVPMat"); - private static _mvInvMatrixProperty = ShaderProperty.getByName("renderer_MVInvMat"); private static _normalMatrixProperty = ShaderProperty.getByName("renderer_NormalMat"); - private static _rendererLayerProperty = ShaderProperty.getByName("renderer_Layer"); /** @internal */ @ignoreClone @@ -49,9 +50,6 @@ export class Renderer extends Component { /** @internal */ @assignmentClone _maskInteraction: SpriteMaskInteraction = SpriteMaskInteraction.None; - /** @internal */ - @ignoreClone - _batchedTransformShaderData: boolean = false; @assignmentClone _maskLayer: SpriteMaskLayer = SpriteMaskLayer.Layer0; @@ -74,8 +72,6 @@ export class Renderer extends Component { @ignoreClone private _mvpMatrix: Matrix = new Matrix(); @ignoreClone - private _mvInvMatrix: Matrix = new Matrix(); - @ignoreClone private _normalMatrix: Matrix = new Matrix(); @ignoreClone private _materialsInstanced: boolean[] = []; @@ -384,7 +380,6 @@ export class Renderer extends Component { this._shaderData = null; this._mvMatrix = null; this._mvpMatrix = null; - this._mvInvMatrix = null; this._normalMatrix = null; this._materialsInstanced = null; this._rendererLayer = null; @@ -393,74 +388,66 @@ export class Renderer extends Component { /** * @internal */ - _updateTransformShaderData(context: RenderContext, onlyMVP: boolean, batched: boolean): void { + _updateTransformShaderData(context: RenderContext, onlyMVP: boolean): void { const worldMatrix = this._transformEntity.transform.worldMatrix; + const { shaderData } = this; if (onlyMVP) { - this._updateProjectionRelatedShaderData(context, worldMatrix, batched); + const mvpMatrix = this._mvpMatrix; + Matrix.multiply(context.viewProjectionMatrix, worldMatrix, mvpMatrix); + shaderData.setMatrix(Renderer._mvpMatrixProperty, mvpMatrix); } else { - this._updateWorldViewRelatedShaderData(context, worldMatrix, batched); + const mvMatrix = this._mvMatrix; + const normalMatrix = this._normalMatrix; + + Matrix.multiply(context.viewMatrix, worldMatrix, mvMatrix); + Matrix.invert(worldMatrix, normalMatrix); + normalMatrix.transpose(); + + shaderData.setMatrix(Renderer._worldMatrixProperty, worldMatrix); + shaderData.setMatrix(Renderer._mvMatrixProperty, mvMatrix); + shaderData.setMatrix(Renderer._normalMatrixProperty, normalMatrix); + + const mvpMatrix = this._mvpMatrix; + Matrix.multiply(context.viewProjectionMatrix, worldMatrix, mvpMatrix); + shaderData.setMatrix(Renderer._mvpMatrixProperty, mvpMatrix); } } /** * @internal */ - _canBatch(elementA: SubRenderElement, elementB: SubRenderElement): boolean { + _canBatch(preElement: RenderElement, curElement: RenderElement): boolean { return false; } /** * @internal */ - _batch(elementA: SubRenderElement, elementB?: SubRenderElement): void {} + _batch(preElement: RenderElement | null, curElement: RenderElement): void {} /** - * Update once per frame per renderer, not influenced by batched. + * Update once per frame per renderer. */ protected _update(context: RenderContext): void { const { layer } = this.entity; this._rendererLayer.set(layer & 65535, (layer >>> 16) & 65535, 0, 0); } - protected _updateWorldViewRelatedShaderData(context: RenderContext, worldMatrix: Matrix, batched: boolean): void { - const { shaderData, _mvInvMatrix: mvInvMatrix } = this; - if (batched) { + /** + * Update transform shader data for world-space vertices (2D renderers). + * Vertices are already in world space, so model matrix is identity. + */ + protected _updateWorldSpaceTransformShaderData(context: RenderContext, onlyMVP: boolean): void { + const { shaderData } = this; + if (onlyMVP) { + shaderData.setMatrix(Renderer._mvpMatrixProperty, context.viewProjectionMatrix); + } else { // @ts-ignore const identityMatrix = Matrix._identity; - - Matrix.invert(context.viewMatrix, mvInvMatrix); - - shaderData.setMatrix(Renderer._localMatrixProperty, identityMatrix); shaderData.setMatrix(Renderer._worldMatrixProperty, identityMatrix); shaderData.setMatrix(Renderer._mvMatrixProperty, context.viewMatrix); - shaderData.setMatrix(Renderer._mvInvMatrixProperty, mvInvMatrix); shaderData.setMatrix(Renderer._normalMatrixProperty, identityMatrix); - } else { - const mvMatrix = this._mvMatrix; - const normalMatrix = this._normalMatrix; - - Matrix.multiply(context.viewMatrix, worldMatrix, mvMatrix); - Matrix.invert(mvMatrix, mvInvMatrix); - Matrix.invert(worldMatrix, normalMatrix); - normalMatrix.transpose(); - - shaderData.setMatrix(Renderer._localMatrixProperty, this._transformEntity.transform.localMatrix); - shaderData.setMatrix(Renderer._worldMatrixProperty, worldMatrix); - shaderData.setMatrix(Renderer._mvMatrixProperty, mvMatrix); - shaderData.setMatrix(Renderer._mvInvMatrixProperty, mvInvMatrix); - shaderData.setMatrix(Renderer._normalMatrixProperty, normalMatrix); - } - - this._updateProjectionRelatedShaderData(context, worldMatrix, batched); - } - - protected _updateProjectionRelatedShaderData(context: RenderContext, worldMatrix: Matrix, batched: boolean): void { - if (batched) { - this.shaderData.setMatrix(Renderer._mvpMatrixProperty, context.viewProjectionMatrix); - } else { - const mvpMatrix = this._mvpMatrix; - Matrix.multiply(context.viewProjectionMatrix, worldMatrix, mvpMatrix); - this.shaderData.setMatrix(Renderer._mvpMatrixProperty, mvpMatrix); + shaderData.setMatrix(Renderer._mvpMatrixProperty, context.viewProjectionMatrix); } } diff --git a/packages/core/src/graphic/enums/BufferBindFlag.ts b/packages/core/src/graphic/enums/BufferBindFlag.ts index 152b9d2e54..4616d1eaff 100644 --- a/packages/core/src/graphic/enums/BufferBindFlag.ts +++ b/packages/core/src/graphic/enums/BufferBindFlag.ts @@ -5,5 +5,7 @@ export enum BufferBindFlag { /** Vertex buffer binding flag. */ VertexBuffer, /** Index buffer binding flag. */ - IndexBuffer + IndexBuffer, + /** Constant buffer binding flag (WebGL2 only). */ + ConstantBuffer } diff --git a/packages/core/src/mesh/MeshRenderer.ts b/packages/core/src/mesh/MeshRenderer.ts index e08e51ac4c..7eaf45be7b 100644 --- a/packages/core/src/mesh/MeshRenderer.ts +++ b/packages/core/src/mesh/MeshRenderer.ts @@ -1,6 +1,7 @@ import { BoundingBox } from "@galacean/engine-math"; import { Entity } from "../Entity"; import { RenderContext } from "../RenderPipeline/RenderContext"; +import { RenderElement } from "../RenderPipeline/RenderElement"; import { Renderer, RendererUpdateFlags } from "../Renderer"; import { Logger } from "../base/Logger"; import { ignoreClone } from "../clone/CloneManager"; @@ -151,9 +152,10 @@ export class MeshRenderer extends Renderer { const { _materials: materials, _engine: engine } = this; const subMeshes = mesh.subMeshes; - const renderElement = engine._renderElementPool.get(); - renderElement.set(this.priority, this._distanceForSort); - const subRenderElementPool = engine._subRenderElementPool; + const priority = this.priority; + const distanceForSort = this._distanceForSort; + const renderElementPool = engine._renderElementPool; + const renderPipeline = context.camera._renderPipeline; for (let i = 0, n = subMeshes.length; i < n; i++) { let material = materials[i]; if (!material) { @@ -163,11 +165,38 @@ export class MeshRenderer extends Renderer { material = this.engine._basicResources.meshMagentaMaterial; } - const subRenderElement = subRenderElementPool.get(); - subRenderElement.set(this, material, mesh._primitive, subMeshes[i]); - renderElement.addSubRenderElement(subRenderElement); + const renderElement = renderElementPool.get(); + renderElement.set(this, material, mesh._primitive, subMeshes[i]); + renderElement.priority = priority; + renderElement.distanceForSort = distanceForSort; + renderPipeline.pushRenderElement(context, renderElement); } - context.camera._renderPipeline.pushRenderElement(context, renderElement); + } + + /** + * @internal + */ + override _canBatch(preElement: RenderElement, curElement: RenderElement): boolean { + if (!this._engine._hardwareRenderer.isWebGL2) return false; + return ( + preElement.primitive === curElement.primitive && + preElement.subPrimitive === curElement.subPrimitive && + preElement.material === curElement.material && + this._isFrontFaceInvert() === (curElement.component)._isFrontFaceInvert() && + this.shaderData._macroCollection.isEqual(curElement.component.shaderData._macroCollection) + ); + } + + /** + * @internal + */ + override _batch(preElement: RenderElement | null, curElement: RenderElement): void { + if (!preElement) return; + const renderers = preElement.instancedRenderers; + if (renderers.length === 0) { + renderers.push(preElement.component); + } + renderers.push(curElement.component); } private _setMesh(mesh: Mesh): void { diff --git a/packages/core/src/mesh/SkinnedMeshRenderer.ts b/packages/core/src/mesh/SkinnedMeshRenderer.ts index d8e83e16bb..4d7f726184 100644 --- a/packages/core/src/mesh/SkinnedMeshRenderer.ts +++ b/packages/core/src/mesh/SkinnedMeshRenderer.ts @@ -1,6 +1,7 @@ import { BoundingBox, Vector2 } from "@galacean/engine-math"; import { Entity } from "../Entity"; import { RenderContext } from "../RenderPipeline/RenderContext"; +import { RenderElement } from "../RenderPipeline/RenderElement"; import { RendererUpdateFlags } from "../Renderer"; import { Logger } from "../base/Logger"; import { deepClone, ignoreClone } from "../clone/CloneManager"; @@ -120,6 +121,13 @@ export class SkinnedMeshRenderer extends MeshRenderer { localBounds.max._onValueChanged = this._onLocalBoundsChanged; } + /** + * @internal + */ + override _canBatch(_preElement: RenderElement, _curElement: RenderElement): boolean { + return false; + } + /** * @internal */ diff --git a/packages/core/src/particle/ParticleRenderer.ts b/packages/core/src/particle/ParticleRenderer.ts index 82d2965142..041040a357 100644 --- a/packages/core/src/particle/ParticleRenderer.ts +++ b/packages/core/src/particle/ParticleRenderer.ts @@ -174,9 +174,9 @@ export class ParticleRenderer extends Renderer { /** * @internal */ - override _updateTransformShaderData(context: RenderContext, onlyMVP: boolean, batched: boolean): void { + override _updateTransformShaderData(context: RenderContext, onlyMVP: boolean): void { //@todo: Don't need to update transform shader data, temp solution - super._updateTransformShaderData(context, onlyMVP, true); + this._updateWorldSpaceTransformShaderData(context, onlyMVP); } protected override _updateBounds(worldBounds: BoundingBox): void { const { generator } = this; @@ -251,10 +251,9 @@ export class ParticleRenderer extends Renderer { const engine = this._engine; const renderElement = engine._renderElementPool.get(); - renderElement.set(this.priority, this._distanceForSort); - const subRenderElement = engine._subRenderElementPool.get(); - subRenderElement.set(this, material, generator._primitive, generator._subPrimitive); - renderElement.addSubRenderElement(subRenderElement); + renderElement.set(this, material, generator._primitive, generator._subPrimitive); + renderElement.priority = this.priority; + renderElement.distanceForSort = this._distanceForSort; context.camera._renderPipeline.pushRenderElement(context, renderElement); } diff --git a/packages/core/src/shader/Shader.ts b/packages/core/src/shader/Shader.ts index 6e8cdea7ae..d17d8630a8 100644 --- a/packages/core/src/shader/Shader.ts +++ b/packages/core/src/shader/Shader.ts @@ -222,12 +222,12 @@ export class Shader implements IReferable { const passes = subShaders[i].passes; for (let j = 0, m = passes.length; j < m; j++) { const pass = passes[j]; - const passShaderProgramPools = pass._shaderProgramPools; - for (let k = passShaderProgramPools.length - 1; k >= 0; k--) { - const shaderProgramPool = passShaderProgramPools[k]; - if (shaderProgramPool.engine !== engine) continue; - shaderProgramPool._destroy(); - passShaderProgramPools.splice(k, 1); + const passShaderProgramMaps = pass._shaderProgramMaps; + for (let k = passShaderProgramMaps.length - 1; k >= 0; k--) { + const map = passShaderProgramMaps[k]; + if (map.engine !== engine) continue; + map.destroy(); + passShaderProgramMaps.splice(k, 1); } } } diff --git a/packages/core/src/shader/ShaderBlockProperty.ts b/packages/core/src/shader/ShaderBlockProperty.ts new file mode 100644 index 0000000000..fd47b4cecc --- /dev/null +++ b/packages/core/src/shader/ShaderBlockProperty.ts @@ -0,0 +1,28 @@ +/** + * @internal + * Shader block property, used to identify uniform blocks by id. + */ +export class ShaderBlockProperty { + private static _counter = 0; + private static _nameMap: Record = Object.create(null); + + /** + * Get shader block property by name. + * @param name - Name of the uniform block + * @returns Shader block property + */ + static getByName(name: string): ShaderBlockProperty { + const nameMap = ShaderBlockProperty._nameMap; + return (nameMap[name] ??= new ShaderBlockProperty(name)); + } + + /** Uniform block name. */ + readonly name: string; + /** @internal */ + readonly _uniqueId: number; + + private constructor(name: string) { + this.name = name; + this._uniqueId = ShaderBlockProperty._counter++; + } +} diff --git a/packages/core/src/shader/ShaderFactory.ts b/packages/core/src/shader/ShaderFactory.ts index 4456b8d789..8301b7d5fa 100644 --- a/packages/core/src/shader/ShaderFactory.ts +++ b/packages/core/src/shader/ShaderFactory.ts @@ -1,9 +1,26 @@ +import { Matrix, Vector2, Vector3, Vector4 } from "@galacean/engine-math"; +import { Logger } from "../base/Logger"; +import { Engine } from "../Engine"; +import { Renderer } from "../Renderer"; +import { ConstantBufferBindingPoint } from "./enums/ConstantBufferBindingPoint"; +import { ShaderDataGroup } from "./enums/ShaderDataGroup"; +import { ShaderBlockProperty } from "./ShaderBlockProperty"; +import { ShaderProperty } from "./ShaderProperty"; + /** * Shader registry and GLSL utilities. Holds the `#include` lookup table - * the runtime preprocessor reads, and the GLSL ES 100 → 300 syntax - * converter the WebGL2 path uses. + * the runtime preprocessor reads, the GLSL ES 100 → 300 syntax converter + * the WebGL2 path uses, and the GPU-instancing UBO injector that + * `ShaderPass` runs over compiled GLSL source. */ export class ShaderFactory { + static readonly RENDERER_INSTANCE_BLOCK_NAME = "RendererInstanceData"; + + static readonly uniformBlockBindingMap: Record = { + [ShaderBlockProperty.getByName(ShaderFactory.RENDERER_INSTANCE_BLOCK_NAME)._uniqueId]: + ConstantBufferBindingPoint.RendererInstance + }; + static readonly includeMap: Record = {}; static readonly shaderExtension = [ @@ -15,8 +32,105 @@ export class ShaderFactory { .map((e) => `#extension ${e} : enable\n`) .join(""); + private static readonly _std140TypeInfoMap: Record = { + float: { size: 4, align: 4 }, + int: { size: 4, align: 4 }, + uint: { size: 4, align: 4 }, + bool: { size: 4, align: 4 }, + vec2: { size: 8, align: 8 }, + ivec2: { size: 8, align: 8 }, + bvec2: { size: 8, align: 8 }, + vec3: { size: 12, align: 16 }, + ivec3: { size: 12, align: 16 }, + bvec3: { size: 12, align: 16 }, + vec4: { size: 16, align: 16 }, + ivec4: { size: 16, align: 16 }, + bvec4: { size: 16, align: 16 }, + mat4: { size: 64, align: 16 }, + mat3x4: { size: 48, align: 16 } + }; + // [layout(location = 0)] out [highp] vec4 [color]; - private static readonly _has300OutInFragReg = /\bout\s+(?:\w+\s+)?(?:vec4)\s+(?:\w+)\s*;/; + private static readonly _has300OutInFragReg = /\bout\s+(?:\w+\s+)?vec4\s+\w+\s*;/; + + private static readonly _derivedDefines = `\ +#define renderer_MVMat (camera_ViewMat * renderer_ModelMat) +#define renderer_MVPMat (camera_VPMat * renderer_ModelMat) +#define renderer_NormalMat mat4(transpose(inverse(mat3(renderer_ModelMat))))`; + + // Built-in renderer uniforms. value=true means derived (remove but not added to UBO) + // NOTE: keep this in sync with _derivedDefines / _cameraMatrixCandidates above. + private static readonly _builtinRendererUniforms: Record = { + renderer_ModelMat: false, + renderer_Layer: false, + renderer_MVMat: true, + renderer_MVPMat: true, + renderer_NormalMat: true + }; + + // Camera matrices the derived defines reference; declared on demand because + // shader-compiler DCE may have stripped them from Transform.glsl. + // NOTE: keep this in sync with _derivedDefines above. + private static readonly _cameraMatrixCandidates: ReadonlyArray = ["camera_ViewMat", "camera_VPMat"]; + + private static readonly _uboUniformRegex = + /^[ \t]*uniform\s+(?:(?:lowp|mediump|highp)\s+)?(\w+)\s+(\w+)\s*(\[.+?\])?\s*;/gm; + + private static _packFuncMap: Record = (() => { + const packScalar = (v: Float32Array | Int32Array, o: number, val: number) => { + v[o] = val; + }; + const packVec2 = (v: Float32Array | Int32Array, o: number, val: Vector2) => { + v[o] = val.x; + v[o + 1] = val.y; + }; + const packVec3 = (v: Float32Array | Int32Array, o: number, val: Vector3) => { + v[o] = val.x; + v[o + 1] = val.y; + v[o + 2] = val.z; + }; + const packVec4 = (v: Float32Array | Int32Array, o: number, val: Vector4) => { + v[o] = val.x; + v[o + 1] = val.y; + v[o + 2] = val.z; + v[o + 3] = val.w; + }; + return { + float: packScalar, + int: packScalar, + uint: packScalar, + bool: packScalar, + vec2: packVec2, + ivec2: packVec2, + bvec2: packVec2, + vec3: packVec3, + ivec3: packVec3, + bvec3: packVec3, + vec4: packVec4, + ivec4: packVec4, + bvec4: packVec4, + mat4: (v: Float32Array | Int32Array, o: number, val: Matrix) => { + const e = val.elements; + for (let k = 0; k < 16; k++) v[o + k] = e[k]; + }, + // Affine mat4 stored as mat3x4: write 3 transposed rows (row3 is always 0,0,0,1) + mat3x4: (v: Float32Array | Int32Array, o: number, val: Matrix) => { + const e = val.elements; + v[o] = e[0]; + v[o + 1] = e[4]; + v[o + 2] = e[8]; + v[o + 3] = e[12]; + v[o + 4] = e[1]; + v[o + 5] = e[5]; + v[o + 6] = e[9]; + v[o + 7] = e[13]; + v[o + 8] = e[2]; + v[o + 9] = e[6]; + v[o + 10] = e[10]; + v[o + 11] = e[14]; + } + }; + })(); /** * Register a chunk source so `#include` resolves it. @@ -73,6 +187,169 @@ export class ShaderFactory { return shader; } + /** + * Scan VS/FS for renderer-group `uniform` declarations, replace them with a shared + * std140 UBO (instanced array), and emit `#define` remapping so original uniform + * names resolve to `rendererData[instanceID].field`. + * + * Inputs are expected to be already preprocessor-evaluated (no `#ifdef` left). + */ + static injectInstanceUBO( + engine: Engine, + vertexSource: string, + fragmentSource: string + ): { vertexSource: string; fragmentSource: string; instanceLayout: InstanceBufferLayout | null } { + const fieldMap: Record = Object.create(null); + vertexSource = ShaderFactory._scanInstanceUniforms(vertexSource, fieldMap); + fragmentSource = ShaderFactory._scanInstanceUniforms(fragmentSource, fieldMap); + + // Even when fieldMap is empty, derived built-ins (e.g. `renderer_MVPMat`) may have + // had their declarations stripped by scan and still need a `#define` to compile + const instanceLayout = ShaderFactory._buildLayout(engine, fieldMap); + + const { instanceFields } = instanceLayout; + const uboDecl = ShaderFactory._buildUBODeclaration(instanceLayout); + const fieldDefinesVS = ShaderFactory._buildFieldDefines(instanceFields, "gl_InstanceID"); + const fieldDefinesFS = ShaderFactory._buildFieldDefines(instanceFields, "v_instanceID"); + const derivedDefines = ShaderFactory._derivedDefines; + const vsCameraDecls = ShaderFactory._buildMissingCameraDecls(vertexSource); + const fsCameraDecls = ShaderFactory._buildMissingCameraDecls(fragmentSource); + + const vsBlock = `${uboDecl}flat out int v_instanceID;\n${vsCameraDecls}${fieldDefinesVS}\n${derivedDefines}\n`; + const fsBlock = `${uboDecl}flat in int v_instanceID;\n${fsCameraDecls}${fieldDefinesFS}\n${derivedDefines}\n`; + + vertexSource = vsBlock + vertexSource; + vertexSource = vertexSource.replace( + /void\s+main\s*\(\s*\)\s*\{/, + "void main() {\n v_instanceID = gl_InstanceID;" + ); + fragmentSource = fsBlock + fragmentSource; + + return { vertexSource, fragmentSource, instanceLayout }; + } + + private static _scanInstanceUniforms(source: string, fieldMap: Record): string { + const builtinUniforms = ShaderFactory._builtinRendererUniforms; + const std140Map = ShaderFactory._std140TypeInfoMap; + return source.replace(ShaderFactory._uboUniformRegex, (match, type, name, arraySize) => { + if (type.includes("sampler")) return match; + const isDerived = builtinUniforms[name]; + if (isDerived === undefined && ShaderProperty._getShaderPropertyGroup(name) !== ShaderDataGroup.Renderer) + return match; + if (isDerived) return ""; + if (arraySize) { + Logger.error(`GPU Instancing does not support array uniform "${name}${arraySize}"`); + return match; + } + // ModelMat is affine, stored as mat3x4 (3 columns) to save 16 bytes per instance + const storageType = type === "mat4" && name === "renderer_ModelMat" ? "mat3x4" : type; + if (!std140Map[storageType]) { + Logger.error(`GPU Instancing does not support uniform "${name}" of type "${type}"`); + return match; + } + fieldMap[ShaderProperty.getByName(name)._uniqueId] = storageType; + return ""; + }); + } + + private static _buildLayout(engine: Engine, fieldMap: Record): InstanceBufferLayout { + const maxUBOSize = engine._hardwareRenderer.maxUniformBlockSize; + const std140Map = ShaderFactory._std140TypeInfoMap; + const instanceFields: InstanceFieldInfo[] = []; + let currentOffset = 0; + + const packFuncMap = ShaderFactory._packFuncMap; + const addField = (id: number): void => { + const type = fieldMap[id]; + // Unsupported types are filtered out in `_scanInstanceUniforms` with a clear error; + // this only triggers if the scan/build contract is violated + const info = std140Map[type]; + if (!info) return; + currentOffset = Math.ceil(currentOffset / info.align) * info.align; + instanceFields.push({ + property: ShaderProperty._propertyIdMap[id], + type, + offset: currentOffset, + offsetInElements: currentOffset / 4, + useIntView: type[0] === "i" || type[0] === "u" || type[0] === "b", + pack: packFuncMap[type] + }); + currentOffset += info.size; + }; + + // renderer_ModelMat is always required: derived defines reference it, so + // even shaders that never declared the plain uniform need it in the UBO. + const modelMatId = Renderer._worldMatrixProperty._uniqueId; + const layerId = Renderer._rendererLayerProperty._uniqueId; + if (!(modelMatId in fieldMap)) fieldMap[modelMatId] = "mat3x4"; + + // Priority order: ModelMat first, Layer second, rest by property id. + addField(modelMatId); + if (layerId in fieldMap) addField(layerId); + const keys: number[] = []; + for (const k in fieldMap) { + const id = +k; + if (id !== modelMatId && id !== layerId) keys.push(id); + } + keys.sort((a, b) => a - b); + for (let i = 0; i < keys.length; i++) addField(keys[i]); + + const structSize = Math.ceil(currentOffset / 16) * 16; + const instanceMaxCount = Math.floor(maxUBOSize / structSize); + + return { instanceFields, instanceMaxCount, structSize }; + } + + private static _buildMissingCameraDecls(source: string): string { + let out = ""; + const candidates = ShaderFactory._cameraMatrixCandidates; + for (let i = 0; i < candidates.length; i++) { + const name = candidates[i]; + const decl = new RegExp(`^\\s*uniform\\s+(?:(?:lowp|mediump|highp)\\s+)?mat4\\s+${name}\\s*;`, "m"); + if (!decl.test(source)) { + out += `uniform mat4 ${name};\n`; + } + } + return out; + } + + private static _buildUBODeclaration(layout: InstanceBufferLayout): string { + const { instanceFields, instanceMaxCount } = layout; + const structLines: string[] = []; + for (let i = 0; i < instanceFields.length; i++) { + const { type, property } = instanceFields[i]; + structLines.push(` ${type} ${property.name};`); + } + return ( + `#define INSTANCE_MAX_COUNT ${instanceMaxCount}\n` + + `struct RendererInstanceStruct {\n${structLines.join("\n")}\n};\n` + + `layout(std140) uniform ${ShaderFactory.RENDERER_INSTANCE_BLOCK_NAME} {\n` + + ` RendererInstanceStruct rendererData[INSTANCE_MAX_COUNT];\n};\n` + ); + } + + private static _buildFieldDefines(fields: InstanceFieldInfo[], idExpr: string): string { + const accessor = `rendererData[${idExpr}]`; + const lines: string[] = []; + for (let i = 0; i < fields.length; i++) { + const { type, property } = fields[i]; + const n = property.name; + if (type === "mat3x4") { + const m = `${accessor}.${n}`; + lines.push( + `#define ${n} mat4(` + + `vec4(${m}[0].x,${m}[1].x,${m}[2].x,0.0),` + + `vec4(${m}[0].y,${m}[1].y,${m}[2].y,0.0),` + + `vec4(${m}[0].z,${m}[1].z,${m}[2].z,0.0),` + + `vec4(${m}[0].w,${m}[1].w,${m}[2].w,1.0))` + ); + } else { + lines.push(`#define ${n} ${accessor}.${n}`); + } + } + return lines.join("\n"); + } + private static _replaceMRTShader(shader: string, result: string[]): string { let declaration = ""; const mrtIndexSet = new Set(); @@ -93,3 +370,27 @@ export class ShaderFactory { return shader; } } + +/** + * @internal + */ +export interface InstanceFieldInfo { + property: ShaderProperty; + type: string; + offset: number; + /** offset / 4, precomputed to avoid repeated division in upload loop */ + offsetInElements: number; + useIntView: boolean; + pack: InstancePackFunc; +} + +/** + * @internal + */ +export interface InstanceBufferLayout { + instanceFields: InstanceFieldInfo[]; + instanceMaxCount: number; + structSize: number; +} + +type InstancePackFunc = (view: Float32Array | Int32Array, offset: number, value: any) => void; diff --git a/packages/core/src/shader/ShaderMacroCollection.ts b/packages/core/src/shader/ShaderMacroCollection.ts index 749abc22ee..3efb98b77c 100644 --- a/packages/core/src/shader/ShaderMacroCollection.ts +++ b/packages/core/src/shader/ShaderMacroCollection.ts @@ -158,6 +158,20 @@ export class ShaderMacroCollection { return (this._mask[index] & macro._maskValue) !== 0; } + /** + * Whether this macro collection is equal to another. + * @param other - macro collection to compare + */ + isEqual(other: ShaderMacroCollection): boolean { + if (this._length !== other._length) return false; + const mask = this._mask; + const otherMask = other._mask; + for (let i = 0, n = this._length; i < n; i++) { + if (mask[i] !== otherMask[i]) return false; + } + return true; + } + /** * Clear this macro collection. */ diff --git a/packages/core/src/shader/ShaderPass.ts b/packages/core/src/shader/ShaderPass.ts index 747b918b64..d0e9c1aa0b 100644 --- a/packages/core/src/shader/ShaderPass.ts +++ b/packages/core/src/shader/ShaderPass.ts @@ -1,13 +1,14 @@ import type { ShaderInstruction } from "@galacean/engine-design"; import { Engine } from "../Engine"; +import { InstanceBuffer } from "../RenderPipeline/InstanceBuffer"; import { PipelineStage } from "../RenderPipeline/enums/PipelineStage"; import { GLCapabilityType } from "../base/Constant"; -import { ShaderFactory } from "./ShaderFactory"; +import { InstanceBufferLayout, ShaderFactory } from "./ShaderFactory"; import { ShaderMacro } from "./ShaderMacro"; import { ShaderMacroCollection } from "./ShaderMacroCollection"; import { ShaderPart } from "./ShaderPart"; +import { ShaderProgramMap } from "./ShaderProgramMap"; import { ShaderProgram } from "./ShaderProgram"; -import { ShaderProgramPool } from "./ShaderProgramPool"; import { ShaderProperty } from "./ShaderProperty"; import { ShaderLanguage } from "./enums/ShaderLanguage"; import { ShaderMacroProcessor } from "./ShaderMacroProcessor"; @@ -48,7 +49,7 @@ export class ShaderPass extends ShaderPart { /** @internal */ _renderStateDataMap: Record = {}; /** @internal */ - _shaderProgramPools: ShaderProgramPool[] = []; + _shaderProgramMaps: ShaderProgramMap[] = []; /** @internal Transform feedback output varyings (WebGL2 only). */ _feedbackVaryings?: string[]; @@ -88,15 +89,15 @@ export class ShaderPass extends ShaderPart { * @internal */ _getShaderProgram(engine: Engine, macroCollection: ShaderMacroCollection): ShaderProgram { - const shaderProgramPool = engine._getShaderProgramPool(this._shaderPassId, this._shaderProgramPools); - let shaderProgram = shaderProgramPool.get(macroCollection); + const shaderProgramMap = engine._getShaderProgramMap(this._shaderPassId, this._shaderProgramMaps); + let shaderProgram = shaderProgramMap.get(macroCollection); if (shaderProgram) { return shaderProgram; } - shaderProgram = this._getCanonicalShaderProgram(engine, macroCollection); + shaderProgram = this._compileShaderProgram(engine, macroCollection); - shaderProgramPool.cache(shaderProgram); + shaderProgramMap.cache(shaderProgram); return shaderProgram; } @@ -104,25 +105,35 @@ export class ShaderPass extends ShaderPart { * @internal */ _destroy(): void { - const shaderProgramPools = this._shaderProgramPools; - for (let i = 0, n = shaderProgramPools.length; i < n; i++) { - const shaderProgramPool = shaderProgramPools[i]; - shaderProgramPool._destroy(); - delete shaderProgramPool.engine._shaderProgramPools[this._shaderPassId]; + const shaderProgramMaps = this._shaderProgramMaps; + for (let i = 0, n = shaderProgramMaps.length; i < n; i++) { + const map = shaderProgramMaps[i]; + map.destroy(); + delete map.engine._shaderProgramMaps[this._shaderPassId]; } - // Clear array storing multiple engine shader program pools - shaderProgramPools.length = 0; + shaderProgramMaps.length = 0; } - private _getCanonicalShaderProgram(engine: Engine, macroCollection: ShaderMacroCollection): ShaderProgram { - const { vertexSource, fragmentSource } = this._compileShaderSource(engine, macroCollection); - return new ShaderProgram(engine, vertexSource, fragmentSource, this._feedbackVaryings); + /** + * @internal + */ + _compileShaderProgram(engine: Engine, macroCollection: ShaderMacroCollection): ShaderProgram { + const isGPUInstance = macroCollection.isEnable(InstanceBuffer.gpuInstanceMacro); + const { vertexSource, fragmentSource, instanceLayout } = this._compileShaderSource( + engine, + macroCollection, + isGPUInstance + ); + const program = new ShaderProgram(engine, vertexSource, fragmentSource, this._feedbackVaryings); + program._instanceLayout = instanceLayout; + return program; } private _compileShaderSource( engine: Engine, - macroCollection: ShaderMacroCollection - ): { vertexSource: string; fragmentSource: string } { + macroCollection: ShaderMacroCollection, + isGPUInstance: boolean + ): { vertexSource: string; fragmentSource: string; instanceLayout: InstanceBufferLayout | null } { const isWebGL2: boolean = engine._hardwareRenderer.isWebGL2; const shaderMacroList = ShaderPass._shaderMacroList; shaderMacroList.length = 0; @@ -144,6 +155,14 @@ export class ShaderPass extends ShaderPart { let vertexSource = ShaderMacroProcessor.evaluate(this._vertexShaderInstructions, macroMap); let fragmentSource = ShaderMacroProcessor.evaluate(this._fragmentShaderInstructions, macroMap); + let instanceLayout: InstanceBufferLayout | null = null; + if (isGPUInstance) { + const injected = ShaderFactory.injectInstanceUBO(engine, vertexSource, fragmentSource); + vertexSource = injected.vertexSource; + fragmentSource = injected.fragmentSource; + instanceLayout = injected.instanceLayout; + } + if (isWebGL2 && this._platformTarget === ShaderLanguage.GLSLES100) { vertexSource = ShaderFactory.convertTo300(vertexSource); fragmentSource = ShaderFactory.convertTo300(fragmentSource, true); @@ -159,7 +178,8 @@ export class ShaderPass extends ShaderPart { ${isWebGL2 ? "" : ShaderFactory.shaderExtension} ${precisionStr} ${fragmentSource} - ` + `, + instanceLayout }; } } diff --git a/packages/core/src/shader/ShaderProgram.ts b/packages/core/src/shader/ShaderProgram.ts index 22151e5f77..4cc46cc7d5 100644 --- a/packages/core/src/shader/ShaderProgram.ts +++ b/packages/core/src/shader/ShaderProgram.ts @@ -7,7 +7,9 @@ import { ShaderData } from "./ShaderData"; import { ShaderProperty } from "./ShaderProperty"; import { ShaderUniform } from "./ShaderUniform"; import { ShaderUniformBlock } from "./ShaderUniformBlock"; +import { ShaderBlockProperty } from "./ShaderBlockProperty"; import { ShaderDataGroup } from "./enums/ShaderDataGroup"; +import { InstanceBufferLayout, ShaderFactory } from "./ShaderFactory"; /** * Shader program, corresponding to the GPU shader program. @@ -52,7 +54,11 @@ export class ShaderProgram { /** @internal */ _uploadMaterialId: number = -1; + /** @internal */ + _instanceLayout: InstanceBufferLayout | null = null; + attributeLocation: Record = Object.create(null); + uniformBlockIds: number[] = []; // @todo: move to RHI. private _isValid: boolean; @@ -339,6 +345,9 @@ export class ShaderProgram { } const location = gl.getUniformLocation(program, name); + // UBO members have no individual location, skip them + if (location === null) return; + shaderUniform.name = name; shaderUniform.propertyId = ShaderProperty.getByName(name)._uniqueId; shaderUniform.location = location; @@ -412,9 +421,33 @@ export class ShaderProgram { shaderUniform.cacheValue = new Vector4(0, 0, 0); } break; + case gl.FLOAT_MAT2: + shaderUniform.applyFunc = shaderUniform.uploadMat2; + break; + case gl.FLOAT_MAT3: + shaderUniform.applyFunc = shaderUniform.uploadMat3; + break; case gl.FLOAT_MAT4: shaderUniform.applyFunc = isArray ? shaderUniform.uploadMat4v : shaderUniform.uploadMat4; break; + case (gl).FLOAT_MAT2x3: + shaderUniform.applyFunc = shaderUniform.uploadMat2x3; + break; + case (gl).FLOAT_MAT2x4: + shaderUniform.applyFunc = shaderUniform.uploadMat2x4; + break; + case (gl).FLOAT_MAT3x2: + shaderUniform.applyFunc = shaderUniform.uploadMat3x2; + break; + case (gl).FLOAT_MAT3x4: + shaderUniform.applyFunc = shaderUniform.uploadMat3x4; + break; + case (gl).FLOAT_MAT4x2: + shaderUniform.applyFunc = shaderUniform.uploadMat4x2; + break; + case (gl).FLOAT_MAT4x3: + shaderUniform.applyFunc = shaderUniform.uploadMat4x3; + break; case gl.SAMPLER_2D: case gl.SAMPLER_CUBE: case (gl).UNSIGNED_INT_SAMPLER_2D: @@ -476,6 +509,21 @@ export class ShaderProgram { attributeInfos.forEach(({ name }) => { this.attributeLocation[name] = gl.getAttribLocation(program, name); }); + + // Record uniform block indices and bind binding points (WebGL2 only) + if (this._engine._hardwareRenderer.isWebGL2) { + const gl2 = gl; + const bindingMap = ShaderFactory.uniformBlockBindingMap; + const blockCount = gl2.getProgramParameter(program, gl2.ACTIVE_UNIFORM_BLOCKS) ?? 0; + for (let i = 0; i < blockCount; i++) { + const id = ShaderBlockProperty.getByName(gl2.getActiveUniformBlockName(program, i))._uniqueId; + this.uniformBlockIds[i] = id; + const bindingPoint = bindingMap[id]; + if (bindingPoint !== undefined) { + gl2.uniformBlockBinding(program, i, bindingPoint); + } + } + } } private _getUniformInfos(): WebGLActiveInfo[] { diff --git a/packages/core/src/shader/ShaderProgramPool.ts b/packages/core/src/shader/ShaderProgramMap.ts similarity index 56% rename from packages/core/src/shader/ShaderProgramPool.ts rename to packages/core/src/shader/ShaderProgramMap.ts index 3b43a07afa..5673708863 100644 --- a/packages/core/src/shader/ShaderProgramPool.ts +++ b/packages/core/src/shader/ShaderProgramMap.ts @@ -2,23 +2,26 @@ import { Engine } from "../Engine"; import { ShaderMacroCollection } from "./ShaderMacroCollection"; import { ShaderProgram } from "./ShaderProgram"; +type Tree = { + [key: number]: Tree | ShaderProgram; +}; + /** - * Shader program pool. + * Map keyed by ShaderMacroCollection bitmask, caching ShaderProgram instances. * @internal */ -export class ShaderProgramPool { +export class ShaderProgramMap { + engine: Engine; + private _cacheHierarchyDepth: number = 1; - private _cacheMap: Tree = Object.create(null); + private _cacheMap: Tree = Object.create(null); private _lastQueryMap: Record; private _lastQueryKey: number; - constructor(public engine: Engine) {} + constructor(engine: Engine) { + this.engine = engine; + } - /** - * Get shader program by macro collection. - * @param macros - macro collection - * @returns shader program - */ get(macros: ShaderMacroCollection): ShaderProgram | null { let cacheMap = this._cacheMap; const maskLength = macros._length; @@ -33,41 +36,31 @@ export class ShaderProgramPool { const maxEndIndex = this._cacheHierarchyDepth - 1; for (let i = 0; i < maxEndIndex; i++) { const subMask = endIndex < i ? 0 : mask[i]; - let subCacheShaders = >cacheMap[subMask]; - subCacheShaders || (cacheMap[subMask] = subCacheShaders = Object.create(null)); - cacheMap = subCacheShaders; + let subCache = cacheMap[subMask]; + subCache || (cacheMap[subMask] = subCache = Object.create(null)); + cacheMap = subCache; } const cacheKey = endIndex < maxEndIndex ? 0 : mask[maxEndIndex]; - const shader = (>cacheMap)[cacheKey]; - if (!shader) { + const value = (>cacheMap)[cacheKey]; + if (!value) { this._lastQueryKey = cacheKey; this._lastQueryMap = >cacheMap; } - return shader; + return value; } - /** - * Cache the shader program. - * - * @remarks - * The method must return an empty value after calling get() to run normally. - * - * @param shaderProgram - shader program - */ - cache(shaderProgram: ShaderProgram): void { - this._lastQueryMap[this._lastQueryKey] = shaderProgram; + cache(value: ShaderProgram): void { + this._lastQueryMap[this._lastQueryKey] = value; } - /** - * @internal - */ - _destroy(): void { - this._recursiveDestroy(0, this._cacheMap); + destroy(): void { + this._recursiveForEach(0, this._cacheMap); this._cacheMap = Object.create(null); + this._cacheHierarchyDepth = 1; } - private _recursiveDestroy(hierarchy: number, cacheMap: Tree): void { + private _recursiveForEach(hierarchy: number, cacheMap: Tree): void { if (hierarchy === this._cacheHierarchyDepth - 1) { for (let k in cacheMap) { (cacheMap[k]).destroy(); @@ -76,35 +69,30 @@ export class ShaderProgramPool { } ++hierarchy; for (let k in cacheMap) { - this._recursiveDestroy(hierarchy, >cacheMap[k]); + this._recursiveForEach(hierarchy, cacheMap[k]); } } private _resizeCacheMapHierarchy( - cacheMap: Tree, + cacheMap: Tree, hierarchy: number, currentHierarchy: number, increaseHierarchy: number ): void { - // Only expand but not shrink if (hierarchy == currentHierarchy - 1) { for (let k in cacheMap) { - const shader = cacheMap[k]; + const value = cacheMap[k]; let subCacheMap = cacheMap; for (let i = 0; i < increaseHierarchy; i++) { subCacheMap[i == 0 ? k : 0] = subCacheMap = Object.create(null); } - subCacheMap[0] = shader; + subCacheMap[0] = value; } } else { hierarchy++; for (let k in cacheMap) { - this._resizeCacheMapHierarchy(>cacheMap[k], hierarchy, currentHierarchy, increaseHierarchy); + this._resizeCacheMapHierarchy(cacheMap[k], hierarchy, currentHierarchy, increaseHierarchy); } } } } - -type Tree = { - [key: number]: Tree | T; -}; diff --git a/packages/core/src/shader/ShaderUniform.ts b/packages/core/src/shader/ShaderUniform.ts index 07017a4abc..90d9233c1b 100644 --- a/packages/core/src/shader/ShaderUniform.ts +++ b/packages/core/src/shader/ShaderUniform.ts @@ -237,6 +237,14 @@ export class ShaderUniform { this._gl.uniform4iv(shaderUniform.location, value); } + uploadMat2(shaderUniform: ShaderUniform, value: Float32Array): void { + this._gl.uniformMatrix2fv(shaderUniform.location, false, value); + } + + uploadMat3(shaderUniform: ShaderUniform, value: Float32Array): void { + this._gl.uniformMatrix3fv(shaderUniform.location, false, value); + } + uploadMat4(shaderUniform: ShaderUniform, value: Matrix): void { this._gl.uniformMatrix4fv(shaderUniform.location, false, value.elements); } @@ -245,6 +253,30 @@ export class ShaderUniform { this._gl.uniformMatrix4fv(shaderUniform.location, false, value); } + uploadMat2x3(shaderUniform: ShaderUniform, value: Float32Array): void { + (this._gl).uniformMatrix2x3fv(shaderUniform.location, false, value); + } + + uploadMat2x4(shaderUniform: ShaderUniform, value: Float32Array): void { + (this._gl).uniformMatrix2x4fv(shaderUniform.location, false, value); + } + + uploadMat3x2(shaderUniform: ShaderUniform, value: Float32Array): void { + (this._gl).uniformMatrix3x2fv(shaderUniform.location, false, value); + } + + uploadMat3x4(shaderUniform: ShaderUniform, value: Float32Array): void { + (this._gl).uniformMatrix3x4fv(shaderUniform.location, false, value); + } + + uploadMat4x2(shaderUniform: ShaderUniform, value: Float32Array): void { + (this._gl).uniformMatrix4x2fv(shaderUniform.location, false, value); + } + + uploadMat4x3(shaderUniform: ShaderUniform, value: Float32Array): void { + (this._gl).uniformMatrix4x3fv(shaderUniform.location, false, value); + } + uploadTexture(shaderUniform: ShaderUniform, value: Texture): void { const rhi = this._rhi; rhi.activeTexture(shaderUniform.textureIndex as GLenum); diff --git a/packages/core/src/shader/enums/ConstantBufferBindingPoint.ts b/packages/core/src/shader/enums/ConstantBufferBindingPoint.ts new file mode 100644 index 0000000000..595d159924 --- /dev/null +++ b/packages/core/src/shader/enums/ConstantBufferBindingPoint.ts @@ -0,0 +1,7 @@ +/** + * @internal + * Constant buffer binding point allocation. + */ +export enum ConstantBufferBindingPoint { + RendererInstance = 0 +} diff --git a/packages/core/src/trail/TrailRenderer.ts b/packages/core/src/trail/TrailRenderer.ts index b8d97f4365..6485d658ca 100644 --- a/packages/core/src/trail/TrailRenderer.ts +++ b/packages/core/src/trail/TrailRenderer.ts @@ -1,7 +1,6 @@ import { BoundingBox, Color, Vector2, Vector3, Vector4 } from "@galacean/engine-math"; import { Entity } from "../Entity"; import { RenderContext } from "../RenderPipeline/RenderContext"; -import { RenderElement } from "../RenderPipeline/RenderElement"; import { Renderer, RendererUpdateFlags } from "../Renderer"; import { deepClone, ignoreClone } from "../clone/CloneManager"; import { Buffer } from "../graphic/Buffer"; @@ -232,8 +231,9 @@ export class TrailRenderer extends Renderer { const { _firstActiveElement: firstActive, _firstFreeElement: firstFree } = this; - const renderElement = this._engine._renderElementPool.get(); - renderElement.set(this.priority, this._distanceForSort); + const priority = this.priority; + const distanceForSort = this._distanceForSort; + const renderPipeline = context.camera._renderPipeline; // spansBoundary: active points cross buffer end // wrapped: spansBoundary AND point 0 has been written (need bridge + second segment) @@ -241,13 +241,19 @@ export class TrailRenderer extends Renderer { const wrapped = spansBoundary && firstFree > 0; const mainCount = (spansBoundary ? this._currentPointCapacity - firstActive + (wrapped ? 1 : 0) : firstFree - firstActive) * 2; - this._addSubRenderElement(renderElement, material, this._mainSubPrimitive, firstActive * 2, mainCount); + this._addRenderElement( + context, + material, + this._mainSubPrimitive, + firstActive * 2, + mainCount, + priority, + distanceForSort + ); if (wrapped) { - this._addSubRenderElement(renderElement, material, this._wrapSubPrimitive, 0, firstFree * 2); + this._addRenderElement(context, material, this._wrapSubPrimitive, 0, firstFree * 2, priority, distanceForSort); } - - context.camera._renderPipeline.pushRenderElement(context, renderElement); } protected override _updateBounds(worldBounds: BoundingBox): void { @@ -588,18 +594,22 @@ export class TrailRenderer extends Renderer { this._bufferResized = false; } - private _addSubRenderElement( - renderElement: RenderElement, + private _addRenderElement( + context: RenderContext, material: Material, subPrimitive: SubPrimitive, start: number, - count: number + count: number, + priority: number, + distanceForSort: number ): void { subPrimitive.start = start; subPrimitive.count = count; - const subRenderElement = this._engine._subRenderElementPool.get(); - subRenderElement.set(this, material, this._primitive, subPrimitive); - renderElement.addSubRenderElement(subRenderElement); + const renderElement = this._engine._renderElementPool.get(); + renderElement.set(this, material, this._primitive, subPrimitive); + renderElement.priority = priority; + renderElement.distanceForSort = distanceForSort; + context.camera._renderPipeline.pushRenderElement(context, renderElement); } @ignoreClone diff --git a/packages/core/src/ui/IUICanvas.ts b/packages/core/src/ui/IUICanvas.ts index 3139b6dba8..444242657c 100644 --- a/packages/core/src/ui/IUICanvas.ts +++ b/packages/core/src/ui/IUICanvas.ts @@ -10,7 +10,8 @@ export interface IUICanvas { entity: Entity; sortOrder: number; _canvasIndex: number; - _renderElement: RenderElement; + _renderElements: RenderElement[]; + _batchedRenderElements: RenderElement[]; _canRender(camera: Camera): boolean; _prepareRender(renderContext: RenderContext): void; } diff --git a/packages/core/src/ui/UIUtils.ts b/packages/core/src/ui/UIUtils.ts index c57c8bdf1f..a61a7d54d3 100644 --- a/packages/core/src/ui/UIUtils.ts +++ b/packages/core/src/ui/UIUtils.ts @@ -44,7 +44,10 @@ export class UIUtils { renderContext.applyVirtualCamera(virtualCamera, false); uiRenderQueue.rendererUpdateFlag |= ContextRendererUpdateFlag.ProjectionMatrix; uiCanvas._prepareRender(renderContext); - uiRenderQueue.pushRenderElement(uiCanvas._renderElement); + const curElements = uiCanvas._batchedRenderElements; + for (let j = 0, m = curElements.length; j < m; j++) { + uiRenderQueue.pushRenderElement(curElements[j]); + } uiRenderQueue.batch(batcherManager); batcherManager.uploadBuffer(); uiRenderQueue.render(renderContext, "Forward"); diff --git a/packages/design/src/renderingHardwareInterface/IHardwareRenderer.ts b/packages/design/src/renderingHardwareInterface/IHardwareRenderer.ts index bccb92bf65..193ef7a558 100644 --- a/packages/design/src/renderingHardwareInterface/IHardwareRenderer.ts +++ b/packages/design/src/renderingHardwareInterface/IHardwareRenderer.ts @@ -2,6 +2,8 @@ * Hardware graphics API renderer. */ export interface IHardwareRenderer { + readonly maxUniformBlockSize: number; + // todo: implements [key: string]: any; } diff --git a/packages/rhi-webgl/src/GLBuffer.ts b/packages/rhi-webgl/src/GLBuffer.ts index 87f635dba9..aea7b38842 100644 --- a/packages/rhi-webgl/src/GLBuffer.ts +++ b/packages/rhi-webgl/src/GLBuffer.ts @@ -21,7 +21,18 @@ export class GLBuffer implements IPlatformBuffer { const gl = rhi.gl; const glBuffer = gl.createBuffer(); const glBufferUsage = this._getGLBufferUsage(gl, bufferUsage); - const glBindTarget = type === BufferBindFlag.VertexBuffer ? gl.ARRAY_BUFFER : gl.ELEMENT_ARRAY_BUFFER; + let glBindTarget: number; + switch (type) { + case BufferBindFlag.VertexBuffer: + glBindTarget = gl.ARRAY_BUFFER; + break; + case BufferBindFlag.IndexBuffer: + glBindTarget = gl.ELEMENT_ARRAY_BUFFER; + break; + case BufferBindFlag.ConstantBuffer: + glBindTarget = (gl).UNIFORM_BUFFER; + break; + } this._gl = gl; this._glBuffer = glBuffer; this._glBufferUsage = glBufferUsage; diff --git a/packages/rhi-webgl/src/WebGLGraphicDevice.ts b/packages/rhi-webgl/src/WebGLGraphicDevice.ts index c937742f36..7394b0409a 100644 --- a/packages/rhi-webgl/src/WebGLGraphicDevice.ts +++ b/packages/rhi-webgl/src/WebGLGraphicDevice.ts @@ -89,6 +89,8 @@ export interface WebGLGraphicDeviceOptions { * WebGL graphic device, including WebGL1.0 and WebGL2.0. */ export class WebGLGraphicDevice implements IHardwareRenderer { + maxUniformBlockSize: number; + /** @internal */ _readFrameBuffer: WebGLFramebuffer = null; /** @internal */ @@ -280,6 +282,20 @@ export class WebGLGraphicDevice implements IHardwareRenderer { return new GLTransformFeedbackPrimitive(this._gl); } + bindUniformBufferBase(bindingPoint: number, buffer: IPlatformBuffer): void { + const gl = this._gl; + gl.bindBufferBase(gl.UNIFORM_BUFFER, bindingPoint, (buffer)._glBuffer); + } + + bindUniformBlock(program: WebGLProgram, blockName: string, bindingPoint: number): number { + const gl = this._gl; + const blockIndex = gl.getUniformBlockIndex(program, blockName); + if (blockIndex !== gl.INVALID_INDEX) { + gl.uniformBlockBinding(program, blockIndex, bindingPoint); + } + return blockIndex; + } + /** * Enable GL_RASTERIZER_DISCARD (WebGL2 only). */ @@ -623,6 +639,11 @@ export class WebGLGraphicDevice implements IHardwareRenderer { if (debugRenderInfo != null) { this._renderer = gl.getParameter(debugRenderInfo.UNMASKED_RENDERER_WEBGL); } + if (this._isWebGL2) { + this.maxUniformBlockSize = (gl).getParameter( + (gl).MAX_UNIFORM_BLOCK_SIZE + ); + } } destroy(): void { diff --git a/packages/shader/compiledShaders/PBR.shaderc b/packages/shader/compiledShaders/PBR.shaderc index 1f05aa7a53..2be685d4df 100644 --- a/packages/shader/compiledShaders/PBR.shaderc +++ b/packages/shader/compiledShaders/PBR.shaderc @@ -1 +1 @@ -{"name":"PBR","platformTarget":0,"subShaders":[{"name":"Default","tags":{},"passes":[{"name":"Pipeline/ShadowCaster/Default/ShadowCaster","isUsePass":true,"tags":{},"renderStates":{"constantMap":{},"variableMap":{}}},{"name":"Pipeline/DepthOnly/Default/DepthOnly","isUsePass":true,"tags":{},"renderStates":{"constantMap":{},"variableMap":{}}},{"name":"Forward Pass","isUsePass":false,"tags":{"pipelineStage":"Forward"},"renderStates":{"constantMap":{},"variableMap":{"0":"blendEnabled","3":"sourceColorBlendFactor","4":"sourceAlphaBlendFactor","5":"destinationColorBlendFactor","6":"destinationAlphaBlendFactor","11":"depthWriteEnabled","25":"rasterStateCullMode","28":"renderQueueType"}},"vertexShaderInstructions":[[0,"\n"],[2,"FORWARD_PASS_PBR_INCLUDED",714],[0,"\n\n"],[7,"FORWARD_PASS_PBR_INCLUDED"],[0,"\n\n"],[4,{"t":"and","l":{"t":"and","l":{"t":"def","m":"RENDERER_HAS_NORMAL"},"r":{"t":"def","m":"RENDERER_HAS_TANGENT"}},"r":{"t":"or","l":{"t":"def","m":"MATERIAL_HAS_NORMALTEXTURE"},"r":{"t":"def","m":"MATERIAL_HAS_CLEAR_COAT_NORMAL_TEXTURE"}}},10],[0,"\n\n"],[7,"NEED_VERTEX_TANGENT"],[0,"\n\n"],[6],[0,"\n\n"],[4,{"t":"or","l":{"t":"or","l":{"t":"def","m":"MATERIAL_HAS_NORMALTEXTURE"},"r":{"t":"def","m":"MATERIAL_HAS_CLEAR_COAT_NORMAL_TEXTURE"}},"r":{"t":"def","m":"MATERIAL_ENABLE_ANISOTROPY"}},16],[0,"\n\n"],[7,"NEED_TANGENT_SPACE"],[0,"\n\n"],[6],[0,"\n\n"],[2,"COMMON_INCLUDED",46],[0,"\n\n"],[7,"COMMON_INCLUDED"],[0,"\n\n"],[8,"PI","3.14159265359"],[0,"\n\n"],[8,"RECIPROCAL_PI","0.31830988618"],[0,"\n\n"],[8,"EPSILON","1e-6"],[0,"\n\n"],[8,"LOG2","1.442695"],[0,"\n\n"],[8,"HALF_MIN","6.103515625e-5"],[0,"\n\n"],[8,"HALF_EPS","4.8828125e-4"],[0,"\n\n"],[9,"saturate",["a"],"clamp ( a , 0.0 , 1.0 )"],[0,"\n\n"],[1,"GRAPHICS_API_WEBGL2",40],[0,"\n\n"],[9,"INVERSE_MAT",["mat"],"inverse ( mat )"],[0,"\n\n"],[5,44],[0,"\nmat2 inverseMat ( mat2 m ) { return mat2 ( m[1][1] , - m[0][1] , - m[1][0] , m[0][0] ) / ( m[0][0] * m[1][1] - m[0][1] * m[1][0] ) ; }\nmat3 inverseMat ( mat3 m ) { float a00 = m[0][0] , a01 = m[0][1] , a02 = m[0][2] ;\nfloat a10 = m[1][0] , a11 = m[1][1] , a12 = m[1][2] ;\nfloat a20 = m[2][0] , a21 = m[2][1] , a22 = m[2][2] ;\nfloat b01 = a22 * a11 - a12 * a21 ;\nfloat b11 = - a22 * a10 + a12 * a20 ;\nfloat b21 = a21 * a10 - a11 * a20 ;\nfloat det = a00 * b01 + a01 * b11 + a02 * b21 ;\nreturn mat3 ( b01 , ( - a22 * a01 + a02 * a21 ) , ( a12 * a01 - a02 * a11 ) , b11 , ( a22 * a00 - a02 * a20 ) , ( - a12 * a00 + a02 * a10 ) , b21 , ( - a21 * a00 + a01 * a20 ) , ( a11 * a00 - a01 * a10 ) ) / det ; }\nmat4 inverseMat ( mat4 m ) { float a00 = m[0][0] , a01 = m[0][1] , a02 = m[0][2] , a03 = m[0][3] , a10 = m[1][0] , a11 = m[1][1] , a12 = m[1][2] , a13 = m[1][3] , a20 = m[2][0] , a21 = m[2][1] , a22 = m[2][2] , a23 = m[2][3] , a30 = m[3][0] , a31 = m[3][1] , a32 = m[3][2] , a33 = m[3][3] , b00 = a00 * a11 - a01 * a10 , b01 = a00 * a12 - a02 * a10 , b02 = a00 * a13 - a03 * a10 , b03 = a01 * a12 - a02 * a11 , b04 = a01 * a13 - a03 * a11 , b05 = a02 * a13 - a03 * a12 , b06 = a20 * a31 - a21 * a30 , b07 = a20 * a32 - a22 * a30 , b08 = a20 * a33 - a23 * a30 , b09 = a21 * a32 - a22 * a31 , b10 = a21 * a33 - a23 * a31 , b11 = a22 * a33 - a23 * a32 , det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06 ;\nreturn mat4 ( a11 * b11 - a12 * b10 + a13 * b09 , a02 * b10 - a01 * b11 - a03 * b09 , a31 * b05 - a32 * b04 + a33 * b03 , a22 * b04 - a21 * b05 - a23 * b03 , a12 * b08 - a10 * b11 - a13 * b07 , a00 * b11 - a02 * b08 + a03 * b07 , a32 * b02 - a30 * b05 - a33 * b01 , a20 * b05 - a22 * b02 + a23 * b01 , a10 * b10 - a11 * b08 + a13 * b06 , a01 * b08 - a00 * b10 - a03 * b06 , a30 * b04 - a31 * b02 + a33 * b00 , a21 * b02 - a20 * b04 - a23 * b00 , a11 * b07 - a10 * b09 - a12 * b06 , a00 * b09 - a01 * b07 + a02 * b06 , a31 * b01 - a30 * b03 - a32 * b00 , a20 * b03 - a21 * b01 + a22 * b00 ) / det ; }\n\n"],[9,"INVERSE_MAT",["mat"],"inverseMat(mat)"],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[2,"FOG_INCLUDED",56],[0,"\n\n"],[7,"FOG_INCLUDED"],[0,"\n\n"],[3,"SCENE_FOG_MODE","!=",0,54],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[2,"TRANSFORM_INCLUDED",62],[0,"\n\n"],[7,"TRANSFORM_INCLUDED"],[0,"\nuniform mat4 renderer_ModelMat;\nuniform mat4 renderer_MVMat;\nuniform mat4 renderer_MVPMat;\nuniform mat4 renderer_NormalMat;\n\n"],[6],[0,"\n\n"],[2,"ATTRIBUTES_INCLUDED",120],[0,"\n\n"],[7,"ATTRIBUTES_INCLUDED"],[0,"\nattribute vec3 POSITION;\n\n"],[1,"RENDERER_HAS_BLENDSHAPE",94],[0,"\n"],[2,"RENDERER_BLENDSHAPE_USE_TEXTURE",92],[0,"attribute vec3 POSITION_BS0;\nattribute vec3 POSITION_BS1;\n\n"],[4,{"t":"and","l":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_NORMAL"},"r":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_TANGENT"}},74],[0,"attribute vec3 NORMAL_BS0;\nattribute vec3 NORMAL_BS1;\nattribute vec3 TANGENT_BS0;\nattribute vec3 TANGENT_BS1;\n\n"],[5,90],[0,"\n"],[4,{"t":"or","l":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_NORMAL"},"r":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_TANGENT"}},86],[0,"attribute vec3 POSITION_BS2;\nattribute vec3 POSITION_BS3;\n\n"],[1,"RENDERER_BLENDSHAPE_HAS_NORMAL",80],[0,"attribute vec3 NORMAL_BS0;\nattribute vec3 NORMAL_BS1;\nattribute vec3 NORMAL_BS2;\nattribute vec3 NORMAL_BS3;\n\n"],[6],[0,"\n"],[1,"RENDERER_BLENDSHAPE_HAS_TANGENT",84],[0,"attribute vec3 TANGENT_BS0;\nattribute vec3 TANGENT_BS1;\nattribute vec3 TANGENT_BS2;\nattribute vec3 TANGENT_BS3;\n\n"],[6],[0,"\n"],[5,88],[0,"attribute vec3 POSITION_BS2;\nattribute vec3 POSITION_BS3;\nattribute vec3 POSITION_BS4;\nattribute vec3 POSITION_BS5;\nattribute vec3 POSITION_BS6;\nattribute vec3 POSITION_BS7;\n\n"],[6],[0,"\n"],[6],[0,"\n"],[6],[0,"\n"],[6],[0,"\n"],[1,"RENDERER_HAS_UV",98],[0,"attribute vec2 TEXCOORD_0;\n\n"],[6],[0,"\n"],[1,"RENDERER_HAS_UV1",102],[0,"attribute vec2 TEXCOORD_1;\n\n"],[6],[0,"\n"],[1,"RENDERER_HAS_SKIN",106],[0,"attribute vec4 JOINTS_0;\nattribute vec4 WEIGHTS_0;\n\n"],[6],[0,"\n"],[1,"RENDERER_ENABLE_VERTEXCOLOR",110],[0,"attribute vec4 COLOR_0;\n\n"],[6],[0,"\n"],[1,"RENDERER_HAS_NORMAL",114],[0,"attribute vec3 NORMAL;\n\n"],[6],[0,"\n"],[1,"RENDERER_HAS_TANGENT",118],[0,"attribute vec4 TANGENT;\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[2,"SKIN_INCLUDED",142],[0,"\n\n"],[7,"SKIN_INCLUDED"],[0,"\n\n"],[1,"RENDERER_HAS_SKIN",140],[0,"\n\n"],[1,"RENDERER_USE_JOINT_TEXTURE",130],[0,"\nuniform sampler2D renderer_JointSampler;\nuniform float renderer_JointCount;\nmat4 getJointMatrix ( sampler2D smp, float index ) { float base = index / renderer_JointCount ;\nfloat hf = 0.5 / renderer_JointCount ;\nfloat v = base + hf ;\nvec4 m0 = texture2D ( smp , vec2 ( 0.125 , v ) ) ;\nvec4 m1 = texture2D ( smp , vec2 ( 0.375 , v ) ) ;\nvec4 m2 = texture2D ( smp , vec2 ( 0.625 , v ) ) ;\nvec4 m3 = texture2D ( smp , vec2 ( 0.875 , v ) ) ;\nreturn mat4 ( m0 , m1 , m2 , m3 ) ; }\n\n"],[5,132],[0,"\nuniform mat4 renderer_JointMatrix [ RENDERER_JOINTS_NUM ];\n\n"],[6],[0,"\nmat4 getSkinMatrix ( ) { \n"],[1,"RENDERER_USE_JOINT_TEXTURE",136],[0," mat4 skinMatrix = WEIGHTS_0.x * getJointMatrix(renderer_JointSampler, JOINTS_0.x) + WEIGHTS_0.y * getJointMatrix(renderer_JointSampler, JOINTS_0.y) + WEIGHTS_0.z * getJointMatrix(renderer_JointSampler, JOINTS_0.z) + WEIGHTS_0.w * getJointMatrix(renderer_JointSampler, JOINTS_0.w) ; \n"],[5,138],[0," mat4 skinMatrix = WEIGHTS_0.x * renderer_JointMatrix[int ( JOINTS_0.x )] + WEIGHTS_0.y * renderer_JointMatrix[int ( JOINTS_0.y )] + WEIGHTS_0.z * renderer_JointMatrix[int ( JOINTS_0.z )] + WEIGHTS_0.w * renderer_JointMatrix[int ( JOINTS_0.w )] ; \n"],[6],[0,"\nreturn skinMatrix ; }\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[2,"BLENDSHAPE_INCLUDED",220],[0,"\n\n"],[7,"BLENDSHAPE_INCLUDED"],[0,"\n\n"],[1,"RENDERER_HAS_BLENDSHAPE",218],[0,"\n\n"],[1,"RENDERER_BLENDSHAPE_USE_TEXTURE",152],[0,"\nuniform mediump sampler2DArray renderer_BlendShapeTexture;\nuniform ivec3 renderer_BlendShapeTextureInfo;\nuniform float renderer_BlendShapeWeights [ RENDERER_BLENDSHAPE_COUNT ];\nvec3 getBlendShapeVertexElement ( int blendShapeIndex, int vertexElementIndex ) { int y = vertexElementIndex / renderer_BlendShapeTextureInfo.y ;\nint x = vertexElementIndex - y * renderer_BlendShapeTextureInfo.y ;\nivec3 uv = ivec3 ( x , y , blendShapeIndex ) ;\nreturn ( texelFetch ( renderer_BlendShapeTexture , uv , 0 ) ).xyz ; }\n\n"],[5,166],[0,"\n\n"],[4,{"t":"and","l":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_NORMAL"},"r":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_TANGENT"}},156],[0,"\nuniform float renderer_BlendShapeWeights [ 2 ];\n\n"],[5,164],[0,"\n\n"],[4,{"t":"or","l":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_NORMAL"},"r":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_TANGENT"}},160],[0,"\nuniform float renderer_BlendShapeWeights [ 4 ];\n\n"],[5,162],[0,"\nuniform float renderer_BlendShapeWeights [ 8 ];\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\nvoid calculateBlendShape ( inout vec4 position\n"],[1,"RENDERER_HAS_NORMAL",174],[0," , inout vec3 normal \n"],[1,"RENDERER_HAS_TANGENT",172],[0," , inout vec4 tangent \n"],[6],[0," \n"],[6],[0," ) { \n"],[1,"RENDERER_BLENDSHAPE_USE_TEXTURE",186],[0," int vertexOffset = gl_VertexID * renderer_BlendShapeTextureInfo.x ;\nfor ( int i = 0 ; i < RENDERER_BLENDSHAPE_COUNT ; i ++ ) { int vertexElementOffset = vertexOffset ;\nfloat weight = renderer_BlendShapeWeights[i] ;\nif ( weight != 0.0 ) { position.xyz += getBlendShapeVertexElement(i, vertexElementOffset) * weight ;\n\n"],[4,{"t":"and","l":{"t":"def","m":"RENDERER_HAS_NORMAL"},"r":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_NORMAL"}},180],[0," vertexElementOffset += 1 ;\nnormal += getBlendShapeVertexElement(i, vertexElementOffset) * weight ; \n"],[6],[0,"\n\n"],[4,{"t":"and","l":{"t":"def","m":"RENDERER_HAS_TANGENT"},"r":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_TANGENT"}},184],[0," vertexElementOffset += 1 ;\ntangent.xyz += getBlendShapeVertexElement(i, vertexElementOffset) * weight ; \n"],[6],[0," } } \n"],[5,216],[0," position.xyz += POSITION_BS0 * renderer_BlendShapeWeights[0] ;\nposition.xyz += POSITION_BS1 * renderer_BlendShapeWeights[1] ;\n\n"],[4,{"t":"and","l":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_NORMAL"},"r":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_TANGENT"}},198],[0," \n"],[1,"RENDERER_HAS_NORMAL",192],[0," normal += NORMAL_BS0 * renderer_BlendShapeWeights[0] ;\nnormal += NORMAL_BS1 * renderer_BlendShapeWeights[1] ; \n"],[6],[0,"\n\n"],[1,"RENDERER_HAS_TANGENT",196],[0," tangent.xyz += TANGENT_BS0 * renderer_BlendShapeWeights[0] ;\ntangent.xyz += TANGENT_BS1 * renderer_BlendShapeWeights[1] ; \n"],[6],[0," \n"],[5,214],[0," \n"],[4,{"t":"or","l":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_NORMAL"},"r":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_TANGENT"}},210],[0," position.xyz += POSITION_BS2 * renderer_BlendShapeWeights[2] ;\nposition.xyz += POSITION_BS3 * renderer_BlendShapeWeights[3] ;\n\n"],[4,{"t":"and","l":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_NORMAL"},"r":{"t":"def","m":"RENDERER_HAS_NORMAL"}},204],[0," normal += NORMAL_BS0 * renderer_BlendShapeWeights[0] ;\nnormal += NORMAL_BS1 * renderer_BlendShapeWeights[1] ;\nnormal += NORMAL_BS2 * renderer_BlendShapeWeights[2] ;\nnormal += NORMAL_BS3 * renderer_BlendShapeWeights[3] ; \n"],[6],[0,"\n\n"],[4,{"t":"and","l":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_TANGENT"},"r":{"t":"def","m":"RENDERER_HAS_TANGENT"}},208],[0," tangent.xyz += TANGENT_BS0 * renderer_BlendShapeWeights[0] ;\ntangent.xyz += TANGENT_BS1 * renderer_BlendShapeWeights[1] ;\ntangent.xyz += TANGENT_BS2 * renderer_BlendShapeWeights[2] ;\ntangent.xyz += TANGENT_BS3 * renderer_BlendShapeWeights[3] ; \n"],[6],[0," \n"],[5,212],[0," position.xyz += POSITION_BS2 * renderer_BlendShapeWeights[2] ;\nposition.xyz += POSITION_BS3 * renderer_BlendShapeWeights[3] ;\nposition.xyz += POSITION_BS4 * renderer_BlendShapeWeights[4] ;\nposition.xyz += POSITION_BS5 * renderer_BlendShapeWeights[5] ;\nposition.xyz += POSITION_BS6 * renderer_BlendShapeWeights[6] ;\nposition.xyz += POSITION_BS7 * renderer_BlendShapeWeights[7] ; \n"],[6],[0," \n"],[6],[0," \n"],[6],[0," }\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[2,"SHADOW_INCLUDED",300],[0,"\n\n"],[7,"SHADOW_INCLUDED"],[0,"\n\n"],[4,{"t":"and","l":{"t":"def","m":"SCENE_SHADOW_TYPE"},"r":{"t":"def","m":"RENDERER_IS_RECEIVE_SHADOWS"}},230],[0,"\n\n"],[7,"NEED_CALCULATE_SHADOWS"],[0,"\n\n"],[6],[0,"\n\n"],[1,"NEED_CALCULATE_SHADOWS",258],[0,"\nuniform mat4 scene_ShadowMatrices [ SCENE_SHADOW_CASCADED_COUNT + 1 ];\nuniform vec4 scene_ShadowSplitSpheres [ 4 ];\nmediump int computeCascadeIndex ( vec3 positionWS ) { vec3 fromCenter0 = positionWS - scene_ShadowSplitSpheres[0].xyz ;\nvec3 fromCenter1 = positionWS - scene_ShadowSplitSpheres[1].xyz ;\nvec3 fromCenter2 = positionWS - scene_ShadowSplitSpheres[2].xyz ;\nvec3 fromCenter3 = positionWS - scene_ShadowSplitSpheres[3].xyz ;\nmediump vec4 comparison = vec4 ( ( dot ( fromCenter0 , fromCenter0 ) < scene_ShadowSplitSpheres[0].w ) , ( dot ( fromCenter1 , fromCenter1 ) < scene_ShadowSplitSpheres[1].w ) , ( dot ( fromCenter2 , fromCenter2 ) < scene_ShadowSplitSpheres[2].w ) , ( dot ( fromCenter3 , fromCenter3 ) < scene_ShadowSplitSpheres[3].w ) ) ;\ncomparison.yzw = clamp ( comparison.yzw - comparison.xyz , 0.0 , 1.0 ) ;\nmediump vec4 indexCoefficient = vec4 ( 4.0 , 3.0 , 2.0 , 1.0 ) ;\nmediump int index = 4 - int ( dot ( comparison , indexCoefficient ) ) ;\nreturn index ; }\nvec3 getShadowCoord ( vec3 positionWS ) { \n"],[3,"SCENE_SHADOW_CASCADED_COUNT","==",1,236],[0," mediump int cascadeIndex = 0 ; \n"],[5,238],[0," mediump int cascadeIndex = computeCascadeIndex(positionWS) ; \n"],[6],[0,"\n\n"],[1,"GRAPHICS_API_WEBGL2",242],[0," mat4 shadowMatrix = scene_ShadowMatrices[cascadeIndex] ; \n"],[5,256],[0," mat4 shadowMatrix ;\n\n"],[3,"SCENE_SHADOW_CASCADED_COUNT","==",4,246],[0," if ( cascadeIndex == 0 ) { shadowMatrix = scene_ShadowMatrices[0] ; } else if ( cascadeIndex == 1 ) { shadowMatrix = scene_ShadowMatrices[1] ; } else if ( cascadeIndex == 2 ) { shadowMatrix = scene_ShadowMatrices[2] ; } else if ( cascadeIndex == 3 ) { shadowMatrix = scene_ShadowMatrices[3] ; } else { shadowMatrix = scene_ShadowMatrices[4] ; } \n"],[6],[0,"\n\n"],[3,"SCENE_SHADOW_CASCADED_COUNT","==",2,250],[0," if ( cascadeIndex == 0 ) { shadowMatrix = scene_ShadowMatrices[0] ; } else if ( cascadeIndex == 1 ) { shadowMatrix = scene_ShadowMatrices[1] ; } else { shadowMatrix = scene_ShadowMatrices[2] ; } \n"],[6],[0,"\n\n"],[3,"SCENE_SHADOW_CASCADED_COUNT","==",1,254],[0," if ( cascadeIndex == 0 ) { shadowMatrix = scene_ShadowMatrices[0] ; } else { shadowMatrix = scene_ShadowMatrices[1] ; } \n"],[6],[0," \n"],[6],[0,"\nvec4 shadowCoord = shadowMatrix * vec4 ( positionWS , 1.0 ) ;\nreturn shadowCoord.xyz ; }\n\n"],[6],[0,"\n\n"],[1,"NEED_CALCULATE_SHADOWS",298],[0,"\n\n"],[1,"GRAPHICS_API_WEBGL2",268],[0,"\n\n"],[9,"SAMPLE_TEXTURE2D_SHADOW",["textureName","coord3"],"textureLod ( textureName , coord3 , 0.0 )"],[0,"\n\n"],[9,"TEXTURE2D_SHADOW_PARAM",["shadowMap"],"mediump sampler2DShadow shadowMap"],[0,"\n\n"],[5,282],[0,"\n\n"],[1,"ENGINE_NO_DEPTH_TEXTURE",274],[0,"\nconst vec4 bitShift = vec4 ( 1.0 , 1.0 / 256.0 , 1.0 / ( 256.0 * 256.0 ) , 1.0 / ( 256.0 * 256.0 * 256.0 ) );\nfloat textureShadowMapDowngrade ( sampler2D scene_ShadowMap, vec3 shadowCoord ) { vec4 rgbaDepth = texture2D ( scene_ShadowMap , shadowCoord.xy ) ;\nfloat unpackDepth = dot ( rgbaDepth , bitShift ) ;\nreturn unpackDepth < shadowCoord.z ? 0.0 : 1.0 ; }\n\n"],[9,"SAMPLE_TEXTURE2D_SHADOW",["textureName","coord3"],"textureShadowMapDowngrade(textureName, coord3)"],[0,"\n\n"],[5,278],[0,"\nfloat textureShadowMapDowngrade ( sampler2D scene_ShadowMap, vec3 shadowCoord ) { float depth = texture2D ( scene_ShadowMap , shadowCoord.xy ).r ;\nreturn depth < shadowCoord.z ? 0.0 : 1.0 ; }\n\n"],[9,"SAMPLE_TEXTURE2D_SHADOW",["textureName","coord3"],"textureShadowMapDowngrade(textureName, coord3)"],[0,"\n\n"],[6],[0,"\n\n"],[9,"TEXTURE2D_SHADOW_PARAM",["shadowMap"],"mediump sampler2D shadowMap"],[0,"\n\n"],[6],[0,"\n\n"],[3,"SCENE_SHADOW_TYPE","==",2,286],[0,"\n\n"],[6],[0,"\n\n"],[3,"SCENE_SHADOW_TYPE","==",3,296],[0,"\n\n"],[2,"SHADOW_SAMPLE_TENT_INCLUDED",294],[0,"\n\n"],[7,"SHADOW_SAMPLE_TENT_INCLUDED"],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[2,"VARYINGS_PBR_INCLUDED",330],[0,"\n\n"],[7,"VARYINGS_PBR_INCLUDED"],[0,"\nvarying vec2 uv;\n\n"],[1,"RENDERER_HAS_UV1",308],[0,"varying vec2 uv1;\n\n"],[6],[0,"\n"],[1,"RENDERER_ENABLE_VERTEXCOLOR",312],[0,"varying vec4 vertexColor;\n\n"],[6],[0,"varying vec3 positionWS;\n\n"],[3,"SCENE_FOG_MODE","!=",0,316],[0,"varying vec3 positionVS;\n\n"],[6],[0,"\n"],[1,"RENDERER_HAS_NORMAL",324],[0,"varying vec3 normalWS;\n\n"],[1,"NEED_VERTEX_TANGENT",322],[0,"varying vec3 tangentWS;\nvarying vec3 bitangentWS;\n\n"],[6],[0,"\n"],[6],[0,"\n"],[4,{"t":"and","l":{"t":"def","m":"NEED_CALCULATE_SHADOWS"},"r":{"t":"cmp","m":"SCENE_SHADOW_CASCADED_COUNT","op":"==","v":1}},328],[0,"varying vec3 shadowCoord;\n\n"],[6],[0,"varying vec4 positionCS;\n\n\n"],[6],[0,"\n\n"],[2,"LIGHT_DIRECT_PBR_INCLUDED",478],[0,"\n\n"],[7,"LIGHT_DIRECT_PBR_INCLUDED"],[0,"\n\n"],[2,"FUNCTION_SURFACE_SHADING",340],[0,"\n\n"],[8,"FUNCTION_SURFACE_SHADING","surfaceShading"],[0,"\n\n"],[6],[0,"\n\n"],[2,"FUNCTION_DIFFUSE_LOBE",346],[0,"\n\n"],[8,"FUNCTION_DIFFUSE_LOBE","diffuseLobe"],[0,"\n\n"],[6],[0,"\n\n"],[2,"FUNCTION_SPECULAR_LOBE",352],[0,"\n\n"],[8,"FUNCTION_SPECULAR_LOBE","specularLobe"],[0,"\n\n"],[6],[0,"\n\n"],[2,"FUNCTION_CLEAR_COAT_LOBE",358],[0,"\n\n"],[8,"FUNCTION_CLEAR_COAT_LOBE","clearCoatLobe"],[0,"\n\n"],[6],[0,"\n\n"],[2,"FUNCTION_SHEEN_LOBE",364],[0,"\n\n"],[8,"FUNCTION_SHEEN_LOBE","sheenLobe"],[0,"\n\n"],[6],[0,"\n\n"],[2,"BSDF_INCLUDED",416],[0,"\n\n"],[7,"BSDF_INCLUDED"],[0,"\n\n"],[2,"REFRACTION_INCLUDED",378],[0,"\n\n"],[7,"REFRACTION_INCLUDED"],[0,"\n\n"],[1,"MATERIAL_ENABLE_TRANSMISSION",376],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[8,"MIN_PERCEPTUAL_ROUGHNESS","0.045"],[0,"\n\n"],[8,"MIN_ROUGHNESS","0.002025"],[0,"\n\n"],[1,"MATERIAL_ENABLE_SHEEN",386],[0,"\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_ENABLE_ANISOTROPY",390],[0,"\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_ENABLE_ANISOTROPY",394],[0,"\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_ENABLE_ANISOTROPY",398],[0,"\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_ENABLE_IRIDESCENCE",402],[0,"\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_ENABLE_SHEEN",406],[0,"\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_ENABLE_TRANSMISSION",410],[0,"\n\n"],[6],[0,"\n\n"],[1,"SCENE_ENABLE_AMBIENT_OCCLUSION",414],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[2,"LIGHT_INCLUDED",458],[0,"\n\n"],[7,"LIGHT_INCLUDED"],[0,"\n\n"],[2,"GRAPHICS_API_WEBGL2",424],[0,"\n\n"],[6],[0,"\n\n"],[1,"SCENE_DIRECT_LIGHT_COUNT",432],[0,"\n\n"],[1,"GRAPHICS_API_WEBGL2",430],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[1,"SCENE_POINT_LIGHT_COUNT",440],[0,"\n\n"],[1,"GRAPHICS_API_WEBGL2",438],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[1,"SCENE_SPOT_LIGHT_COUNT",448],[0,"\n\n"],[1,"GRAPHICS_API_WEBGL2",446],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[1,"SCENE_USE_SH",452],[0,"\n\n"],[6],[0,"\n\n"],[1,"SCENE_USE_SPECULAR_ENV",456],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[2,"REFLECTION_LOBE_INCLUDED",464],[0,"\n\n"],[7,"REFLECTION_LOBE_INCLUDED"],[0,"\n\n"],[6],[0,"\n\n"],[1,"SCENE_DIRECT_LIGHT_COUNT",468],[0,"\n\n"],[6],[0,"\n\n"],[1,"SCENE_POINT_LIGHT_COUNT",472],[0,"\n\n"],[6],[0,"\n\n"],[1,"SCENE_SPOT_LIGHT_COUNT",476],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[2,"LIGHT_INDIRECT_PBR_INCLUDED",514],[0,"\n\n"],[7,"LIGHT_INDIRECT_PBR_INCLUDED"],[0,"\n\n"],[2,"FUNCTION_DIFFUSE_IBL",488],[0,"\n\n"],[8,"FUNCTION_DIFFUSE_IBL","evaluateDiffuseIBL"],[0,"\n\n"],[6],[0,"\n\n"],[2,"FUNCTION_SPECULAR_IBL",494],[0,"\n\n"],[8,"FUNCTION_SPECULAR_IBL","evaluateSpecularIBL"],[0,"\n\n"],[6],[0,"\n\n"],[2,"FUNCTION_CLEAR_COAT_IBL",500],[0,"\n\n"],[8,"FUNCTION_CLEAR_COAT_IBL","evaluateClearCoatIBL"],[0,"\n\n"],[6],[0,"\n\n"],[2,"FUNCTION_SHEEN_IBL",506],[0,"\n\n"],[8,"FUNCTION_SHEEN_IBL","evaluateSheenIBL"],[0,"\n\n"],[6],[0,"\n\n"],[2,"LIGHT_INDIRECT_FUNCTIONS_INCLUDED",512],[0,"\n\n"],[7,"LIGHT_INDIRECT_FUNCTIONS_INCLUDED"],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[2,"VERTEX_INCLUDE",580],[0,"\n\n"],[7,"VERTEX_INCLUDE"],[0,"\nstruct VertexInputs { vec4 positionOS ; vec3 positionWS ; \n"],[3,"SCENE_FOG_MODE","!=",0,522],[0," vec3 positionVS ; \n"],[6],[0," \n"],[1,"RENDERER_HAS_NORMAL",530],[0," vec3 normalWS ; \n"],[1,"NEED_VERTEX_TANGENT",528],[0," vec3 tangentWS ; vec3 bitangentWS ; \n"],[6],[0," \n"],[6],[0," } ;\nuniform vec4 material_TilingOffset;\nvec2 getUV0 ( ) { vec2 uv0 = vec2 ( 0 ) ;\n\n"],[1,"RENDERER_HAS_UV",534],[0," uv0 = TEXCOORD_0 ; \n"],[6],[0,"\nreturn uv0 * material_TilingOffset.xy + material_TilingOffset.zw ; }\nVertexInputs getVertexInputs ( ) { VertexInputs inputs ;\nvec4 position = vec4 ( POSITION , 1.0 ) ;\n\n"],[1,"RENDERER_HAS_NORMAL",542],[0," vec3 normal = vec3 ( NORMAL ) ;\n\n"],[1,"RENDERER_HAS_TANGENT",540],[0," vec4 tangent = vec4 ( TANGENT ) ; \n"],[6],[0," \n"],[6],[0,"\n\n"],[1,"RENDERER_HAS_BLENDSHAPE",554],[0," calculateBlendShape(position\n"],[1,"RENDERER_HAS_NORMAL",552],[0," , normal \n"],[1,"RENDERER_HAS_TANGENT",550],[0," , tangent \n"],[6],[0," \n"],[6],[0,") ; \n"],[6],[0,"\n\n"],[1,"RENDERER_HAS_SKIN",566],[0," mat4 skinMatrix = getSkinMatrix() ;\nposition = skinMatrix * position ;\n\n"],[4,{"t":"and","l":{"t":"def","m":"RENDERER_HAS_NORMAL"},"r":{"t":"not","c":{"t":"def","m":"MATERIAL_OMIT_NORMAL"}}},564],[0," mat3 skinNormalMatrix = INVERSE_MAT(mat3 ( skinMatrix )) ;\nnormal = normal * skinNormalMatrix ;\n\n"],[1,"NEED_VERTEX_TANGENT",562],[0," tangent.xyz = tangent.xyz * skinNormalMatrix ; \n"],[6],[0," \n"],[6],[0," \n"],[6],[0,"\n\n"],[4,{"t":"and","l":{"t":"def","m":"RENDERER_HAS_NORMAL"},"r":{"t":"not","c":{"t":"def","m":"MATERIAL_OMIT_NORMAL"}}},574],[0," inputs.normalWS = normalize ( mat3 ( renderer_NormalMat ) * normal ) ;\n\n"],[1,"NEED_VERTEX_TANGENT",572],[0," vec3 tangentWS = normalize ( mat3 ( renderer_NormalMat ) * tangent.xyz ) ;\nvec3 bitangentWS = cross ( inputs.normalWS , tangentWS ) * tangent.w ;\ninputs.tangentWS = tangentWS ;\ninputs.bitangentWS = bitangentWS ; \n"],[6],[0," \n"],[6],[0,"\ninputs.positionOS = position ;\nvec4 positionWS = renderer_ModelMat * position ;\ninputs.positionWS = positionWS.xyz / positionWS.w ;\n\n"],[3,"SCENE_FOG_MODE","!=",0,578],[0," vec4 positionVS = renderer_MVMat * position ;\ninputs.positionVS = positionVS.xyz / positionVS.w ; \n"],[6],[0,"\nreturn inputs ; }\n\n"],[6],[0,"\n\n"],[2,"MATERIAL_INPUT_PBR_INCLUDED",688],[0,"\n\n"],[7,"MATERIAL_INPUT_PBR_INCLUDED"],[0,"\n\n"],[2,"NORMAL_INCLUDED",590],[0,"\n\n"],[7,"NORMAL_INCLUDED"],[0,"\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_HAS_SPECULAR_TEXTURE",594],[0,"\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_HAS_SPECULAR_COLOR_TEXTURE",598],[0,"\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_ENABLE_CLEAR_COAT",614],[0,"\n\n"],[1,"MATERIAL_HAS_CLEAR_COAT_TEXTURE",604],[0,"\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_HAS_CLEAR_COAT_ROUGHNESS_TEXTURE",608],[0,"\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_HAS_CLEAR_COAT_NORMAL_TEXTURE",612],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_ENABLE_ANISOTROPY",622],[0,"\n\n"],[1,"MATERIAL_HAS_ANISOTROPY_TEXTURE",620],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_ENABLE_IRIDESCENCE",634],[0,"\n\n"],[1,"MATERIAL_HAS_IRIDESCENCE_THICKNESS_TEXTURE",628],[0,"\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_HAS_IRIDESCENCE_TEXTURE",632],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_ENABLE_SHEEN",646],[0,"\n\n"],[1,"MATERIAL_HAS_SHEEN_TEXTURE",640],[0,"\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_HAS_SHEEN_ROUGHNESS_TEXTURE",644],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_ENABLE_TRANSMISSION",662],[0,"\n\n"],[1,"MATERIAL_HAS_TRANSMISSION_TEXTURE",652],[0,"\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_HAS_THICKNESS",660],[0,"\n\n"],[1,"MATERIAL_HAS_THICKNESS_TEXTURE",658],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_HAS_BASETEXTURE",666],[0,"\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_HAS_NORMALTEXTURE",670],[0,"\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_HAS_EMISSIVETEXTURE",674],[0,"\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_HAS_ROUGHNESS_METALLIC_TEXTURE",678],[0,"\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_HAS_OCCLUSION_TEXTURE",682],[0,"\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_ENABLE_ANISOTROPY",686],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\nvoid main() { \nuv = getUV0() ;\n\n"],[1,"RENDERER_HAS_UV1",692],[0," uv1 = TEXCOORD_1 ; \n"],[6],[0,"\n\n"],[1,"RENDERER_ENABLE_VERTEXCOLOR",696],[0," vertexColor = COLOR_0 ; \n"],[6],[0,"\nVertexInputs vertexInputs = getVertexInputs() ;\npositionWS = vertexInputs.positionWS ;\n\n"],[3,"SCENE_FOG_MODE","!=",0,700],[0," positionVS = vertexInputs.positionVS ; \n"],[6],[0,"\n\n"],[1,"RENDERER_HAS_NORMAL",708],[0," normalWS = vertexInputs.normalWS ;\n\n"],[1,"NEED_VERTEX_TANGENT",706],[0," tangentWS = vertexInputs.tangentWS ;\nbitangentWS = vertexInputs.bitangentWS ; \n"],[6],[0," \n"],[6],[0,"\n\n"],[4,{"t":"and","l":{"t":"def","m":"NEED_CALCULATE_SHADOWS"},"r":{"t":"cmp","m":"SCENE_SHADOW_CASCADED_COUNT","op":"==","v":1}},712],[0," shadowCoord = getShadowCoord(vertexInputs.positionWS) ; \n"],[6],[0,"\ngl_Position = renderer_MVPMat * vertexInputs.positionOS ;\npositionCS = gl_Position ;\n }\n\n"],[6]],"fragmentShaderInstructions":[[0,"\n"],[2,"FORWARD_PASS_PBR_INCLUDED",896],[0,"\n\n"],[7,"FORWARD_PASS_PBR_INCLUDED"],[0,"\n\n"],[4,{"t":"and","l":{"t":"and","l":{"t":"def","m":"RENDERER_HAS_NORMAL"},"r":{"t":"def","m":"RENDERER_HAS_TANGENT"}},"r":{"t":"or","l":{"t":"def","m":"MATERIAL_HAS_NORMALTEXTURE"},"r":{"t":"def","m":"MATERIAL_HAS_CLEAR_COAT_NORMAL_TEXTURE"}}},10],[0,"\n\n"],[7,"NEED_VERTEX_TANGENT"],[0,"\n\n"],[6],[0,"\n\n"],[4,{"t":"or","l":{"t":"or","l":{"t":"def","m":"MATERIAL_HAS_NORMALTEXTURE"},"r":{"t":"def","m":"MATERIAL_HAS_CLEAR_COAT_NORMAL_TEXTURE"}},"r":{"t":"def","m":"MATERIAL_ENABLE_ANISOTROPY"}},16],[0,"\n\n"],[7,"NEED_TANGENT_SPACE"],[0,"\n\n"],[6],[0,"\n\n"],[2,"COMMON_INCLUDED",50],[0,"\n\n"],[7,"COMMON_INCLUDED"],[0,"\n\n"],[8,"PI","3.14159265359"],[0,"\n\n"],[8,"RECIPROCAL_PI","0.31830988618"],[0,"\n\n"],[8,"EPSILON","1e-6"],[0,"\n\n"],[8,"LOG2","1.442695"],[0,"\n\n"],[8,"HALF_MIN","6.103515625e-5"],[0,"\n\n"],[8,"HALF_EPS","4.8828125e-4"],[0,"\n\n"],[9,"saturate",["a"],"clamp ( a , 0.0 , 1.0 )"],[0,"\nfloat pow2 ( float x ) { return x * x ; }\nfloat sRGBToLinear ( float value ) { float linearRGBLo = value / 12.92 ;\nfloat linearRGBHi = pow ( ( value + 0.055 ) / 1.055 , 2.4 ) ;\nfloat linearRGB = ( value <= 0.04045 ) ? linearRGBLo : linearRGBHi ;\nreturn linearRGB ; }\nvec4 sRGBToLinear ( vec4 value ) { return vec4 ( sRGBToLinear(value.r) , sRGBToLinear(value.g) , sRGBToLinear(value.b) , value.a ) ; }\nvec4 texture2DSRGB ( sampler2D tex, vec2 uv ) { vec4 color = texture2D ( tex , uv ) ;\n\n"],[1,"ENGINE_NO_SRGB",38],[0," color = sRGBToLinear(color) ; \n"],[6],[0,"\nreturn color ; }\nuniform vec4 camera_ProjectionParams;\n\n"],[1,"GRAPHICS_API_WEBGL2",44],[0,"\n\n"],[9,"INVERSE_MAT",["mat"],"inverse ( mat )"],[0,"\n\n"],[5,48],[0,"\nmat2 inverseMat ( mat2 m ) { return mat2 ( m[1][1] , - m[0][1] , - m[1][0] , m[0][0] ) / ( m[0][0] * m[1][1] - m[0][1] * m[1][0] ) ; }\nmat3 inverseMat ( mat3 m ) { float a00 = m[0][0] , a01 = m[0][1] , a02 = m[0][2] ;\nfloat a10 = m[1][0] , a11 = m[1][1] , a12 = m[1][2] ;\nfloat a20 = m[2][0] , a21 = m[2][1] , a22 = m[2][2] ;\nfloat b01 = a22 * a11 - a12 * a21 ;\nfloat b11 = - a22 * a10 + a12 * a20 ;\nfloat b21 = a21 * a10 - a11 * a20 ;\nfloat det = a00 * b01 + a01 * b11 + a02 * b21 ;\nreturn mat3 ( b01 , ( - a22 * a01 + a02 * a21 ) , ( a12 * a01 - a02 * a11 ) , b11 , ( a22 * a00 - a02 * a20 ) , ( - a12 * a00 + a02 * a10 ) , b21 , ( - a21 * a00 + a01 * a20 ) , ( a11 * a00 - a01 * a10 ) ) / det ; }\nmat4 inverseMat ( mat4 m ) { float a00 = m[0][0] , a01 = m[0][1] , a02 = m[0][2] , a03 = m[0][3] , a10 = m[1][0] , a11 = m[1][1] , a12 = m[1][2] , a13 = m[1][3] , a20 = m[2][0] , a21 = m[2][1] , a22 = m[2][2] , a23 = m[2][3] , a30 = m[3][0] , a31 = m[3][1] , a32 = m[3][2] , a33 = m[3][3] , b00 = a00 * a11 - a01 * a10 , b01 = a00 * a12 - a02 * a10 , b02 = a00 * a13 - a03 * a10 , b03 = a01 * a12 - a02 * a11 , b04 = a01 * a13 - a03 * a11 , b05 = a02 * a13 - a03 * a12 , b06 = a20 * a31 - a21 * a30 , b07 = a20 * a32 - a22 * a30 , b08 = a20 * a33 - a23 * a30 , b09 = a21 * a32 - a22 * a31 , b10 = a21 * a33 - a23 * a31 , b11 = a22 * a33 - a23 * a32 , det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06 ;\nreturn mat4 ( a11 * b11 - a12 * b10 + a13 * b09 , a02 * b10 - a01 * b11 - a03 * b09 , a31 * b05 - a32 * b04 + a33 * b03 , a22 * b04 - a21 * b05 - a23 * b03 , a12 * b08 - a10 * b11 - a13 * b07 , a00 * b11 - a02 * b08 + a03 * b07 , a32 * b02 - a30 * b05 - a33 * b01 , a20 * b05 - a22 * b02 + a23 * b01 , a10 * b10 - a11 * b08 + a13 * b06 , a01 * b08 - a00 * b10 - a03 * b06 , a30 * b04 - a31 * b02 + a33 * b00 , a21 * b02 - a20 * b04 - a23 * b00 , a11 * b07 - a10 * b09 - a12 * b06 , a00 * b09 - a01 * b07 + a02 * b06 , a31 * b01 - a30 * b03 - a32 * b00 , a20 * b03 - a21 * b01 + a22 * b00 ) / det ; }\n\n"],[9,"INVERSE_MAT",["mat"],"inverseMat(mat)"],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[2,"FOG_INCLUDED",70],[0,"\n\n"],[7,"FOG_INCLUDED"],[0,"\n\n"],[3,"SCENE_FOG_MODE","!=",0,68],[0,"\nuniform vec4 scene_FogColor;\nuniform vec4 scene_FogParams;\nvec4 fog ( vec4 color, vec3 positionVS ) { float fogDepth = length ( positionVS ) ;\n\n"],[3,"SCENE_FOG_MODE","==",1,60],[0," float fogIntensity = clamp ( fogDepth * scene_FogParams.x + scene_FogParams.y , 0.0 , 1.0 ) ; \n"],[5,66],[3,"SCENE_FOG_MODE","==",2,63],[0," float fogIntensity = clamp ( exp2 ( - fogDepth * scene_FogParams.z ) , 0.0 , 1.0 ) ; \n"],[5,66],[3,"SCENE_FOG_MODE","==",3,66],[0," float factor = fogDepth * scene_FogParams.w ;\nfloat fogIntensity = clamp ( exp2 ( - factor * factor ) , 0.0 , 1.0 ) ; \n"],[6],[0,"\ncolor.rgb = mix ( scene_FogColor.rgb , color.rgb , fogIntensity ) ;\nreturn color ; }\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[2,"TRANSFORM_INCLUDED",76],[0,"\n\n"],[7,"TRANSFORM_INCLUDED"],[0,"\nuniform mat4 camera_ViewMat;\nuniform mat4 camera_ProjMat;\nuniform vec3 camera_Position;\nuniform vec3 camera_Forward;\n\n"],[6],[0,"\n\n"],[2,"ATTRIBUTES_INCLUDED",82],[0,"\n\n"],[7,"ATTRIBUTES_INCLUDED"],[0,"\n\n"],[6],[0,"\n\n"],[2,"SKIN_INCLUDED",98],[0,"\n\n"],[7,"SKIN_INCLUDED"],[0,"\n\n"],[1,"RENDERER_HAS_SKIN",96],[0,"\n\n"],[1,"RENDERER_USE_JOINT_TEXTURE",92],[0,"\n\n"],[5,94],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[2,"BLENDSHAPE_INCLUDED",126],[0,"\n\n"],[7,"BLENDSHAPE_INCLUDED"],[0,"\n\n"],[1,"RENDERER_HAS_BLENDSHAPE",124],[0,"\n\n"],[1,"RENDERER_BLENDSHAPE_USE_TEXTURE",108],[0,"\n\n"],[5,122],[0,"\n\n"],[4,{"t":"and","l":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_NORMAL"},"r":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_TANGENT"}},112],[0,"\n\n"],[5,120],[0,"\n\n"],[4,{"t":"or","l":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_NORMAL"},"r":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_TANGENT"}},116],[0,"\n\n"],[5,118],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[2,"SHADOW_INCLUDED",218],[0,"\n\n"],[7,"SHADOW_INCLUDED"],[0,"\n\n"],[4,{"t":"and","l":{"t":"def","m":"SCENE_SHADOW_TYPE"},"r":{"t":"def","m":"RENDERER_IS_RECEIVE_SHADOWS"}},136],[0,"\n\n"],[7,"NEED_CALCULATE_SHADOWS"],[0,"\n\n"],[6],[0,"\n\n"],[1,"NEED_CALCULATE_SHADOWS",164],[0,"\nuniform mat4 scene_ShadowMatrices [ SCENE_SHADOW_CASCADED_COUNT + 1 ];\nuniform vec4 scene_ShadowSplitSpheres [ 4 ];\nmediump int computeCascadeIndex ( vec3 positionWS ) { vec3 fromCenter0 = positionWS - scene_ShadowSplitSpheres[0].xyz ;\nvec3 fromCenter1 = positionWS - scene_ShadowSplitSpheres[1].xyz ;\nvec3 fromCenter2 = positionWS - scene_ShadowSplitSpheres[2].xyz ;\nvec3 fromCenter3 = positionWS - scene_ShadowSplitSpheres[3].xyz ;\nmediump vec4 comparison = vec4 ( ( dot ( fromCenter0 , fromCenter0 ) < scene_ShadowSplitSpheres[0].w ) , ( dot ( fromCenter1 , fromCenter1 ) < scene_ShadowSplitSpheres[1].w ) , ( dot ( fromCenter2 , fromCenter2 ) < scene_ShadowSplitSpheres[2].w ) , ( dot ( fromCenter3 , fromCenter3 ) < scene_ShadowSplitSpheres[3].w ) ) ;\ncomparison.yzw = clamp ( comparison.yzw - comparison.xyz , 0.0 , 1.0 ) ;\nmediump vec4 indexCoefficient = vec4 ( 4.0 , 3.0 , 2.0 , 1.0 ) ;\nmediump int index = 4 - int ( dot ( comparison , indexCoefficient ) ) ;\nreturn index ; }\nvec3 getShadowCoord ( vec3 positionWS ) { \n"],[3,"SCENE_SHADOW_CASCADED_COUNT","==",1,142],[0," mediump int cascadeIndex = 0 ; \n"],[5,144],[0," mediump int cascadeIndex = computeCascadeIndex(positionWS) ; \n"],[6],[0,"\n\n"],[1,"GRAPHICS_API_WEBGL2",148],[0," mat4 shadowMatrix = scene_ShadowMatrices[cascadeIndex] ; \n"],[5,162],[0," mat4 shadowMatrix ;\n\n"],[3,"SCENE_SHADOW_CASCADED_COUNT","==",4,152],[0," if ( cascadeIndex == 0 ) { shadowMatrix = scene_ShadowMatrices[0] ; } else if ( cascadeIndex == 1 ) { shadowMatrix = scene_ShadowMatrices[1] ; } else if ( cascadeIndex == 2 ) { shadowMatrix = scene_ShadowMatrices[2] ; } else if ( cascadeIndex == 3 ) { shadowMatrix = scene_ShadowMatrices[3] ; } else { shadowMatrix = scene_ShadowMatrices[4] ; } \n"],[6],[0,"\n\n"],[3,"SCENE_SHADOW_CASCADED_COUNT","==",2,156],[0," if ( cascadeIndex == 0 ) { shadowMatrix = scene_ShadowMatrices[0] ; } else if ( cascadeIndex == 1 ) { shadowMatrix = scene_ShadowMatrices[1] ; } else { shadowMatrix = scene_ShadowMatrices[2] ; } \n"],[6],[0,"\n\n"],[3,"SCENE_SHADOW_CASCADED_COUNT","==",1,160],[0," if ( cascadeIndex == 0 ) { shadowMatrix = scene_ShadowMatrices[0] ; } else { shadowMatrix = scene_ShadowMatrices[1] ; } \n"],[6],[0," \n"],[6],[0,"\nvec4 shadowCoord = shadowMatrix * vec4 ( positionWS , 1.0 ) ;\nreturn shadowCoord.xyz ; }\n\n"],[6],[0,"\n\n"],[1,"NEED_CALCULATE_SHADOWS",216],[0,"\nuniform vec4 scene_ShadowInfo;\nuniform vec4 scene_ShadowMapSize;\n\n"],[1,"GRAPHICS_API_WEBGL2",174],[0,"\nuniform mediump sampler2DShadow scene_ShadowMap;\n\n"],[9,"SAMPLE_TEXTURE2D_SHADOW",["textureName","coord3"],"textureLod ( textureName , coord3 , 0.0 )"],[0,"\n\n"],[9,"TEXTURE2D_SHADOW_PARAM",["shadowMap"],"mediump sampler2DShadow shadowMap"],[0,"\n\n"],[5,188],[0,"\nuniform sampler2D scene_ShadowMap;\n\n"],[1,"ENGINE_NO_DEPTH_TEXTURE",180],[0,"\nconst vec4 bitShift = vec4 ( 1.0 , 1.0 / 256.0 , 1.0 / ( 256.0 * 256.0 ) , 1.0 / ( 256.0 * 256.0 * 256.0 ) );\nfloat textureShadowMapDowngrade ( sampler2D scene_ShadowMap, vec3 shadowCoord ) { vec4 rgbaDepth = texture2D ( scene_ShadowMap , shadowCoord.xy ) ;\nfloat unpackDepth = dot ( rgbaDepth , bitShift ) ;\nreturn unpackDepth < shadowCoord.z ? 0.0 : 1.0 ; }\n\n"],[9,"SAMPLE_TEXTURE2D_SHADOW",["textureName","coord3"],"textureShadowMapDowngrade(textureName, coord3)"],[0,"\n\n"],[5,184],[0,"\nfloat textureShadowMapDowngrade ( sampler2D scene_ShadowMap, vec3 shadowCoord ) { float depth = texture2D ( scene_ShadowMap , shadowCoord.xy ).r ;\nreturn depth < shadowCoord.z ? 0.0 : 1.0 ; }\n\n"],[9,"SAMPLE_TEXTURE2D_SHADOW",["textureName","coord3"],"textureShadowMapDowngrade(textureName, coord3)"],[0,"\n\n"],[6],[0,"\n\n"],[9,"TEXTURE2D_SHADOW_PARAM",["shadowMap"],"mediump sampler2D shadowMap"],[0,"\n\n"],[6],[0,"\n\n"],[3,"SCENE_SHADOW_TYPE","==",2,192],[0,"\nfloat sampleShadowMapFiltered4 ( TEXTURE2D_SHADOW_PARAM(shadowMap), vec3 shadowCoord, vec4 shadowMapSize ) { float attenuation ;\nvec4 attenuation4 ;\nvec2 offset = shadowMapSize.xy / 2.0 ;\nvec3 shadowCoord0 = shadowCoord + vec3 ( - offset , 0.0 ) ;\nvec3 shadowCoord1 = shadowCoord + vec3 ( offset.x , - offset.y , 0.0 ) ;\nvec3 shadowCoord2 = shadowCoord + vec3 ( - offset.x , offset.y , 0.0 ) ;\nvec3 shadowCoord3 = shadowCoord + vec3 ( offset , 0.0 ) ;\nattenuation4.x = SAMPLE_TEXTURE2D_SHADOW(shadowMap, shadowCoord0) ;\nattenuation4.y = SAMPLE_TEXTURE2D_SHADOW(shadowMap, shadowCoord1) ;\nattenuation4.z = SAMPLE_TEXTURE2D_SHADOW(shadowMap, shadowCoord2) ;\nattenuation4.w = SAMPLE_TEXTURE2D_SHADOW(shadowMap, shadowCoord3) ;\nattenuation = dot ( attenuation4 , vec4 ( 0.25 ) ) ;\nreturn attenuation ; }\n\n"],[6],[0,"\n\n"],[3,"SCENE_SHADOW_TYPE","==",3,202],[0,"\n\n"],[2,"SHADOW_SAMPLE_TENT_INCLUDED",200],[0,"\n\n"],[7,"SHADOW_SAMPLE_TENT_INCLUDED"],[0,"\nfloat sampleShadowGetIRTriangleTexelArea ( float triangleHeight ) { return triangleHeight - 0.5 ; }\nvoid sampleShadowGetTexelAreasTent3x3 ( float offset, out vec4 computedArea, out vec4 computedAreaUncut ) { float a = offset + 0.5 ;\nfloat offsetSquaredHalved = a * a * 0.5 ;\ncomputedAreaUncut.x = computedArea.x = offsetSquaredHalved - offset ;\ncomputedAreaUncut.w = computedArea.w = offsetSquaredHalved ;\ncomputedAreaUncut.y = sampleShadowGetIRTriangleTexelArea(1.5 - offset) ;\nfloat clampedOffsetLeft = min ( offset , 0.0 ) ;\nfloat areaOfSmallLeftTriangle = clampedOffsetLeft * clampedOffsetLeft ;\ncomputedArea.y = computedAreaUncut.y - areaOfSmallLeftTriangle ;\ncomputedAreaUncut.z = sampleShadowGetIRTriangleTexelArea(1.5 + offset) ;\nfloat clampedOffsetRight = max ( offset , 0.0 ) ;\nfloat areaOfSmallRightTriangle = clampedOffsetRight * clampedOffsetRight ;\ncomputedArea.z = computedAreaUncut.z - areaOfSmallRightTriangle ; }\nvoid sampleShadowGetTexelWeightsTent5x5 ( float offset, out vec3 texelsWeightsA, out vec3 texelsWeightsB ) { vec4 areaFrom3texelTriangle ;\nvec4 areaUncutFrom3texelTriangle ;\nsampleShadowGetTexelAreasTent3x3(offset, areaFrom3texelTriangle, areaUncutFrom3texelTriangle) ;\ntexelsWeightsA.x = 0.16 * ( areaFrom3texelTriangle.x ) ;\ntexelsWeightsA.y = 0.16 * ( areaUncutFrom3texelTriangle.y ) ;\ntexelsWeightsA.z = 0.16 * ( areaFrom3texelTriangle.y + 1.0 ) ;\ntexelsWeightsB.x = 0.16 * ( areaFrom3texelTriangle.z + 1.0 ) ;\ntexelsWeightsB.y = 0.16 * ( areaUncutFrom3texelTriangle.z ) ;\ntexelsWeightsB.z = 0.16 * ( areaFrom3texelTriangle.w ) ; }\nvoid sampleShadowComputeSamplesTent5x5 ( vec4 shadowMapTextureTexelSize, vec2 coord, out float fetchesWeights [ 9 ], out vec2 fetchesUV [ 9 ] ) { vec2 tentCenterInTexelSpace = coord.xy * shadowMapTextureTexelSize.zw ;\nvec2 centerOfFetchesInTexelSpace = floor ( tentCenterInTexelSpace + 0.5 ) ;\nvec2 offsetFromTentCenterToCenterOfFetches = tentCenterInTexelSpace - centerOfFetchesInTexelSpace ;\nvec3 texelsWeightsUA , texelsWeightsUB ;\nvec3 texelsWeightsVA , texelsWeightsVB ;\nsampleShadowGetTexelWeightsTent5x5(offsetFromTentCenterToCenterOfFetches.x, texelsWeightsUA, texelsWeightsUB) ;\nsampleShadowGetTexelWeightsTent5x5(offsetFromTentCenterToCenterOfFetches.y, texelsWeightsVA, texelsWeightsVB) ;\nvec3 fetchesWeightsU = vec3 ( texelsWeightsUA.xz , texelsWeightsUB.y ) + vec3 ( texelsWeightsUA.y , texelsWeightsUB.xz ) ;\nvec3 fetchesWeightsV = vec3 ( texelsWeightsVA.xz , texelsWeightsVB.y ) + vec3 ( texelsWeightsVA.y , texelsWeightsVB.xz ) ;\nvec3 fetchesOffsetsU = vec3 ( texelsWeightsUA.y , texelsWeightsUB.xz ) / fetchesWeightsU.xyz + vec3 ( - 2.5 , - 0.5 , 1.5 ) ;\nvec3 fetchesOffsetsV = vec3 ( texelsWeightsVA.y , texelsWeightsVB.xz ) / fetchesWeightsV.xyz + vec3 ( - 2.5 , - 0.5 , 1.5 ) ;\nfetchesOffsetsU *= shadowMapTextureTexelSize.xxx ;\nfetchesOffsetsV *= shadowMapTextureTexelSize.yyy ;\nvec2 bilinearFetchOrigin = centerOfFetchesInTexelSpace * shadowMapTextureTexelSize.xy ;\nfetchesUV[0] = bilinearFetchOrigin + vec2 ( fetchesOffsetsU.x , fetchesOffsetsV.x ) ;\nfetchesUV[1] = bilinearFetchOrigin + vec2 ( fetchesOffsetsU.y , fetchesOffsetsV.x ) ;\nfetchesUV[2] = bilinearFetchOrigin + vec2 ( fetchesOffsetsU.z , fetchesOffsetsV.x ) ;\nfetchesUV[3] = bilinearFetchOrigin + vec2 ( fetchesOffsetsU.x , fetchesOffsetsV.y ) ;\nfetchesUV[4] = bilinearFetchOrigin + vec2 ( fetchesOffsetsU.y , fetchesOffsetsV.y ) ;\nfetchesUV[5] = bilinearFetchOrigin + vec2 ( fetchesOffsetsU.z , fetchesOffsetsV.y ) ;\nfetchesUV[6] = bilinearFetchOrigin + vec2 ( fetchesOffsetsU.x , fetchesOffsetsV.z ) ;\nfetchesUV[7] = bilinearFetchOrigin + vec2 ( fetchesOffsetsU.y , fetchesOffsetsV.z ) ;\nfetchesUV[8] = bilinearFetchOrigin + vec2 ( fetchesOffsetsU.z , fetchesOffsetsV.z ) ;\nfetchesWeights[0] = fetchesWeightsU.x * fetchesWeightsV.x ;\nfetchesWeights[1] = fetchesWeightsU.y * fetchesWeightsV.x ;\nfetchesWeights[2] = fetchesWeightsU.z * fetchesWeightsV.x ;\nfetchesWeights[3] = fetchesWeightsU.x * fetchesWeightsV.y ;\nfetchesWeights[4] = fetchesWeightsU.y * fetchesWeightsV.y ;\nfetchesWeights[5] = fetchesWeightsU.z * fetchesWeightsV.y ;\nfetchesWeights[6] = fetchesWeightsU.x * fetchesWeightsV.z ;\nfetchesWeights[7] = fetchesWeightsU.y * fetchesWeightsV.z ;\nfetchesWeights[8] = fetchesWeightsU.z * fetchesWeightsV.z ; }\n\n"],[6],[0,"\nfloat sampleShadowMapFiltered9 ( TEXTURE2D_SHADOW_PARAM(shadowMap), vec3 shadowCoord, vec4 shadowmapSize ) { float attenuation ;\nfloat fetchesWeights [ 9 ] ;\nvec2 fetchesUV [ 9 ] ;\nsampleShadowComputeSamplesTent5x5(shadowmapSize, shadowCoord.xy, fetchesWeights, fetchesUV) ;\nattenuation = fetchesWeights[0] * SAMPLE_TEXTURE2D_SHADOW(shadowMap, vec3 ( fetchesUV[0].xy , shadowCoord.z )) ;\nattenuation += fetchesWeights[1] * SAMPLE_TEXTURE2D_SHADOW(shadowMap, vec3 ( fetchesUV[1].xy , shadowCoord.z )) ;\nattenuation += fetchesWeights[2] * SAMPLE_TEXTURE2D_SHADOW(shadowMap, vec3 ( fetchesUV[2].xy , shadowCoord.z )) ;\nattenuation += fetchesWeights[3] * SAMPLE_TEXTURE2D_SHADOW(shadowMap, vec3 ( fetchesUV[3].xy , shadowCoord.z )) ;\nattenuation += fetchesWeights[4] * SAMPLE_TEXTURE2D_SHADOW(shadowMap, vec3 ( fetchesUV[4].xy , shadowCoord.z )) ;\nattenuation += fetchesWeights[5] * SAMPLE_TEXTURE2D_SHADOW(shadowMap, vec3 ( fetchesUV[5].xy , shadowCoord.z )) ;\nattenuation += fetchesWeights[6] * SAMPLE_TEXTURE2D_SHADOW(shadowMap, vec3 ( fetchesUV[6].xy , shadowCoord.z )) ;\nattenuation += fetchesWeights[7] * SAMPLE_TEXTURE2D_SHADOW(shadowMap, vec3 ( fetchesUV[7].xy , shadowCoord.z )) ;\nattenuation += fetchesWeights[8] * SAMPLE_TEXTURE2D_SHADOW(shadowMap, vec3 ( fetchesUV[8].xy , shadowCoord.z )) ;\nreturn attenuation ; }\n\n"],[6],[0,"\nfloat getShadowFade ( vec3 positionWS ) { vec3 camToPixel = positionWS - camera_Position ;\nfloat distanceCamToPixel2 = dot ( camToPixel , camToPixel ) ;\nreturn saturate(distanceCamToPixel2 * scene_ShadowInfo.z + scene_ShadowInfo.w) ; }\nfloat sampleShadowMap ( vec3 positionWS, vec3 shadowCoord ) { float attenuation = 1.0 ;\nif ( shadowCoord.z > 0.0 && shadowCoord.z < 1.0 ) { \n"],[3,"SCENE_SHADOW_TYPE","==",1,206],[0," attenuation = SAMPLE_TEXTURE2D_SHADOW(scene_ShadowMap, shadowCoord) ; \n"],[6],[0,"\n\n"],[3,"SCENE_SHADOW_TYPE","==",2,210],[0," attenuation = sampleShadowMapFiltered4(scene_ShadowMap, shadowCoord, scene_ShadowMapSize) ; \n"],[6],[0,"\n\n"],[3,"SCENE_SHADOW_TYPE","==",3,214],[0," attenuation = sampleShadowMapFiltered9(scene_ShadowMap, shadowCoord, scene_ShadowMapSize) ; \n"],[6],[0,"\nfloat shadowFade = getShadowFade(positionWS) ;\nattenuation = mix ( 1.0 , mix ( attenuation , 1.0 , shadowFade ) , scene_ShadowInfo.x ) ; }\nreturn attenuation ; }\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[2,"VARYINGS_PBR_INCLUDED",248],[0,"\n\n"],[7,"VARYINGS_PBR_INCLUDED"],[0,"\nvarying vec2 uv;\n\n"],[1,"RENDERER_HAS_UV1",226],[0,"varying vec2 uv1;\n\n"],[6],[0,"\n"],[1,"RENDERER_ENABLE_VERTEXCOLOR",230],[0,"varying vec4 vertexColor;\n\n"],[6],[0,"varying vec3 positionWS;\n\n"],[3,"SCENE_FOG_MODE","!=",0,234],[0,"varying vec3 positionVS;\n\n"],[6],[0,"\n"],[1,"RENDERER_HAS_NORMAL",242],[0,"varying vec3 normalWS;\n\n"],[1,"NEED_VERTEX_TANGENT",240],[0,"varying vec3 tangentWS;\nvarying vec3 bitangentWS;\n\n"],[6],[0,"\n"],[6],[0,"\n"],[4,{"t":"and","l":{"t":"def","m":"NEED_CALCULATE_SHADOWS"},"r":{"t":"cmp","m":"SCENE_SHADOW_CASCADED_COUNT","op":"==","v":1}},246],[0,"varying vec3 shadowCoord;\n\n"],[6],[0,"varying vec4 positionCS;\n\n\n"],[6],[0,"\n\n"],[2,"LIGHT_DIRECT_PBR_INCLUDED",539],[0,"\n\n"],[7,"LIGHT_DIRECT_PBR_INCLUDED"],[0,"\n\n"],[2,"FUNCTION_SURFACE_SHADING",258],[0,"\n\n"],[8,"FUNCTION_SURFACE_SHADING","surfaceShading"],[0,"\n\n"],[6],[0,"\n\n"],[2,"FUNCTION_DIFFUSE_LOBE",264],[0,"\n\n"],[8,"FUNCTION_DIFFUSE_LOBE","diffuseLobe"],[0,"\n\n"],[6],[0,"\n\n"],[2,"FUNCTION_SPECULAR_LOBE",270],[0,"\n\n"],[8,"FUNCTION_SPECULAR_LOBE","specularLobe"],[0,"\n\n"],[6],[0,"\n\n"],[2,"FUNCTION_CLEAR_COAT_LOBE",276],[0,"\n\n"],[8,"FUNCTION_CLEAR_COAT_LOBE","clearCoatLobe"],[0,"\n\n"],[6],[0,"\n\n"],[2,"FUNCTION_SHEEN_LOBE",282],[0,"\n\n"],[8,"FUNCTION_SHEEN_LOBE","sheenLobe"],[0,"\n\n"],[6],[0,"\n\n"],[2,"BSDF_INCLUDED",429],[0,"\n\n"],[7,"BSDF_INCLUDED"],[0,"\n\n"],[2,"REFRACTION_INCLUDED",296],[0,"\n\n"],[7,"REFRACTION_INCLUDED"],[0,"\n\n"],[1,"MATERIAL_ENABLE_TRANSMISSION",294],[0,"\nstruct RefractionModelResult { float transmissionLength ; vec3 positionExit ; } ;\nvoid refractionModelSphere ( vec3 V, vec3 positionWS, vec3 normalWS, float ior, float thickness, out RefractionModelResult ray ) { vec3 R1 = refract ( V , normalWS , 1.0 / ior ) ;\nfloat dist = dot ( - normalWS , R1 ) * thickness ;\nvec3 P1 = positionWS + R1 * dist ;\nray.transmissionLength = dist ;\nray.positionExit = P1 ; }\nvoid refractionModelPlanar ( vec3 V, vec3 positionWS, vec3 normalWS, float ior, float thickness, out RefractionModelResult ray ) { vec3 R = refract ( V , normalWS , 1.0 / ior ) ;\nfloat dist = thickness / max ( dot ( - normalWS , R ) , 1e-5f ) ;\nray.transmissionLength = dist ;\nray.positionExit = vec3 ( positionWS + R * dist ) ; }\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[8,"MIN_PERCEPTUAL_ROUGHNESS","0.045"],[0,"\n\n"],[8,"MIN_ROUGHNESS","0.002025"],[0,"\n\n"],[1,"MATERIAL_ENABLE_SHEEN",304],[0,"\nuniform sampler2D scene_PrefilteredDFG;\n\n"],[6],[0,"\nstruct SurfaceData { vec3 albedoColor ; vec3 emissiveColor ; float metallic ; float roughness ; float ambientOcclusion ; float opacity ; float IOR ; vec3 position ; vec4 positionCS ; vec3 normal ; \n"],[1,"NEED_TANGENT_SPACE",308],[0," vec3 tangent ; vec3 bitangent ; \n"],[6],[0," vec3 viewDir ; float dotNV ; float specularIntensity ; vec3 specularColor ; \n"],[1,"MATERIAL_ENABLE_ANISOTROPY",312],[0," float anisotropy ; vec3 anisotropicT ; vec3 anisotropicB ; vec3 anisotropicN ; \n"],[6],[0," \n"],[1,"MATERIAL_ENABLE_CLEAR_COAT",316],[0," float clearCoat ; float clearCoatRoughness ; vec3 clearCoatNormal ; float clearCoatDotNV ; \n"],[6],[0," \n"],[1,"MATERIAL_ENABLE_IRIDESCENCE",320],[0," float iridescenceIOR ; float iridescenceFactor ; float iridescenceThickness ; \n"],[6],[0," \n"],[1,"MATERIAL_ENABLE_SHEEN",324],[0," float sheenRoughness ; vec3 sheenColor ; \n"],[6],[0," \n"],[1,"MATERIAL_ENABLE_TRANSMISSION",328],[0," vec3 absorptionCoefficient ; float transmission ; float thickness ; \n"],[6],[0," } ;\nstruct BSDFData { vec3 diffuseColor ; float roughness ; vec3 envSpecularDFG ; float diffuseAO ; vec3 specularF0 ; vec3 resolvedSpecularF0 ; float specularF90 ; vec3 energyCompensation ; \n"],[1,"MATERIAL_ENABLE_CLEAR_COAT",332],[0," vec3 clearCoatSpecularColor ; float clearCoatRoughness ; \n"],[6],[0," \n"],[1,"MATERIAL_ENABLE_IRIDESCENCE",336],[0," vec3 iridescenceSpecularColor ; \n"],[6],[0," \n"],[1,"MATERIAL_ENABLE_SHEEN",340],[0," float sheenRoughness ; float sheenScaling ; float approxIBLSheenDG ; \n"],[6],[0," } ;\nfloat getAARoughnessFactor ( vec3 normal ) { \n"],[1,"HAS_DERIVATIVES",344],[0," vec3 dxy = max ( abs ( dFdx ( normal ) ) , abs ( dFdy ( normal ) ) ) ;\nreturn max ( max ( dxy.x , dxy.y ) , dxy.z ) ; \n"],[5,346],[0," return 0.0 ; \n"],[6],[0," }\nfloat F_Schlick ( float f0, float f90, float dotLH ) { return f0 + ( f90 - f0 ) * ( pow ( 1.0 - dotLH , 5.0 ) ) ; }\nvec3 F_Schlick ( vec3 f0, float f90, float dotLH ) { float fresnel = exp2 ( ( - 5.55473 * dotLH - 6.98316 ) * dotLH ) ;\nreturn ( f90 - f0 ) * fresnel + f0 ; }\nfloat G_GGX_SmithCorrelated ( float alpha, float dotNL, float dotNV ) { float a2 = pow2(alpha) ;\nfloat gv = dotNL * sqrt ( a2 + ( 1.0 - a2 ) * pow2(dotNV) ) ;\nfloat gl = dotNV * sqrt ( a2 + ( 1.0 - a2 ) * pow2(dotNL) ) ;\nreturn 0.5 / max ( gv + gl , EPSILON ) ; }\n\n"],[1,"MATERIAL_ENABLE_ANISOTROPY",350],[0,"\nfloat G_GGX_SmithCorrelated_Anisotropic ( float at, float ab, float ToV, float BoV, float ToL, float BoL, float NoV, float NoL ) { float lambdaV = NoL * length ( vec3 ( at * ToV , ab * BoV , NoV ) ) ;\nfloat lambdaL = NoV * length ( vec3 ( at * ToL , ab * BoL , NoL ) ) ;\nreturn 0.5 / max ( lambdaV + lambdaL , EPSILON ) ; }\n\n"],[6],[0,"\nfloat D_GGX ( float alpha, float dotNH ) { float a2 = pow2(alpha) ;\nfloat denom = pow2(dotNH) * ( a2 - 1.0 ) + 1.0 ;\nreturn RECIPROCAL_PI * a2 / pow2(denom) ; }\n\n"],[1,"MATERIAL_ENABLE_ANISOTROPY",354],[0,"\nfloat D_GGX_Anisotropic ( float at, float ab, float ToH, float BoH, float NoH ) { float a2 = at * ab ;\nhighp vec3 d = vec3 ( ab * ToH , at * BoH , a2 * NoH ) ;\nhighp float d2 = dot ( d , d ) ;\nfloat b2 = a2 / d2 ;\nreturn a2 * b2 * b2 * RECIPROCAL_PI ; }\n\n"],[6],[0,"\nfloat DG_GGX ( float alpha, float dotNV, float dotNL, float dotNH ) { float D = D_GGX(alpha, dotNH) ;\nfloat G = G_GGX_SmithCorrelated(alpha, dotNL, dotNV) ;\nreturn G * D ; }\n\n"],[1,"MATERIAL_ENABLE_ANISOTROPY",358],[0,"\nfloat DG_GGX_anisotropic ( vec3 h, vec3 l, SurfaceData surfaceData, float alpha, float dotNV, float dotNL, float dotNH ) { vec3 t = surfaceData.anisotropicT ;\nvec3 b = surfaceData.anisotropicB ;\nvec3 v = surfaceData.viewDir ;\nfloat dotTV = dot ( t , v ) ;\nfloat dotBV = dot ( b , v ) ;\nfloat dotTL = dot ( t , l ) ;\nfloat dotBL = dot ( b , l ) ;\nfloat dotTH = dot ( t , h ) ;\nfloat dotBH = dot ( b , h ) ;\nfloat at = max ( alpha * ( 1.0 + surfaceData.anisotropy ) , MIN_ROUGHNESS ) ;\nfloat ab = max ( alpha * ( 1.0 - surfaceData.anisotropy ) , MIN_ROUGHNESS ) ;\nfloat D = D_GGX_Anisotropic(at, ab, dotTH, dotBH, dotNH) ;\nfloat G = G_GGX_SmithCorrelated_Anisotropic(at, ab, dotTV, dotBV, dotTL, dotBL, dotNV, dotNL) ;\nreturn G * D ; }\n\n"],[6],[0,"\nvec3 BRDF_Specular_GGX ( vec3 incidentDirection, SurfaceData surfaceData, BSDFData bsdfData, vec3 normal, vec3 specularColor, float roughness ) { float alpha = pow2(roughness) ;\nvec3 halfDir = normalize ( incidentDirection + surfaceData.viewDir ) ;\nfloat dotNL = saturate(dot ( normal , incidentDirection )) ;\nfloat dotNV = saturate(dot ( normal , surfaceData.viewDir )) ;\nfloat dotNH = saturate(dot ( normal , halfDir )) ;\nfloat dotLH = saturate(dot ( incidentDirection , halfDir )) ;\nvec3 F = F_Schlick(specularColor, bsdfData.specularF90, dotLH) ;\n\n"],[1,"MATERIAL_ENABLE_IRIDESCENCE",362],[0," F = mix ( F , bsdfData.iridescenceSpecularColor , surfaceData.iridescenceFactor ) ; \n"],[6],[0,"\n\n"],[1,"MATERIAL_ENABLE_ANISOTROPY",366],[0," float GD = DG_GGX_anisotropic(halfDir, incidentDirection, surfaceData, alpha, dotNV, dotNL, dotNH) ; \n"],[5,368],[0," float GD = DG_GGX(alpha, dotNV, dotNL, dotNH) ; \n"],[6],[0,"\nreturn F * GD ; }\nvec3 BRDF_Diffuse_Lambert ( vec3 diffuseColor ) { return RECIPROCAL_PI * diffuseColor ; }\n\n"],[1,"MATERIAL_ENABLE_IRIDESCENCE",372],[0,"\nvec3 iorToFresnel0 ( vec3 transmittedIOR, float incidentIOR ) { return pow ( ( transmittedIOR - incidentIOR ) / ( transmittedIOR + incidentIOR ) , vec3 ( 2.0 ) ) ; }\nfloat iorToFresnel0 ( float transmittedIOR, float incidentIOR ) { return pow ( ( transmittedIOR - incidentIOR ) / ( transmittedIOR + incidentIOR ) , 2.0 ) ; }\nvec3 fresnelToIOR ( vec3 f0 ) { vec3 sqrtF0 = sqrt ( f0 ) ;\nreturn ( vec3 ( 1.0 ) + sqrtF0 ) / ( vec3 ( 1.0 ) - sqrtF0 ) ; }\nvec3 evalSensitivity ( float opd, vec3 shift ) { float phase = 2.0 * PI * opd * 1.0e-9 ;\nconst vec3 val = vec3 ( 5.4856e-13 , 4.4201e-13 , 5.2481e-13 ) ;\nconst vec3 pos = vec3 ( 1.6810e+06 , 1.7953e+06 , 2.2084e+06 ) ;\nconst vec3 var = vec3 ( 4.3278e+09 , 9.3046e+09 , 6.6121e+09 ) ;\nvec3 xyz = val * sqrt ( 2.0 * PI * var ) * cos ( pos * phase + shift ) * exp ( - var * pow2(phase) ) ;\nxyz.x += 9.7470e-14 * sqrt ( 2.0 * PI * 4.5282e+09 ) * cos ( 2.2399e+06 * phase + shift[0] ) * exp ( - 4.5282e+09 * pow2(phase) ) ;\nxyz /= 1.0685e-7 ;\nconst mat3 XYZ_TO_RGB = mat3 ( 3.2404542 , - 0.9692660 , 0.0556434 , - 1.5371385 , 1.8760108 , - 0.2040259 , - 0.4985314 , 0.0415560 , 1.0572252 ) ;\nvec3 rgb = XYZ_TO_RGB * xyz ;\nreturn rgb ; }\nvec3 evalIridescenceSpecular ( float outsideIOR, float dotNV, float thinIOR, vec3 baseF0, float baseF90, float iridescenceThickness ) { vec3 iridescence = vec3 ( 1.0 ) ;\nfloat iridescenceIOR = mix ( outsideIOR , thinIOR , smoothstep ( 0.0 , 0.03 , iridescenceThickness ) ) ;\nfloat sinTheta2Sq = pow ( outsideIOR / iridescenceIOR , 2.0 ) * ( 1.0 - pow ( dotNV , 2.0 ) ) ;\nfloat cosTheta2Sq = 1.0 - sinTheta2Sq ;\nif ( cosTheta2Sq < 0.0 ) { return iridescence ; }\nfloat cosTheta2 = sqrt ( cosTheta2Sq ) ;\nfloat f0 = iorToFresnel0(iridescenceIOR, outsideIOR) ;\nfloat reflectance = F_Schlick(f0, baseF90, dotNV) ;\nfloat t121 = 1.0 - reflectance ;\nfloat phi12 = 0.0 ;\nfloat phi21 = PI - phi12 ;\nvec3 baseIOR = fresnelToIOR(clamp ( baseF0 , 0.0 , 0.9999 )) ;\nvec3 r1 = iorToFresnel0(baseIOR, iridescenceIOR) ;\nvec3 r23 = F_Schlick(r1, baseF90, cosTheta2) ;\nvec3 phi23 = vec3 ( 0.0 ) ;\nif ( baseIOR[0] < iridescenceIOR ) { phi23[0] = PI ; }\nif ( baseIOR[1] < iridescenceIOR ) { phi23[1] = PI ; }\nif ( baseIOR[2] < iridescenceIOR ) { phi23[2] = PI ; }\nfloat opd = 2.0 * iridescenceIOR * iridescenceThickness * cosTheta2 ;\nvec3 phi = vec3 ( phi21 ) + phi23 ;\nvec3 r123 = clamp ( reflectance * r23 , 1e-5 , 0.9999 ) ;\nvec3 sr123 = sqrt ( r123 ) ;\nvec3 rs = pow2(t121) * r23 / ( vec3 ( 1.0 ) - r123 ) ;\nvec3 c0 = reflectance + rs ;\niridescence = c0 ;\nvec3 cm = rs - t121 ;\nfor ( int m = 1 ; m <= 2 ; ++ m ) { cm *= sr123 ;\nvec3 sm = 2.0 * evalSensitivity(float ( m ) * opd, float ( m ) * phi) ;\niridescence += cm * sm ; }\nreturn iridescence = max ( iridescence , vec3 ( 0.0 ) ) ; }\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_ENABLE_SHEEN",382],[0,"\nfloat D_Charlie ( float roughness, float dotNH ) { float invAlpha = 1.0 / roughness ;\nfloat cos2h = dotNH * dotNH ;\nfloat sin2h = max ( 1.0 - cos2h , 0.0078125 ) ;\nreturn ( 2.0 + invAlpha ) * pow ( sin2h , invAlpha * 0.5 ) / ( 2.0 * PI ) ; }\nfloat V_Neubelt ( float NoV, float NoL ) { return saturate(1.0 / ( 4.0 * ( NoL + NoV - NoL * NoV ) )) ; }\nvec3 sheenBRDF ( vec3 incidentDirection, SurfaceData surfaceData, vec3 sheenColor, float sheenRoughness ) { vec3 halfDir = normalize ( incidentDirection + surfaceData.viewDir ) ;\nfloat dotNL = saturate(dot ( surfaceData.normal , incidentDirection )) ;\nfloat dotNH = saturate(dot ( surfaceData.normal , halfDir )) ;\nfloat D = D_Charlie(sheenRoughness, dotNH) ;\nfloat V = V_Neubelt(surfaceData.dotNV, dotNL) ;\nvec3 F = sheenColor ;\nreturn D * V * F ; }\nfloat prefilteredSheenDFG ( float dotNV, float sheenRoughness ) { \n"],[1,"HAS_TEX_LOD",378],[0," return texture2DLodEXT ( scene_PrefilteredDFG , vec2 ( dotNV , sheenRoughness ) , 0.0 ).b ; \n"],[5,380],[0," return texture2D ( scene_PrefilteredDFG , vec2 ( dotNV , sheenRoughness ) , 0.0 ).b ; \n"],[6],[0," }\n\n"],[6],[0,"\nvec2 envDFGApprox ( float roughness, float dotNV ) { const vec4 c0 = vec4 ( - 1 , - 0.0275 , - 0.572 , 0.022 ) ;\nconst vec4 c1 = vec4 ( 1 , 0.0425 , 1.04 , - 0.04 ) ;\nvec4 r = roughness * c0 + c1 ;\nfloat a004 = min ( r.x * r.x , exp2 ( - 9.28 * dotNV ) ) * r.x + r.y ;\nreturn vec2 ( - 1.04 , 1.04 ) * a004 + r.zw ; }\nvec3 envBRDFApprox ( vec3 f0, float f90, float roughness, float dotNV ) { vec2 AB = envDFGApprox(roughness, dotNV) ;\nreturn f0 * AB.x + f90 * AB.y ; }\n\n"],[1,"MATERIAL_ENABLE_TRANSMISSION",397],[0,"\nuniform sampler2D camera_OpaqueTexture;\nvec3 evaluateTransmission ( SurfaceData surfaceData, BSDFData bsdfData ) { RefractionModelResult ray ;\n\n"],[3,"REFRACTION_MODE","==",0,388],[0," refractionModelSphere(- surfaceData.viewDir, surfaceData.position, surfaceData.normal, surfaceData.IOR, surfaceData.thickness, ray) ; \n"],[5,391],[3,"REFRACTION_MODE","==",1,391],[0," refractionModelPlanar(- surfaceData.viewDir, surfaceData.position, surfaceData.normal, surfaceData.IOR, surfaceData.thickness, ray) ; \n"],[6],[0,"\nvec3 refractedRayExit = ray.positionExit ;\nvec4 samplingPositionNDC = camera_ProjMat * camera_ViewMat * vec4 ( refractedRayExit , 1.0 ) ;\nvec2 refractionCoords = ( samplingPositionNDC.xy / samplingPositionNDC.w ) * 0.5 + 0.5 ;\nvec3 refractionTransmitted = texture2DSRGB(camera_OpaqueTexture, refractionCoords).rgb ;\nrefractionTransmitted *= bsdfData.diffuseColor ;\nrefractionTransmitted *= ( 1.0 - max ( max ( bsdfData.envSpecularDFG.r , bsdfData.envSpecularDFG.g ) , bsdfData.envSpecularDFG.b ) ) ;\n\n"],[1,"MATERIAL_HAS_THICKNESS",395],[0," vec3 transmittance = min ( vec3 ( 1.0 ) , exp ( - surfaceData.absorptionCoefficient * ray.transmissionLength ) ) ;\nrefractionTransmitted *= transmittance ; \n"],[6],[0,"\nreturn refractionTransmitted ; }\n\n"],[6],[0,"\n\n"],[1,"SCENE_ENABLE_AMBIENT_OCCLUSION",407],[0,"\nuniform sampler2D camera_AOTexture;\nfloat evaluateAmbientOcclusion ( vec2 uv ) { \n"],[1,"MATERIAL_IS_TRANSPARENT",403],[0," return 1.0 ; \n"],[5,405],[0," return texture2D ( camera_AOTexture , uv ).r ; \n"],[6],[0," }\n\n"],[6],[0,"\nvoid initBSDFData ( SurfaceData surfaceData, out BSDFData bsdfData ) { vec3 albedoColor = surfaceData.albedoColor ;\nfloat metallic = surfaceData.metallic ;\nfloat roughness = surfaceData.roughness ;\nvec3 dielectricBaseF0 = vec3 ( pow2(( surfaceData.IOR - 1.0 ) / ( surfaceData.IOR + 1.0 )) ) ;\nvec3 dielectricF0 = min ( dielectricBaseF0 * surfaceData.specularColor , vec3 ( 1.0 ) ) * surfaceData.specularIntensity ;\nfloat dielectricF90 = surfaceData.specularIntensity ;\nbsdfData.specularF0 = mix ( dielectricF0 , albedoColor , metallic ) ;\nbsdfData.specularF90 = mix ( dielectricF90 , 1.0 , metallic ) ;\nbsdfData.diffuseColor = albedoColor * ( 1.0 - metallic ) * ( 1.0 - max ( max ( dielectricF0.r , dielectricF0.g ) , dielectricF0.b ) ) ;\nbsdfData.roughness = max ( MIN_PERCEPTUAL_ROUGHNESS , min ( roughness + getAARoughnessFactor(surfaceData.normal) , 1.0 ) ) ;\n\n"],[1,"MATERIAL_ENABLE_IRIDESCENCE",411],[0," float topIOR = 1.0 ;\nbsdfData.iridescenceSpecularColor = evalIridescenceSpecular(topIOR, surfaceData.dotNV, surfaceData.iridescenceIOR, bsdfData.specularF0, bsdfData.specularF90, surfaceData.iridescenceThickness) ; \n"],[6],[0,"\nbsdfData.resolvedSpecularF0 = bsdfData.specularF0 ;\n\n"],[1,"MATERIAL_ENABLE_IRIDESCENCE",415],[0," bsdfData.resolvedSpecularF0 = mix ( bsdfData.resolvedSpecularF0 , bsdfData.iridescenceSpecularColor , surfaceData.iridescenceFactor ) ; \n"],[6],[0,"\nvec2 dfg = envDFGApprox(bsdfData.roughness, surfaceData.dotNV) ;\nbsdfData.envSpecularDFG = bsdfData.resolvedSpecularF0 * dfg.x + bsdfData.specularF90 * dfg.y ;\nbsdfData.energyCompensation = 1.0 + bsdfData.resolvedSpecularF0 * ( 1.0 / max ( dfg.x + dfg.y , EPSILON ) - 1.0 ) ;\nbsdfData.diffuseAO = surfaceData.ambientOcclusion ;\n\n"],[1,"SCENE_ENABLE_AMBIENT_OCCLUSION",419],[0," float ambientAO = evaluateAmbientOcclusion(( surfaceData.positionCS.xy / surfaceData.positionCS.w ) * 0.5 + 0.5) ;\nbsdfData.diffuseAO = min ( bsdfData.diffuseAO , ambientAO ) ; \n"],[6],[0,"\n\n"],[1,"MATERIAL_ENABLE_CLEAR_COAT",423],[0," bsdfData.clearCoatRoughness = max ( MIN_PERCEPTUAL_ROUGHNESS , min ( surfaceData.clearCoatRoughness + getAARoughnessFactor(surfaceData.clearCoatNormal) , 1.0 ) ) ;\nbsdfData.clearCoatSpecularColor = vec3 ( 0.04 ) ; \n"],[6],[0,"\n\n"],[1,"MATERIAL_ENABLE_SHEEN",427],[0," bsdfData.sheenRoughness = max ( MIN_PERCEPTUAL_ROUGHNESS , min ( surfaceData.sheenRoughness + getAARoughnessFactor(surfaceData.normal) , 1.0 ) ) ;\nbsdfData.approxIBLSheenDG = prefilteredSheenDFG(surfaceData.dotNV, bsdfData.sheenRoughness) ;\nbsdfData.sheenScaling = 1.0 - bsdfData.approxIBLSheenDG * max ( max ( surfaceData.sheenColor.r , surfaceData.sheenColor.g ) , surfaceData.sheenColor.b ) ; \n"],[6],[0," }\n\n"],[6],[0,"\n\n"],[2,"LIGHT_INCLUDED",477],[0,"\n\n"],[7,"LIGHT_INCLUDED"],[0,"\nuniform ivec4 renderer_Layer;\n\n"],[2,"GRAPHICS_API_WEBGL2",437],[0,"\nbool isBitSet ( float value, float mask, float bitIndex ) { return mod ( floor ( value / pow ( 2.0 , bitIndex ) ) , 2.0 ) == 1.0 && mod ( floor ( mask / pow ( 2.0 , bitIndex ) ) , 2.0 ) == 1.0 ; }\n\n"],[6],[0,"\nbool isRendererCulledByLight ( ivec2 rendererLayer, ivec2 lightCullingMask ) { \n"],[1,"GRAPHICS_API_WEBGL2",441],[0," return ! ( ( rendererLayer.x & lightCullingMask.x ) != 0 || ( rendererLayer.y & lightCullingMask.y ) != 0 ) ; \n"],[5,443],[0," for ( int i = 0 ; i < 16 ; i ++ ) { if ( isBitSet(float ( rendererLayer.x ), float ( lightCullingMask.x ), float ( i )) || isBitSet(float ( rendererLayer.y ), float ( lightCullingMask.y ), float ( i )) ) { return false ; } }\nreturn true ; \n"],[6],[0," }\n\n"],[1,"SCENE_DIRECT_LIGHT_COUNT",451],[0,"\nstruct DirectLight { vec3 color ; vec3 direction ; } ;\nuniform ivec2 scene_DirectLightCullingMask [ SCENE_DIRECT_LIGHT_COUNT ];\nuniform vec3 scene_DirectLightColor [ SCENE_DIRECT_LIGHT_COUNT ];\nuniform vec3 scene_DirectLightDirection [ SCENE_DIRECT_LIGHT_COUNT ];\n\n"],[1,"GRAPHICS_API_WEBGL2",449],[0,"\nDirectLight getDirectLight ( int index ) { DirectLight light ;\nlight.color = scene_DirectLightColor[index] ;\nlight.direction = scene_DirectLightDirection[index] ;\nreturn light ; }\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[1,"SCENE_POINT_LIGHT_COUNT",459],[0,"\nstruct PointLight { vec3 color ; vec3 position ; float distance ; } ;\nuniform ivec2 scene_PointLightCullingMask [ SCENE_POINT_LIGHT_COUNT ];\nuniform vec3 scene_PointLightColor [ SCENE_POINT_LIGHT_COUNT ];\nuniform vec3 scene_PointLightPosition [ SCENE_POINT_LIGHT_COUNT ];\nuniform float scene_PointLightDistance [ SCENE_POINT_LIGHT_COUNT ];\n\n"],[1,"GRAPHICS_API_WEBGL2",457],[0,"\nPointLight getPointLight ( int index ) { PointLight light ;\nlight.color = scene_PointLightColor[index] ;\nlight.position = scene_PointLightPosition[index] ;\nlight.distance = scene_PointLightDistance[index] ;\nreturn light ; }\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[1,"SCENE_SPOT_LIGHT_COUNT",467],[0,"\nstruct SpotLight { vec3 color ; vec3 position ; vec3 direction ; float distance ; float angleCos ; float penumbraCos ; } ;\nuniform ivec2 scene_SpotLightCullingMask [ SCENE_SPOT_LIGHT_COUNT ];\nuniform vec3 scene_SpotLightColor [ SCENE_SPOT_LIGHT_COUNT ];\nuniform vec3 scene_SpotLightPosition [ SCENE_SPOT_LIGHT_COUNT ];\nuniform vec3 scene_SpotLightDirection [ SCENE_SPOT_LIGHT_COUNT ];\nuniform float scene_SpotLightDistance [ SCENE_SPOT_LIGHT_COUNT ];\nuniform float scene_SpotLightAngleCos [ SCENE_SPOT_LIGHT_COUNT ];\nuniform float scene_SpotLightPenumbraCos [ SCENE_SPOT_LIGHT_COUNT ];\n\n"],[1,"GRAPHICS_API_WEBGL2",465],[0,"\nSpotLight getSpotLight ( int index ) { SpotLight light ;\nlight.color = scene_SpotLightColor[index] ;\nlight.position = scene_SpotLightPosition[index] ;\nlight.direction = scene_SpotLightDirection[index] ;\nlight.distance = scene_SpotLightDistance[index] ;\nlight.angleCos = scene_SpotLightAngleCos[index] ;\nlight.penumbraCos = scene_SpotLightPenumbraCos[index] ;\nreturn light ; }\n\n"],[6],[0,"\n\n"],[6],[0,"\nstruct EnvMapLight { vec3 diffuse ; float mipMapLevel ; float diffuseIntensity ; float specularIntensity ; } ;\nuniform EnvMapLight scene_EnvMapLight;\n\n"],[1,"SCENE_USE_SH",471],[0,"\nuniform vec3 scene_EnvSH [ 9 ];\n\n"],[6],[0,"\n\n"],[1,"SCENE_USE_SPECULAR_ENV",475],[0,"\nuniform samplerCube scene_EnvSpecularSampler;\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[2,"REFLECTION_LOBE_INCLUDED",491],[0,"\n\n"],[7,"REFLECTION_LOBE_INCLUDED"],[0,"\nvoid diffuseLobe ( SurfaceData surfaceData, BSDFData bsdfData, vec3 attenuationIrradiance, inout vec3 diffuseColor ) { diffuseColor += attenuationIrradiance * BRDF_Diffuse_Lambert(bsdfData.diffuseColor) ; }\nvoid specularLobe ( SurfaceData surfaceData, BSDFData bsdfData, vec3 incidentDirection, vec3 attenuationIrradiance, inout vec3 specularColor ) { specularColor += attenuationIrradiance * BRDF_Specular_GGX(incidentDirection, surfaceData, bsdfData, surfaceData.normal, bsdfData.specularF0, bsdfData.roughness) * bsdfData.energyCompensation ; }\nvoid sheenLobe ( SurfaceData surfaceData, BSDFData bsdfData, vec3 incidentDirection, vec3 attenuationIrradiance, inout vec3 diffuseColor, inout vec3 specularColor ) { \n"],[1,"MATERIAL_ENABLE_SHEEN",485],[0," diffuseColor *= bsdfData.sheenScaling ;\nspecularColor *= bsdfData.sheenScaling ;\nspecularColor += attenuationIrradiance * sheenBRDF(incidentDirection, surfaceData, surfaceData.sheenColor, bsdfData.sheenRoughness) ; \n"],[6],[0," }\nfloat clearCoatLobe ( SurfaceData surfaceData, BSDFData bsdfData, vec3 incidentDirection, vec3 color, inout vec3 specularColor ) { float attenuation = 1.0 ;\n\n"],[1,"MATERIAL_ENABLE_CLEAR_COAT",489],[0," float clearCoatDotNL = saturate(dot ( surfaceData.clearCoatNormal , incidentDirection )) ;\nvec3 clearCoatIrradiance = clearCoatDotNL * color ;\nspecularColor += surfaceData.clearCoat * clearCoatIrradiance * BRDF_Specular_GGX(incidentDirection, surfaceData, bsdfData, surfaceData.clearCoatNormal, bsdfData.clearCoatSpecularColor, bsdfData.clearCoatRoughness) ;\nattenuation -= surfaceData.clearCoat * F_Schlick(0.04, 1.0, surfaceData.clearCoatDotNV) ; \n"],[6],[0,"\nreturn attenuation ; }\n\n"],[6],[0,"\nvoid surfaceShading ( SurfaceData surfaceData, BSDFData bsdfData, vec3 incidentDirection, vec3 lightColor, inout vec3 totalDiffuseColor, inout vec3 totalSpecularColor ) { vec3 diffuseColor = vec3 ( 0 ) ;\nvec3 specularColor = vec3 ( 0 ) ;\nfloat dotNL = saturate(dot ( surfaceData.normal , incidentDirection )) ;\nvec3 irradiance = dotNL * lightColor * PI ;\nfloat attenuation = FUNCTION_CLEAR_COAT_LOBE(surfaceData, bsdfData, incidentDirection, lightColor, specularColor) ;\nvec3 attenuationIrradiance = attenuation * irradiance ;\nFUNCTION_DIFFUSE_LOBE(surfaceData, bsdfData, attenuationIrradiance, diffuseColor) ;\nFUNCTION_SPECULAR_LOBE(surfaceData, bsdfData, incidentDirection, attenuationIrradiance, specularColor) ;\nFUNCTION_SHEEN_LOBE(surfaceData, bsdfData, incidentDirection, attenuationIrradiance, diffuseColor, specularColor) ;\ntotalDiffuseColor += diffuseColor ;\ntotalSpecularColor += specularColor ; }\n\n"],[1,"SCENE_DIRECT_LIGHT_COUNT",495],[0,"\nvoid addDirectionalDirectLightRadiance ( SurfaceData surfaceData, BSDFData bsdfData, DirectLight directionalLight, inout vec3 totalDiffuseColor, inout vec3 totalSpecularColor ) { vec3 lightColor = directionalLight.color ;\nvec3 direction = - directionalLight.direction ;\nFUNCTION_SURFACE_SHADING(surfaceData, bsdfData, direction, lightColor, totalDiffuseColor, totalSpecularColor) ; }\n\n"],[6],[0,"\n\n"],[1,"SCENE_POINT_LIGHT_COUNT",499],[0,"\nvoid addPointDirectLightRadiance ( SurfaceData surfaceData, BSDFData bsdfData, PointLight pointLight, inout vec3 totalDiffuseColor, inout vec3 totalSpecularColor ) { vec3 lVector = pointLight.position - surfaceData.position ;\nvec3 direction = normalize ( lVector ) ;\nfloat lightDistance = length ( lVector ) ;\nvec3 lightColor = pointLight.color ;\nlightColor *= clamp ( 1.0 - pow ( lightDistance / pointLight.distance , 4.0 ) , 0.0 , 1.0 ) ;\nFUNCTION_SURFACE_SHADING(surfaceData, bsdfData, direction, lightColor, totalDiffuseColor, totalSpecularColor) ; }\n\n"],[6],[0,"\n\n"],[1,"SCENE_SPOT_LIGHT_COUNT",503],[0,"\nvoid addSpotDirectLightRadiance ( SurfaceData surfaceData, BSDFData bsdfData, SpotLight spotLight, inout vec3 totalDiffuseColor, inout vec3 totalSpecularColor ) { vec3 lVector = spotLight.position - surfaceData.position ;\nvec3 direction = normalize ( lVector ) ;\nfloat lightDistance = length ( lVector ) ;\nfloat angleCos = dot ( direction , - spotLight.direction ) ;\nfloat spotEffect = smoothstep ( spotLight.penumbraCos , spotLight.angleCos , angleCos ) ;\nfloat decayEffect = clamp ( 1.0 - pow ( lightDistance / spotLight.distance , 4.0 ) , 0.0 , 1.0 ) ;\nvec3 lightColor = spotLight.color ;\nlightColor *= spotEffect * decayEffect ;\nFUNCTION_SURFACE_SHADING(surfaceData, bsdfData, direction, lightColor, totalDiffuseColor, totalSpecularColor) ; }\n\n"],[6],[0,"\nvoid evaluateDirectRadiance ( SurfaceData surfaceData, BSDFData bsdfData, float shadowAttenuation, inout vec3 totalDiffuseColor, inout vec3 totalSpecularColor ) { \n"],[1,"SCENE_DIRECT_LIGHT_COUNT",517],[0," for ( int i = 0 ; i < SCENE_DIRECT_LIGHT_COUNT ; i ++ ) { if ( ! isRendererCulledByLight(renderer_Layer.xy, scene_DirectLightCullingMask[i]) ) { \n"],[1,"GRAPHICS_API_WEBGL2",509],[0," DirectLight directionalLight = getDirectLight(i) ; \n"],[5,511],[0," DirectLight directionalLight ;\ndirectionalLight.color = scene_DirectLightColor[i] ;\ndirectionalLight.direction = scene_DirectLightDirection[i] ; \n"],[6],[0,"\n\n"],[1,"NEED_CALCULATE_SHADOWS",515],[0," if ( i == 0 ) { directionalLight.color *= shadowAttenuation ; } \n"],[6],[0,"\naddDirectionalDirectLightRadiance(surfaceData, bsdfData, directionalLight, totalDiffuseColor, totalSpecularColor) ; } } \n"],[6],[0,"\n\n"],[1,"SCENE_POINT_LIGHT_COUNT",527],[0," for ( int i = 0 ; i < SCENE_POINT_LIGHT_COUNT ; i ++ ) { if ( ! isRendererCulledByLight(renderer_Layer.xy, scene_PointLightCullingMask[i]) ) { \n"],[1,"GRAPHICS_API_WEBGL2",523],[0," PointLight pointLight = getPointLight(i) ; \n"],[5,525],[0," PointLight pointLight ;\npointLight.color = scene_PointLightColor[i] ;\npointLight.position = scene_PointLightPosition[i] ;\npointLight.distance = scene_PointLightDistance[i] ; \n"],[6],[0,"\naddPointDirectLightRadiance(surfaceData, bsdfData, pointLight, totalDiffuseColor, totalSpecularColor) ; } } \n"],[6],[0,"\n\n"],[1,"SCENE_SPOT_LIGHT_COUNT",537],[0," for ( int i = 0 ; i < SCENE_SPOT_LIGHT_COUNT ; i ++ ) { if ( ! isRendererCulledByLight(renderer_Layer.xy, scene_SpotLightCullingMask[i]) ) { \n"],[1,"GRAPHICS_API_WEBGL2",533],[0," SpotLight spotLight = getSpotLight(i) ; \n"],[5,535],[0," SpotLight spotLight ;\nspotLight.color = scene_SpotLightColor[i] ;\nspotLight.position = scene_SpotLightPosition[i] ;\nspotLight.direction = scene_SpotLightDirection[i] ;\nspotLight.distance = scene_SpotLightDistance[i] ;\nspotLight.angleCos = scene_SpotLightAngleCos[i] ;\nspotLight.penumbraCos = scene_SpotLightPenumbraCos[i] ; \n"],[6],[0,"\naddSpotDirectLightRadiance(surfaceData, bsdfData, spotLight, totalDiffuseColor, totalSpecularColor) ; } } \n"],[6],[0," }\n\n"],[6],[0,"\n\n"],[2,"LIGHT_INDIRECT_PBR_INCLUDED",615],[0,"\n\n"],[7,"LIGHT_INDIRECT_PBR_INCLUDED"],[0,"\n\n"],[2,"FUNCTION_DIFFUSE_IBL",549],[0,"\n\n"],[8,"FUNCTION_DIFFUSE_IBL","evaluateDiffuseIBL"],[0,"\n\n"],[6],[0,"\n\n"],[2,"FUNCTION_SPECULAR_IBL",555],[0,"\n\n"],[8,"FUNCTION_SPECULAR_IBL","evaluateSpecularIBL"],[0,"\n\n"],[6],[0,"\n\n"],[2,"FUNCTION_CLEAR_COAT_IBL",561],[0,"\n\n"],[8,"FUNCTION_CLEAR_COAT_IBL","evaluateClearCoatIBL"],[0,"\n\n"],[6],[0,"\n\n"],[2,"FUNCTION_SHEEN_IBL",567],[0,"\n\n"],[8,"FUNCTION_SHEEN_IBL","evaluateSheenIBL"],[0,"\n\n"],[6],[0,"\n\n"],[2,"LIGHT_INDIRECT_FUNCTIONS_INCLUDED",599],[0,"\n\n"],[7,"LIGHT_INDIRECT_FUNCTIONS_INCLUDED"],[0,"\nvec3 getReflectedVector ( SurfaceData surfaceData, vec3 n ) { \n"],[1,"MATERIAL_ENABLE_ANISOTROPY",575],[0," vec3 r = reflect ( - surfaceData.viewDir , surfaceData.anisotropicN ) ; \n"],[5,577],[0," vec3 r = reflect ( - surfaceData.viewDir , n ) ; \n"],[6],[0,"\nreturn r ; }\nfloat getSpecularMIPLevel ( float roughness, int maxMIPLevel ) { return roughness * float ( maxMIPLevel ) ; }\nvec3 getLightProbeRadiance ( SurfaceData surfaceData, vec3 normal, float roughness ) { \n"],[2,"SCENE_USE_SPECULAR_ENV",581],[0," return vec3 ( 0 ) ; \n"],[5,593],[0," vec3 reflectVec = getReflectedVector(surfaceData, normal) ;\nfloat specularMIPLevel = getSpecularMIPLevel(roughness, int ( scene_EnvMapLight.mipMapLevel )) ;\n\n"],[1,"HAS_TEX_LOD",585],[0," vec4 envMapColor = textureCubeLodEXT ( scene_EnvSpecularSampler , reflectVec , specularMIPLevel ) ; \n"],[5,587],[0," vec4 envMapColor = textureCube ( scene_EnvSpecularSampler , reflectVec , specularMIPLevel ) ; \n"],[6],[0,"\n\n"],[1,"ENGINE_NO_SRGB",591],[0," envMapColor = sRGBToLinear(envMapColor) ; \n"],[6],[0,"\nreturn envMapColor.rgb * scene_EnvMapLight.specularIntensity ; \n"],[6],[0," }\nfloat evaluateSpecularOcclusion ( float dotNV, float diffuseAO, float roughness ) { float specularAOFactor = 1.0 ;\n\n"],[4,{"t":"and","l":{"t":"or","l":{"t":"def","m":"MATERIAL_HAS_OCCLUSION_TEXTURE"},"r":{"t":"def","m":"SCENE_ENABLE_AMBIENT_OCCLUSION"}},"r":{"t":"def","m":"SCENE_USE_SPECULAR_ENV"}},597],[0," specularAOFactor = saturate(pow ( dotNV + diffuseAO , exp2 ( - 16.0 * roughness - 1.0 ) ) - 1.0 + diffuseAO) ; \n"],[6],[0,"\nreturn specularAOFactor ; }\n\n"],[6],[0,"\nvec3 getLightProbeIrradiance ( vec3 sh [ 9 ], vec3 normal ) { vec3 result = sh[0] + sh[1] * ( normal.y ) + sh[2] * ( normal.z ) + sh[3] * ( normal.x ) + sh[4] * ( normal.y * normal.x ) + sh[5] * ( normal.y * normal.z ) + sh[6] * ( 3.0 * normal.z * normal.z - 1.0 ) + sh[7] * ( normal.z * normal.x ) + sh[8] * ( normal.x * normal.x - normal.y * normal.y ) ;\nreturn max ( result , vec3 ( 0.0 ) ) ; }\nvoid evaluateDiffuseIBL ( SurfaceData surfaceData, BSDFData bsdfData, inout vec3 diffuseColor ) { \n"],[1,"SCENE_USE_SH",603],[0," vec3 irradiance = getLightProbeIrradiance(scene_EnvSH, surfaceData.normal) ;\nirradiance *= scene_EnvMapLight.diffuseIntensity ; \n"],[5,605],[0," vec3 irradiance = scene_EnvMapLight.diffuse * scene_EnvMapLight.diffuseIntensity ;\nirradiance *= PI ; \n"],[6],[0,"\ndiffuseColor += bsdfData.diffuseAO * irradiance * BRDF_Diffuse_Lambert(bsdfData.diffuseColor) ; }\nfloat evaluateClearCoatIBL ( SurfaceData surfaceData, BSDFData bsdfData, inout vec3 specularColor ) { float radianceAttenuation = 1.0 ;\n\n"],[1,"MATERIAL_ENABLE_CLEAR_COAT",609],[0," vec3 clearCoatRadiance = getLightProbeRadiance(surfaceData, surfaceData.clearCoatNormal, bsdfData.clearCoatRoughness) ;\nfloat specularAO = evaluateSpecularOcclusion(surfaceData.dotNV, bsdfData.diffuseAO, bsdfData.clearCoatRoughness) ;\nspecularColor += specularAO * clearCoatRadiance * surfaceData.clearCoat * envBRDFApprox(bsdfData.clearCoatSpecularColor, 1.0, bsdfData.clearCoatRoughness, surfaceData.clearCoatDotNV) ;\nradianceAttenuation -= surfaceData.clearCoat * F_Schlick(0.04, 1.0, surfaceData.clearCoatDotNV) ; \n"],[6],[0,"\nreturn radianceAttenuation ; }\nvoid evaluateSpecularIBL ( SurfaceData surfaceData, BSDFData bsdfData, float radianceAttenuation, inout vec3 outSpecularColor ) { vec3 radiance = getLightProbeRadiance(surfaceData, surfaceData.normal, bsdfData.roughness) ;\nfloat specularAO = evaluateSpecularOcclusion(surfaceData.dotNV, bsdfData.diffuseAO, bsdfData.roughness) ;\noutSpecularColor += specularAO * radianceAttenuation * radiance * envBRDFApprox(bsdfData.resolvedSpecularF0, bsdfData.specularF90, bsdfData.roughness, surfaceData.dotNV) * bsdfData.energyCompensation ; }\nvoid evaluateSheenIBL ( SurfaceData surfaceData, BSDFData bsdfData, float radianceAttenuation, inout vec3 diffuseColor, inout vec3 specularColor ) { \n"],[1,"MATERIAL_ENABLE_SHEEN",613],[0," diffuseColor *= bsdfData.sheenScaling ;\nspecularColor *= bsdfData.sheenScaling ;\nfloat specularAO = evaluateSpecularOcclusion(surfaceData.dotNV, bsdfData.diffuseAO, bsdfData.sheenRoughness) ;\nvec3 reflectance = specularAO * radianceAttenuation * bsdfData.approxIBLSheenDG * surfaceData.sheenColor ;\nspecularColor += reflectance ; \n"],[6],[0," }\nvoid evaluateIBL ( SurfaceData surfaceData, BSDFData bsdfData, inout vec3 totalDiffuseColor, inout vec3 totalSpecularColor ) { vec3 diffuseColor = vec3 ( 0 ) ;\nvec3 specularColor = vec3 ( 0 ) ;\nFUNCTION_DIFFUSE_IBL(surfaceData, bsdfData, diffuseColor) ;\nfloat radianceAttenuation = FUNCTION_CLEAR_COAT_IBL(surfaceData, bsdfData, specularColor) ;\nFUNCTION_SPECULAR_IBL(surfaceData, bsdfData, radianceAttenuation, specularColor) ;\nFUNCTION_SHEEN_IBL(surfaceData, bsdfData, radianceAttenuation, diffuseColor, specularColor) ;\ntotalDiffuseColor += diffuseColor ;\ntotalSpecularColor += specularColor ; }\n\n"],[6],[0,"\n\n"],[2,"VERTEX_INCLUDE",621],[0,"\n\n"],[7,"VERTEX_INCLUDE"],[0,"\n\n"],[6],[0,"\n\n"],[2,"MATERIAL_INPUT_PBR_INCLUDED",872],[0,"\n\n"],[7,"MATERIAL_INPUT_PBR_INCLUDED"],[0,"\n\n"],[2,"NORMAL_INCLUDED",637],[0,"\n\n"],[7,"NORMAL_INCLUDED"],[0,"\nvec3 getNormalByNormalTexture ( mat3 tbn, sampler2D normalTexture, float normalIntensity, vec2 uv, bool isFrontFacing ) { vec3 normal = ( texture2D ( normalTexture , uv ) ).rgb ;\nnormal = normalize ( tbn * ( ( 2.0 * normal - 1.0 ) * vec3 ( normalIntensity , normalIntensity , 1.0 ) ) ) ;\nnormal *= float ( isFrontFacing ) * 2.0 - 1.0 ;\nreturn normal ; }\nmat3 getTBNByDerivatives ( vec2 uv, vec3 normal, vec3 position, bool isFrontFacing ) { \n"],[1,"HAS_DERIVATIVES",633],[0," uv = isFrontFacing ? uv : - uv ;\nvec3 dp1 = dFdx ( position ) ;\nvec3 dp2 = dFdy ( position ) ;\nvec2 duv1 = dFdx ( uv ) ;\nvec2 duv2 = dFdy ( uv ) ;\nvec3 dp2perp = cross ( dp2 , normal ) ;\nvec3 dp1perp = cross ( normal , dp1 ) ;\nvec3 tangent = dp2perp * duv1.x + dp1perp * duv2.x ;\nvec3 bitangent = dp2perp * duv1.y + dp1perp * duv2.y ;\nfloat denom = max ( dot ( tangent , tangent ) , dot ( bitangent , bitangent ) ) ;\nfloat invmax = ( denom == 0.0 ) ? 0.0 : camera_ProjectionParams.x / sqrt ( denom ) ;\nreturn mat3 ( tangent * invmax , bitangent * invmax , normal ) ; \n"],[5,635],[0," return mat3 ( vec3 ( 0.0 ) , vec3 ( 0.0 ) , normal ) ; \n"],[6],[0," }\n\n"],[6],[0,"\nuniform float material_AlphaCutoff;\nuniform vec4 material_BaseColor;\nuniform float material_Metal;\nuniform float material_Roughness;\nuniform float material_IOR;\nuniform vec3 material_EmissiveColor;\nuniform float material_NormalIntensity;\nuniform float material_OcclusionIntensity;\nuniform float material_OcclusionTextureCoord;\nuniform float material_SpecularIntensity;\nuniform vec3 material_SpecularColor;\n\n"],[1,"MATERIAL_HAS_SPECULAR_TEXTURE",641],[0,"\nuniform sampler2D material_SpecularIntensityTexture;\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_HAS_SPECULAR_COLOR_TEXTURE",645],[0,"\nuniform sampler2D material_SpecularColorTexture;\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_ENABLE_CLEAR_COAT",661],[0,"\nuniform float material_ClearCoat;\nuniform float material_ClearCoatRoughness;\n\n"],[1,"MATERIAL_HAS_CLEAR_COAT_TEXTURE",651],[0,"\nuniform sampler2D material_ClearCoatTexture;\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_HAS_CLEAR_COAT_ROUGHNESS_TEXTURE",655],[0,"\nuniform sampler2D material_ClearCoatRoughnessTexture;\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_HAS_CLEAR_COAT_NORMAL_TEXTURE",659],[0,"\nuniform sampler2D material_ClearCoatNormalTexture;\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_ENABLE_ANISOTROPY",669],[0,"\nuniform vec3 material_AnisotropyInfo;\n\n"],[1,"MATERIAL_HAS_ANISOTROPY_TEXTURE",667],[0,"\nuniform sampler2D material_AnisotropyTexture;\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_ENABLE_IRIDESCENCE",681],[0,"\nuniform vec4 material_IridescenceInfo;\n\n"],[1,"MATERIAL_HAS_IRIDESCENCE_THICKNESS_TEXTURE",675],[0,"\nuniform sampler2D material_IridescenceThicknessTexture;\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_HAS_IRIDESCENCE_TEXTURE",679],[0,"\nuniform sampler2D material_IridescenceTexture;\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_ENABLE_SHEEN",693],[0,"\nuniform float material_SheenRoughness;\nuniform vec3 material_SheenColor;\n\n"],[1,"MATERIAL_HAS_SHEEN_TEXTURE",687],[0,"\nuniform sampler2D material_SheenTexture;\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_HAS_SHEEN_ROUGHNESS_TEXTURE",691],[0,"\nuniform sampler2D material_SheenRoughnessTexture;\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_ENABLE_TRANSMISSION",709],[0,"\nuniform float material_Transmission;\n\n"],[1,"MATERIAL_HAS_TRANSMISSION_TEXTURE",699],[0,"\nuniform sampler2D material_TransmissionTexture;\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_HAS_THICKNESS",707],[0,"\nuniform vec3 material_AttenuationColor;\nuniform float material_AttenuationDistance;\nuniform float material_Thickness;\n\n"],[1,"MATERIAL_HAS_THICKNESS_TEXTURE",705],[0,"\nuniform sampler2D material_ThicknessTexture;\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_HAS_BASETEXTURE",713],[0,"\nuniform sampler2D material_BaseTexture;\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_HAS_NORMALTEXTURE",717],[0,"\nuniform sampler2D material_NormalTexture;\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_HAS_EMISSIVETEXTURE",721],[0,"\nuniform sampler2D material_EmissiveTexture;\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_HAS_ROUGHNESS_METALLIC_TEXTURE",725],[0,"\nuniform sampler2D material_RoughnessMetallicTexture;\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_HAS_OCCLUSION_TEXTURE",729],[0,"\nuniform sampler2D material_OcclusionTexture;\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_ENABLE_ANISOTROPY",733],[0,"\nvec3 getAnisotropicBentNormal ( SurfaceData surfaceData ) { vec3 anisotropyDirection = ( surfaceData.anisotropy >= 0.0 ) ? surfaceData.anisotropicB : surfaceData.anisotropicT ;\nvec3 anisotropicTangent = cross ( anisotropyDirection , surfaceData.viewDir ) ;\nvec3 anisotropicNormal = cross ( anisotropicTangent , anisotropyDirection ) ;\nvec3 bentNormal = normalize ( mix ( surfaceData.normal , anisotropicNormal , abs ( surfaceData.anisotropy ) * saturate(5.0 * surfaceData.roughness) ) ) ;\nreturn bentNormal ; }\n\n"],[6],[0,"\nSurfaceData getSurfaceData ( vec2 aoUV, bool isFrontFacing ) { SurfaceData surfaceData ;\nvec2 uv = uv ;\nvec4 baseColor = material_BaseColor ;\nfloat metallic = material_Metal ;\nfloat roughness = material_Roughness ;\nvec3 emissiveRadiance = material_EmissiveColor ;\n\n"],[1,"MATERIAL_HAS_BASETEXTURE",737],[0," baseColor *= texture2DSRGB(material_BaseTexture, uv) ; \n"],[6],[0,"\n\n"],[1,"RENDERER_ENABLE_VERTEXCOLOR",741],[0," baseColor *= vertexColor ; \n"],[6],[0,"\n\n"],[1,"MATERIAL_IS_ALPHA_CUTOFF",745],[0," if ( baseColor.a < material_AlphaCutoff ) { discard ; } \n"],[6],[0,"\n\n"],[1,"MATERIAL_HAS_ROUGHNESS_METALLIC_TEXTURE",749],[0," vec4 metalRoughMapColor = texture2D ( material_RoughnessMetallicTexture , uv ) ;\nroughness *= metalRoughMapColor.g ;\nmetallic *= metalRoughMapColor.b ; \n"],[6],[0,"\n\n"],[1,"MATERIAL_HAS_EMISSIVETEXTURE",753],[0," emissiveRadiance *= texture2DSRGB(material_EmissiveTexture, uv).rgb ; \n"],[6],[0,"\nsurfaceData.albedoColor = baseColor.rgb ;\nsurfaceData.emissiveColor = emissiveRadiance ;\nsurfaceData.metallic = metallic ;\nsurfaceData.roughness = roughness ;\nsurfaceData.IOR = material_IOR ;\n\n"],[1,"MATERIAL_IS_TRANSPARENT",757],[0," surfaceData.opacity = baseColor.a ; \n"],[5,759],[0," surfaceData.opacity = 1.0 ; \n"],[6],[0,"\nsurfaceData.position = positionWS ;\nsurfaceData.positionCS = positionCS ;\n\n"],[1,"CAMERA_ORTHOGRAPHIC",763],[0," surfaceData.viewDir = - camera_Forward ; \n"],[5,765],[0," surfaceData.viewDir = normalize ( camera_Position - positionWS ) ; \n"],[6],[0,"\n\n"],[1,"RENDERER_HAS_NORMAL",769],[0," vec3 normal = normalize ( normalWS ) ; \n"],[5,774],[1,"HAS_DERIVATIVES",772],[0," vec3 pos_dx = dFdx ( positionWS ) ;\nvec3 pos_dy = dFdy ( positionWS ) ;\nvec3 normal = normalize ( cross ( pos_dx , pos_dy ) ) ;\nnormal *= camera_ProjectionParams.x ; \n"],[5,774],[0," vec3 normal = vec3 ( 0 , 0 , 1 ) ; \n"],[6],[0,"\nnormal *= float ( isFrontFacing ) * 2.0 - 1.0 ;\nsurfaceData.normal = normal ;\n\n"],[1,"NEED_TANGENT_SPACE",788],[0," \n"],[1,"NEED_VERTEX_TANGENT",780],[0," surfaceData.tangent = tangentWS ;\nsurfaceData.bitangent = bitangentWS ;\nmat3 tbn = mat3 ( tangentWS , bitangentWS , normalWS ) ; \n"],[5,782],[0," mat3 tbn = getTBNByDerivatives(uv, normal, positionWS, isFrontFacing) ;\nsurfaceData.tangent = tbn[0] ;\nsurfaceData.bitangent = tbn[1] ; \n"],[6],[0,"\n\n"],[1,"MATERIAL_HAS_NORMALTEXTURE",786],[0," surfaceData.normal = getNormalByNormalTexture(tbn, material_NormalTexture, material_NormalIntensity, uv, isFrontFacing) ; \n"],[6],[0," \n"],[6],[0,"\nsurfaceData.dotNV = saturate(dot ( surfaceData.normal , surfaceData.viewDir )) ;\nsurfaceData.specularIntensity = material_SpecularIntensity ;\nsurfaceData.specularColor = material_SpecularColor ;\n\n"],[1,"MATERIAL_HAS_SPECULAR_TEXTURE",792],[0," surfaceData.specularIntensity *= texture2D ( material_SpecularIntensityTexture , uv ).a ; \n"],[6],[0,"\n\n"],[1,"MATERIAL_HAS_SPECULAR_COLOR_TEXTURE",796],[0," surfaceData.specularColor *= texture2D ( material_SpecularColorTexture , uv ).rgb ; \n"],[6],[0,"\n\n"],[1,"MATERIAL_ENABLE_CLEAR_COAT",814],[0," \n"],[1,"MATERIAL_HAS_CLEAR_COAT_NORMAL_TEXTURE",802],[0," surfaceData.clearCoatNormal = getNormalByNormalTexture(tbn, material_ClearCoatNormalTexture, material_NormalIntensity, uv, isFrontFacing) ; \n"],[5,804],[0," surfaceData.clearCoatNormal = normal ; \n"],[6],[0,"\nsurfaceData.clearCoatDotNV = saturate(dot ( surfaceData.clearCoatNormal , surfaceData.viewDir )) ;\nsurfaceData.clearCoat = material_ClearCoat ;\nsurfaceData.clearCoatRoughness = material_ClearCoatRoughness ;\n\n"],[1,"MATERIAL_HAS_CLEAR_COAT_TEXTURE",808],[0," surfaceData.clearCoat *= ( texture2D ( material_ClearCoatTexture , uv ) ).r ; \n"],[6],[0,"\n\n"],[1,"MATERIAL_HAS_CLEAR_COAT_ROUGHNESS_TEXTURE",812],[0," surfaceData.clearCoatRoughness *= ( texture2D ( material_ClearCoatRoughnessTexture , uv ) ).g ; \n"],[6],[0,"\nsurfaceData.clearCoat = saturate(surfaceData.clearCoat) ; \n"],[6],[0,"\n\n"],[1,"MATERIAL_ENABLE_ANISOTROPY",822],[0," float anisotropy = material_AnisotropyInfo.z ;\nvec3 anisotropicDirection = vec3 ( material_AnisotropyInfo.xy , 0.0 ) ;\n\n"],[1,"MATERIAL_HAS_ANISOTROPY_TEXTURE",820],[0," vec3 anisotropyTextureInfo = ( texture2D ( material_AnisotropyTexture , uv ) ).rgb ;\nanisotropy *= anisotropyTextureInfo.b ;\nanisotropicDirection.xy *= anisotropyTextureInfo.rg * 2.0 - 1.0 ; \n"],[6],[0,"\nsurfaceData.anisotropy = anisotropy ;\nsurfaceData.anisotropicT = normalize ( mat3 ( surfaceData.tangent , surfaceData.bitangent , surfaceData.normal ) * anisotropicDirection ) ;\nsurfaceData.anisotropicB = normalize ( cross ( surfaceData.normal , surfaceData.anisotropicT ) ) ;\nsurfaceData.anisotropicN = getAnisotropicBentNormal(surfaceData) ; \n"],[6],[0,"\n\n"],[1,"MATERIAL_ENABLE_IRIDESCENCE",836],[0," surfaceData.iridescenceFactor = material_IridescenceInfo.x ;\nsurfaceData.iridescenceIOR = material_IridescenceInfo.y ;\n\n"],[1,"MATERIAL_HAS_IRIDESCENCE_THICKNESS_TEXTURE",828],[0," float iridescenceThicknessWeight = texture2D ( material_IridescenceThicknessTexture , uv ).g ;\nsurfaceData.iridescenceThickness = mix ( material_IridescenceInfo.z , material_IridescenceInfo.w , iridescenceThicknessWeight ) ; \n"],[5,830],[0," surfaceData.iridescenceThickness = material_IridescenceInfo.w ; \n"],[6],[0,"\n\n"],[1,"MATERIAL_HAS_IRIDESCENCE_TEXTURE",834],[0," surfaceData.iridescenceFactor *= texture2D ( material_IridescenceTexture , uv ).r ; \n"],[6],[0," \n"],[6],[0,"\n\n"],[1,"MATERIAL_ENABLE_SHEEN",848],[0," vec3 sheenColor = material_SheenColor ;\n\n"],[1,"MATERIAL_HAS_SHEEN_TEXTURE",842],[0," sheenColor *= texture2DSRGB(material_SheenTexture, uv).rgb ; \n"],[6],[0,"\nsurfaceData.sheenColor = sheenColor ;\nsurfaceData.sheenRoughness = material_SheenRoughness ;\n\n"],[1,"MATERIAL_HAS_SHEEN_ROUGHNESS_TEXTURE",846],[0," surfaceData.sheenRoughness *= texture2D ( material_SheenRoughnessTexture , uv ).a ; \n"],[6],[0," \n"],[6],[0,"\n\n"],[1,"MATERIAL_ENABLE_TRANSMISSION",864],[0," surfaceData.transmission = material_Transmission ;\n\n"],[1,"MATERIAL_HAS_TRANSMISSION_TEXTURE",854],[0," surfaceData.transmission *= texture2D ( material_TransmissionTexture , uv ).r ; \n"],[6],[0,"\n\n"],[1,"MATERIAL_HAS_THICKNESS",862],[0," surfaceData.absorptionCoefficient = - log ( material_AttenuationColor + HALF_EPS ) / max ( HALF_EPS , material_AttenuationDistance ) ;\nsurfaceData.thickness = max ( material_Thickness , 0.0001 ) ;\n\n"],[1,"MATERIAL_HAS_THICKNESS_TEXTURE",860],[0," surfaceData.thickness *= texture2D ( material_ThicknessTexture , uv ).g ; \n"],[6],[0," \n"],[6],[0," \n"],[6],[0,"\n\n"],[1,"MATERIAL_HAS_OCCLUSION_TEXTURE",868],[0," surfaceData.ambientOcclusion = ( ( texture2D ( material_OcclusionTexture , aoUV ) ).r - 1.0 ) * material_OcclusionIntensity + 1.0 ; \n"],[5,870],[0," surfaceData.ambientOcclusion = 1.0 ; \n"],[6],[0,"\nreturn surfaceData ; }\n\n"],[6],[0,"\nvoid main() { BSDFData bsdfData ;\nvec2 aoUV = uv ;\n\n"],[4,{"t":"and","l":{"t":"def","m":"MATERIAL_HAS_OCCLUSION_TEXTURE"},"r":{"t":"def","m":"RENDERER_HAS_UV1"}},876],[0," if ( material_OcclusionTextureCoord == 1.0 ) { aoUV = uv1 ; } \n"],[6],[0,"\nSurfaceData surfaceData = getSurfaceData(aoUV, gl_FrontFacing) ;\ninitBSDFData(surfaceData, bsdfData) ;\nvec3 totalDiffuseColor = vec3 ( 0 , 0 , 0 ) ;\nvec3 totalSpecularColor = vec3 ( 0 , 0 , 0 ) ;\nfloat shadowAttenuation = 1.0 ;\n\n"],[4,{"t":"and","l":{"t":"def","m":"SCENE_DIRECT_LIGHT_COUNT"},"r":{"t":"def","m":"NEED_CALCULATE_SHADOWS"}},886],[0," \n"],[3,"SCENE_SHADOW_CASCADED_COUNT","==",1,882],[0," vec3 shadowCoord = shadowCoord ; \n"],[5,884],[0," vec3 shadowCoord = getShadowCoord(positionWS) ; \n"],[6],[0,"\nshadowAttenuation *= sampleShadowMap(positionWS, shadowCoord) ; \n"],[6],[0,"\nevaluateDirectRadiance(surfaceData, bsdfData, shadowAttenuation, totalDiffuseColor, totalSpecularColor) ;\nevaluateIBL(surfaceData, bsdfData, totalDiffuseColor, totalSpecularColor) ;\n\n"],[1,"MATERIAL_ENABLE_TRANSMISSION",890],[0," vec3 refractionTransmitted = evaluateTransmission(surfaceData, bsdfData) ;\ntotalDiffuseColor = mix ( totalDiffuseColor , refractionTransmitted , surfaceData.transmission ) ; \n"],[6],[0,"\nvec4 color = vec4 ( ( totalDiffuseColor + totalSpecularColor ).rgb , surfaceData.opacity ) ;\ncolor.rgb += surfaceData.emissiveColor ;\n\n"],[3,"SCENE_FOG_MODE","!=",0,894],[0," color = fog(color, positionVS) ; \n"],[6],[0,"\ngl_FragColor = color ; }\n\n"],[6]]}]}]} \ No newline at end of file +{"name":"PBR","platformTarget":0,"subShaders":[{"name":"Default","tags":{},"passes":[{"name":"Pipeline/ShadowCaster/Default/ShadowCaster","isUsePass":true,"tags":{},"renderStates":{"constantMap":{},"variableMap":{}}},{"name":"Pipeline/DepthOnly/Default/DepthOnly","isUsePass":true,"tags":{},"renderStates":{"constantMap":{},"variableMap":{}}},{"name":"Forward Pass","isUsePass":false,"tags":{"pipelineStage":"Forward"},"renderStates":{"constantMap":{},"variableMap":{"0":"blendEnabled","3":"sourceColorBlendFactor","4":"sourceAlphaBlendFactor","5":"destinationColorBlendFactor","6":"destinationAlphaBlendFactor","11":"depthWriteEnabled","25":"rasterStateCullMode","28":"renderQueueType"}},"vertexShaderInstructions":[[0,"\n"],[2,"FORWARD_PASS_PBR_INCLUDED",714],[0,"\n\n"],[7,"FORWARD_PASS_PBR_INCLUDED"],[0,"\n\n"],[4,{"t":"and","l":{"t":"and","l":{"t":"def","m":"RENDERER_HAS_NORMAL"},"r":{"t":"def","m":"RENDERER_HAS_TANGENT"}},"r":{"t":"or","l":{"t":"def","m":"MATERIAL_HAS_NORMALTEXTURE"},"r":{"t":"def","m":"MATERIAL_HAS_CLEAR_COAT_NORMAL_TEXTURE"}}},10],[0,"\n\n"],[7,"NEED_VERTEX_TANGENT"],[0,"\n\n"],[6],[0,"\n\n"],[4,{"t":"or","l":{"t":"or","l":{"t":"def","m":"MATERIAL_HAS_NORMALTEXTURE"},"r":{"t":"def","m":"MATERIAL_HAS_CLEAR_COAT_NORMAL_TEXTURE"}},"r":{"t":"def","m":"MATERIAL_ENABLE_ANISOTROPY"}},16],[0,"\n\n"],[7,"NEED_TANGENT_SPACE"],[0,"\n\n"],[6],[0,"\n\n"],[2,"COMMON_INCLUDED",46],[0,"\n\n"],[7,"COMMON_INCLUDED"],[0,"\n\n"],[8,"PI","3.14159265359"],[0,"\n\n"],[8,"RECIPROCAL_PI","0.31830988618"],[0,"\n\n"],[8,"EPSILON","1e-6"],[0,"\n\n"],[8,"LOG2","1.442695"],[0,"\n\n"],[8,"HALF_MIN","6.103515625e-5"],[0,"\n\n"],[8,"HALF_EPS","4.8828125e-4"],[0,"\n\n"],[9,"saturate",["a"],"clamp ( a , 0.0 , 1.0 )"],[0,"\n\n"],[1,"GRAPHICS_API_WEBGL2",40],[0,"\n\n"],[9,"INVERSE_MAT",["mat"],"inverse ( mat )"],[0,"\n\n"],[5,44],[0,"\nmat2 inverseMat ( mat2 m ) { return mat2 ( m[1][1] , - m[0][1] , - m[1][0] , m[0][0] ) / ( m[0][0] * m[1][1] - m[0][1] * m[1][0] ) ; }\nmat3 inverseMat ( mat3 m ) { float a00 = m[0][0] , a01 = m[0][1] , a02 = m[0][2] ;\nfloat a10 = m[1][0] , a11 = m[1][1] , a12 = m[1][2] ;\nfloat a20 = m[2][0] , a21 = m[2][1] , a22 = m[2][2] ;\nfloat b01 = a22 * a11 - a12 * a21 ;\nfloat b11 = - a22 * a10 + a12 * a20 ;\nfloat b21 = a21 * a10 - a11 * a20 ;\nfloat det = a00 * b01 + a01 * b11 + a02 * b21 ;\nreturn mat3 ( b01 , ( - a22 * a01 + a02 * a21 ) , ( a12 * a01 - a02 * a11 ) , b11 , ( a22 * a00 - a02 * a20 ) , ( - a12 * a00 + a02 * a10 ) , b21 , ( - a21 * a00 + a01 * a20 ) , ( a11 * a00 - a01 * a10 ) ) / det ; }\nmat4 inverseMat ( mat4 m ) { float a00 = m[0][0] , a01 = m[0][1] , a02 = m[0][2] , a03 = m[0][3] , a10 = m[1][0] , a11 = m[1][1] , a12 = m[1][2] , a13 = m[1][3] , a20 = m[2][0] , a21 = m[2][1] , a22 = m[2][2] , a23 = m[2][3] , a30 = m[3][0] , a31 = m[3][1] , a32 = m[3][2] , a33 = m[3][3] , b00 = a00 * a11 - a01 * a10 , b01 = a00 * a12 - a02 * a10 , b02 = a00 * a13 - a03 * a10 , b03 = a01 * a12 - a02 * a11 , b04 = a01 * a13 - a03 * a11 , b05 = a02 * a13 - a03 * a12 , b06 = a20 * a31 - a21 * a30 , b07 = a20 * a32 - a22 * a30 , b08 = a20 * a33 - a23 * a30 , b09 = a21 * a32 - a22 * a31 , b10 = a21 * a33 - a23 * a31 , b11 = a22 * a33 - a23 * a32 , det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06 ;\nreturn mat4 ( a11 * b11 - a12 * b10 + a13 * b09 , a02 * b10 - a01 * b11 - a03 * b09 , a31 * b05 - a32 * b04 + a33 * b03 , a22 * b04 - a21 * b05 - a23 * b03 , a12 * b08 - a10 * b11 - a13 * b07 , a00 * b11 - a02 * b08 + a03 * b07 , a32 * b02 - a30 * b05 - a33 * b01 , a20 * b05 - a22 * b02 + a23 * b01 , a10 * b10 - a11 * b08 + a13 * b06 , a01 * b08 - a00 * b10 - a03 * b06 , a30 * b04 - a31 * b02 + a33 * b00 , a21 * b02 - a20 * b04 - a23 * b00 , a11 * b07 - a10 * b09 - a12 * b06 , a00 * b09 - a01 * b07 + a02 * b06 , a31 * b01 - a30 * b03 - a32 * b00 , a20 * b03 - a21 * b01 + a22 * b00 ) / det ; }\n\n"],[9,"INVERSE_MAT",["mat"],"inverseMat(mat)"],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[2,"FOG_INCLUDED",56],[0,"\n\n"],[7,"FOG_INCLUDED"],[0,"\n\n"],[3,"SCENE_FOG_MODE","!=",0,54],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[2,"TRANSFORM_INCLUDED",62],[0,"\n\n"],[7,"TRANSFORM_INCLUDED"],[0,"\nuniform mat4 renderer_ModelMat;\nuniform mat4 renderer_MVMat;\nuniform mat4 renderer_MVPMat;\nuniform mat4 renderer_NormalMat;\n\n"],[6],[0,"\n\n"],[2,"ATTRIBUTES_INCLUDED",120],[0,"\n\n"],[7,"ATTRIBUTES_INCLUDED"],[0,"\nattribute vec3 POSITION;\n\n"],[1,"RENDERER_HAS_BLENDSHAPE",94],[0,"\n"],[2,"RENDERER_BLENDSHAPE_USE_TEXTURE",92],[0,"attribute vec3 POSITION_BS0;\nattribute vec3 POSITION_BS1;\n\n"],[4,{"t":"and","l":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_NORMAL"},"r":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_TANGENT"}},74],[0,"attribute vec3 NORMAL_BS0;\nattribute vec3 NORMAL_BS1;\nattribute vec3 TANGENT_BS0;\nattribute vec3 TANGENT_BS1;\n\n"],[5,90],[0,"\n"],[4,{"t":"or","l":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_NORMAL"},"r":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_TANGENT"}},86],[0,"attribute vec3 POSITION_BS2;\nattribute vec3 POSITION_BS3;\n\n"],[1,"RENDERER_BLENDSHAPE_HAS_NORMAL",80],[0,"attribute vec3 NORMAL_BS0;\nattribute vec3 NORMAL_BS1;\nattribute vec3 NORMAL_BS2;\nattribute vec3 NORMAL_BS3;\n\n"],[6],[0,"\n"],[1,"RENDERER_BLENDSHAPE_HAS_TANGENT",84],[0,"attribute vec3 TANGENT_BS0;\nattribute vec3 TANGENT_BS1;\nattribute vec3 TANGENT_BS2;\nattribute vec3 TANGENT_BS3;\n\n"],[6],[0,"\n"],[5,88],[0,"attribute vec3 POSITION_BS2;\nattribute vec3 POSITION_BS3;\nattribute vec3 POSITION_BS4;\nattribute vec3 POSITION_BS5;\nattribute vec3 POSITION_BS6;\nattribute vec3 POSITION_BS7;\n\n"],[6],[0,"\n"],[6],[0,"\n"],[6],[0,"\n"],[6],[0,"\n"],[1,"RENDERER_HAS_UV",98],[0,"attribute vec2 TEXCOORD_0;\n\n"],[6],[0,"\n"],[1,"RENDERER_HAS_UV1",102],[0,"attribute vec2 TEXCOORD_1;\n\n"],[6],[0,"\n"],[1,"RENDERER_HAS_SKIN",106],[0,"attribute vec4 JOINTS_0;\nattribute vec4 WEIGHTS_0;\n\n"],[6],[0,"\n"],[1,"RENDERER_ENABLE_VERTEXCOLOR",110],[0,"attribute vec4 COLOR_0;\n\n"],[6],[0,"\n"],[1,"RENDERER_HAS_NORMAL",114],[0,"attribute vec3 NORMAL;\n\n"],[6],[0,"\n"],[1,"RENDERER_HAS_TANGENT",118],[0,"attribute vec4 TANGENT;\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[2,"SKIN_INCLUDED",142],[0,"\n\n"],[7,"SKIN_INCLUDED"],[0,"\n\n"],[1,"RENDERER_HAS_SKIN",140],[0,"\n\n"],[1,"RENDERER_USE_JOINT_TEXTURE",130],[0,"\nuniform sampler2D renderer_JointSampler;\nuniform float renderer_JointCount;\nmat4 getJointMatrix ( sampler2D smp, float index ) { float base = index / renderer_JointCount ;\nfloat hf = 0.5 / renderer_JointCount ;\nfloat v = base + hf ;\nvec4 m0 = texture2D ( smp , vec2 ( 0.125 , v ) ) ;\nvec4 m1 = texture2D ( smp , vec2 ( 0.375 , v ) ) ;\nvec4 m2 = texture2D ( smp , vec2 ( 0.625 , v ) ) ;\nvec4 m3 = texture2D ( smp , vec2 ( 0.875 , v ) ) ;\nreturn mat4 ( m0 , m1 , m2 , m3 ) ; }\n\n"],[5,132],[0,"\nuniform mat4 renderer_JointMatrix [ RENDERER_JOINTS_NUM ];\n\n"],[6],[0,"\nmat4 getSkinMatrix ( ) { \n"],[1,"RENDERER_USE_JOINT_TEXTURE",136],[0," mat4 skinMatrix = WEIGHTS_0.x * getJointMatrix(renderer_JointSampler, JOINTS_0.x) + WEIGHTS_0.y * getJointMatrix(renderer_JointSampler, JOINTS_0.y) + WEIGHTS_0.z * getJointMatrix(renderer_JointSampler, JOINTS_0.z) + WEIGHTS_0.w * getJointMatrix(renderer_JointSampler, JOINTS_0.w) ; \n"],[5,138],[0," mat4 skinMatrix = WEIGHTS_0.x * renderer_JointMatrix[int ( JOINTS_0.x )] + WEIGHTS_0.y * renderer_JointMatrix[int ( JOINTS_0.y )] + WEIGHTS_0.z * renderer_JointMatrix[int ( JOINTS_0.z )] + WEIGHTS_0.w * renderer_JointMatrix[int ( JOINTS_0.w )] ; \n"],[6],[0,"\nreturn skinMatrix ; }\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[2,"BLENDSHAPE_INCLUDED",220],[0,"\n\n"],[7,"BLENDSHAPE_INCLUDED"],[0,"\n\n"],[1,"RENDERER_HAS_BLENDSHAPE",218],[0,"\n\n"],[1,"RENDERER_BLENDSHAPE_USE_TEXTURE",152],[0,"\nuniform mediump sampler2DArray renderer_BlendShapeTexture;\nuniform ivec3 renderer_BlendShapeTextureInfo;\nuniform float renderer_BlendShapeWeights [ RENDERER_BLENDSHAPE_COUNT ];\nvec3 getBlendShapeVertexElement ( int blendShapeIndex, int vertexElementIndex ) { int y = vertexElementIndex / renderer_BlendShapeTextureInfo.y ;\nint x = vertexElementIndex - y * renderer_BlendShapeTextureInfo.y ;\nivec3 uv = ivec3 ( x , y , blendShapeIndex ) ;\nreturn ( texelFetch ( renderer_BlendShapeTexture , uv , 0 ) ).xyz ; }\n\n"],[5,166],[0,"\n\n"],[4,{"t":"and","l":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_NORMAL"},"r":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_TANGENT"}},156],[0,"\nuniform float renderer_BlendShapeWeights [ 2 ];\n\n"],[5,164],[0,"\n\n"],[4,{"t":"or","l":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_NORMAL"},"r":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_TANGENT"}},160],[0,"\nuniform float renderer_BlendShapeWeights [ 4 ];\n\n"],[5,162],[0,"\nuniform float renderer_BlendShapeWeights [ 8 ];\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\nvoid calculateBlendShape ( inout vec4 position\n"],[1,"RENDERER_HAS_NORMAL",174],[0," , inout vec3 normal \n"],[1,"RENDERER_HAS_TANGENT",172],[0," , inout vec4 tangent \n"],[6],[0," \n"],[6],[0," ) { \n"],[1,"RENDERER_BLENDSHAPE_USE_TEXTURE",186],[0," int vertexOffset = gl_VertexID * renderer_BlendShapeTextureInfo.x ;\nfor ( int i = 0 ; i < RENDERER_BLENDSHAPE_COUNT ; i ++ ) { int vertexElementOffset = vertexOffset ;\nfloat weight = renderer_BlendShapeWeights[i] ;\nif ( weight != 0.0 ) { position.xyz += getBlendShapeVertexElement(i, vertexElementOffset) * weight ;\n\n"],[4,{"t":"and","l":{"t":"def","m":"RENDERER_HAS_NORMAL"},"r":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_NORMAL"}},180],[0," vertexElementOffset += 1 ;\nnormal += getBlendShapeVertexElement(i, vertexElementOffset) * weight ; \n"],[6],[0,"\n\n"],[4,{"t":"and","l":{"t":"def","m":"RENDERER_HAS_TANGENT"},"r":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_TANGENT"}},184],[0," vertexElementOffset += 1 ;\ntangent.xyz += getBlendShapeVertexElement(i, vertexElementOffset) * weight ; \n"],[6],[0," } } \n"],[5,216],[0," position.xyz += POSITION_BS0 * renderer_BlendShapeWeights[0] ;\nposition.xyz += POSITION_BS1 * renderer_BlendShapeWeights[1] ;\n\n"],[4,{"t":"and","l":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_NORMAL"},"r":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_TANGENT"}},198],[0," \n"],[1,"RENDERER_HAS_NORMAL",192],[0," normal += NORMAL_BS0 * renderer_BlendShapeWeights[0] ;\nnormal += NORMAL_BS1 * renderer_BlendShapeWeights[1] ; \n"],[6],[0,"\n\n"],[1,"RENDERER_HAS_TANGENT",196],[0," tangent.xyz += TANGENT_BS0 * renderer_BlendShapeWeights[0] ;\ntangent.xyz += TANGENT_BS1 * renderer_BlendShapeWeights[1] ; \n"],[6],[0," \n"],[5,214],[0," \n"],[4,{"t":"or","l":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_NORMAL"},"r":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_TANGENT"}},210],[0," position.xyz += POSITION_BS2 * renderer_BlendShapeWeights[2] ;\nposition.xyz += POSITION_BS3 * renderer_BlendShapeWeights[3] ;\n\n"],[4,{"t":"and","l":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_NORMAL"},"r":{"t":"def","m":"RENDERER_HAS_NORMAL"}},204],[0," normal += NORMAL_BS0 * renderer_BlendShapeWeights[0] ;\nnormal += NORMAL_BS1 * renderer_BlendShapeWeights[1] ;\nnormal += NORMAL_BS2 * renderer_BlendShapeWeights[2] ;\nnormal += NORMAL_BS3 * renderer_BlendShapeWeights[3] ; \n"],[6],[0,"\n\n"],[4,{"t":"and","l":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_TANGENT"},"r":{"t":"def","m":"RENDERER_HAS_TANGENT"}},208],[0," tangent.xyz += TANGENT_BS0 * renderer_BlendShapeWeights[0] ;\ntangent.xyz += TANGENT_BS1 * renderer_BlendShapeWeights[1] ;\ntangent.xyz += TANGENT_BS2 * renderer_BlendShapeWeights[2] ;\ntangent.xyz += TANGENT_BS3 * renderer_BlendShapeWeights[3] ; \n"],[6],[0," \n"],[5,212],[0," position.xyz += POSITION_BS2 * renderer_BlendShapeWeights[2] ;\nposition.xyz += POSITION_BS3 * renderer_BlendShapeWeights[3] ;\nposition.xyz += POSITION_BS4 * renderer_BlendShapeWeights[4] ;\nposition.xyz += POSITION_BS5 * renderer_BlendShapeWeights[5] ;\nposition.xyz += POSITION_BS6 * renderer_BlendShapeWeights[6] ;\nposition.xyz += POSITION_BS7 * renderer_BlendShapeWeights[7] ; \n"],[6],[0," \n"],[6],[0," \n"],[6],[0," }\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[2,"SHADOW_INCLUDED",300],[0,"\n\n"],[7,"SHADOW_INCLUDED"],[0,"\n\n"],[4,{"t":"and","l":{"t":"def","m":"SCENE_SHADOW_TYPE"},"r":{"t":"def","m":"RENDERER_IS_RECEIVE_SHADOWS"}},230],[0,"\n\n"],[7,"NEED_CALCULATE_SHADOWS"],[0,"\n\n"],[6],[0,"\n\n"],[1,"NEED_CALCULATE_SHADOWS",258],[0,"\nuniform mat4 scene_ShadowMatrices [ SCENE_SHADOW_CASCADED_COUNT + 1 ];\nuniform vec4 scene_ShadowSplitSpheres [ 4 ];\nmediump int computeCascadeIndex ( vec3 positionWS ) { vec3 fromCenter0 = positionWS - scene_ShadowSplitSpheres[0].xyz ;\nvec3 fromCenter1 = positionWS - scene_ShadowSplitSpheres[1].xyz ;\nvec3 fromCenter2 = positionWS - scene_ShadowSplitSpheres[2].xyz ;\nvec3 fromCenter3 = positionWS - scene_ShadowSplitSpheres[3].xyz ;\nmediump vec4 comparison = vec4 ( ( dot ( fromCenter0 , fromCenter0 ) < scene_ShadowSplitSpheres[0].w ) , ( dot ( fromCenter1 , fromCenter1 ) < scene_ShadowSplitSpheres[1].w ) , ( dot ( fromCenter2 , fromCenter2 ) < scene_ShadowSplitSpheres[2].w ) , ( dot ( fromCenter3 , fromCenter3 ) < scene_ShadowSplitSpheres[3].w ) ) ;\ncomparison.yzw = clamp ( comparison.yzw - comparison.xyz , 0.0 , 1.0 ) ;\nmediump vec4 indexCoefficient = vec4 ( 4.0 , 3.0 , 2.0 , 1.0 ) ;\nmediump int index = 4 - int ( dot ( comparison , indexCoefficient ) ) ;\nreturn index ; }\nvec3 getShadowCoord ( vec3 positionWS ) { \n"],[3,"SCENE_SHADOW_CASCADED_COUNT","==",1,236],[0," mediump int cascadeIndex = 0 ; \n"],[5,238],[0," mediump int cascadeIndex = computeCascadeIndex(positionWS) ; \n"],[6],[0,"\n\n"],[1,"GRAPHICS_API_WEBGL2",242],[0," mat4 shadowMatrix = scene_ShadowMatrices[cascadeIndex] ; \n"],[5,256],[0," mat4 shadowMatrix ;\n\n"],[3,"SCENE_SHADOW_CASCADED_COUNT","==",4,246],[0," if ( cascadeIndex == 0 ) { shadowMatrix = scene_ShadowMatrices[0] ; } else if ( cascadeIndex == 1 ) { shadowMatrix = scene_ShadowMatrices[1] ; } else if ( cascadeIndex == 2 ) { shadowMatrix = scene_ShadowMatrices[2] ; } else if ( cascadeIndex == 3 ) { shadowMatrix = scene_ShadowMatrices[3] ; } else { shadowMatrix = scene_ShadowMatrices[4] ; } \n"],[6],[0,"\n\n"],[3,"SCENE_SHADOW_CASCADED_COUNT","==",2,250],[0," if ( cascadeIndex == 0 ) { shadowMatrix = scene_ShadowMatrices[0] ; } else if ( cascadeIndex == 1 ) { shadowMatrix = scene_ShadowMatrices[1] ; } else { shadowMatrix = scene_ShadowMatrices[2] ; } \n"],[6],[0,"\n\n"],[3,"SCENE_SHADOW_CASCADED_COUNT","==",1,254],[0," if ( cascadeIndex == 0 ) { shadowMatrix = scene_ShadowMatrices[0] ; } else { shadowMatrix = scene_ShadowMatrices[1] ; } \n"],[6],[0," \n"],[6],[0,"\nvec4 shadowCoord = shadowMatrix * vec4 ( positionWS , 1.0 ) ;\nreturn shadowCoord.xyz ; }\n\n"],[6],[0,"\n\n"],[1,"NEED_CALCULATE_SHADOWS",298],[0,"\n\n"],[1,"GRAPHICS_API_WEBGL2",268],[0,"\n\n"],[9,"SAMPLE_TEXTURE2D_SHADOW",["textureName","coord3"],"textureLod ( textureName , coord3 , 0.0 )"],[0,"\n\n"],[9,"TEXTURE2D_SHADOW_PARAM",["shadowMap"],"mediump sampler2DShadow shadowMap"],[0,"\n\n"],[5,282],[0,"\n\n"],[1,"ENGINE_NO_DEPTH_TEXTURE",274],[0,"\nconst vec4 bitShift = vec4 ( 1.0 , 1.0 / 256.0 , 1.0 / ( 256.0 * 256.0 ) , 1.0 / ( 256.0 * 256.0 * 256.0 ) );\nfloat textureShadowMapDowngrade ( sampler2D scene_ShadowMap, vec3 shadowCoord ) { vec4 rgbaDepth = texture2D ( scene_ShadowMap , shadowCoord.xy ) ;\nfloat unpackDepth = dot ( rgbaDepth , bitShift ) ;\nreturn unpackDepth < shadowCoord.z ? 0.0 : 1.0 ; }\n\n"],[9,"SAMPLE_TEXTURE2D_SHADOW",["textureName","coord3"],"textureShadowMapDowngrade(textureName, coord3)"],[0,"\n\n"],[5,278],[0,"\nfloat textureShadowMapDowngrade ( sampler2D scene_ShadowMap, vec3 shadowCoord ) { float depth = texture2D ( scene_ShadowMap , shadowCoord.xy ).r ;\nreturn depth < shadowCoord.z ? 0.0 : 1.0 ; }\n\n"],[9,"SAMPLE_TEXTURE2D_SHADOW",["textureName","coord3"],"textureShadowMapDowngrade(textureName, coord3)"],[0,"\n\n"],[6],[0,"\n\n"],[9,"TEXTURE2D_SHADOW_PARAM",["shadowMap"],"mediump sampler2D shadowMap"],[0,"\n\n"],[6],[0,"\n\n"],[3,"SCENE_SHADOW_TYPE","==",2,286],[0,"\n\n"],[6],[0,"\n\n"],[3,"SCENE_SHADOW_TYPE","==",3,296],[0,"\n\n"],[2,"SHADOW_SAMPLE_TENT_INCLUDED",294],[0,"\n\n"],[7,"SHADOW_SAMPLE_TENT_INCLUDED"],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[2,"VARYINGS_PBR_INCLUDED",330],[0,"\n\n"],[7,"VARYINGS_PBR_INCLUDED"],[0,"\nvarying vec2 uv;\n\n"],[1,"RENDERER_HAS_UV1",308],[0,"varying vec2 uv1;\n\n"],[6],[0,"\n"],[1,"RENDERER_ENABLE_VERTEXCOLOR",312],[0,"varying vec4 vertexColor;\n\n"],[6],[0,"varying vec3 positionWS;\n\n"],[3,"SCENE_FOG_MODE","!=",0,316],[0,"varying vec3 positionVS;\n\n"],[6],[0,"\n"],[1,"RENDERER_HAS_NORMAL",324],[0,"varying vec3 normalWS;\n\n"],[1,"NEED_VERTEX_TANGENT",322],[0,"varying vec3 tangentWS;\nvarying vec3 bitangentWS;\n\n"],[6],[0,"\n"],[6],[0,"\n"],[4,{"t":"and","l":{"t":"def","m":"NEED_CALCULATE_SHADOWS"},"r":{"t":"cmp","m":"SCENE_SHADOW_CASCADED_COUNT","op":"==","v":1}},328],[0,"varying vec3 shadowCoord;\n\n"],[6],[0,"varying vec4 positionCS;\n\n\n"],[6],[0,"\n\n"],[2,"LIGHT_DIRECT_PBR_INCLUDED",478],[0,"\n\n"],[7,"LIGHT_DIRECT_PBR_INCLUDED"],[0,"\n\n"],[2,"FUNCTION_SURFACE_SHADING",340],[0,"\n\n"],[8,"FUNCTION_SURFACE_SHADING","surfaceShading"],[0,"\n\n"],[6],[0,"\n\n"],[2,"FUNCTION_DIFFUSE_LOBE",346],[0,"\n\n"],[8,"FUNCTION_DIFFUSE_LOBE","diffuseLobe"],[0,"\n\n"],[6],[0,"\n\n"],[2,"FUNCTION_SPECULAR_LOBE",352],[0,"\n\n"],[8,"FUNCTION_SPECULAR_LOBE","specularLobe"],[0,"\n\n"],[6],[0,"\n\n"],[2,"FUNCTION_CLEAR_COAT_LOBE",358],[0,"\n\n"],[8,"FUNCTION_CLEAR_COAT_LOBE","clearCoatLobe"],[0,"\n\n"],[6],[0,"\n\n"],[2,"FUNCTION_SHEEN_LOBE",364],[0,"\n\n"],[8,"FUNCTION_SHEEN_LOBE","sheenLobe"],[0,"\n\n"],[6],[0,"\n\n"],[2,"BSDF_INCLUDED",416],[0,"\n\n"],[7,"BSDF_INCLUDED"],[0,"\n\n"],[2,"REFRACTION_INCLUDED",378],[0,"\n\n"],[7,"REFRACTION_INCLUDED"],[0,"\n\n"],[1,"MATERIAL_ENABLE_TRANSMISSION",376],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[8,"MIN_PERCEPTUAL_ROUGHNESS","0.045"],[0,"\n\n"],[8,"MIN_ROUGHNESS","0.002025"],[0,"\n\n"],[1,"MATERIAL_ENABLE_SHEEN",386],[0,"\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_ENABLE_ANISOTROPY",390],[0,"\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_ENABLE_ANISOTROPY",394],[0,"\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_ENABLE_ANISOTROPY",398],[0,"\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_ENABLE_IRIDESCENCE",402],[0,"\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_ENABLE_SHEEN",406],[0,"\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_ENABLE_TRANSMISSION",410],[0,"\n\n"],[6],[0,"\n\n"],[1,"SCENE_ENABLE_AMBIENT_OCCLUSION",414],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[2,"LIGHT_INCLUDED",458],[0,"\n\n"],[7,"LIGHT_INCLUDED"],[0,"\n\n"],[2,"GRAPHICS_API_WEBGL2",424],[0,"\n\n"],[6],[0,"\n\n"],[1,"SCENE_DIRECT_LIGHT_COUNT",432],[0,"\n\n"],[1,"GRAPHICS_API_WEBGL2",430],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[1,"SCENE_POINT_LIGHT_COUNT",440],[0,"\n\n"],[1,"GRAPHICS_API_WEBGL2",438],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[1,"SCENE_SPOT_LIGHT_COUNT",448],[0,"\n\n"],[1,"GRAPHICS_API_WEBGL2",446],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[1,"SCENE_USE_SH",452],[0,"\n\n"],[6],[0,"\n\n"],[1,"SCENE_USE_SPECULAR_ENV",456],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[2,"REFLECTION_LOBE_INCLUDED",464],[0,"\n\n"],[7,"REFLECTION_LOBE_INCLUDED"],[0,"\n\n"],[6],[0,"\n\n"],[1,"SCENE_DIRECT_LIGHT_COUNT",468],[0,"\n\n"],[6],[0,"\n\n"],[1,"SCENE_POINT_LIGHT_COUNT",472],[0,"\n\n"],[6],[0,"\n\n"],[1,"SCENE_SPOT_LIGHT_COUNT",476],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[2,"LIGHT_INDIRECT_PBR_INCLUDED",514],[0,"\n\n"],[7,"LIGHT_INDIRECT_PBR_INCLUDED"],[0,"\n\n"],[2,"FUNCTION_DIFFUSE_IBL",488],[0,"\n\n"],[8,"FUNCTION_DIFFUSE_IBL","evaluateDiffuseIBL"],[0,"\n\n"],[6],[0,"\n\n"],[2,"FUNCTION_SPECULAR_IBL",494],[0,"\n\n"],[8,"FUNCTION_SPECULAR_IBL","evaluateSpecularIBL"],[0,"\n\n"],[6],[0,"\n\n"],[2,"FUNCTION_CLEAR_COAT_IBL",500],[0,"\n\n"],[8,"FUNCTION_CLEAR_COAT_IBL","evaluateClearCoatIBL"],[0,"\n\n"],[6],[0,"\n\n"],[2,"FUNCTION_SHEEN_IBL",506],[0,"\n\n"],[8,"FUNCTION_SHEEN_IBL","evaluateSheenIBL"],[0,"\n\n"],[6],[0,"\n\n"],[2,"LIGHT_INDIRECT_FUNCTIONS_INCLUDED",512],[0,"\n\n"],[7,"LIGHT_INDIRECT_FUNCTIONS_INCLUDED"],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[2,"VERTEX_INCLUDE",580],[0,"\n\n"],[7,"VERTEX_INCLUDE"],[0,"\nstruct VertexInputs { vec4 positionOS ; vec3 positionWS ; \n"],[3,"SCENE_FOG_MODE","!=",0,522],[0," vec3 positionVS ; \n"],[6],[0," \n"],[1,"RENDERER_HAS_NORMAL",530],[0," vec3 normalWS ; \n"],[1,"NEED_VERTEX_TANGENT",528],[0," vec3 tangentWS ; vec3 bitangentWS ; \n"],[6],[0," \n"],[6],[0," } ;\nuniform vec4 material_TilingOffset;\nvec2 getUV0 ( ) { vec2 uv0 = vec2 ( 0 ) ;\n\n"],[1,"RENDERER_HAS_UV",534],[0," uv0 = TEXCOORD_0 ; \n"],[6],[0,"\nreturn uv0 * material_TilingOffset.xy + material_TilingOffset.zw ; }\nVertexInputs getVertexInputs ( ) { VertexInputs inputs ;\nvec4 position = vec4 ( POSITION , 1.0 ) ;\n\n"],[1,"RENDERER_HAS_NORMAL",542],[0," vec3 normal = vec3 ( NORMAL ) ;\n\n"],[1,"RENDERER_HAS_TANGENT",540],[0," vec4 tangent = vec4 ( TANGENT ) ; \n"],[6],[0," \n"],[6],[0,"\n\n"],[1,"RENDERER_HAS_BLENDSHAPE",554],[0," calculateBlendShape(position\n"],[1,"RENDERER_HAS_NORMAL",552],[0," , normal \n"],[1,"RENDERER_HAS_TANGENT",550],[0," , tangent \n"],[6],[0," \n"],[6],[0,") ; \n"],[6],[0,"\n\n"],[1,"RENDERER_HAS_SKIN",566],[0," mat4 skinMatrix = getSkinMatrix() ;\nposition = skinMatrix * position ;\n\n"],[4,{"t":"and","l":{"t":"def","m":"RENDERER_HAS_NORMAL"},"r":{"t":"not","c":{"t":"def","m":"MATERIAL_OMIT_NORMAL"}}},564],[0," mat3 skinNormalMatrix = INVERSE_MAT(mat3 ( skinMatrix )) ;\nnormal = normal * skinNormalMatrix ;\n\n"],[1,"NEED_VERTEX_TANGENT",562],[0," tangent.xyz = tangent.xyz * skinNormalMatrix ; \n"],[6],[0," \n"],[6],[0," \n"],[6],[0,"\n\n"],[4,{"t":"and","l":{"t":"def","m":"RENDERER_HAS_NORMAL"},"r":{"t":"not","c":{"t":"def","m":"MATERIAL_OMIT_NORMAL"}}},574],[0," mat3 normalMat = mat3 ( renderer_NormalMat ) ;\ninputs.normalWS = normalize ( normalMat * normal ) ;\n\n"],[1,"NEED_VERTEX_TANGENT",572],[0," vec3 tangentWS = normalize ( normalMat * tangent.xyz ) ;\nvec3 bitangentWS = cross ( inputs.normalWS , tangentWS ) * tangent.w ;\ninputs.tangentWS = tangentWS ;\ninputs.bitangentWS = bitangentWS ; \n"],[6],[0," \n"],[6],[0,"\ninputs.positionOS = position ;\nvec4 positionWS = renderer_ModelMat * position ;\ninputs.positionWS = positionWS.xyz / positionWS.w ;\n\n"],[3,"SCENE_FOG_MODE","!=",0,578],[0," vec4 positionVS = renderer_MVMat * position ;\ninputs.positionVS = positionVS.xyz / positionVS.w ; \n"],[6],[0,"\nreturn inputs ; }\n\n"],[6],[0,"\n\n"],[2,"MATERIAL_INPUT_PBR_INCLUDED",688],[0,"\n\n"],[7,"MATERIAL_INPUT_PBR_INCLUDED"],[0,"\n\n"],[2,"NORMAL_INCLUDED",590],[0,"\n\n"],[7,"NORMAL_INCLUDED"],[0,"\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_HAS_SPECULAR_TEXTURE",594],[0,"\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_HAS_SPECULAR_COLOR_TEXTURE",598],[0,"\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_ENABLE_CLEAR_COAT",614],[0,"\n\n"],[1,"MATERIAL_HAS_CLEAR_COAT_TEXTURE",604],[0,"\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_HAS_CLEAR_COAT_ROUGHNESS_TEXTURE",608],[0,"\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_HAS_CLEAR_COAT_NORMAL_TEXTURE",612],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_ENABLE_ANISOTROPY",622],[0,"\n\n"],[1,"MATERIAL_HAS_ANISOTROPY_TEXTURE",620],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_ENABLE_IRIDESCENCE",634],[0,"\n\n"],[1,"MATERIAL_HAS_IRIDESCENCE_THICKNESS_TEXTURE",628],[0,"\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_HAS_IRIDESCENCE_TEXTURE",632],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_ENABLE_SHEEN",646],[0,"\n\n"],[1,"MATERIAL_HAS_SHEEN_TEXTURE",640],[0,"\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_HAS_SHEEN_ROUGHNESS_TEXTURE",644],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_ENABLE_TRANSMISSION",662],[0,"\n\n"],[1,"MATERIAL_HAS_TRANSMISSION_TEXTURE",652],[0,"\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_HAS_THICKNESS",660],[0,"\n\n"],[1,"MATERIAL_HAS_THICKNESS_TEXTURE",658],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_HAS_BASETEXTURE",666],[0,"\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_HAS_NORMALTEXTURE",670],[0,"\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_HAS_EMISSIVETEXTURE",674],[0,"\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_HAS_ROUGHNESS_METALLIC_TEXTURE",678],[0,"\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_HAS_OCCLUSION_TEXTURE",682],[0,"\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_ENABLE_ANISOTROPY",686],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\nvoid main() { \nuv = getUV0() ;\n\n"],[1,"RENDERER_HAS_UV1",692],[0," uv1 = TEXCOORD_1 ; \n"],[6],[0,"\n\n"],[1,"RENDERER_ENABLE_VERTEXCOLOR",696],[0," vertexColor = COLOR_0 ; \n"],[6],[0,"\nVertexInputs vertexInputs = getVertexInputs() ;\npositionWS = vertexInputs.positionWS ;\n\n"],[3,"SCENE_FOG_MODE","!=",0,700],[0," positionVS = vertexInputs.positionVS ; \n"],[6],[0,"\n\n"],[1,"RENDERER_HAS_NORMAL",708],[0," normalWS = vertexInputs.normalWS ;\n\n"],[1,"NEED_VERTEX_TANGENT",706],[0," tangentWS = vertexInputs.tangentWS ;\nbitangentWS = vertexInputs.bitangentWS ; \n"],[6],[0," \n"],[6],[0,"\n\n"],[4,{"t":"and","l":{"t":"def","m":"NEED_CALCULATE_SHADOWS"},"r":{"t":"cmp","m":"SCENE_SHADOW_CASCADED_COUNT","op":"==","v":1}},712],[0," shadowCoord = getShadowCoord(vertexInputs.positionWS) ; \n"],[6],[0,"\ngl_Position = renderer_MVPMat * vertexInputs.positionOS ;\npositionCS = gl_Position ;\n }\n\n"],[6]],"fragmentShaderInstructions":[[0,"\n"],[2,"FORWARD_PASS_PBR_INCLUDED",896],[0,"\n\n"],[7,"FORWARD_PASS_PBR_INCLUDED"],[0,"\n\n"],[4,{"t":"and","l":{"t":"and","l":{"t":"def","m":"RENDERER_HAS_NORMAL"},"r":{"t":"def","m":"RENDERER_HAS_TANGENT"}},"r":{"t":"or","l":{"t":"def","m":"MATERIAL_HAS_NORMALTEXTURE"},"r":{"t":"def","m":"MATERIAL_HAS_CLEAR_COAT_NORMAL_TEXTURE"}}},10],[0,"\n\n"],[7,"NEED_VERTEX_TANGENT"],[0,"\n\n"],[6],[0,"\n\n"],[4,{"t":"or","l":{"t":"or","l":{"t":"def","m":"MATERIAL_HAS_NORMALTEXTURE"},"r":{"t":"def","m":"MATERIAL_HAS_CLEAR_COAT_NORMAL_TEXTURE"}},"r":{"t":"def","m":"MATERIAL_ENABLE_ANISOTROPY"}},16],[0,"\n\n"],[7,"NEED_TANGENT_SPACE"],[0,"\n\n"],[6],[0,"\n\n"],[2,"COMMON_INCLUDED",50],[0,"\n\n"],[7,"COMMON_INCLUDED"],[0,"\n\n"],[8,"PI","3.14159265359"],[0,"\n\n"],[8,"RECIPROCAL_PI","0.31830988618"],[0,"\n\n"],[8,"EPSILON","1e-6"],[0,"\n\n"],[8,"LOG2","1.442695"],[0,"\n\n"],[8,"HALF_MIN","6.103515625e-5"],[0,"\n\n"],[8,"HALF_EPS","4.8828125e-4"],[0,"\n\n"],[9,"saturate",["a"],"clamp ( a , 0.0 , 1.0 )"],[0,"\nfloat pow2 ( float x ) { return x * x ; }\nfloat sRGBToLinear ( float value ) { float linearRGBLo = value / 12.92 ;\nfloat linearRGBHi = pow ( ( value + 0.055 ) / 1.055 , 2.4 ) ;\nfloat linearRGB = ( value <= 0.04045 ) ? linearRGBLo : linearRGBHi ;\nreturn linearRGB ; }\nvec4 sRGBToLinear ( vec4 value ) { return vec4 ( sRGBToLinear(value.r) , sRGBToLinear(value.g) , sRGBToLinear(value.b) , value.a ) ; }\nvec4 texture2DSRGB ( sampler2D tex, vec2 uv ) { vec4 color = texture2D ( tex , uv ) ;\n\n"],[1,"ENGINE_NO_SRGB",38],[0," color = sRGBToLinear(color) ; \n"],[6],[0,"\nreturn color ; }\nuniform vec4 camera_ProjectionParams;\n\n"],[1,"GRAPHICS_API_WEBGL2",44],[0,"\n\n"],[9,"INVERSE_MAT",["mat"],"inverse ( mat )"],[0,"\n\n"],[5,48],[0,"\nmat2 inverseMat ( mat2 m ) { return mat2 ( m[1][1] , - m[0][1] , - m[1][0] , m[0][0] ) / ( m[0][0] * m[1][1] - m[0][1] * m[1][0] ) ; }\nmat3 inverseMat ( mat3 m ) { float a00 = m[0][0] , a01 = m[0][1] , a02 = m[0][2] ;\nfloat a10 = m[1][0] , a11 = m[1][1] , a12 = m[1][2] ;\nfloat a20 = m[2][0] , a21 = m[2][1] , a22 = m[2][2] ;\nfloat b01 = a22 * a11 - a12 * a21 ;\nfloat b11 = - a22 * a10 + a12 * a20 ;\nfloat b21 = a21 * a10 - a11 * a20 ;\nfloat det = a00 * b01 + a01 * b11 + a02 * b21 ;\nreturn mat3 ( b01 , ( - a22 * a01 + a02 * a21 ) , ( a12 * a01 - a02 * a11 ) , b11 , ( a22 * a00 - a02 * a20 ) , ( - a12 * a00 + a02 * a10 ) , b21 , ( - a21 * a00 + a01 * a20 ) , ( a11 * a00 - a01 * a10 ) ) / det ; }\nmat4 inverseMat ( mat4 m ) { float a00 = m[0][0] , a01 = m[0][1] , a02 = m[0][2] , a03 = m[0][3] , a10 = m[1][0] , a11 = m[1][1] , a12 = m[1][2] , a13 = m[1][3] , a20 = m[2][0] , a21 = m[2][1] , a22 = m[2][2] , a23 = m[2][3] , a30 = m[3][0] , a31 = m[3][1] , a32 = m[3][2] , a33 = m[3][3] , b00 = a00 * a11 - a01 * a10 , b01 = a00 * a12 - a02 * a10 , b02 = a00 * a13 - a03 * a10 , b03 = a01 * a12 - a02 * a11 , b04 = a01 * a13 - a03 * a11 , b05 = a02 * a13 - a03 * a12 , b06 = a20 * a31 - a21 * a30 , b07 = a20 * a32 - a22 * a30 , b08 = a20 * a33 - a23 * a30 , b09 = a21 * a32 - a22 * a31 , b10 = a21 * a33 - a23 * a31 , b11 = a22 * a33 - a23 * a32 , det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06 ;\nreturn mat4 ( a11 * b11 - a12 * b10 + a13 * b09 , a02 * b10 - a01 * b11 - a03 * b09 , a31 * b05 - a32 * b04 + a33 * b03 , a22 * b04 - a21 * b05 - a23 * b03 , a12 * b08 - a10 * b11 - a13 * b07 , a00 * b11 - a02 * b08 + a03 * b07 , a32 * b02 - a30 * b05 - a33 * b01 , a20 * b05 - a22 * b02 + a23 * b01 , a10 * b10 - a11 * b08 + a13 * b06 , a01 * b08 - a00 * b10 - a03 * b06 , a30 * b04 - a31 * b02 + a33 * b00 , a21 * b02 - a20 * b04 - a23 * b00 , a11 * b07 - a10 * b09 - a12 * b06 , a00 * b09 - a01 * b07 + a02 * b06 , a31 * b01 - a30 * b03 - a32 * b00 , a20 * b03 - a21 * b01 + a22 * b00 ) / det ; }\n\n"],[9,"INVERSE_MAT",["mat"],"inverseMat(mat)"],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[2,"FOG_INCLUDED",70],[0,"\n\n"],[7,"FOG_INCLUDED"],[0,"\n\n"],[3,"SCENE_FOG_MODE","!=",0,68],[0,"\nuniform vec4 scene_FogColor;\nuniform vec4 scene_FogParams;\nvec4 fog ( vec4 color, vec3 positionVS ) { float fogDepth = length ( positionVS ) ;\n\n"],[3,"SCENE_FOG_MODE","==",1,60],[0," float fogIntensity = clamp ( fogDepth * scene_FogParams.x + scene_FogParams.y , 0.0 , 1.0 ) ; \n"],[5,66],[3,"SCENE_FOG_MODE","==",2,63],[0," float fogIntensity = clamp ( exp2 ( - fogDepth * scene_FogParams.z ) , 0.0 , 1.0 ) ; \n"],[5,66],[3,"SCENE_FOG_MODE","==",3,66],[0," float factor = fogDepth * scene_FogParams.w ;\nfloat fogIntensity = clamp ( exp2 ( - factor * factor ) , 0.0 , 1.0 ) ; \n"],[6],[0,"\ncolor.rgb = mix ( scene_FogColor.rgb , color.rgb , fogIntensity ) ;\nreturn color ; }\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[2,"TRANSFORM_INCLUDED",76],[0,"\n\n"],[7,"TRANSFORM_INCLUDED"],[0,"\nuniform mat4 camera_ViewMat;\nuniform mat4 camera_ProjMat;\nuniform vec3 camera_Position;\nuniform vec3 camera_Forward;\n\n"],[6],[0,"\n\n"],[2,"ATTRIBUTES_INCLUDED",82],[0,"\n\n"],[7,"ATTRIBUTES_INCLUDED"],[0,"\n\n"],[6],[0,"\n\n"],[2,"SKIN_INCLUDED",98],[0,"\n\n"],[7,"SKIN_INCLUDED"],[0,"\n\n"],[1,"RENDERER_HAS_SKIN",96],[0,"\n\n"],[1,"RENDERER_USE_JOINT_TEXTURE",92],[0,"\n\n"],[5,94],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[2,"BLENDSHAPE_INCLUDED",126],[0,"\n\n"],[7,"BLENDSHAPE_INCLUDED"],[0,"\n\n"],[1,"RENDERER_HAS_BLENDSHAPE",124],[0,"\n\n"],[1,"RENDERER_BLENDSHAPE_USE_TEXTURE",108],[0,"\n\n"],[5,122],[0,"\n\n"],[4,{"t":"and","l":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_NORMAL"},"r":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_TANGENT"}},112],[0,"\n\n"],[5,120],[0,"\n\n"],[4,{"t":"or","l":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_NORMAL"},"r":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_TANGENT"}},116],[0,"\n\n"],[5,118],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[2,"SHADOW_INCLUDED",218],[0,"\n\n"],[7,"SHADOW_INCLUDED"],[0,"\n\n"],[4,{"t":"and","l":{"t":"def","m":"SCENE_SHADOW_TYPE"},"r":{"t":"def","m":"RENDERER_IS_RECEIVE_SHADOWS"}},136],[0,"\n\n"],[7,"NEED_CALCULATE_SHADOWS"],[0,"\n\n"],[6],[0,"\n\n"],[1,"NEED_CALCULATE_SHADOWS",164],[0,"\nuniform mat4 scene_ShadowMatrices [ SCENE_SHADOW_CASCADED_COUNT + 1 ];\nuniform vec4 scene_ShadowSplitSpheres [ 4 ];\nmediump int computeCascadeIndex ( vec3 positionWS ) { vec3 fromCenter0 = positionWS - scene_ShadowSplitSpheres[0].xyz ;\nvec3 fromCenter1 = positionWS - scene_ShadowSplitSpheres[1].xyz ;\nvec3 fromCenter2 = positionWS - scene_ShadowSplitSpheres[2].xyz ;\nvec3 fromCenter3 = positionWS - scene_ShadowSplitSpheres[3].xyz ;\nmediump vec4 comparison = vec4 ( ( dot ( fromCenter0 , fromCenter0 ) < scene_ShadowSplitSpheres[0].w ) , ( dot ( fromCenter1 , fromCenter1 ) < scene_ShadowSplitSpheres[1].w ) , ( dot ( fromCenter2 , fromCenter2 ) < scene_ShadowSplitSpheres[2].w ) , ( dot ( fromCenter3 , fromCenter3 ) < scene_ShadowSplitSpheres[3].w ) ) ;\ncomparison.yzw = clamp ( comparison.yzw - comparison.xyz , 0.0 , 1.0 ) ;\nmediump vec4 indexCoefficient = vec4 ( 4.0 , 3.0 , 2.0 , 1.0 ) ;\nmediump int index = 4 - int ( dot ( comparison , indexCoefficient ) ) ;\nreturn index ; }\nvec3 getShadowCoord ( vec3 positionWS ) { \n"],[3,"SCENE_SHADOW_CASCADED_COUNT","==",1,142],[0," mediump int cascadeIndex = 0 ; \n"],[5,144],[0," mediump int cascadeIndex = computeCascadeIndex(positionWS) ; \n"],[6],[0,"\n\n"],[1,"GRAPHICS_API_WEBGL2",148],[0," mat4 shadowMatrix = scene_ShadowMatrices[cascadeIndex] ; \n"],[5,162],[0," mat4 shadowMatrix ;\n\n"],[3,"SCENE_SHADOW_CASCADED_COUNT","==",4,152],[0," if ( cascadeIndex == 0 ) { shadowMatrix = scene_ShadowMatrices[0] ; } else if ( cascadeIndex == 1 ) { shadowMatrix = scene_ShadowMatrices[1] ; } else if ( cascadeIndex == 2 ) { shadowMatrix = scene_ShadowMatrices[2] ; } else if ( cascadeIndex == 3 ) { shadowMatrix = scene_ShadowMatrices[3] ; } else { shadowMatrix = scene_ShadowMatrices[4] ; } \n"],[6],[0,"\n\n"],[3,"SCENE_SHADOW_CASCADED_COUNT","==",2,156],[0," if ( cascadeIndex == 0 ) { shadowMatrix = scene_ShadowMatrices[0] ; } else if ( cascadeIndex == 1 ) { shadowMatrix = scene_ShadowMatrices[1] ; } else { shadowMatrix = scene_ShadowMatrices[2] ; } \n"],[6],[0,"\n\n"],[3,"SCENE_SHADOW_CASCADED_COUNT","==",1,160],[0," if ( cascadeIndex == 0 ) { shadowMatrix = scene_ShadowMatrices[0] ; } else { shadowMatrix = scene_ShadowMatrices[1] ; } \n"],[6],[0," \n"],[6],[0,"\nvec4 shadowCoord = shadowMatrix * vec4 ( positionWS , 1.0 ) ;\nreturn shadowCoord.xyz ; }\n\n"],[6],[0,"\n\n"],[1,"NEED_CALCULATE_SHADOWS",216],[0,"\nuniform vec4 scene_ShadowInfo;\nuniform vec4 scene_ShadowMapSize;\n\n"],[1,"GRAPHICS_API_WEBGL2",174],[0,"\nuniform mediump sampler2DShadow scene_ShadowMap;\n\n"],[9,"SAMPLE_TEXTURE2D_SHADOW",["textureName","coord3"],"textureLod ( textureName , coord3 , 0.0 )"],[0,"\n\n"],[9,"TEXTURE2D_SHADOW_PARAM",["shadowMap"],"mediump sampler2DShadow shadowMap"],[0,"\n\n"],[5,188],[0,"\nuniform sampler2D scene_ShadowMap;\n\n"],[1,"ENGINE_NO_DEPTH_TEXTURE",180],[0,"\nconst vec4 bitShift = vec4 ( 1.0 , 1.0 / 256.0 , 1.0 / ( 256.0 * 256.0 ) , 1.0 / ( 256.0 * 256.0 * 256.0 ) );\nfloat textureShadowMapDowngrade ( sampler2D scene_ShadowMap, vec3 shadowCoord ) { vec4 rgbaDepth = texture2D ( scene_ShadowMap , shadowCoord.xy ) ;\nfloat unpackDepth = dot ( rgbaDepth , bitShift ) ;\nreturn unpackDepth < shadowCoord.z ? 0.0 : 1.0 ; }\n\n"],[9,"SAMPLE_TEXTURE2D_SHADOW",["textureName","coord3"],"textureShadowMapDowngrade(textureName, coord3)"],[0,"\n\n"],[5,184],[0,"\nfloat textureShadowMapDowngrade ( sampler2D scene_ShadowMap, vec3 shadowCoord ) { float depth = texture2D ( scene_ShadowMap , shadowCoord.xy ).r ;\nreturn depth < shadowCoord.z ? 0.0 : 1.0 ; }\n\n"],[9,"SAMPLE_TEXTURE2D_SHADOW",["textureName","coord3"],"textureShadowMapDowngrade(textureName, coord3)"],[0,"\n\n"],[6],[0,"\n\n"],[9,"TEXTURE2D_SHADOW_PARAM",["shadowMap"],"mediump sampler2D shadowMap"],[0,"\n\n"],[6],[0,"\n\n"],[3,"SCENE_SHADOW_TYPE","==",2,192],[0,"\nfloat sampleShadowMapFiltered4 ( TEXTURE2D_SHADOW_PARAM(shadowMap), vec3 shadowCoord, vec4 shadowMapSize ) { float attenuation ;\nvec4 attenuation4 ;\nvec2 offset = shadowMapSize.xy / 2.0 ;\nvec3 shadowCoord0 = shadowCoord + vec3 ( - offset , 0.0 ) ;\nvec3 shadowCoord1 = shadowCoord + vec3 ( offset.x , - offset.y , 0.0 ) ;\nvec3 shadowCoord2 = shadowCoord + vec3 ( - offset.x , offset.y , 0.0 ) ;\nvec3 shadowCoord3 = shadowCoord + vec3 ( offset , 0.0 ) ;\nattenuation4.x = SAMPLE_TEXTURE2D_SHADOW(shadowMap, shadowCoord0) ;\nattenuation4.y = SAMPLE_TEXTURE2D_SHADOW(shadowMap, shadowCoord1) ;\nattenuation4.z = SAMPLE_TEXTURE2D_SHADOW(shadowMap, shadowCoord2) ;\nattenuation4.w = SAMPLE_TEXTURE2D_SHADOW(shadowMap, shadowCoord3) ;\nattenuation = dot ( attenuation4 , vec4 ( 0.25 ) ) ;\nreturn attenuation ; }\n\n"],[6],[0,"\n\n"],[3,"SCENE_SHADOW_TYPE","==",3,202],[0,"\n\n"],[2,"SHADOW_SAMPLE_TENT_INCLUDED",200],[0,"\n\n"],[7,"SHADOW_SAMPLE_TENT_INCLUDED"],[0,"\nfloat sampleShadowGetIRTriangleTexelArea ( float triangleHeight ) { return triangleHeight - 0.5 ; }\nvoid sampleShadowGetTexelAreasTent3x3 ( float offset, out vec4 computedArea, out vec4 computedAreaUncut ) { float a = offset + 0.5 ;\nfloat offsetSquaredHalved = a * a * 0.5 ;\ncomputedAreaUncut.x = computedArea.x = offsetSquaredHalved - offset ;\ncomputedAreaUncut.w = computedArea.w = offsetSquaredHalved ;\ncomputedAreaUncut.y = sampleShadowGetIRTriangleTexelArea(1.5 - offset) ;\nfloat clampedOffsetLeft = min ( offset , 0.0 ) ;\nfloat areaOfSmallLeftTriangle = clampedOffsetLeft * clampedOffsetLeft ;\ncomputedArea.y = computedAreaUncut.y - areaOfSmallLeftTriangle ;\ncomputedAreaUncut.z = sampleShadowGetIRTriangleTexelArea(1.5 + offset) ;\nfloat clampedOffsetRight = max ( offset , 0.0 ) ;\nfloat areaOfSmallRightTriangle = clampedOffsetRight * clampedOffsetRight ;\ncomputedArea.z = computedAreaUncut.z - areaOfSmallRightTriangle ; }\nvoid sampleShadowGetTexelWeightsTent5x5 ( float offset, out vec3 texelsWeightsA, out vec3 texelsWeightsB ) { vec4 areaFrom3texelTriangle ;\nvec4 areaUncutFrom3texelTriangle ;\nsampleShadowGetTexelAreasTent3x3(offset, areaFrom3texelTriangle, areaUncutFrom3texelTriangle) ;\ntexelsWeightsA.x = 0.16 * ( areaFrom3texelTriangle.x ) ;\ntexelsWeightsA.y = 0.16 * ( areaUncutFrom3texelTriangle.y ) ;\ntexelsWeightsA.z = 0.16 * ( areaFrom3texelTriangle.y + 1.0 ) ;\ntexelsWeightsB.x = 0.16 * ( areaFrom3texelTriangle.z + 1.0 ) ;\ntexelsWeightsB.y = 0.16 * ( areaUncutFrom3texelTriangle.z ) ;\ntexelsWeightsB.z = 0.16 * ( areaFrom3texelTriangle.w ) ; }\nvoid sampleShadowComputeSamplesTent5x5 ( vec4 shadowMapTextureTexelSize, vec2 coord, out float fetchesWeights [ 9 ], out vec2 fetchesUV [ 9 ] ) { vec2 tentCenterInTexelSpace = coord.xy * shadowMapTextureTexelSize.zw ;\nvec2 centerOfFetchesInTexelSpace = floor ( tentCenterInTexelSpace + 0.5 ) ;\nvec2 offsetFromTentCenterToCenterOfFetches = tentCenterInTexelSpace - centerOfFetchesInTexelSpace ;\nvec3 texelsWeightsUA , texelsWeightsUB ;\nvec3 texelsWeightsVA , texelsWeightsVB ;\nsampleShadowGetTexelWeightsTent5x5(offsetFromTentCenterToCenterOfFetches.x, texelsWeightsUA, texelsWeightsUB) ;\nsampleShadowGetTexelWeightsTent5x5(offsetFromTentCenterToCenterOfFetches.y, texelsWeightsVA, texelsWeightsVB) ;\nvec3 fetchesWeightsU = vec3 ( texelsWeightsUA.xz , texelsWeightsUB.y ) + vec3 ( texelsWeightsUA.y , texelsWeightsUB.xz ) ;\nvec3 fetchesWeightsV = vec3 ( texelsWeightsVA.xz , texelsWeightsVB.y ) + vec3 ( texelsWeightsVA.y , texelsWeightsVB.xz ) ;\nvec3 fetchesOffsetsU = vec3 ( texelsWeightsUA.y , texelsWeightsUB.xz ) / fetchesWeightsU.xyz + vec3 ( - 2.5 , - 0.5 , 1.5 ) ;\nvec3 fetchesOffsetsV = vec3 ( texelsWeightsVA.y , texelsWeightsVB.xz ) / fetchesWeightsV.xyz + vec3 ( - 2.5 , - 0.5 , 1.5 ) ;\nfetchesOffsetsU *= shadowMapTextureTexelSize.xxx ;\nfetchesOffsetsV *= shadowMapTextureTexelSize.yyy ;\nvec2 bilinearFetchOrigin = centerOfFetchesInTexelSpace * shadowMapTextureTexelSize.xy ;\nfetchesUV[0] = bilinearFetchOrigin + vec2 ( fetchesOffsetsU.x , fetchesOffsetsV.x ) ;\nfetchesUV[1] = bilinearFetchOrigin + vec2 ( fetchesOffsetsU.y , fetchesOffsetsV.x ) ;\nfetchesUV[2] = bilinearFetchOrigin + vec2 ( fetchesOffsetsU.z , fetchesOffsetsV.x ) ;\nfetchesUV[3] = bilinearFetchOrigin + vec2 ( fetchesOffsetsU.x , fetchesOffsetsV.y ) ;\nfetchesUV[4] = bilinearFetchOrigin + vec2 ( fetchesOffsetsU.y , fetchesOffsetsV.y ) ;\nfetchesUV[5] = bilinearFetchOrigin + vec2 ( fetchesOffsetsU.z , fetchesOffsetsV.y ) ;\nfetchesUV[6] = bilinearFetchOrigin + vec2 ( fetchesOffsetsU.x , fetchesOffsetsV.z ) ;\nfetchesUV[7] = bilinearFetchOrigin + vec2 ( fetchesOffsetsU.y , fetchesOffsetsV.z ) ;\nfetchesUV[8] = bilinearFetchOrigin + vec2 ( fetchesOffsetsU.z , fetchesOffsetsV.z ) ;\nfetchesWeights[0] = fetchesWeightsU.x * fetchesWeightsV.x ;\nfetchesWeights[1] = fetchesWeightsU.y * fetchesWeightsV.x ;\nfetchesWeights[2] = fetchesWeightsU.z * fetchesWeightsV.x ;\nfetchesWeights[3] = fetchesWeightsU.x * fetchesWeightsV.y ;\nfetchesWeights[4] = fetchesWeightsU.y * fetchesWeightsV.y ;\nfetchesWeights[5] = fetchesWeightsU.z * fetchesWeightsV.y ;\nfetchesWeights[6] = fetchesWeightsU.x * fetchesWeightsV.z ;\nfetchesWeights[7] = fetchesWeightsU.y * fetchesWeightsV.z ;\nfetchesWeights[8] = fetchesWeightsU.z * fetchesWeightsV.z ; }\n\n"],[6],[0,"\nfloat sampleShadowMapFiltered9 ( TEXTURE2D_SHADOW_PARAM(shadowMap), vec3 shadowCoord, vec4 shadowmapSize ) { float attenuation ;\nfloat fetchesWeights [ 9 ] ;\nvec2 fetchesUV [ 9 ] ;\nsampleShadowComputeSamplesTent5x5(shadowmapSize, shadowCoord.xy, fetchesWeights, fetchesUV) ;\nattenuation = fetchesWeights[0] * SAMPLE_TEXTURE2D_SHADOW(shadowMap, vec3 ( fetchesUV[0].xy , shadowCoord.z )) ;\nattenuation += fetchesWeights[1] * SAMPLE_TEXTURE2D_SHADOW(shadowMap, vec3 ( fetchesUV[1].xy , shadowCoord.z )) ;\nattenuation += fetchesWeights[2] * SAMPLE_TEXTURE2D_SHADOW(shadowMap, vec3 ( fetchesUV[2].xy , shadowCoord.z )) ;\nattenuation += fetchesWeights[3] * SAMPLE_TEXTURE2D_SHADOW(shadowMap, vec3 ( fetchesUV[3].xy , shadowCoord.z )) ;\nattenuation += fetchesWeights[4] * SAMPLE_TEXTURE2D_SHADOW(shadowMap, vec3 ( fetchesUV[4].xy , shadowCoord.z )) ;\nattenuation += fetchesWeights[5] * SAMPLE_TEXTURE2D_SHADOW(shadowMap, vec3 ( fetchesUV[5].xy , shadowCoord.z )) ;\nattenuation += fetchesWeights[6] * SAMPLE_TEXTURE2D_SHADOW(shadowMap, vec3 ( fetchesUV[6].xy , shadowCoord.z )) ;\nattenuation += fetchesWeights[7] * SAMPLE_TEXTURE2D_SHADOW(shadowMap, vec3 ( fetchesUV[7].xy , shadowCoord.z )) ;\nattenuation += fetchesWeights[8] * SAMPLE_TEXTURE2D_SHADOW(shadowMap, vec3 ( fetchesUV[8].xy , shadowCoord.z )) ;\nreturn attenuation ; }\n\n"],[6],[0,"\nfloat getShadowFade ( vec3 positionWS ) { vec3 camToPixel = positionWS - camera_Position ;\nfloat distanceCamToPixel2 = dot ( camToPixel , camToPixel ) ;\nreturn saturate(distanceCamToPixel2 * scene_ShadowInfo.z + scene_ShadowInfo.w) ; }\nfloat sampleShadowMap ( vec3 positionWS, vec3 shadowCoord ) { float attenuation = 1.0 ;\nif ( shadowCoord.z > 0.0 && shadowCoord.z < 1.0 ) { \n"],[3,"SCENE_SHADOW_TYPE","==",1,206],[0," attenuation = SAMPLE_TEXTURE2D_SHADOW(scene_ShadowMap, shadowCoord) ; \n"],[6],[0,"\n\n"],[3,"SCENE_SHADOW_TYPE","==",2,210],[0," attenuation = sampleShadowMapFiltered4(scene_ShadowMap, shadowCoord, scene_ShadowMapSize) ; \n"],[6],[0,"\n\n"],[3,"SCENE_SHADOW_TYPE","==",3,214],[0," attenuation = sampleShadowMapFiltered9(scene_ShadowMap, shadowCoord, scene_ShadowMapSize) ; \n"],[6],[0,"\nfloat shadowFade = getShadowFade(positionWS) ;\nattenuation = mix ( 1.0 , mix ( attenuation , 1.0 , shadowFade ) , scene_ShadowInfo.x ) ; }\nreturn attenuation ; }\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[2,"VARYINGS_PBR_INCLUDED",248],[0,"\n\n"],[7,"VARYINGS_PBR_INCLUDED"],[0,"\nvarying vec2 uv;\n\n"],[1,"RENDERER_HAS_UV1",226],[0,"varying vec2 uv1;\n\n"],[6],[0,"\n"],[1,"RENDERER_ENABLE_VERTEXCOLOR",230],[0,"varying vec4 vertexColor;\n\n"],[6],[0,"varying vec3 positionWS;\n\n"],[3,"SCENE_FOG_MODE","!=",0,234],[0,"varying vec3 positionVS;\n\n"],[6],[0,"\n"],[1,"RENDERER_HAS_NORMAL",242],[0,"varying vec3 normalWS;\n\n"],[1,"NEED_VERTEX_TANGENT",240],[0,"varying vec3 tangentWS;\nvarying vec3 bitangentWS;\n\n"],[6],[0,"\n"],[6],[0,"\n"],[4,{"t":"and","l":{"t":"def","m":"NEED_CALCULATE_SHADOWS"},"r":{"t":"cmp","m":"SCENE_SHADOW_CASCADED_COUNT","op":"==","v":1}},246],[0,"varying vec3 shadowCoord;\n\n"],[6],[0,"varying vec4 positionCS;\n\n\n"],[6],[0,"\n\n"],[2,"LIGHT_DIRECT_PBR_INCLUDED",539],[0,"\n\n"],[7,"LIGHT_DIRECT_PBR_INCLUDED"],[0,"\n\n"],[2,"FUNCTION_SURFACE_SHADING",258],[0,"\n\n"],[8,"FUNCTION_SURFACE_SHADING","surfaceShading"],[0,"\n\n"],[6],[0,"\n\n"],[2,"FUNCTION_DIFFUSE_LOBE",264],[0,"\n\n"],[8,"FUNCTION_DIFFUSE_LOBE","diffuseLobe"],[0,"\n\n"],[6],[0,"\n\n"],[2,"FUNCTION_SPECULAR_LOBE",270],[0,"\n\n"],[8,"FUNCTION_SPECULAR_LOBE","specularLobe"],[0,"\n\n"],[6],[0,"\n\n"],[2,"FUNCTION_CLEAR_COAT_LOBE",276],[0,"\n\n"],[8,"FUNCTION_CLEAR_COAT_LOBE","clearCoatLobe"],[0,"\n\n"],[6],[0,"\n\n"],[2,"FUNCTION_SHEEN_LOBE",282],[0,"\n\n"],[8,"FUNCTION_SHEEN_LOBE","sheenLobe"],[0,"\n\n"],[6],[0,"\n\n"],[2,"BSDF_INCLUDED",429],[0,"\n\n"],[7,"BSDF_INCLUDED"],[0,"\n\n"],[2,"REFRACTION_INCLUDED",296],[0,"\n\n"],[7,"REFRACTION_INCLUDED"],[0,"\n\n"],[1,"MATERIAL_ENABLE_TRANSMISSION",294],[0,"\nstruct RefractionModelResult { float transmissionLength ; vec3 positionExit ; } ;\nvoid refractionModelSphere ( vec3 V, vec3 positionWS, vec3 normalWS, float ior, float thickness, out RefractionModelResult ray ) { vec3 R1 = refract ( V , normalWS , 1.0 / ior ) ;\nfloat dist = dot ( - normalWS , R1 ) * thickness ;\nvec3 P1 = positionWS + R1 * dist ;\nray.transmissionLength = dist ;\nray.positionExit = P1 ; }\nvoid refractionModelPlanar ( vec3 V, vec3 positionWS, vec3 normalWS, float ior, float thickness, out RefractionModelResult ray ) { vec3 R = refract ( V , normalWS , 1.0 / ior ) ;\nfloat dist = thickness / max ( dot ( - normalWS , R ) , 1e-5f ) ;\nray.transmissionLength = dist ;\nray.positionExit = vec3 ( positionWS + R * dist ) ; }\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[8,"MIN_PERCEPTUAL_ROUGHNESS","0.045"],[0,"\n\n"],[8,"MIN_ROUGHNESS","0.002025"],[0,"\n\n"],[1,"MATERIAL_ENABLE_SHEEN",304],[0,"\nuniform sampler2D scene_PrefilteredDFG;\n\n"],[6],[0,"\nstruct SurfaceData { vec3 albedoColor ; vec3 emissiveColor ; float metallic ; float roughness ; float ambientOcclusion ; float opacity ; float IOR ; vec3 position ; vec4 positionCS ; vec3 normal ; \n"],[1,"NEED_TANGENT_SPACE",308],[0," vec3 tangent ; vec3 bitangent ; \n"],[6],[0," vec3 viewDir ; float dotNV ; float specularIntensity ; vec3 specularColor ; \n"],[1,"MATERIAL_ENABLE_ANISOTROPY",312],[0," float anisotropy ; vec3 anisotropicT ; vec3 anisotropicB ; vec3 anisotropicN ; \n"],[6],[0," \n"],[1,"MATERIAL_ENABLE_CLEAR_COAT",316],[0," float clearCoat ; float clearCoatRoughness ; vec3 clearCoatNormal ; float clearCoatDotNV ; \n"],[6],[0," \n"],[1,"MATERIAL_ENABLE_IRIDESCENCE",320],[0," float iridescenceIOR ; float iridescenceFactor ; float iridescenceThickness ; \n"],[6],[0," \n"],[1,"MATERIAL_ENABLE_SHEEN",324],[0," float sheenRoughness ; vec3 sheenColor ; \n"],[6],[0," \n"],[1,"MATERIAL_ENABLE_TRANSMISSION",328],[0," vec3 absorptionCoefficient ; float transmission ; float thickness ; \n"],[6],[0," } ;\nstruct BSDFData { vec3 diffuseColor ; float roughness ; vec3 envSpecularDFG ; float diffuseAO ; vec3 specularF0 ; vec3 resolvedSpecularF0 ; float specularF90 ; vec3 energyCompensation ; \n"],[1,"MATERIAL_ENABLE_CLEAR_COAT",332],[0," vec3 clearCoatSpecularColor ; float clearCoatRoughness ; \n"],[6],[0," \n"],[1,"MATERIAL_ENABLE_IRIDESCENCE",336],[0," vec3 iridescenceSpecularColor ; \n"],[6],[0," \n"],[1,"MATERIAL_ENABLE_SHEEN",340],[0," float sheenRoughness ; float sheenScaling ; float approxIBLSheenDG ; \n"],[6],[0," } ;\nfloat getAARoughnessFactor ( vec3 normal ) { \n"],[1,"HAS_DERIVATIVES",344],[0," vec3 dxy = max ( abs ( dFdx ( normal ) ) , abs ( dFdy ( normal ) ) ) ;\nreturn max ( max ( dxy.x , dxy.y ) , dxy.z ) ; \n"],[5,346],[0," return 0.0 ; \n"],[6],[0," }\nfloat F_Schlick ( float f0, float f90, float dotLH ) { return f0 + ( f90 - f0 ) * ( pow ( 1.0 - dotLH , 5.0 ) ) ; }\nvec3 F_Schlick ( vec3 f0, float f90, float dotLH ) { float fresnel = exp2 ( ( - 5.55473 * dotLH - 6.98316 ) * dotLH ) ;\nreturn ( f90 - f0 ) * fresnel + f0 ; }\nfloat G_GGX_SmithCorrelated ( float alpha, float dotNL, float dotNV ) { float a2 = pow2(alpha) ;\nfloat gv = dotNL * sqrt ( a2 + ( 1.0 - a2 ) * pow2(dotNV) ) ;\nfloat gl = dotNV * sqrt ( a2 + ( 1.0 - a2 ) * pow2(dotNL) ) ;\nreturn 0.5 / max ( gv + gl , EPSILON ) ; }\n\n"],[1,"MATERIAL_ENABLE_ANISOTROPY",350],[0,"\nfloat G_GGX_SmithCorrelated_Anisotropic ( float at, float ab, float ToV, float BoV, float ToL, float BoL, float NoV, float NoL ) { float lambdaV = NoL * length ( vec3 ( at * ToV , ab * BoV , NoV ) ) ;\nfloat lambdaL = NoV * length ( vec3 ( at * ToL , ab * BoL , NoL ) ) ;\nreturn 0.5 / max ( lambdaV + lambdaL , EPSILON ) ; }\n\n"],[6],[0,"\nfloat D_GGX ( float alpha, float dotNH ) { float a2 = pow2(alpha) ;\nfloat denom = pow2(dotNH) * ( a2 - 1.0 ) + 1.0 ;\nreturn RECIPROCAL_PI * a2 / pow2(denom) ; }\n\n"],[1,"MATERIAL_ENABLE_ANISOTROPY",354],[0,"\nfloat D_GGX_Anisotropic ( float at, float ab, float ToH, float BoH, float NoH ) { float a2 = at * ab ;\nhighp vec3 d = vec3 ( ab * ToH , at * BoH , a2 * NoH ) ;\nhighp float d2 = dot ( d , d ) ;\nfloat b2 = a2 / d2 ;\nreturn a2 * b2 * b2 * RECIPROCAL_PI ; }\n\n"],[6],[0,"\nfloat DG_GGX ( float alpha, float dotNV, float dotNL, float dotNH ) { float D = D_GGX(alpha, dotNH) ;\nfloat G = G_GGX_SmithCorrelated(alpha, dotNL, dotNV) ;\nreturn G * D ; }\n\n"],[1,"MATERIAL_ENABLE_ANISOTROPY",358],[0,"\nfloat DG_GGX_anisotropic ( vec3 h, vec3 l, SurfaceData surfaceData, float alpha, float dotNV, float dotNL, float dotNH ) { vec3 t = surfaceData.anisotropicT ;\nvec3 b = surfaceData.anisotropicB ;\nvec3 v = surfaceData.viewDir ;\nfloat dotTV = dot ( t , v ) ;\nfloat dotBV = dot ( b , v ) ;\nfloat dotTL = dot ( t , l ) ;\nfloat dotBL = dot ( b , l ) ;\nfloat dotTH = dot ( t , h ) ;\nfloat dotBH = dot ( b , h ) ;\nfloat at = max ( alpha * ( 1.0 + surfaceData.anisotropy ) , MIN_ROUGHNESS ) ;\nfloat ab = max ( alpha * ( 1.0 - surfaceData.anisotropy ) , MIN_ROUGHNESS ) ;\nfloat D = D_GGX_Anisotropic(at, ab, dotTH, dotBH, dotNH) ;\nfloat G = G_GGX_SmithCorrelated_Anisotropic(at, ab, dotTV, dotBV, dotTL, dotBL, dotNV, dotNL) ;\nreturn G * D ; }\n\n"],[6],[0,"\nvec3 BRDF_Specular_GGX ( vec3 incidentDirection, SurfaceData surfaceData, BSDFData bsdfData, vec3 normal, vec3 specularColor, float roughness ) { float alpha = pow2(roughness) ;\nvec3 halfDir = normalize ( incidentDirection + surfaceData.viewDir ) ;\nfloat dotNL = saturate(dot ( normal , incidentDirection )) ;\nfloat dotNV = saturate(dot ( normal , surfaceData.viewDir )) ;\nfloat dotNH = saturate(dot ( normal , halfDir )) ;\nfloat dotLH = saturate(dot ( incidentDirection , halfDir )) ;\nvec3 F = F_Schlick(specularColor, bsdfData.specularF90, dotLH) ;\n\n"],[1,"MATERIAL_ENABLE_IRIDESCENCE",362],[0," F = mix ( F , bsdfData.iridescenceSpecularColor , surfaceData.iridescenceFactor ) ; \n"],[6],[0,"\n\n"],[1,"MATERIAL_ENABLE_ANISOTROPY",366],[0," float GD = DG_GGX_anisotropic(halfDir, incidentDirection, surfaceData, alpha, dotNV, dotNL, dotNH) ; \n"],[5,368],[0," float GD = DG_GGX(alpha, dotNV, dotNL, dotNH) ; \n"],[6],[0,"\nreturn F * GD ; }\nvec3 BRDF_Diffuse_Lambert ( vec3 diffuseColor ) { return RECIPROCAL_PI * diffuseColor ; }\n\n"],[1,"MATERIAL_ENABLE_IRIDESCENCE",372],[0,"\nvec3 iorToFresnel0 ( vec3 transmittedIOR, float incidentIOR ) { return pow ( ( transmittedIOR - incidentIOR ) / ( transmittedIOR + incidentIOR ) , vec3 ( 2.0 ) ) ; }\nfloat iorToFresnel0 ( float transmittedIOR, float incidentIOR ) { return pow ( ( transmittedIOR - incidentIOR ) / ( transmittedIOR + incidentIOR ) , 2.0 ) ; }\nvec3 fresnelToIOR ( vec3 f0 ) { vec3 sqrtF0 = sqrt ( f0 ) ;\nreturn ( vec3 ( 1.0 ) + sqrtF0 ) / ( vec3 ( 1.0 ) - sqrtF0 ) ; }\nvec3 evalSensitivity ( float opd, vec3 shift ) { float phase = 2.0 * PI * opd * 1.0e-9 ;\nconst vec3 val = vec3 ( 5.4856e-13 , 4.4201e-13 , 5.2481e-13 ) ;\nconst vec3 pos = vec3 ( 1.6810e+06 , 1.7953e+06 , 2.2084e+06 ) ;\nconst vec3 var = vec3 ( 4.3278e+09 , 9.3046e+09 , 6.6121e+09 ) ;\nvec3 xyz = val * sqrt ( 2.0 * PI * var ) * cos ( pos * phase + shift ) * exp ( - var * pow2(phase) ) ;\nxyz.x += 9.7470e-14 * sqrt ( 2.0 * PI * 4.5282e+09 ) * cos ( 2.2399e+06 * phase + shift[0] ) * exp ( - 4.5282e+09 * pow2(phase) ) ;\nxyz /= 1.0685e-7 ;\nconst mat3 XYZ_TO_RGB = mat3 ( 3.2404542 , - 0.9692660 , 0.0556434 , - 1.5371385 , 1.8760108 , - 0.2040259 , - 0.4985314 , 0.0415560 , 1.0572252 ) ;\nvec3 rgb = XYZ_TO_RGB * xyz ;\nreturn rgb ; }\nvec3 evalIridescenceSpecular ( float outsideIOR, float dotNV, float thinIOR, vec3 baseF0, float baseF90, float iridescenceThickness ) { vec3 iridescence = vec3 ( 1.0 ) ;\nfloat iridescenceIOR = mix ( outsideIOR , thinIOR , smoothstep ( 0.0 , 0.03 , iridescenceThickness ) ) ;\nfloat sinTheta2Sq = pow ( outsideIOR / iridescenceIOR , 2.0 ) * ( 1.0 - pow ( dotNV , 2.0 ) ) ;\nfloat cosTheta2Sq = 1.0 - sinTheta2Sq ;\nif ( cosTheta2Sq < 0.0 ) { return iridescence ; }\nfloat cosTheta2 = sqrt ( cosTheta2Sq ) ;\nfloat f0 = iorToFresnel0(iridescenceIOR, outsideIOR) ;\nfloat reflectance = F_Schlick(f0, baseF90, dotNV) ;\nfloat t121 = 1.0 - reflectance ;\nfloat phi12 = 0.0 ;\nfloat phi21 = PI - phi12 ;\nvec3 baseIOR = fresnelToIOR(clamp ( baseF0 , 0.0 , 0.9999 )) ;\nvec3 r1 = iorToFresnel0(baseIOR, iridescenceIOR) ;\nvec3 r23 = F_Schlick(r1, baseF90, cosTheta2) ;\nvec3 phi23 = vec3 ( 0.0 ) ;\nif ( baseIOR[0] < iridescenceIOR ) { phi23[0] = PI ; }\nif ( baseIOR[1] < iridescenceIOR ) { phi23[1] = PI ; }\nif ( baseIOR[2] < iridescenceIOR ) { phi23[2] = PI ; }\nfloat opd = 2.0 * iridescenceIOR * iridescenceThickness * cosTheta2 ;\nvec3 phi = vec3 ( phi21 ) + phi23 ;\nvec3 r123 = clamp ( reflectance * r23 , 1e-5 , 0.9999 ) ;\nvec3 sr123 = sqrt ( r123 ) ;\nvec3 rs = pow2(t121) * r23 / ( vec3 ( 1.0 ) - r123 ) ;\nvec3 c0 = reflectance + rs ;\niridescence = c0 ;\nvec3 cm = rs - t121 ;\nfor ( int m = 1 ; m <= 2 ; ++ m ) { cm *= sr123 ;\nvec3 sm = 2.0 * evalSensitivity(float ( m ) * opd, float ( m ) * phi) ;\niridescence += cm * sm ; }\nreturn iridescence = max ( iridescence , vec3 ( 0.0 ) ) ; }\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_ENABLE_SHEEN",382],[0,"\nfloat D_Charlie ( float roughness, float dotNH ) { float invAlpha = 1.0 / roughness ;\nfloat cos2h = dotNH * dotNH ;\nfloat sin2h = max ( 1.0 - cos2h , 0.0078125 ) ;\nreturn ( 2.0 + invAlpha ) * pow ( sin2h , invAlpha * 0.5 ) / ( 2.0 * PI ) ; }\nfloat V_Neubelt ( float NoV, float NoL ) { return saturate(1.0 / ( 4.0 * ( NoL + NoV - NoL * NoV ) )) ; }\nvec3 sheenBRDF ( vec3 incidentDirection, SurfaceData surfaceData, vec3 sheenColor, float sheenRoughness ) { vec3 halfDir = normalize ( incidentDirection + surfaceData.viewDir ) ;\nfloat dotNL = saturate(dot ( surfaceData.normal , incidentDirection )) ;\nfloat dotNH = saturate(dot ( surfaceData.normal , halfDir )) ;\nfloat D = D_Charlie(sheenRoughness, dotNH) ;\nfloat V = V_Neubelt(surfaceData.dotNV, dotNL) ;\nvec3 F = sheenColor ;\nreturn D * V * F ; }\nfloat prefilteredSheenDFG ( float dotNV, float sheenRoughness ) { \n"],[1,"HAS_TEX_LOD",378],[0," return texture2DLodEXT ( scene_PrefilteredDFG , vec2 ( dotNV , sheenRoughness ) , 0.0 ).b ; \n"],[5,380],[0," return texture2D ( scene_PrefilteredDFG , vec2 ( dotNV , sheenRoughness ) , 0.0 ).b ; \n"],[6],[0," }\n\n"],[6],[0,"\nvec2 envDFGApprox ( float roughness, float dotNV ) { const vec4 c0 = vec4 ( - 1 , - 0.0275 , - 0.572 , 0.022 ) ;\nconst vec4 c1 = vec4 ( 1 , 0.0425 , 1.04 , - 0.04 ) ;\nvec4 r = roughness * c0 + c1 ;\nfloat a004 = min ( r.x * r.x , exp2 ( - 9.28 * dotNV ) ) * r.x + r.y ;\nreturn vec2 ( - 1.04 , 1.04 ) * a004 + r.zw ; }\nvec3 envBRDFApprox ( vec3 f0, float f90, float roughness, float dotNV ) { vec2 AB = envDFGApprox(roughness, dotNV) ;\nreturn f0 * AB.x + f90 * AB.y ; }\n\n"],[1,"MATERIAL_ENABLE_TRANSMISSION",397],[0,"\nuniform sampler2D camera_OpaqueTexture;\nvec3 evaluateTransmission ( SurfaceData surfaceData, BSDFData bsdfData ) { RefractionModelResult ray ;\n\n"],[3,"REFRACTION_MODE","==",0,388],[0," refractionModelSphere(- surfaceData.viewDir, surfaceData.position, surfaceData.normal, surfaceData.IOR, surfaceData.thickness, ray) ; \n"],[5,391],[3,"REFRACTION_MODE","==",1,391],[0," refractionModelPlanar(- surfaceData.viewDir, surfaceData.position, surfaceData.normal, surfaceData.IOR, surfaceData.thickness, ray) ; \n"],[6],[0,"\nvec3 refractedRayExit = ray.positionExit ;\nvec4 samplingPositionNDC = camera_ProjMat * camera_ViewMat * vec4 ( refractedRayExit , 1.0 ) ;\nvec2 refractionCoords = ( samplingPositionNDC.xy / samplingPositionNDC.w ) * 0.5 + 0.5 ;\nvec3 refractionTransmitted = texture2DSRGB(camera_OpaqueTexture, refractionCoords).rgb ;\nrefractionTransmitted *= bsdfData.diffuseColor ;\nrefractionTransmitted *= ( 1.0 - max ( max ( bsdfData.envSpecularDFG.r , bsdfData.envSpecularDFG.g ) , bsdfData.envSpecularDFG.b ) ) ;\n\n"],[1,"MATERIAL_HAS_THICKNESS",395],[0," vec3 transmittance = min ( vec3 ( 1.0 ) , exp ( - surfaceData.absorptionCoefficient * ray.transmissionLength ) ) ;\nrefractionTransmitted *= transmittance ; \n"],[6],[0,"\nreturn refractionTransmitted ; }\n\n"],[6],[0,"\n\n"],[1,"SCENE_ENABLE_AMBIENT_OCCLUSION",407],[0,"\nuniform sampler2D camera_AOTexture;\nfloat evaluateAmbientOcclusion ( vec2 uv ) { \n"],[1,"MATERIAL_IS_TRANSPARENT",403],[0," return 1.0 ; \n"],[5,405],[0," return texture2D ( camera_AOTexture , uv ).r ; \n"],[6],[0," }\n\n"],[6],[0,"\nvoid initBSDFData ( SurfaceData surfaceData, out BSDFData bsdfData ) { vec3 albedoColor = surfaceData.albedoColor ;\nfloat metallic = surfaceData.metallic ;\nfloat roughness = surfaceData.roughness ;\nvec3 dielectricBaseF0 = vec3 ( pow2(( surfaceData.IOR - 1.0 ) / ( surfaceData.IOR + 1.0 )) ) ;\nvec3 dielectricF0 = min ( dielectricBaseF0 * surfaceData.specularColor , vec3 ( 1.0 ) ) * surfaceData.specularIntensity ;\nfloat dielectricF90 = surfaceData.specularIntensity ;\nbsdfData.specularF0 = mix ( dielectricF0 , albedoColor , metallic ) ;\nbsdfData.specularF90 = mix ( dielectricF90 , 1.0 , metallic ) ;\nbsdfData.diffuseColor = albedoColor * ( 1.0 - metallic ) * ( 1.0 - max ( max ( dielectricF0.r , dielectricF0.g ) , dielectricF0.b ) ) ;\nbsdfData.roughness = max ( MIN_PERCEPTUAL_ROUGHNESS , min ( roughness + getAARoughnessFactor(surfaceData.normal) , 1.0 ) ) ;\n\n"],[1,"MATERIAL_ENABLE_IRIDESCENCE",411],[0," float topIOR = 1.0 ;\nbsdfData.iridescenceSpecularColor = evalIridescenceSpecular(topIOR, surfaceData.dotNV, surfaceData.iridescenceIOR, bsdfData.specularF0, bsdfData.specularF90, surfaceData.iridescenceThickness) ; \n"],[6],[0,"\nbsdfData.resolvedSpecularF0 = bsdfData.specularF0 ;\n\n"],[1,"MATERIAL_ENABLE_IRIDESCENCE",415],[0," bsdfData.resolvedSpecularF0 = mix ( bsdfData.resolvedSpecularF0 , bsdfData.iridescenceSpecularColor , surfaceData.iridescenceFactor ) ; \n"],[6],[0,"\nvec2 dfg = envDFGApprox(bsdfData.roughness, surfaceData.dotNV) ;\nbsdfData.envSpecularDFG = bsdfData.resolvedSpecularF0 * dfg.x + bsdfData.specularF90 * dfg.y ;\nbsdfData.energyCompensation = 1.0 + bsdfData.resolvedSpecularF0 * ( 1.0 / max ( dfg.x + dfg.y , EPSILON ) - 1.0 ) ;\nbsdfData.diffuseAO = surfaceData.ambientOcclusion ;\n\n"],[1,"SCENE_ENABLE_AMBIENT_OCCLUSION",419],[0," float ambientAO = evaluateAmbientOcclusion(( surfaceData.positionCS.xy / surfaceData.positionCS.w ) * 0.5 + 0.5) ;\nbsdfData.diffuseAO = min ( bsdfData.diffuseAO , ambientAO ) ; \n"],[6],[0,"\n\n"],[1,"MATERIAL_ENABLE_CLEAR_COAT",423],[0," bsdfData.clearCoatRoughness = max ( MIN_PERCEPTUAL_ROUGHNESS , min ( surfaceData.clearCoatRoughness + getAARoughnessFactor(surfaceData.clearCoatNormal) , 1.0 ) ) ;\nbsdfData.clearCoatSpecularColor = vec3 ( 0.04 ) ; \n"],[6],[0,"\n\n"],[1,"MATERIAL_ENABLE_SHEEN",427],[0," bsdfData.sheenRoughness = max ( MIN_PERCEPTUAL_ROUGHNESS , min ( surfaceData.sheenRoughness + getAARoughnessFactor(surfaceData.normal) , 1.0 ) ) ;\nbsdfData.approxIBLSheenDG = prefilteredSheenDFG(surfaceData.dotNV, bsdfData.sheenRoughness) ;\nbsdfData.sheenScaling = 1.0 - bsdfData.approxIBLSheenDG * max ( max ( surfaceData.sheenColor.r , surfaceData.sheenColor.g ) , surfaceData.sheenColor.b ) ; \n"],[6],[0," }\n\n"],[6],[0,"\n\n"],[2,"LIGHT_INCLUDED",477],[0,"\n\n"],[7,"LIGHT_INCLUDED"],[0,"\nuniform ivec4 renderer_Layer;\n\n"],[2,"GRAPHICS_API_WEBGL2",437],[0,"\nbool isBitSet ( float value, float mask, float bitIndex ) { return mod ( floor ( value / pow ( 2.0 , bitIndex ) ) , 2.0 ) == 1.0 && mod ( floor ( mask / pow ( 2.0 , bitIndex ) ) , 2.0 ) == 1.0 ; }\n\n"],[6],[0,"\nbool isRendererCulledByLight ( ivec2 rendererLayer, ivec2 lightCullingMask ) { \n"],[1,"GRAPHICS_API_WEBGL2",441],[0," return ! ( ( rendererLayer.x & lightCullingMask.x ) != 0 || ( rendererLayer.y & lightCullingMask.y ) != 0 ) ; \n"],[5,443],[0," for ( int i = 0 ; i < 16 ; i ++ ) { if ( isBitSet(float ( rendererLayer.x ), float ( lightCullingMask.x ), float ( i )) || isBitSet(float ( rendererLayer.y ), float ( lightCullingMask.y ), float ( i )) ) { return false ; } }\nreturn true ; \n"],[6],[0," }\n\n"],[1,"SCENE_DIRECT_LIGHT_COUNT",451],[0,"\nstruct DirectLight { vec3 color ; vec3 direction ; } ;\nuniform ivec2 scene_DirectLightCullingMask [ SCENE_DIRECT_LIGHT_COUNT ];\nuniform vec3 scene_DirectLightColor [ SCENE_DIRECT_LIGHT_COUNT ];\nuniform vec3 scene_DirectLightDirection [ SCENE_DIRECT_LIGHT_COUNT ];\n\n"],[1,"GRAPHICS_API_WEBGL2",449],[0,"\nDirectLight getDirectLight ( int index ) { DirectLight light ;\nlight.color = scene_DirectLightColor[index] ;\nlight.direction = scene_DirectLightDirection[index] ;\nreturn light ; }\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[1,"SCENE_POINT_LIGHT_COUNT",459],[0,"\nstruct PointLight { vec3 color ; vec3 position ; float distance ; } ;\nuniform ivec2 scene_PointLightCullingMask [ SCENE_POINT_LIGHT_COUNT ];\nuniform vec3 scene_PointLightColor [ SCENE_POINT_LIGHT_COUNT ];\nuniform vec3 scene_PointLightPosition [ SCENE_POINT_LIGHT_COUNT ];\nuniform float scene_PointLightDistance [ SCENE_POINT_LIGHT_COUNT ];\n\n"],[1,"GRAPHICS_API_WEBGL2",457],[0,"\nPointLight getPointLight ( int index ) { PointLight light ;\nlight.color = scene_PointLightColor[index] ;\nlight.position = scene_PointLightPosition[index] ;\nlight.distance = scene_PointLightDistance[index] ;\nreturn light ; }\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[1,"SCENE_SPOT_LIGHT_COUNT",467],[0,"\nstruct SpotLight { vec3 color ; vec3 position ; vec3 direction ; float distance ; float angleCos ; float penumbraCos ; } ;\nuniform ivec2 scene_SpotLightCullingMask [ SCENE_SPOT_LIGHT_COUNT ];\nuniform vec3 scene_SpotLightColor [ SCENE_SPOT_LIGHT_COUNT ];\nuniform vec3 scene_SpotLightPosition [ SCENE_SPOT_LIGHT_COUNT ];\nuniform vec3 scene_SpotLightDirection [ SCENE_SPOT_LIGHT_COUNT ];\nuniform float scene_SpotLightDistance [ SCENE_SPOT_LIGHT_COUNT ];\nuniform float scene_SpotLightAngleCos [ SCENE_SPOT_LIGHT_COUNT ];\nuniform float scene_SpotLightPenumbraCos [ SCENE_SPOT_LIGHT_COUNT ];\n\n"],[1,"GRAPHICS_API_WEBGL2",465],[0,"\nSpotLight getSpotLight ( int index ) { SpotLight light ;\nlight.color = scene_SpotLightColor[index] ;\nlight.position = scene_SpotLightPosition[index] ;\nlight.direction = scene_SpotLightDirection[index] ;\nlight.distance = scene_SpotLightDistance[index] ;\nlight.angleCos = scene_SpotLightAngleCos[index] ;\nlight.penumbraCos = scene_SpotLightPenumbraCos[index] ;\nreturn light ; }\n\n"],[6],[0,"\n\n"],[6],[0,"\nstruct EnvMapLight { vec3 diffuse ; float mipMapLevel ; float diffuseIntensity ; float specularIntensity ; } ;\nuniform EnvMapLight scene_EnvMapLight;\n\n"],[1,"SCENE_USE_SH",471],[0,"\nuniform vec3 scene_EnvSH [ 9 ];\n\n"],[6],[0,"\n\n"],[1,"SCENE_USE_SPECULAR_ENV",475],[0,"\nuniform samplerCube scene_EnvSpecularSampler;\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[2,"REFLECTION_LOBE_INCLUDED",491],[0,"\n\n"],[7,"REFLECTION_LOBE_INCLUDED"],[0,"\nvoid diffuseLobe ( SurfaceData surfaceData, BSDFData bsdfData, vec3 attenuationIrradiance, inout vec3 diffuseColor ) { diffuseColor += attenuationIrradiance * BRDF_Diffuse_Lambert(bsdfData.diffuseColor) ; }\nvoid specularLobe ( SurfaceData surfaceData, BSDFData bsdfData, vec3 incidentDirection, vec3 attenuationIrradiance, inout vec3 specularColor ) { specularColor += attenuationIrradiance * BRDF_Specular_GGX(incidentDirection, surfaceData, bsdfData, surfaceData.normal, bsdfData.specularF0, bsdfData.roughness) * bsdfData.energyCompensation ; }\nvoid sheenLobe ( SurfaceData surfaceData, BSDFData bsdfData, vec3 incidentDirection, vec3 attenuationIrradiance, inout vec3 diffuseColor, inout vec3 specularColor ) { \n"],[1,"MATERIAL_ENABLE_SHEEN",485],[0," diffuseColor *= bsdfData.sheenScaling ;\nspecularColor *= bsdfData.sheenScaling ;\nspecularColor += attenuationIrradiance * sheenBRDF(incidentDirection, surfaceData, surfaceData.sheenColor, bsdfData.sheenRoughness) ; \n"],[6],[0," }\nfloat clearCoatLobe ( SurfaceData surfaceData, BSDFData bsdfData, vec3 incidentDirection, vec3 color, inout vec3 specularColor ) { float attenuation = 1.0 ;\n\n"],[1,"MATERIAL_ENABLE_CLEAR_COAT",489],[0," float clearCoatDotNL = saturate(dot ( surfaceData.clearCoatNormal , incidentDirection )) ;\nvec3 clearCoatIrradiance = clearCoatDotNL * color ;\nspecularColor += surfaceData.clearCoat * clearCoatIrradiance * BRDF_Specular_GGX(incidentDirection, surfaceData, bsdfData, surfaceData.clearCoatNormal, bsdfData.clearCoatSpecularColor, bsdfData.clearCoatRoughness) ;\nattenuation -= surfaceData.clearCoat * F_Schlick(0.04, 1.0, surfaceData.clearCoatDotNV) ; \n"],[6],[0,"\nreturn attenuation ; }\n\n"],[6],[0,"\nvoid surfaceShading ( SurfaceData surfaceData, BSDFData bsdfData, vec3 incidentDirection, vec3 lightColor, inout vec3 totalDiffuseColor, inout vec3 totalSpecularColor ) { vec3 diffuseColor = vec3 ( 0 ) ;\nvec3 specularColor = vec3 ( 0 ) ;\nfloat dotNL = saturate(dot ( surfaceData.normal , incidentDirection )) ;\nvec3 irradiance = dotNL * lightColor * PI ;\nfloat attenuation = FUNCTION_CLEAR_COAT_LOBE(surfaceData, bsdfData, incidentDirection, lightColor, specularColor) ;\nvec3 attenuationIrradiance = attenuation * irradiance ;\nFUNCTION_DIFFUSE_LOBE(surfaceData, bsdfData, attenuationIrradiance, diffuseColor) ;\nFUNCTION_SPECULAR_LOBE(surfaceData, bsdfData, incidentDirection, attenuationIrradiance, specularColor) ;\nFUNCTION_SHEEN_LOBE(surfaceData, bsdfData, incidentDirection, attenuationIrradiance, diffuseColor, specularColor) ;\ntotalDiffuseColor += diffuseColor ;\ntotalSpecularColor += specularColor ; }\n\n"],[1,"SCENE_DIRECT_LIGHT_COUNT",495],[0,"\nvoid addDirectionalDirectLightRadiance ( SurfaceData surfaceData, BSDFData bsdfData, DirectLight directionalLight, inout vec3 totalDiffuseColor, inout vec3 totalSpecularColor ) { vec3 lightColor = directionalLight.color ;\nvec3 direction = - directionalLight.direction ;\nFUNCTION_SURFACE_SHADING(surfaceData, bsdfData, direction, lightColor, totalDiffuseColor, totalSpecularColor) ; }\n\n"],[6],[0,"\n\n"],[1,"SCENE_POINT_LIGHT_COUNT",499],[0,"\nvoid addPointDirectLightRadiance ( SurfaceData surfaceData, BSDFData bsdfData, PointLight pointLight, inout vec3 totalDiffuseColor, inout vec3 totalSpecularColor ) { vec3 lVector = pointLight.position - surfaceData.position ;\nvec3 direction = normalize ( lVector ) ;\nfloat lightDistance = length ( lVector ) ;\nvec3 lightColor = pointLight.color ;\nlightColor *= clamp ( 1.0 - pow ( lightDistance / pointLight.distance , 4.0 ) , 0.0 , 1.0 ) ;\nFUNCTION_SURFACE_SHADING(surfaceData, bsdfData, direction, lightColor, totalDiffuseColor, totalSpecularColor) ; }\n\n"],[6],[0,"\n\n"],[1,"SCENE_SPOT_LIGHT_COUNT",503],[0,"\nvoid addSpotDirectLightRadiance ( SurfaceData surfaceData, BSDFData bsdfData, SpotLight spotLight, inout vec3 totalDiffuseColor, inout vec3 totalSpecularColor ) { vec3 lVector = spotLight.position - surfaceData.position ;\nvec3 direction = normalize ( lVector ) ;\nfloat lightDistance = length ( lVector ) ;\nfloat angleCos = dot ( direction , - spotLight.direction ) ;\nfloat spotEffect = smoothstep ( spotLight.penumbraCos , spotLight.angleCos , angleCos ) ;\nfloat decayEffect = clamp ( 1.0 - pow ( lightDistance / spotLight.distance , 4.0 ) , 0.0 , 1.0 ) ;\nvec3 lightColor = spotLight.color ;\nlightColor *= spotEffect * decayEffect ;\nFUNCTION_SURFACE_SHADING(surfaceData, bsdfData, direction, lightColor, totalDiffuseColor, totalSpecularColor) ; }\n\n"],[6],[0,"\nvoid evaluateDirectRadiance ( SurfaceData surfaceData, BSDFData bsdfData, float shadowAttenuation, inout vec3 totalDiffuseColor, inout vec3 totalSpecularColor ) { \n"],[1,"SCENE_DIRECT_LIGHT_COUNT",517],[0," for ( int i = 0 ; i < SCENE_DIRECT_LIGHT_COUNT ; i ++ ) { if ( ! isRendererCulledByLight(renderer_Layer.xy, scene_DirectLightCullingMask[i]) ) { \n"],[1,"GRAPHICS_API_WEBGL2",509],[0," DirectLight directionalLight = getDirectLight(i) ; \n"],[5,511],[0," DirectLight directionalLight ;\ndirectionalLight.color = scene_DirectLightColor[i] ;\ndirectionalLight.direction = scene_DirectLightDirection[i] ; \n"],[6],[0,"\n\n"],[1,"NEED_CALCULATE_SHADOWS",515],[0," if ( i == 0 ) { directionalLight.color *= shadowAttenuation ; } \n"],[6],[0,"\naddDirectionalDirectLightRadiance(surfaceData, bsdfData, directionalLight, totalDiffuseColor, totalSpecularColor) ; } } \n"],[6],[0,"\n\n"],[1,"SCENE_POINT_LIGHT_COUNT",527],[0," for ( int i = 0 ; i < SCENE_POINT_LIGHT_COUNT ; i ++ ) { if ( ! isRendererCulledByLight(renderer_Layer.xy, scene_PointLightCullingMask[i]) ) { \n"],[1,"GRAPHICS_API_WEBGL2",523],[0," PointLight pointLight = getPointLight(i) ; \n"],[5,525],[0," PointLight pointLight ;\npointLight.color = scene_PointLightColor[i] ;\npointLight.position = scene_PointLightPosition[i] ;\npointLight.distance = scene_PointLightDistance[i] ; \n"],[6],[0,"\naddPointDirectLightRadiance(surfaceData, bsdfData, pointLight, totalDiffuseColor, totalSpecularColor) ; } } \n"],[6],[0,"\n\n"],[1,"SCENE_SPOT_LIGHT_COUNT",537],[0," for ( int i = 0 ; i < SCENE_SPOT_LIGHT_COUNT ; i ++ ) { if ( ! isRendererCulledByLight(renderer_Layer.xy, scene_SpotLightCullingMask[i]) ) { \n"],[1,"GRAPHICS_API_WEBGL2",533],[0," SpotLight spotLight = getSpotLight(i) ; \n"],[5,535],[0," SpotLight spotLight ;\nspotLight.color = scene_SpotLightColor[i] ;\nspotLight.position = scene_SpotLightPosition[i] ;\nspotLight.direction = scene_SpotLightDirection[i] ;\nspotLight.distance = scene_SpotLightDistance[i] ;\nspotLight.angleCos = scene_SpotLightAngleCos[i] ;\nspotLight.penumbraCos = scene_SpotLightPenumbraCos[i] ; \n"],[6],[0,"\naddSpotDirectLightRadiance(surfaceData, bsdfData, spotLight, totalDiffuseColor, totalSpecularColor) ; } } \n"],[6],[0," }\n\n"],[6],[0,"\n\n"],[2,"LIGHT_INDIRECT_PBR_INCLUDED",615],[0,"\n\n"],[7,"LIGHT_INDIRECT_PBR_INCLUDED"],[0,"\n\n"],[2,"FUNCTION_DIFFUSE_IBL",549],[0,"\n\n"],[8,"FUNCTION_DIFFUSE_IBL","evaluateDiffuseIBL"],[0,"\n\n"],[6],[0,"\n\n"],[2,"FUNCTION_SPECULAR_IBL",555],[0,"\n\n"],[8,"FUNCTION_SPECULAR_IBL","evaluateSpecularIBL"],[0,"\n\n"],[6],[0,"\n\n"],[2,"FUNCTION_CLEAR_COAT_IBL",561],[0,"\n\n"],[8,"FUNCTION_CLEAR_COAT_IBL","evaluateClearCoatIBL"],[0,"\n\n"],[6],[0,"\n\n"],[2,"FUNCTION_SHEEN_IBL",567],[0,"\n\n"],[8,"FUNCTION_SHEEN_IBL","evaluateSheenIBL"],[0,"\n\n"],[6],[0,"\n\n"],[2,"LIGHT_INDIRECT_FUNCTIONS_INCLUDED",599],[0,"\n\n"],[7,"LIGHT_INDIRECT_FUNCTIONS_INCLUDED"],[0,"\nvec3 getReflectedVector ( SurfaceData surfaceData, vec3 n ) { \n"],[1,"MATERIAL_ENABLE_ANISOTROPY",575],[0," vec3 r = reflect ( - surfaceData.viewDir , surfaceData.anisotropicN ) ; \n"],[5,577],[0," vec3 r = reflect ( - surfaceData.viewDir , n ) ; \n"],[6],[0,"\nreturn r ; }\nfloat getSpecularMIPLevel ( float roughness, int maxMIPLevel ) { return roughness * float ( maxMIPLevel ) ; }\nvec3 getLightProbeRadiance ( SurfaceData surfaceData, vec3 normal, float roughness ) { \n"],[2,"SCENE_USE_SPECULAR_ENV",581],[0," return vec3 ( 0 ) ; \n"],[5,593],[0," vec3 reflectVec = getReflectedVector(surfaceData, normal) ;\nfloat specularMIPLevel = getSpecularMIPLevel(roughness, int ( scene_EnvMapLight.mipMapLevel )) ;\n\n"],[1,"HAS_TEX_LOD",585],[0," vec4 envMapColor = textureCubeLodEXT ( scene_EnvSpecularSampler , reflectVec , specularMIPLevel ) ; \n"],[5,587],[0," vec4 envMapColor = textureCube ( scene_EnvSpecularSampler , reflectVec , specularMIPLevel ) ; \n"],[6],[0,"\n\n"],[1,"ENGINE_NO_SRGB",591],[0," envMapColor = sRGBToLinear(envMapColor) ; \n"],[6],[0,"\nreturn envMapColor.rgb * scene_EnvMapLight.specularIntensity ; \n"],[6],[0," }\nfloat evaluateSpecularOcclusion ( float dotNV, float diffuseAO, float roughness ) { float specularAOFactor = 1.0 ;\n\n"],[4,{"t":"and","l":{"t":"or","l":{"t":"def","m":"MATERIAL_HAS_OCCLUSION_TEXTURE"},"r":{"t":"def","m":"SCENE_ENABLE_AMBIENT_OCCLUSION"}},"r":{"t":"def","m":"SCENE_USE_SPECULAR_ENV"}},597],[0," specularAOFactor = saturate(pow ( dotNV + diffuseAO , exp2 ( - 16.0 * roughness - 1.0 ) ) - 1.0 + diffuseAO) ; \n"],[6],[0,"\nreturn specularAOFactor ; }\n\n"],[6],[0,"\nvec3 getLightProbeIrradiance ( vec3 sh [ 9 ], vec3 normal ) { vec3 result = sh[0] + sh[1] * ( normal.y ) + sh[2] * ( normal.z ) + sh[3] * ( normal.x ) + sh[4] * ( normal.y * normal.x ) + sh[5] * ( normal.y * normal.z ) + sh[6] * ( 3.0 * normal.z * normal.z - 1.0 ) + sh[7] * ( normal.z * normal.x ) + sh[8] * ( normal.x * normal.x - normal.y * normal.y ) ;\nreturn max ( result , vec3 ( 0.0 ) ) ; }\nvoid evaluateDiffuseIBL ( SurfaceData surfaceData, BSDFData bsdfData, inout vec3 diffuseColor ) { \n"],[1,"SCENE_USE_SH",603],[0," vec3 irradiance = getLightProbeIrradiance(scene_EnvSH, surfaceData.normal) ;\nirradiance *= scene_EnvMapLight.diffuseIntensity ; \n"],[5,605],[0," vec3 irradiance = scene_EnvMapLight.diffuse * scene_EnvMapLight.diffuseIntensity ;\nirradiance *= PI ; \n"],[6],[0,"\ndiffuseColor += bsdfData.diffuseAO * irradiance * BRDF_Diffuse_Lambert(bsdfData.diffuseColor) ; }\nfloat evaluateClearCoatIBL ( SurfaceData surfaceData, BSDFData bsdfData, inout vec3 specularColor ) { float radianceAttenuation = 1.0 ;\n\n"],[1,"MATERIAL_ENABLE_CLEAR_COAT",609],[0," vec3 clearCoatRadiance = getLightProbeRadiance(surfaceData, surfaceData.clearCoatNormal, bsdfData.clearCoatRoughness) ;\nfloat specularAO = evaluateSpecularOcclusion(surfaceData.dotNV, bsdfData.diffuseAO, bsdfData.clearCoatRoughness) ;\nspecularColor += specularAO * clearCoatRadiance * surfaceData.clearCoat * envBRDFApprox(bsdfData.clearCoatSpecularColor, 1.0, bsdfData.clearCoatRoughness, surfaceData.clearCoatDotNV) ;\nradianceAttenuation -= surfaceData.clearCoat * F_Schlick(0.04, 1.0, surfaceData.clearCoatDotNV) ; \n"],[6],[0,"\nreturn radianceAttenuation ; }\nvoid evaluateSpecularIBL ( SurfaceData surfaceData, BSDFData bsdfData, float radianceAttenuation, inout vec3 outSpecularColor ) { vec3 radiance = getLightProbeRadiance(surfaceData, surfaceData.normal, bsdfData.roughness) ;\nfloat specularAO = evaluateSpecularOcclusion(surfaceData.dotNV, bsdfData.diffuseAO, bsdfData.roughness) ;\noutSpecularColor += specularAO * radianceAttenuation * radiance * envBRDFApprox(bsdfData.resolvedSpecularF0, bsdfData.specularF90, bsdfData.roughness, surfaceData.dotNV) * bsdfData.energyCompensation ; }\nvoid evaluateSheenIBL ( SurfaceData surfaceData, BSDFData bsdfData, float radianceAttenuation, inout vec3 diffuseColor, inout vec3 specularColor ) { \n"],[1,"MATERIAL_ENABLE_SHEEN",613],[0," diffuseColor *= bsdfData.sheenScaling ;\nspecularColor *= bsdfData.sheenScaling ;\nfloat specularAO = evaluateSpecularOcclusion(surfaceData.dotNV, bsdfData.diffuseAO, bsdfData.sheenRoughness) ;\nvec3 reflectance = specularAO * radianceAttenuation * bsdfData.approxIBLSheenDG * surfaceData.sheenColor ;\nspecularColor += reflectance ; \n"],[6],[0," }\nvoid evaluateIBL ( SurfaceData surfaceData, BSDFData bsdfData, inout vec3 totalDiffuseColor, inout vec3 totalSpecularColor ) { vec3 diffuseColor = vec3 ( 0 ) ;\nvec3 specularColor = vec3 ( 0 ) ;\nFUNCTION_DIFFUSE_IBL(surfaceData, bsdfData, diffuseColor) ;\nfloat radianceAttenuation = FUNCTION_CLEAR_COAT_IBL(surfaceData, bsdfData, specularColor) ;\nFUNCTION_SPECULAR_IBL(surfaceData, bsdfData, radianceAttenuation, specularColor) ;\nFUNCTION_SHEEN_IBL(surfaceData, bsdfData, radianceAttenuation, diffuseColor, specularColor) ;\ntotalDiffuseColor += diffuseColor ;\ntotalSpecularColor += specularColor ; }\n\n"],[6],[0,"\n\n"],[2,"VERTEX_INCLUDE",621],[0,"\n\n"],[7,"VERTEX_INCLUDE"],[0,"\n\n"],[6],[0,"\n\n"],[2,"MATERIAL_INPUT_PBR_INCLUDED",872],[0,"\n\n"],[7,"MATERIAL_INPUT_PBR_INCLUDED"],[0,"\n\n"],[2,"NORMAL_INCLUDED",637],[0,"\n\n"],[7,"NORMAL_INCLUDED"],[0,"\nvec3 getNormalByNormalTexture ( mat3 tbn, sampler2D normalTexture, float normalIntensity, vec2 uv, bool isFrontFacing ) { vec3 normal = ( texture2D ( normalTexture , uv ) ).rgb ;\nnormal = normalize ( tbn * ( ( 2.0 * normal - 1.0 ) * vec3 ( normalIntensity , normalIntensity , 1.0 ) ) ) ;\nnormal *= float ( isFrontFacing ) * 2.0 - 1.0 ;\nreturn normal ; }\nmat3 getTBNByDerivatives ( vec2 uv, vec3 normal, vec3 position, bool isFrontFacing ) { \n"],[1,"HAS_DERIVATIVES",633],[0," uv = isFrontFacing ? uv : - uv ;\nvec3 dp1 = dFdx ( position ) ;\nvec3 dp2 = dFdy ( position ) ;\nvec2 duv1 = dFdx ( uv ) ;\nvec2 duv2 = dFdy ( uv ) ;\nvec3 dp2perp = cross ( dp2 , normal ) ;\nvec3 dp1perp = cross ( normal , dp1 ) ;\nvec3 tangent = dp2perp * duv1.x + dp1perp * duv2.x ;\nvec3 bitangent = dp2perp * duv1.y + dp1perp * duv2.y ;\nfloat denom = max ( dot ( tangent , tangent ) , dot ( bitangent , bitangent ) ) ;\nfloat invmax = ( denom == 0.0 ) ? 0.0 : camera_ProjectionParams.x / sqrt ( denom ) ;\nreturn mat3 ( tangent * invmax , bitangent * invmax , normal ) ; \n"],[5,635],[0," return mat3 ( vec3 ( 0.0 ) , vec3 ( 0.0 ) , normal ) ; \n"],[6],[0," }\n\n"],[6],[0,"\nuniform float material_AlphaCutoff;\nuniform vec4 material_BaseColor;\nuniform float material_Metal;\nuniform float material_Roughness;\nuniform float material_IOR;\nuniform vec3 material_EmissiveColor;\nuniform float material_NormalIntensity;\nuniform float material_OcclusionIntensity;\nuniform float material_OcclusionTextureCoord;\nuniform float material_SpecularIntensity;\nuniform vec3 material_SpecularColor;\n\n"],[1,"MATERIAL_HAS_SPECULAR_TEXTURE",641],[0,"\nuniform sampler2D material_SpecularIntensityTexture;\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_HAS_SPECULAR_COLOR_TEXTURE",645],[0,"\nuniform sampler2D material_SpecularColorTexture;\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_ENABLE_CLEAR_COAT",661],[0,"\nuniform float material_ClearCoat;\nuniform float material_ClearCoatRoughness;\n\n"],[1,"MATERIAL_HAS_CLEAR_COAT_TEXTURE",651],[0,"\nuniform sampler2D material_ClearCoatTexture;\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_HAS_CLEAR_COAT_ROUGHNESS_TEXTURE",655],[0,"\nuniform sampler2D material_ClearCoatRoughnessTexture;\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_HAS_CLEAR_COAT_NORMAL_TEXTURE",659],[0,"\nuniform sampler2D material_ClearCoatNormalTexture;\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_ENABLE_ANISOTROPY",669],[0,"\nuniform vec3 material_AnisotropyInfo;\n\n"],[1,"MATERIAL_HAS_ANISOTROPY_TEXTURE",667],[0,"\nuniform sampler2D material_AnisotropyTexture;\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_ENABLE_IRIDESCENCE",681],[0,"\nuniform vec4 material_IridescenceInfo;\n\n"],[1,"MATERIAL_HAS_IRIDESCENCE_THICKNESS_TEXTURE",675],[0,"\nuniform sampler2D material_IridescenceThicknessTexture;\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_HAS_IRIDESCENCE_TEXTURE",679],[0,"\nuniform sampler2D material_IridescenceTexture;\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_ENABLE_SHEEN",693],[0,"\nuniform float material_SheenRoughness;\nuniform vec3 material_SheenColor;\n\n"],[1,"MATERIAL_HAS_SHEEN_TEXTURE",687],[0,"\nuniform sampler2D material_SheenTexture;\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_HAS_SHEEN_ROUGHNESS_TEXTURE",691],[0,"\nuniform sampler2D material_SheenRoughnessTexture;\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_ENABLE_TRANSMISSION",709],[0,"\nuniform float material_Transmission;\n\n"],[1,"MATERIAL_HAS_TRANSMISSION_TEXTURE",699],[0,"\nuniform sampler2D material_TransmissionTexture;\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_HAS_THICKNESS",707],[0,"\nuniform vec3 material_AttenuationColor;\nuniform float material_AttenuationDistance;\nuniform float material_Thickness;\n\n"],[1,"MATERIAL_HAS_THICKNESS_TEXTURE",705],[0,"\nuniform sampler2D material_ThicknessTexture;\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_HAS_BASETEXTURE",713],[0,"\nuniform sampler2D material_BaseTexture;\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_HAS_NORMALTEXTURE",717],[0,"\nuniform sampler2D material_NormalTexture;\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_HAS_EMISSIVETEXTURE",721],[0,"\nuniform sampler2D material_EmissiveTexture;\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_HAS_ROUGHNESS_METALLIC_TEXTURE",725],[0,"\nuniform sampler2D material_RoughnessMetallicTexture;\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_HAS_OCCLUSION_TEXTURE",729],[0,"\nuniform sampler2D material_OcclusionTexture;\n\n"],[6],[0,"\n\n"],[1,"MATERIAL_ENABLE_ANISOTROPY",733],[0,"\nvec3 getAnisotropicBentNormal ( SurfaceData surfaceData ) { vec3 anisotropyDirection = ( surfaceData.anisotropy >= 0.0 ) ? surfaceData.anisotropicB : surfaceData.anisotropicT ;\nvec3 anisotropicTangent = cross ( anisotropyDirection , surfaceData.viewDir ) ;\nvec3 anisotropicNormal = cross ( anisotropicTangent , anisotropyDirection ) ;\nvec3 bentNormal = normalize ( mix ( surfaceData.normal , anisotropicNormal , abs ( surfaceData.anisotropy ) * saturate(5.0 * surfaceData.roughness) ) ) ;\nreturn bentNormal ; }\n\n"],[6],[0,"\nSurfaceData getSurfaceData ( vec2 aoUV, bool isFrontFacing ) { SurfaceData surfaceData ;\nvec2 uv = uv ;\nvec4 baseColor = material_BaseColor ;\nfloat metallic = material_Metal ;\nfloat roughness = material_Roughness ;\nvec3 emissiveRadiance = material_EmissiveColor ;\n\n"],[1,"MATERIAL_HAS_BASETEXTURE",737],[0," baseColor *= texture2DSRGB(material_BaseTexture, uv) ; \n"],[6],[0,"\n\n"],[1,"RENDERER_ENABLE_VERTEXCOLOR",741],[0," baseColor *= vertexColor ; \n"],[6],[0,"\n\n"],[1,"MATERIAL_IS_ALPHA_CUTOFF",745],[0," if ( baseColor.a < material_AlphaCutoff ) { discard ; } \n"],[6],[0,"\n\n"],[1,"MATERIAL_HAS_ROUGHNESS_METALLIC_TEXTURE",749],[0," vec4 metalRoughMapColor = texture2D ( material_RoughnessMetallicTexture , uv ) ;\nroughness *= metalRoughMapColor.g ;\nmetallic *= metalRoughMapColor.b ; \n"],[6],[0,"\n\n"],[1,"MATERIAL_HAS_EMISSIVETEXTURE",753],[0," emissiveRadiance *= texture2DSRGB(material_EmissiveTexture, uv).rgb ; \n"],[6],[0,"\nsurfaceData.albedoColor = baseColor.rgb ;\nsurfaceData.emissiveColor = emissiveRadiance ;\nsurfaceData.metallic = metallic ;\nsurfaceData.roughness = roughness ;\nsurfaceData.IOR = material_IOR ;\n\n"],[1,"MATERIAL_IS_TRANSPARENT",757],[0," surfaceData.opacity = baseColor.a ; \n"],[5,759],[0," surfaceData.opacity = 1.0 ; \n"],[6],[0,"\nsurfaceData.position = positionWS ;\nsurfaceData.positionCS = positionCS ;\n\n"],[1,"CAMERA_ORTHOGRAPHIC",763],[0," surfaceData.viewDir = - camera_Forward ; \n"],[5,765],[0," surfaceData.viewDir = normalize ( camera_Position - positionWS ) ; \n"],[6],[0,"\n\n"],[1,"RENDERER_HAS_NORMAL",769],[0," vec3 normal = normalize ( normalWS ) ; \n"],[5,774],[1,"HAS_DERIVATIVES",772],[0," vec3 pos_dx = dFdx ( positionWS ) ;\nvec3 pos_dy = dFdy ( positionWS ) ;\nvec3 normal = normalize ( cross ( pos_dx , pos_dy ) ) ;\nnormal *= camera_ProjectionParams.x ; \n"],[5,774],[0," vec3 normal = vec3 ( 0 , 0 , 1 ) ; \n"],[6],[0,"\nnormal *= float ( isFrontFacing ) * 2.0 - 1.0 ;\nsurfaceData.normal = normal ;\n\n"],[1,"NEED_TANGENT_SPACE",788],[0," \n"],[1,"NEED_VERTEX_TANGENT",780],[0," surfaceData.tangent = tangentWS ;\nsurfaceData.bitangent = bitangentWS ;\nmat3 tbn = mat3 ( tangentWS , bitangentWS , normalWS ) ; \n"],[5,782],[0," mat3 tbn = getTBNByDerivatives(uv, normal, positionWS, isFrontFacing) ;\nsurfaceData.tangent = tbn[0] ;\nsurfaceData.bitangent = tbn[1] ; \n"],[6],[0,"\n\n"],[1,"MATERIAL_HAS_NORMALTEXTURE",786],[0," surfaceData.normal = getNormalByNormalTexture(tbn, material_NormalTexture, material_NormalIntensity, uv, isFrontFacing) ; \n"],[6],[0," \n"],[6],[0,"\nsurfaceData.dotNV = saturate(dot ( surfaceData.normal , surfaceData.viewDir )) ;\nsurfaceData.specularIntensity = material_SpecularIntensity ;\nsurfaceData.specularColor = material_SpecularColor ;\n\n"],[1,"MATERIAL_HAS_SPECULAR_TEXTURE",792],[0," surfaceData.specularIntensity *= texture2D ( material_SpecularIntensityTexture , uv ).a ; \n"],[6],[0,"\n\n"],[1,"MATERIAL_HAS_SPECULAR_COLOR_TEXTURE",796],[0," surfaceData.specularColor *= texture2D ( material_SpecularColorTexture , uv ).rgb ; \n"],[6],[0,"\n\n"],[1,"MATERIAL_ENABLE_CLEAR_COAT",814],[0," \n"],[1,"MATERIAL_HAS_CLEAR_COAT_NORMAL_TEXTURE",802],[0," surfaceData.clearCoatNormal = getNormalByNormalTexture(tbn, material_ClearCoatNormalTexture, material_NormalIntensity, uv, isFrontFacing) ; \n"],[5,804],[0," surfaceData.clearCoatNormal = normal ; \n"],[6],[0,"\nsurfaceData.clearCoatDotNV = saturate(dot ( surfaceData.clearCoatNormal , surfaceData.viewDir )) ;\nsurfaceData.clearCoat = material_ClearCoat ;\nsurfaceData.clearCoatRoughness = material_ClearCoatRoughness ;\n\n"],[1,"MATERIAL_HAS_CLEAR_COAT_TEXTURE",808],[0," surfaceData.clearCoat *= ( texture2D ( material_ClearCoatTexture , uv ) ).r ; \n"],[6],[0,"\n\n"],[1,"MATERIAL_HAS_CLEAR_COAT_ROUGHNESS_TEXTURE",812],[0," surfaceData.clearCoatRoughness *= ( texture2D ( material_ClearCoatRoughnessTexture , uv ) ).g ; \n"],[6],[0,"\nsurfaceData.clearCoat = saturate(surfaceData.clearCoat) ; \n"],[6],[0,"\n\n"],[1,"MATERIAL_ENABLE_ANISOTROPY",822],[0," float anisotropy = material_AnisotropyInfo.z ;\nvec3 anisotropicDirection = vec3 ( material_AnisotropyInfo.xy , 0.0 ) ;\n\n"],[1,"MATERIAL_HAS_ANISOTROPY_TEXTURE",820],[0," vec3 anisotropyTextureInfo = ( texture2D ( material_AnisotropyTexture , uv ) ).rgb ;\nanisotropy *= anisotropyTextureInfo.b ;\nanisotropicDirection.xy *= anisotropyTextureInfo.rg * 2.0 - 1.0 ; \n"],[6],[0,"\nsurfaceData.anisotropy = anisotropy ;\nsurfaceData.anisotropicT = normalize ( mat3 ( surfaceData.tangent , surfaceData.bitangent , surfaceData.normal ) * anisotropicDirection ) ;\nsurfaceData.anisotropicB = normalize ( cross ( surfaceData.normal , surfaceData.anisotropicT ) ) ;\nsurfaceData.anisotropicN = getAnisotropicBentNormal(surfaceData) ; \n"],[6],[0,"\n\n"],[1,"MATERIAL_ENABLE_IRIDESCENCE",836],[0," surfaceData.iridescenceFactor = material_IridescenceInfo.x ;\nsurfaceData.iridescenceIOR = material_IridescenceInfo.y ;\n\n"],[1,"MATERIAL_HAS_IRIDESCENCE_THICKNESS_TEXTURE",828],[0," float iridescenceThicknessWeight = texture2D ( material_IridescenceThicknessTexture , uv ).g ;\nsurfaceData.iridescenceThickness = mix ( material_IridescenceInfo.z , material_IridescenceInfo.w , iridescenceThicknessWeight ) ; \n"],[5,830],[0," surfaceData.iridescenceThickness = material_IridescenceInfo.w ; \n"],[6],[0,"\n\n"],[1,"MATERIAL_HAS_IRIDESCENCE_TEXTURE",834],[0," surfaceData.iridescenceFactor *= texture2D ( material_IridescenceTexture , uv ).r ; \n"],[6],[0," \n"],[6],[0,"\n\n"],[1,"MATERIAL_ENABLE_SHEEN",848],[0," vec3 sheenColor = material_SheenColor ;\n\n"],[1,"MATERIAL_HAS_SHEEN_TEXTURE",842],[0," sheenColor *= texture2DSRGB(material_SheenTexture, uv).rgb ; \n"],[6],[0,"\nsurfaceData.sheenColor = sheenColor ;\nsurfaceData.sheenRoughness = material_SheenRoughness ;\n\n"],[1,"MATERIAL_HAS_SHEEN_ROUGHNESS_TEXTURE",846],[0," surfaceData.sheenRoughness *= texture2D ( material_SheenRoughnessTexture , uv ).a ; \n"],[6],[0," \n"],[6],[0,"\n\n"],[1,"MATERIAL_ENABLE_TRANSMISSION",864],[0," surfaceData.transmission = material_Transmission ;\n\n"],[1,"MATERIAL_HAS_TRANSMISSION_TEXTURE",854],[0," surfaceData.transmission *= texture2D ( material_TransmissionTexture , uv ).r ; \n"],[6],[0,"\n\n"],[1,"MATERIAL_HAS_THICKNESS",862],[0," surfaceData.absorptionCoefficient = - log ( material_AttenuationColor + HALF_EPS ) / max ( HALF_EPS , material_AttenuationDistance ) ;\nsurfaceData.thickness = max ( material_Thickness , 0.0001 ) ;\n\n"],[1,"MATERIAL_HAS_THICKNESS_TEXTURE",860],[0," surfaceData.thickness *= texture2D ( material_ThicknessTexture , uv ).g ; \n"],[6],[0," \n"],[6],[0," \n"],[6],[0,"\n\n"],[1,"MATERIAL_HAS_OCCLUSION_TEXTURE",868],[0," surfaceData.ambientOcclusion = ( ( texture2D ( material_OcclusionTexture , aoUV ) ).r - 1.0 ) * material_OcclusionIntensity + 1.0 ; \n"],[5,870],[0," surfaceData.ambientOcclusion = 1.0 ; \n"],[6],[0,"\nreturn surfaceData ; }\n\n"],[6],[0,"\nvoid main() { BSDFData bsdfData ;\nvec2 aoUV = uv ;\n\n"],[4,{"t":"and","l":{"t":"def","m":"MATERIAL_HAS_OCCLUSION_TEXTURE"},"r":{"t":"def","m":"RENDERER_HAS_UV1"}},876],[0," if ( material_OcclusionTextureCoord == 1.0 ) { aoUV = uv1 ; } \n"],[6],[0,"\nSurfaceData surfaceData = getSurfaceData(aoUV, gl_FrontFacing) ;\ninitBSDFData(surfaceData, bsdfData) ;\nvec3 totalDiffuseColor = vec3 ( 0 , 0 , 0 ) ;\nvec3 totalSpecularColor = vec3 ( 0 , 0 , 0 ) ;\nfloat shadowAttenuation = 1.0 ;\n\n"],[4,{"t":"and","l":{"t":"def","m":"SCENE_DIRECT_LIGHT_COUNT"},"r":{"t":"def","m":"NEED_CALCULATE_SHADOWS"}},886],[0," \n"],[3,"SCENE_SHADOW_CASCADED_COUNT","==",1,882],[0," vec3 shadowCoord = shadowCoord ; \n"],[5,884],[0," vec3 shadowCoord = getShadowCoord(positionWS) ; \n"],[6],[0,"\nshadowAttenuation *= sampleShadowMap(positionWS, shadowCoord) ; \n"],[6],[0,"\nevaluateDirectRadiance(surfaceData, bsdfData, shadowAttenuation, totalDiffuseColor, totalSpecularColor) ;\nevaluateIBL(surfaceData, bsdfData, totalDiffuseColor, totalSpecularColor) ;\n\n"],[1,"MATERIAL_ENABLE_TRANSMISSION",890],[0," vec3 refractionTransmitted = evaluateTransmission(surfaceData, bsdfData) ;\ntotalDiffuseColor = mix ( totalDiffuseColor , refractionTransmitted , surfaceData.transmission ) ; \n"],[6],[0,"\nvec4 color = vec4 ( ( totalDiffuseColor + totalSpecularColor ).rgb , surfaceData.opacity ) ;\ncolor.rgb += surfaceData.emissiveColor ;\n\n"],[3,"SCENE_FOG_MODE","!=",0,894],[0," color = fog(color, positionVS) ; \n"],[6],[0,"\ngl_FragColor = color ; }\n\n"],[6]]}]}]} \ No newline at end of file diff --git a/packages/shader/compiledShaders/Pipeline/DepthOnly.shaderc b/packages/shader/compiledShaders/Pipeline/DepthOnly.shaderc index 50b2f52951..c6603a76b2 100644 --- a/packages/shader/compiledShaders/Pipeline/DepthOnly.shaderc +++ b/packages/shader/compiledShaders/Pipeline/DepthOnly.shaderc @@ -1 +1 @@ -{"name":"Pipeline/DepthOnly","platformTarget":0,"subShaders":[{"name":"Default","tags":{},"passes":[{"name":"DepthOnly","isUsePass":false,"tags":{"pipelineStage":"DepthOnly"},"renderStates":{"constantMap":{},"variableMap":{"28":"material_DepthOnlyRenderQueue"}},"vertexShaderInstructions":[[0,"\n"],[2,"COMMON_INCLUDED",30],[0,"\n\n"],[7,"COMMON_INCLUDED"],[0,"\n\n"],[8,"PI","3.14159265359"],[0,"\n\n"],[8,"RECIPROCAL_PI","0.31830988618"],[0,"\n\n"],[8,"EPSILON","1e-6"],[0,"\n\n"],[8,"LOG2","1.442695"],[0,"\n\n"],[8,"HALF_MIN","6.103515625e-5"],[0,"\n\n"],[8,"HALF_EPS","4.8828125e-4"],[0,"\n\n"],[9,"saturate",["a"],"clamp ( a , 0.0 , 1.0 )"],[0,"\n\n"],[1,"GRAPHICS_API_WEBGL2",24],[0,"\n\n"],[9,"INVERSE_MAT",["mat"],"inverse ( mat )"],[0,"\n\n"],[5,28],[0,"\nmat2 inverseMat ( mat2 m ) { return mat2 ( m[1][1] , - m[0][1] , - m[1][0] , m[0][0] ) / ( m[0][0] * m[1][1] - m[0][1] * m[1][0] ) ; }\nmat3 inverseMat ( mat3 m ) { float a00 = m[0][0] , a01 = m[0][1] , a02 = m[0][2] ;\nfloat a10 = m[1][0] , a11 = m[1][1] , a12 = m[1][2] ;\nfloat a20 = m[2][0] , a21 = m[2][1] , a22 = m[2][2] ;\nfloat b01 = a22 * a11 - a12 * a21 ;\nfloat b11 = - a22 * a10 + a12 * a20 ;\nfloat b21 = a21 * a10 - a11 * a20 ;\nfloat det = a00 * b01 + a01 * b11 + a02 * b21 ;\nreturn mat3 ( b01 , ( - a22 * a01 + a02 * a21 ) , ( a12 * a01 - a02 * a11 ) , b11 , ( a22 * a00 - a02 * a20 ) , ( - a12 * a00 + a02 * a10 ) , b21 , ( - a21 * a00 + a01 * a20 ) , ( a11 * a00 - a01 * a10 ) ) / det ; }\nmat4 inverseMat ( mat4 m ) { float a00 = m[0][0] , a01 = m[0][1] , a02 = m[0][2] , a03 = m[0][3] , a10 = m[1][0] , a11 = m[1][1] , a12 = m[1][2] , a13 = m[1][3] , a20 = m[2][0] , a21 = m[2][1] , a22 = m[2][2] , a23 = m[2][3] , a30 = m[3][0] , a31 = m[3][1] , a32 = m[3][2] , a33 = m[3][3] , b00 = a00 * a11 - a01 * a10 , b01 = a00 * a12 - a02 * a10 , b02 = a00 * a13 - a03 * a10 , b03 = a01 * a12 - a02 * a11 , b04 = a01 * a13 - a03 * a11 , b05 = a02 * a13 - a03 * a12 , b06 = a20 * a31 - a21 * a30 , b07 = a20 * a32 - a22 * a30 , b08 = a20 * a33 - a23 * a30 , b09 = a21 * a32 - a22 * a31 , b10 = a21 * a33 - a23 * a31 , b11 = a22 * a33 - a23 * a32 , det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06 ;\nreturn mat4 ( a11 * b11 - a12 * b10 + a13 * b09 , a02 * b10 - a01 * b11 - a03 * b09 , a31 * b05 - a32 * b04 + a33 * b03 , a22 * b04 - a21 * b05 - a23 * b03 , a12 * b08 - a10 * b11 - a13 * b07 , a00 * b11 - a02 * b08 + a03 * b07 , a32 * b02 - a30 * b05 - a33 * b01 , a20 * b05 - a22 * b02 + a23 * b01 , a10 * b10 - a11 * b08 + a13 * b06 , a01 * b08 - a00 * b10 - a03 * b06 , a30 * b04 - a31 * b02 + a33 * b00 , a21 * b02 - a20 * b04 - a23 * b00 , a11 * b07 - a10 * b09 - a12 * b06 , a00 * b09 - a01 * b07 + a02 * b06 , a31 * b01 - a30 * b03 - a32 * b00 , a20 * b03 - a21 * b01 + a22 * b00 ) / det ; }\n\n"],[9,"INVERSE_MAT",["mat"],"inverseMat(mat)"],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[2,"TRANSFORM_INCLUDED",36],[0,"\n\n"],[7,"TRANSFORM_INCLUDED"],[0,"\nuniform mat4 renderer_ModelMat;\nuniform mat4 camera_VPMat;\n\n"],[6],[0,"\n\n"],[2,"ATTRIBUTES_INCLUDED",94],[0,"\n\n"],[7,"ATTRIBUTES_INCLUDED"],[0,"\nattribute vec3 POSITION;\n\n"],[1,"RENDERER_HAS_BLENDSHAPE",68],[0,"\n"],[2,"RENDERER_BLENDSHAPE_USE_TEXTURE",66],[0,"attribute vec3 POSITION_BS0;\nattribute vec3 POSITION_BS1;\n\n"],[4,{"t":"and","l":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_NORMAL"},"r":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_TANGENT"}},48],[0,"attribute vec3 NORMAL_BS0;\nattribute vec3 NORMAL_BS1;\nattribute vec3 TANGENT_BS0;\nattribute vec3 TANGENT_BS1;\n\n"],[5,64],[0,"\n"],[4,{"t":"or","l":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_NORMAL"},"r":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_TANGENT"}},60],[0,"attribute vec3 POSITION_BS2;\nattribute vec3 POSITION_BS3;\n\n"],[1,"RENDERER_BLENDSHAPE_HAS_NORMAL",54],[0,"attribute vec3 NORMAL_BS0;\nattribute vec3 NORMAL_BS1;\nattribute vec3 NORMAL_BS2;\nattribute vec3 NORMAL_BS3;\n\n"],[6],[0,"\n"],[1,"RENDERER_BLENDSHAPE_HAS_TANGENT",58],[0,"attribute vec3 TANGENT_BS0;\nattribute vec3 TANGENT_BS1;\nattribute vec3 TANGENT_BS2;\nattribute vec3 TANGENT_BS3;\n\n"],[6],[0,"\n"],[5,62],[0,"attribute vec3 POSITION_BS2;\nattribute vec3 POSITION_BS3;\nattribute vec3 POSITION_BS4;\nattribute vec3 POSITION_BS5;\nattribute vec3 POSITION_BS6;\nattribute vec3 POSITION_BS7;\n\n"],[6],[0,"\n"],[6],[0,"\n"],[6],[0,"\n"],[6],[0,"\n"],[1,"RENDERER_HAS_UV",72],[0,"\n"],[6],[0,"\n"],[1,"RENDERER_HAS_UV1",76],[0,"\n"],[6],[0,"\n"],[1,"RENDERER_HAS_SKIN",80],[0,"attribute vec4 JOINTS_0;\nattribute vec4 WEIGHTS_0;\n\n"],[6],[0,"\n"],[1,"RENDERER_ENABLE_VERTEXCOLOR",84],[0,"\n"],[6],[0,"\n"],[1,"RENDERER_HAS_NORMAL",88],[0,"attribute vec3 NORMAL;\n\n"],[6],[0,"\n"],[1,"RENDERER_HAS_TANGENT",92],[0,"attribute vec4 TANGENT;\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[2,"SKIN_INCLUDED",116],[0,"\n\n"],[7,"SKIN_INCLUDED"],[0,"\n\n"],[1,"RENDERER_HAS_SKIN",114],[0,"\n\n"],[1,"RENDERER_USE_JOINT_TEXTURE",104],[0,"\nuniform sampler2D renderer_JointSampler;\nuniform float renderer_JointCount;\nmat4 getJointMatrix ( sampler2D smp, float index ) { float base = index / renderer_JointCount ;\nfloat hf = 0.5 / renderer_JointCount ;\nfloat v = base + hf ;\nvec4 m0 = texture2D ( smp , vec2 ( 0.125 , v ) ) ;\nvec4 m1 = texture2D ( smp , vec2 ( 0.375 , v ) ) ;\nvec4 m2 = texture2D ( smp , vec2 ( 0.625 , v ) ) ;\nvec4 m3 = texture2D ( smp , vec2 ( 0.875 , v ) ) ;\nreturn mat4 ( m0 , m1 , m2 , m3 ) ; }\n\n"],[5,106],[0,"\nuniform mat4 renderer_JointMatrix [ RENDERER_JOINTS_NUM ];\n\n"],[6],[0,"\nmat4 getSkinMatrix ( ) { \n"],[1,"RENDERER_USE_JOINT_TEXTURE",110],[0," mat4 skinMatrix = WEIGHTS_0.x * getJointMatrix(renderer_JointSampler, JOINTS_0.x) + WEIGHTS_0.y * getJointMatrix(renderer_JointSampler, JOINTS_0.y) + WEIGHTS_0.z * getJointMatrix(renderer_JointSampler, JOINTS_0.z) + WEIGHTS_0.w * getJointMatrix(renderer_JointSampler, JOINTS_0.w) ; \n"],[5,112],[0," mat4 skinMatrix = WEIGHTS_0.x * renderer_JointMatrix[int ( JOINTS_0.x )] + WEIGHTS_0.y * renderer_JointMatrix[int ( JOINTS_0.y )] + WEIGHTS_0.z * renderer_JointMatrix[int ( JOINTS_0.z )] + WEIGHTS_0.w * renderer_JointMatrix[int ( JOINTS_0.w )] ; \n"],[6],[0,"\nreturn skinMatrix ; }\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[2,"BLENDSHAPE_INCLUDED",194],[0,"\n\n"],[7,"BLENDSHAPE_INCLUDED"],[0,"\n\n"],[1,"RENDERER_HAS_BLENDSHAPE",192],[0,"\n\n"],[1,"RENDERER_BLENDSHAPE_USE_TEXTURE",126],[0,"\nuniform mediump sampler2DArray renderer_BlendShapeTexture;\nuniform ivec3 renderer_BlendShapeTextureInfo;\nuniform float renderer_BlendShapeWeights [ RENDERER_BLENDSHAPE_COUNT ];\nvec3 getBlendShapeVertexElement ( int blendShapeIndex, int vertexElementIndex ) { int y = vertexElementIndex / renderer_BlendShapeTextureInfo.y ;\nint x = vertexElementIndex - y * renderer_BlendShapeTextureInfo.y ;\nivec3 uv = ivec3 ( x , y , blendShapeIndex ) ;\nreturn ( texelFetch ( renderer_BlendShapeTexture , uv , 0 ) ).xyz ; }\n\n"],[5,140],[0,"\n\n"],[4,{"t":"and","l":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_NORMAL"},"r":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_TANGENT"}},130],[0,"\nuniform float renderer_BlendShapeWeights [ 2 ];\n\n"],[5,138],[0,"\n\n"],[4,{"t":"or","l":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_NORMAL"},"r":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_TANGENT"}},134],[0,"\nuniform float renderer_BlendShapeWeights [ 4 ];\n\n"],[5,136],[0,"\nuniform float renderer_BlendShapeWeights [ 8 ];\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\nvoid calculateBlendShape ( inout vec4 position\n"],[1,"RENDERER_HAS_NORMAL",148],[0," , inout vec3 normal \n"],[1,"RENDERER_HAS_TANGENT",146],[0," , inout vec4 tangent \n"],[6],[0," \n"],[6],[0," ) { \n"],[1,"RENDERER_BLENDSHAPE_USE_TEXTURE",160],[0," int vertexOffset = gl_VertexID * renderer_BlendShapeTextureInfo.x ;\nfor ( int i = 0 ; i < RENDERER_BLENDSHAPE_COUNT ; i ++ ) { int vertexElementOffset = vertexOffset ;\nfloat weight = renderer_BlendShapeWeights[i] ;\nif ( weight != 0.0 ) { position.xyz += getBlendShapeVertexElement(i, vertexElementOffset) * weight ;\n\n"],[4,{"t":"and","l":{"t":"def","m":"RENDERER_HAS_NORMAL"},"r":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_NORMAL"}},154],[0," vertexElementOffset += 1 ;\nnormal += getBlendShapeVertexElement(i, vertexElementOffset) * weight ; \n"],[6],[0,"\n\n"],[4,{"t":"and","l":{"t":"def","m":"RENDERER_HAS_TANGENT"},"r":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_TANGENT"}},158],[0," vertexElementOffset += 1 ;\ntangent.xyz += getBlendShapeVertexElement(i, vertexElementOffset) * weight ; \n"],[6],[0," } } \n"],[5,190],[0," position.xyz += POSITION_BS0 * renderer_BlendShapeWeights[0] ;\nposition.xyz += POSITION_BS1 * renderer_BlendShapeWeights[1] ;\n\n"],[4,{"t":"and","l":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_NORMAL"},"r":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_TANGENT"}},172],[0," \n"],[1,"RENDERER_HAS_NORMAL",166],[0," normal += NORMAL_BS0 * renderer_BlendShapeWeights[0] ;\nnormal += NORMAL_BS1 * renderer_BlendShapeWeights[1] ; \n"],[6],[0,"\n\n"],[1,"RENDERER_HAS_TANGENT",170],[0," tangent.xyz += TANGENT_BS0 * renderer_BlendShapeWeights[0] ;\ntangent.xyz += TANGENT_BS1 * renderer_BlendShapeWeights[1] ; \n"],[6],[0," \n"],[5,188],[0," \n"],[4,{"t":"or","l":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_NORMAL"},"r":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_TANGENT"}},184],[0," position.xyz += POSITION_BS2 * renderer_BlendShapeWeights[2] ;\nposition.xyz += POSITION_BS3 * renderer_BlendShapeWeights[3] ;\n\n"],[4,{"t":"and","l":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_NORMAL"},"r":{"t":"def","m":"RENDERER_HAS_NORMAL"}},178],[0," normal += NORMAL_BS0 * renderer_BlendShapeWeights[0] ;\nnormal += NORMAL_BS1 * renderer_BlendShapeWeights[1] ;\nnormal += NORMAL_BS2 * renderer_BlendShapeWeights[2] ;\nnormal += NORMAL_BS3 * renderer_BlendShapeWeights[3] ; \n"],[6],[0,"\n\n"],[4,{"t":"and","l":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_TANGENT"},"r":{"t":"def","m":"RENDERER_HAS_TANGENT"}},182],[0," tangent.xyz += TANGENT_BS0 * renderer_BlendShapeWeights[0] ;\ntangent.xyz += TANGENT_BS1 * renderer_BlendShapeWeights[1] ;\ntangent.xyz += TANGENT_BS2 * renderer_BlendShapeWeights[2] ;\ntangent.xyz += TANGENT_BS3 * renderer_BlendShapeWeights[3] ; \n"],[6],[0," \n"],[5,186],[0," position.xyz += POSITION_BS2 * renderer_BlendShapeWeights[2] ;\nposition.xyz += POSITION_BS3 * renderer_BlendShapeWeights[3] ;\nposition.xyz += POSITION_BS4 * renderer_BlendShapeWeights[4] ;\nposition.xyz += POSITION_BS5 * renderer_BlendShapeWeights[5] ;\nposition.xyz += POSITION_BS6 * renderer_BlendShapeWeights[6] ;\nposition.xyz += POSITION_BS7 * renderer_BlendShapeWeights[7] ; \n"],[6],[0," \n"],[6],[0," \n"],[6],[0," }\n\n"],[6],[0,"\n\n"],[6],[0,"\nvoid main() { vec4 position = vec4 ( POSITION , 1.0 ) ;\n\n"],[1,"RENDERER_HAS_NORMAL",202],[0," vec3 normal = vec3 ( NORMAL ) ;\n\n"],[1,"RENDERER_HAS_TANGENT",200],[0," vec4 tangent = vec4 ( TANGENT ) ; \n"],[6],[0," \n"],[6],[0,"\n\n"],[1,"RENDERER_HAS_BLENDSHAPE",214],[0," calculateBlendShape(position\n"],[1,"RENDERER_HAS_NORMAL",212],[0," , normal \n"],[1,"RENDERER_HAS_TANGENT",210],[0," , tangent \n"],[6],[0," \n"],[6],[0,") ; \n"],[6],[0,"\n\n"],[1,"RENDERER_HAS_SKIN",218],[0," mat4 skinMatrix = getSkinMatrix() ;\nposition = skinMatrix * position ; \n"],[6],[0,"\ngl_Position = camera_VPMat * renderer_ModelMat * position ; }"]],"fragmentShaderInstructions":[[0,"\n"],[2,"COMMON_INCLUDED",30],[0,"\n\n"],[7,"COMMON_INCLUDED"],[0,"\n\n"],[8,"PI","3.14159265359"],[0,"\n\n"],[8,"RECIPROCAL_PI","0.31830988618"],[0,"\n\n"],[8,"EPSILON","1e-6"],[0,"\n\n"],[8,"LOG2","1.442695"],[0,"\n\n"],[8,"HALF_MIN","6.103515625e-5"],[0,"\n\n"],[8,"HALF_EPS","4.8828125e-4"],[0,"\n\n"],[9,"saturate",["a"],"clamp ( a , 0.0 , 1.0 )"],[0,"\n\n"],[1,"GRAPHICS_API_WEBGL2",24],[0,"\n\n"],[9,"INVERSE_MAT",["mat"],"inverse ( mat )"],[0,"\n\n"],[5,28],[0,"\nmat2 inverseMat ( mat2 m ) { return mat2 ( m[1][1] , - m[0][1] , - m[1][0] , m[0][0] ) / ( m[0][0] * m[1][1] - m[0][1] * m[1][0] ) ; }\nmat3 inverseMat ( mat3 m ) { float a00 = m[0][0] , a01 = m[0][1] , a02 = m[0][2] ;\nfloat a10 = m[1][0] , a11 = m[1][1] , a12 = m[1][2] ;\nfloat a20 = m[2][0] , a21 = m[2][1] , a22 = m[2][2] ;\nfloat b01 = a22 * a11 - a12 * a21 ;\nfloat b11 = - a22 * a10 + a12 * a20 ;\nfloat b21 = a21 * a10 - a11 * a20 ;\nfloat det = a00 * b01 + a01 * b11 + a02 * b21 ;\nreturn mat3 ( b01 , ( - a22 * a01 + a02 * a21 ) , ( a12 * a01 - a02 * a11 ) , b11 , ( a22 * a00 - a02 * a20 ) , ( - a12 * a00 + a02 * a10 ) , b21 , ( - a21 * a00 + a01 * a20 ) , ( a11 * a00 - a01 * a10 ) ) / det ; }\nmat4 inverseMat ( mat4 m ) { float a00 = m[0][0] , a01 = m[0][1] , a02 = m[0][2] , a03 = m[0][3] , a10 = m[1][0] , a11 = m[1][1] , a12 = m[1][2] , a13 = m[1][3] , a20 = m[2][0] , a21 = m[2][1] , a22 = m[2][2] , a23 = m[2][3] , a30 = m[3][0] , a31 = m[3][1] , a32 = m[3][2] , a33 = m[3][3] , b00 = a00 * a11 - a01 * a10 , b01 = a00 * a12 - a02 * a10 , b02 = a00 * a13 - a03 * a10 , b03 = a01 * a12 - a02 * a11 , b04 = a01 * a13 - a03 * a11 , b05 = a02 * a13 - a03 * a12 , b06 = a20 * a31 - a21 * a30 , b07 = a20 * a32 - a22 * a30 , b08 = a20 * a33 - a23 * a30 , b09 = a21 * a32 - a22 * a31 , b10 = a21 * a33 - a23 * a31 , b11 = a22 * a33 - a23 * a32 , det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06 ;\nreturn mat4 ( a11 * b11 - a12 * b10 + a13 * b09 , a02 * b10 - a01 * b11 - a03 * b09 , a31 * b05 - a32 * b04 + a33 * b03 , a22 * b04 - a21 * b05 - a23 * b03 , a12 * b08 - a10 * b11 - a13 * b07 , a00 * b11 - a02 * b08 + a03 * b07 , a32 * b02 - a30 * b05 - a33 * b01 , a20 * b05 - a22 * b02 + a23 * b01 , a10 * b10 - a11 * b08 + a13 * b06 , a01 * b08 - a00 * b10 - a03 * b06 , a30 * b04 - a31 * b02 + a33 * b00 , a21 * b02 - a20 * b04 - a23 * b00 , a11 * b07 - a10 * b09 - a12 * b06 , a00 * b09 - a01 * b07 + a02 * b06 , a31 * b01 - a30 * b03 - a32 * b00 , a20 * b03 - a21 * b01 + a22 * b00 ) / det ; }\n\n"],[9,"INVERSE_MAT",["mat"],"inverseMat(mat)"],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[2,"TRANSFORM_INCLUDED",36],[0,"\n\n"],[7,"TRANSFORM_INCLUDED"],[0,"\n\n"],[6],[0,"\n\n"],[2,"ATTRIBUTES_INCLUDED",42],[0,"\n\n"],[7,"ATTRIBUTES_INCLUDED"],[0,"\n\n"],[6],[0,"\n\n"],[2,"SKIN_INCLUDED",58],[0,"\n\n"],[7,"SKIN_INCLUDED"],[0,"\n\n"],[1,"RENDERER_HAS_SKIN",56],[0,"\n\n"],[1,"RENDERER_USE_JOINT_TEXTURE",52],[0,"\n\n"],[5,54],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[2,"BLENDSHAPE_INCLUDED",86],[0,"\n\n"],[7,"BLENDSHAPE_INCLUDED"],[0,"\n\n"],[1,"RENDERER_HAS_BLENDSHAPE",84],[0,"\n\n"],[1,"RENDERER_BLENDSHAPE_USE_TEXTURE",68],[0,"\n\n"],[5,82],[0,"\n\n"],[4,{"t":"and","l":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_NORMAL"},"r":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_TANGENT"}},72],[0,"\n\n"],[5,80],[0,"\n\n"],[4,{"t":"or","l":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_NORMAL"},"r":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_TANGENT"}},76],[0,"\n\n"],[5,78],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\nvoid main() { }"]]}]}]} \ No newline at end of file +{"name":"Pipeline/DepthOnly","platformTarget":0,"subShaders":[{"name":"Default","tags":{},"passes":[{"name":"DepthOnly","isUsePass":false,"tags":{"pipelineStage":"DepthOnly"},"renderStates":{"constantMap":{},"variableMap":{"28":"material_DepthOnlyRenderQueue"}},"vertexShaderInstructions":[[0,"\n"],[2,"COMMON_INCLUDED",30],[0,"\n\n"],[7,"COMMON_INCLUDED"],[0,"\n\n"],[8,"PI","3.14159265359"],[0,"\n\n"],[8,"RECIPROCAL_PI","0.31830988618"],[0,"\n\n"],[8,"EPSILON","1e-6"],[0,"\n\n"],[8,"LOG2","1.442695"],[0,"\n\n"],[8,"HALF_MIN","6.103515625e-5"],[0,"\n\n"],[8,"HALF_EPS","4.8828125e-4"],[0,"\n\n"],[9,"saturate",["a"],"clamp ( a , 0.0 , 1.0 )"],[0,"\n\n"],[1,"GRAPHICS_API_WEBGL2",24],[0,"\n\n"],[9,"INVERSE_MAT",["mat"],"inverse ( mat )"],[0,"\n\n"],[5,28],[0,"\nmat2 inverseMat ( mat2 m ) { return mat2 ( m[1][1] , - m[0][1] , - m[1][0] , m[0][0] ) / ( m[0][0] * m[1][1] - m[0][1] * m[1][0] ) ; }\nmat3 inverseMat ( mat3 m ) { float a00 = m[0][0] , a01 = m[0][1] , a02 = m[0][2] ;\nfloat a10 = m[1][0] , a11 = m[1][1] , a12 = m[1][2] ;\nfloat a20 = m[2][0] , a21 = m[2][1] , a22 = m[2][2] ;\nfloat b01 = a22 * a11 - a12 * a21 ;\nfloat b11 = - a22 * a10 + a12 * a20 ;\nfloat b21 = a21 * a10 - a11 * a20 ;\nfloat det = a00 * b01 + a01 * b11 + a02 * b21 ;\nreturn mat3 ( b01 , ( - a22 * a01 + a02 * a21 ) , ( a12 * a01 - a02 * a11 ) , b11 , ( a22 * a00 - a02 * a20 ) , ( - a12 * a00 + a02 * a10 ) , b21 , ( - a21 * a00 + a01 * a20 ) , ( a11 * a00 - a01 * a10 ) ) / det ; }\nmat4 inverseMat ( mat4 m ) { float a00 = m[0][0] , a01 = m[0][1] , a02 = m[0][2] , a03 = m[0][3] , a10 = m[1][0] , a11 = m[1][1] , a12 = m[1][2] , a13 = m[1][3] , a20 = m[2][0] , a21 = m[2][1] , a22 = m[2][2] , a23 = m[2][3] , a30 = m[3][0] , a31 = m[3][1] , a32 = m[3][2] , a33 = m[3][3] , b00 = a00 * a11 - a01 * a10 , b01 = a00 * a12 - a02 * a10 , b02 = a00 * a13 - a03 * a10 , b03 = a01 * a12 - a02 * a11 , b04 = a01 * a13 - a03 * a11 , b05 = a02 * a13 - a03 * a12 , b06 = a20 * a31 - a21 * a30 , b07 = a20 * a32 - a22 * a30 , b08 = a20 * a33 - a23 * a30 , b09 = a21 * a32 - a22 * a31 , b10 = a21 * a33 - a23 * a31 , b11 = a22 * a33 - a23 * a32 , det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06 ;\nreturn mat4 ( a11 * b11 - a12 * b10 + a13 * b09 , a02 * b10 - a01 * b11 - a03 * b09 , a31 * b05 - a32 * b04 + a33 * b03 , a22 * b04 - a21 * b05 - a23 * b03 , a12 * b08 - a10 * b11 - a13 * b07 , a00 * b11 - a02 * b08 + a03 * b07 , a32 * b02 - a30 * b05 - a33 * b01 , a20 * b05 - a22 * b02 + a23 * b01 , a10 * b10 - a11 * b08 + a13 * b06 , a01 * b08 - a00 * b10 - a03 * b06 , a30 * b04 - a31 * b02 + a33 * b00 , a21 * b02 - a20 * b04 - a23 * b00 , a11 * b07 - a10 * b09 - a12 * b06 , a00 * b09 - a01 * b07 + a02 * b06 , a31 * b01 - a30 * b03 - a32 * b00 , a20 * b03 - a21 * b01 + a22 * b00 ) / det ; }\n\n"],[9,"INVERSE_MAT",["mat"],"inverseMat(mat)"],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[2,"TRANSFORM_INCLUDED",36],[0,"\n\n"],[7,"TRANSFORM_INCLUDED"],[0,"\nuniform mat4 camera_VPMat;\nuniform mat4 renderer_ModelMat;\n\n"],[6],[0,"\n\n"],[2,"ATTRIBUTES_INCLUDED",94],[0,"\n\n"],[7,"ATTRIBUTES_INCLUDED"],[0,"\nattribute vec3 POSITION;\n\n"],[1,"RENDERER_HAS_BLENDSHAPE",68],[0,"\n"],[2,"RENDERER_BLENDSHAPE_USE_TEXTURE",66],[0,"attribute vec3 POSITION_BS0;\nattribute vec3 POSITION_BS1;\n\n"],[4,{"t":"and","l":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_NORMAL"},"r":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_TANGENT"}},48],[0,"attribute vec3 NORMAL_BS0;\nattribute vec3 NORMAL_BS1;\nattribute vec3 TANGENT_BS0;\nattribute vec3 TANGENT_BS1;\n\n"],[5,64],[0,"\n"],[4,{"t":"or","l":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_NORMAL"},"r":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_TANGENT"}},60],[0,"attribute vec3 POSITION_BS2;\nattribute vec3 POSITION_BS3;\n\n"],[1,"RENDERER_BLENDSHAPE_HAS_NORMAL",54],[0,"attribute vec3 NORMAL_BS0;\nattribute vec3 NORMAL_BS1;\nattribute vec3 NORMAL_BS2;\nattribute vec3 NORMAL_BS3;\n\n"],[6],[0,"\n"],[1,"RENDERER_BLENDSHAPE_HAS_TANGENT",58],[0,"attribute vec3 TANGENT_BS0;\nattribute vec3 TANGENT_BS1;\nattribute vec3 TANGENT_BS2;\nattribute vec3 TANGENT_BS3;\n\n"],[6],[0,"\n"],[5,62],[0,"attribute vec3 POSITION_BS2;\nattribute vec3 POSITION_BS3;\nattribute vec3 POSITION_BS4;\nattribute vec3 POSITION_BS5;\nattribute vec3 POSITION_BS6;\nattribute vec3 POSITION_BS7;\n\n"],[6],[0,"\n"],[6],[0,"\n"],[6],[0,"\n"],[6],[0,"\n"],[1,"RENDERER_HAS_UV",72],[0,"\n"],[6],[0,"\n"],[1,"RENDERER_HAS_UV1",76],[0,"\n"],[6],[0,"\n"],[1,"RENDERER_HAS_SKIN",80],[0,"attribute vec4 JOINTS_0;\nattribute vec4 WEIGHTS_0;\n\n"],[6],[0,"\n"],[1,"RENDERER_ENABLE_VERTEXCOLOR",84],[0,"\n"],[6],[0,"\n"],[1,"RENDERER_HAS_NORMAL",88],[0,"attribute vec3 NORMAL;\n\n"],[6],[0,"\n"],[1,"RENDERER_HAS_TANGENT",92],[0,"attribute vec4 TANGENT;\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[2,"SKIN_INCLUDED",116],[0,"\n\n"],[7,"SKIN_INCLUDED"],[0,"\n\n"],[1,"RENDERER_HAS_SKIN",114],[0,"\n\n"],[1,"RENDERER_USE_JOINT_TEXTURE",104],[0,"\nuniform sampler2D renderer_JointSampler;\nuniform float renderer_JointCount;\nmat4 getJointMatrix ( sampler2D smp, float index ) { float base = index / renderer_JointCount ;\nfloat hf = 0.5 / renderer_JointCount ;\nfloat v = base + hf ;\nvec4 m0 = texture2D ( smp , vec2 ( 0.125 , v ) ) ;\nvec4 m1 = texture2D ( smp , vec2 ( 0.375 , v ) ) ;\nvec4 m2 = texture2D ( smp , vec2 ( 0.625 , v ) ) ;\nvec4 m3 = texture2D ( smp , vec2 ( 0.875 , v ) ) ;\nreturn mat4 ( m0 , m1 , m2 , m3 ) ; }\n\n"],[5,106],[0,"\nuniform mat4 renderer_JointMatrix [ RENDERER_JOINTS_NUM ];\n\n"],[6],[0,"\nmat4 getSkinMatrix ( ) { \n"],[1,"RENDERER_USE_JOINT_TEXTURE",110],[0," mat4 skinMatrix = WEIGHTS_0.x * getJointMatrix(renderer_JointSampler, JOINTS_0.x) + WEIGHTS_0.y * getJointMatrix(renderer_JointSampler, JOINTS_0.y) + WEIGHTS_0.z * getJointMatrix(renderer_JointSampler, JOINTS_0.z) + WEIGHTS_0.w * getJointMatrix(renderer_JointSampler, JOINTS_0.w) ; \n"],[5,112],[0," mat4 skinMatrix = WEIGHTS_0.x * renderer_JointMatrix[int ( JOINTS_0.x )] + WEIGHTS_0.y * renderer_JointMatrix[int ( JOINTS_0.y )] + WEIGHTS_0.z * renderer_JointMatrix[int ( JOINTS_0.z )] + WEIGHTS_0.w * renderer_JointMatrix[int ( JOINTS_0.w )] ; \n"],[6],[0,"\nreturn skinMatrix ; }\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[2,"BLENDSHAPE_INCLUDED",194],[0,"\n\n"],[7,"BLENDSHAPE_INCLUDED"],[0,"\n\n"],[1,"RENDERER_HAS_BLENDSHAPE",192],[0,"\n\n"],[1,"RENDERER_BLENDSHAPE_USE_TEXTURE",126],[0,"\nuniform mediump sampler2DArray renderer_BlendShapeTexture;\nuniform ivec3 renderer_BlendShapeTextureInfo;\nuniform float renderer_BlendShapeWeights [ RENDERER_BLENDSHAPE_COUNT ];\nvec3 getBlendShapeVertexElement ( int blendShapeIndex, int vertexElementIndex ) { int y = vertexElementIndex / renderer_BlendShapeTextureInfo.y ;\nint x = vertexElementIndex - y * renderer_BlendShapeTextureInfo.y ;\nivec3 uv = ivec3 ( x , y , blendShapeIndex ) ;\nreturn ( texelFetch ( renderer_BlendShapeTexture , uv , 0 ) ).xyz ; }\n\n"],[5,140],[0,"\n\n"],[4,{"t":"and","l":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_NORMAL"},"r":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_TANGENT"}},130],[0,"\nuniform float renderer_BlendShapeWeights [ 2 ];\n\n"],[5,138],[0,"\n\n"],[4,{"t":"or","l":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_NORMAL"},"r":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_TANGENT"}},134],[0,"\nuniform float renderer_BlendShapeWeights [ 4 ];\n\n"],[5,136],[0,"\nuniform float renderer_BlendShapeWeights [ 8 ];\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\nvoid calculateBlendShape ( inout vec4 position\n"],[1,"RENDERER_HAS_NORMAL",148],[0," , inout vec3 normal \n"],[1,"RENDERER_HAS_TANGENT",146],[0," , inout vec4 tangent \n"],[6],[0," \n"],[6],[0," ) { \n"],[1,"RENDERER_BLENDSHAPE_USE_TEXTURE",160],[0," int vertexOffset = gl_VertexID * renderer_BlendShapeTextureInfo.x ;\nfor ( int i = 0 ; i < RENDERER_BLENDSHAPE_COUNT ; i ++ ) { int vertexElementOffset = vertexOffset ;\nfloat weight = renderer_BlendShapeWeights[i] ;\nif ( weight != 0.0 ) { position.xyz += getBlendShapeVertexElement(i, vertexElementOffset) * weight ;\n\n"],[4,{"t":"and","l":{"t":"def","m":"RENDERER_HAS_NORMAL"},"r":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_NORMAL"}},154],[0," vertexElementOffset += 1 ;\nnormal += getBlendShapeVertexElement(i, vertexElementOffset) * weight ; \n"],[6],[0,"\n\n"],[4,{"t":"and","l":{"t":"def","m":"RENDERER_HAS_TANGENT"},"r":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_TANGENT"}},158],[0," vertexElementOffset += 1 ;\ntangent.xyz += getBlendShapeVertexElement(i, vertexElementOffset) * weight ; \n"],[6],[0," } } \n"],[5,190],[0," position.xyz += POSITION_BS0 * renderer_BlendShapeWeights[0] ;\nposition.xyz += POSITION_BS1 * renderer_BlendShapeWeights[1] ;\n\n"],[4,{"t":"and","l":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_NORMAL"},"r":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_TANGENT"}},172],[0," \n"],[1,"RENDERER_HAS_NORMAL",166],[0," normal += NORMAL_BS0 * renderer_BlendShapeWeights[0] ;\nnormal += NORMAL_BS1 * renderer_BlendShapeWeights[1] ; \n"],[6],[0,"\n\n"],[1,"RENDERER_HAS_TANGENT",170],[0," tangent.xyz += TANGENT_BS0 * renderer_BlendShapeWeights[0] ;\ntangent.xyz += TANGENT_BS1 * renderer_BlendShapeWeights[1] ; \n"],[6],[0," \n"],[5,188],[0," \n"],[4,{"t":"or","l":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_NORMAL"},"r":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_TANGENT"}},184],[0," position.xyz += POSITION_BS2 * renderer_BlendShapeWeights[2] ;\nposition.xyz += POSITION_BS3 * renderer_BlendShapeWeights[3] ;\n\n"],[4,{"t":"and","l":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_NORMAL"},"r":{"t":"def","m":"RENDERER_HAS_NORMAL"}},178],[0," normal += NORMAL_BS0 * renderer_BlendShapeWeights[0] ;\nnormal += NORMAL_BS1 * renderer_BlendShapeWeights[1] ;\nnormal += NORMAL_BS2 * renderer_BlendShapeWeights[2] ;\nnormal += NORMAL_BS3 * renderer_BlendShapeWeights[3] ; \n"],[6],[0,"\n\n"],[4,{"t":"and","l":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_TANGENT"},"r":{"t":"def","m":"RENDERER_HAS_TANGENT"}},182],[0," tangent.xyz += TANGENT_BS0 * renderer_BlendShapeWeights[0] ;\ntangent.xyz += TANGENT_BS1 * renderer_BlendShapeWeights[1] ;\ntangent.xyz += TANGENT_BS2 * renderer_BlendShapeWeights[2] ;\ntangent.xyz += TANGENT_BS3 * renderer_BlendShapeWeights[3] ; \n"],[6],[0," \n"],[5,186],[0," position.xyz += POSITION_BS2 * renderer_BlendShapeWeights[2] ;\nposition.xyz += POSITION_BS3 * renderer_BlendShapeWeights[3] ;\nposition.xyz += POSITION_BS4 * renderer_BlendShapeWeights[4] ;\nposition.xyz += POSITION_BS5 * renderer_BlendShapeWeights[5] ;\nposition.xyz += POSITION_BS6 * renderer_BlendShapeWeights[6] ;\nposition.xyz += POSITION_BS7 * renderer_BlendShapeWeights[7] ; \n"],[6],[0," \n"],[6],[0," \n"],[6],[0," }\n\n"],[6],[0,"\n\n"],[6],[0,"\nvoid main() { vec4 position = vec4 ( POSITION , 1.0 ) ;\n\n"],[1,"RENDERER_HAS_NORMAL",202],[0," vec3 normal = vec3 ( NORMAL ) ;\n\n"],[1,"RENDERER_HAS_TANGENT",200],[0," vec4 tangent = vec4 ( TANGENT ) ; \n"],[6],[0," \n"],[6],[0,"\n\n"],[1,"RENDERER_HAS_BLENDSHAPE",214],[0," calculateBlendShape(position\n"],[1,"RENDERER_HAS_NORMAL",212],[0," , normal \n"],[1,"RENDERER_HAS_TANGENT",210],[0," , tangent \n"],[6],[0," \n"],[6],[0,") ; \n"],[6],[0,"\n\n"],[1,"RENDERER_HAS_SKIN",218],[0," mat4 skinMatrix = getSkinMatrix() ;\nposition = skinMatrix * position ; \n"],[6],[0,"\ngl_Position = camera_VPMat * renderer_ModelMat * position ; }"]],"fragmentShaderInstructions":[[0,"\n"],[2,"COMMON_INCLUDED",30],[0,"\n\n"],[7,"COMMON_INCLUDED"],[0,"\n\n"],[8,"PI","3.14159265359"],[0,"\n\n"],[8,"RECIPROCAL_PI","0.31830988618"],[0,"\n\n"],[8,"EPSILON","1e-6"],[0,"\n\n"],[8,"LOG2","1.442695"],[0,"\n\n"],[8,"HALF_MIN","6.103515625e-5"],[0,"\n\n"],[8,"HALF_EPS","4.8828125e-4"],[0,"\n\n"],[9,"saturate",["a"],"clamp ( a , 0.0 , 1.0 )"],[0,"\n\n"],[1,"GRAPHICS_API_WEBGL2",24],[0,"\n\n"],[9,"INVERSE_MAT",["mat"],"inverse ( mat )"],[0,"\n\n"],[5,28],[0,"\nmat2 inverseMat ( mat2 m ) { return mat2 ( m[1][1] , - m[0][1] , - m[1][0] , m[0][0] ) / ( m[0][0] * m[1][1] - m[0][1] * m[1][0] ) ; }\nmat3 inverseMat ( mat3 m ) { float a00 = m[0][0] , a01 = m[0][1] , a02 = m[0][2] ;\nfloat a10 = m[1][0] , a11 = m[1][1] , a12 = m[1][2] ;\nfloat a20 = m[2][0] , a21 = m[2][1] , a22 = m[2][2] ;\nfloat b01 = a22 * a11 - a12 * a21 ;\nfloat b11 = - a22 * a10 + a12 * a20 ;\nfloat b21 = a21 * a10 - a11 * a20 ;\nfloat det = a00 * b01 + a01 * b11 + a02 * b21 ;\nreturn mat3 ( b01 , ( - a22 * a01 + a02 * a21 ) , ( a12 * a01 - a02 * a11 ) , b11 , ( a22 * a00 - a02 * a20 ) , ( - a12 * a00 + a02 * a10 ) , b21 , ( - a21 * a00 + a01 * a20 ) , ( a11 * a00 - a01 * a10 ) ) / det ; }\nmat4 inverseMat ( mat4 m ) { float a00 = m[0][0] , a01 = m[0][1] , a02 = m[0][2] , a03 = m[0][3] , a10 = m[1][0] , a11 = m[1][1] , a12 = m[1][2] , a13 = m[1][3] , a20 = m[2][0] , a21 = m[2][1] , a22 = m[2][2] , a23 = m[2][3] , a30 = m[3][0] , a31 = m[3][1] , a32 = m[3][2] , a33 = m[3][3] , b00 = a00 * a11 - a01 * a10 , b01 = a00 * a12 - a02 * a10 , b02 = a00 * a13 - a03 * a10 , b03 = a01 * a12 - a02 * a11 , b04 = a01 * a13 - a03 * a11 , b05 = a02 * a13 - a03 * a12 , b06 = a20 * a31 - a21 * a30 , b07 = a20 * a32 - a22 * a30 , b08 = a20 * a33 - a23 * a30 , b09 = a21 * a32 - a22 * a31 , b10 = a21 * a33 - a23 * a31 , b11 = a22 * a33 - a23 * a32 , det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06 ;\nreturn mat4 ( a11 * b11 - a12 * b10 + a13 * b09 , a02 * b10 - a01 * b11 - a03 * b09 , a31 * b05 - a32 * b04 + a33 * b03 , a22 * b04 - a21 * b05 - a23 * b03 , a12 * b08 - a10 * b11 - a13 * b07 , a00 * b11 - a02 * b08 + a03 * b07 , a32 * b02 - a30 * b05 - a33 * b01 , a20 * b05 - a22 * b02 + a23 * b01 , a10 * b10 - a11 * b08 + a13 * b06 , a01 * b08 - a00 * b10 - a03 * b06 , a30 * b04 - a31 * b02 + a33 * b00 , a21 * b02 - a20 * b04 - a23 * b00 , a11 * b07 - a10 * b09 - a12 * b06 , a00 * b09 - a01 * b07 + a02 * b06 , a31 * b01 - a30 * b03 - a32 * b00 , a20 * b03 - a21 * b01 + a22 * b00 ) / det ; }\n\n"],[9,"INVERSE_MAT",["mat"],"inverseMat(mat)"],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[2,"TRANSFORM_INCLUDED",36],[0,"\n\n"],[7,"TRANSFORM_INCLUDED"],[0,"\n\n"],[6],[0,"\n\n"],[2,"ATTRIBUTES_INCLUDED",42],[0,"\n\n"],[7,"ATTRIBUTES_INCLUDED"],[0,"\n\n"],[6],[0,"\n\n"],[2,"SKIN_INCLUDED",58],[0,"\n\n"],[7,"SKIN_INCLUDED"],[0,"\n\n"],[1,"RENDERER_HAS_SKIN",56],[0,"\n\n"],[1,"RENDERER_USE_JOINT_TEXTURE",52],[0,"\n\n"],[5,54],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[2,"BLENDSHAPE_INCLUDED",86],[0,"\n\n"],[7,"BLENDSHAPE_INCLUDED"],[0,"\n\n"],[1,"RENDERER_HAS_BLENDSHAPE",84],[0,"\n\n"],[1,"RENDERER_BLENDSHAPE_USE_TEXTURE",68],[0,"\n\n"],[5,82],[0,"\n\n"],[4,{"t":"and","l":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_NORMAL"},"r":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_TANGENT"}},72],[0,"\n\n"],[5,80],[0,"\n\n"],[4,{"t":"or","l":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_NORMAL"},"r":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_TANGENT"}},76],[0,"\n\n"],[5,78],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\nvoid main() { }"]]}]}]} \ No newline at end of file diff --git a/packages/shader/compiledShaders/Pipeline/ShadowCaster.shaderc b/packages/shader/compiledShaders/Pipeline/ShadowCaster.shaderc index b269b8d604..c4d98c9b62 100644 --- a/packages/shader/compiledShaders/Pipeline/ShadowCaster.shaderc +++ b/packages/shader/compiledShaders/Pipeline/ShadowCaster.shaderc @@ -1 +1 @@ -{"name":"Pipeline/ShadowCaster","platformTarget":0,"subShaders":[{"name":"Default","tags":{},"passes":[{"name":"ShadowCaster","isUsePass":false,"tags":{"pipelineStage":"ShadowCaster"},"renderStates":{"constantMap":{},"variableMap":{"28":"material_ShadowCasterRenderQueue"}},"vertexShaderInstructions":[[0,"\n"],[2,"COMMON_INCLUDED",30],[0,"\n\n"],[7,"COMMON_INCLUDED"],[0,"\n\n"],[8,"PI","3.14159265359"],[0,"\n\n"],[8,"RECIPROCAL_PI","0.31830988618"],[0,"\n\n"],[8,"EPSILON","1e-6"],[0,"\n\n"],[8,"LOG2","1.442695"],[0,"\n\n"],[8,"HALF_MIN","6.103515625e-5"],[0,"\n\n"],[8,"HALF_EPS","4.8828125e-4"],[0,"\n\n"],[9,"saturate",["a"],"clamp ( a , 0.0 , 1.0 )"],[0,"\n\n"],[1,"GRAPHICS_API_WEBGL2",24],[0,"\n\n"],[9,"INVERSE_MAT",["mat"],"inverse ( mat )"],[0,"\n\n"],[5,28],[0,"\nmat2 inverseMat ( mat2 m ) { return mat2 ( m[1][1] , - m[0][1] , - m[1][0] , m[0][0] ) / ( m[0][0] * m[1][1] - m[0][1] * m[1][0] ) ; }\nmat3 inverseMat ( mat3 m ) { float a00 = m[0][0] , a01 = m[0][1] , a02 = m[0][2] ;\nfloat a10 = m[1][0] , a11 = m[1][1] , a12 = m[1][2] ;\nfloat a20 = m[2][0] , a21 = m[2][1] , a22 = m[2][2] ;\nfloat b01 = a22 * a11 - a12 * a21 ;\nfloat b11 = - a22 * a10 + a12 * a20 ;\nfloat b21 = a21 * a10 - a11 * a20 ;\nfloat det = a00 * b01 + a01 * b11 + a02 * b21 ;\nreturn mat3 ( b01 , ( - a22 * a01 + a02 * a21 ) , ( a12 * a01 - a02 * a11 ) , b11 , ( a22 * a00 - a02 * a20 ) , ( - a12 * a00 + a02 * a10 ) , b21 , ( - a21 * a00 + a01 * a20 ) , ( a11 * a00 - a01 * a10 ) ) / det ; }\nmat4 inverseMat ( mat4 m ) { float a00 = m[0][0] , a01 = m[0][1] , a02 = m[0][2] , a03 = m[0][3] , a10 = m[1][0] , a11 = m[1][1] , a12 = m[1][2] , a13 = m[1][3] , a20 = m[2][0] , a21 = m[2][1] , a22 = m[2][2] , a23 = m[2][3] , a30 = m[3][0] , a31 = m[3][1] , a32 = m[3][2] , a33 = m[3][3] , b00 = a00 * a11 - a01 * a10 , b01 = a00 * a12 - a02 * a10 , b02 = a00 * a13 - a03 * a10 , b03 = a01 * a12 - a02 * a11 , b04 = a01 * a13 - a03 * a11 , b05 = a02 * a13 - a03 * a12 , b06 = a20 * a31 - a21 * a30 , b07 = a20 * a32 - a22 * a30 , b08 = a20 * a33 - a23 * a30 , b09 = a21 * a32 - a22 * a31 , b10 = a21 * a33 - a23 * a31 , b11 = a22 * a33 - a23 * a32 , det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06 ;\nreturn mat4 ( a11 * b11 - a12 * b10 + a13 * b09 , a02 * b10 - a01 * b11 - a03 * b09 , a31 * b05 - a32 * b04 + a33 * b03 , a22 * b04 - a21 * b05 - a23 * b03 , a12 * b08 - a10 * b11 - a13 * b07 , a00 * b11 - a02 * b08 + a03 * b07 , a32 * b02 - a30 * b05 - a33 * b01 , a20 * b05 - a22 * b02 + a23 * b01 , a10 * b10 - a11 * b08 + a13 * b06 , a01 * b08 - a00 * b10 - a03 * b06 , a30 * b04 - a31 * b02 + a33 * b00 , a21 * b02 - a20 * b04 - a23 * b00 , a11 * b07 - a10 * b09 - a12 * b06 , a00 * b09 - a01 * b07 + a02 * b06 , a31 * b01 - a30 * b03 - a32 * b00 , a20 * b03 - a21 * b01 + a22 * b00 ) / det ; }\n\n"],[9,"INVERSE_MAT",["mat"],"inverseMat(mat)"],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[2,"TRANSFORM_INCLUDED",36],[0,"\n\n"],[7,"TRANSFORM_INCLUDED"],[0,"\nuniform mat4 renderer_ModelMat;\nuniform mat4 camera_VPMat;\nuniform mat4 renderer_NormalMat;\n\n"],[6],[0,"\n\n"],[2,"ATTRIBUTES_INCLUDED",94],[0,"\n\n"],[7,"ATTRIBUTES_INCLUDED"],[0,"\nattribute vec3 POSITION;\n\n"],[1,"RENDERER_HAS_BLENDSHAPE",68],[0,"\n"],[2,"RENDERER_BLENDSHAPE_USE_TEXTURE",66],[0,"attribute vec3 POSITION_BS0;\nattribute vec3 POSITION_BS1;\n\n"],[4,{"t":"and","l":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_NORMAL"},"r":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_TANGENT"}},48],[0,"attribute vec3 NORMAL_BS0;\nattribute vec3 NORMAL_BS1;\nattribute vec3 TANGENT_BS0;\nattribute vec3 TANGENT_BS1;\n\n"],[5,64],[0,"\n"],[4,{"t":"or","l":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_NORMAL"},"r":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_TANGENT"}},60],[0,"attribute vec3 POSITION_BS2;\nattribute vec3 POSITION_BS3;\n\n"],[1,"RENDERER_BLENDSHAPE_HAS_NORMAL",54],[0,"attribute vec3 NORMAL_BS0;\nattribute vec3 NORMAL_BS1;\nattribute vec3 NORMAL_BS2;\nattribute vec3 NORMAL_BS3;\n\n"],[6],[0,"\n"],[1,"RENDERER_BLENDSHAPE_HAS_TANGENT",58],[0,"attribute vec3 TANGENT_BS0;\nattribute vec3 TANGENT_BS1;\nattribute vec3 TANGENT_BS2;\nattribute vec3 TANGENT_BS3;\n\n"],[6],[0,"\n"],[5,62],[0,"attribute vec3 POSITION_BS2;\nattribute vec3 POSITION_BS3;\nattribute vec3 POSITION_BS4;\nattribute vec3 POSITION_BS5;\nattribute vec3 POSITION_BS6;\nattribute vec3 POSITION_BS7;\n\n"],[6],[0,"\n"],[6],[0,"\n"],[6],[0,"\n"],[6],[0,"\n"],[1,"RENDERER_HAS_UV",72],[0,"attribute vec2 TEXCOORD_0;\n\n"],[6],[0,"\n"],[1,"RENDERER_HAS_UV1",76],[0,"\n"],[6],[0,"\n"],[1,"RENDERER_HAS_SKIN",80],[0,"attribute vec4 JOINTS_0;\nattribute vec4 WEIGHTS_0;\n\n"],[6],[0,"\n"],[1,"RENDERER_ENABLE_VERTEXCOLOR",84],[0,"\n"],[6],[0,"\n"],[1,"RENDERER_HAS_NORMAL",88],[0,"attribute vec3 NORMAL;\n\n"],[6],[0,"\n"],[1,"RENDERER_HAS_TANGENT",92],[0,"attribute vec4 TANGENT;\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[2,"SKIN_INCLUDED",116],[0,"\n\n"],[7,"SKIN_INCLUDED"],[0,"\n\n"],[1,"RENDERER_HAS_SKIN",114],[0,"\n\n"],[1,"RENDERER_USE_JOINT_TEXTURE",104],[0,"\nuniform sampler2D renderer_JointSampler;\nuniform float renderer_JointCount;\nmat4 getJointMatrix ( sampler2D smp, float index ) { float base = index / renderer_JointCount ;\nfloat hf = 0.5 / renderer_JointCount ;\nfloat v = base + hf ;\nvec4 m0 = texture2D ( smp , vec2 ( 0.125 , v ) ) ;\nvec4 m1 = texture2D ( smp , vec2 ( 0.375 , v ) ) ;\nvec4 m2 = texture2D ( smp , vec2 ( 0.625 , v ) ) ;\nvec4 m3 = texture2D ( smp , vec2 ( 0.875 , v ) ) ;\nreturn mat4 ( m0 , m1 , m2 , m3 ) ; }\n\n"],[5,106],[0,"\nuniform mat4 renderer_JointMatrix [ RENDERER_JOINTS_NUM ];\n\n"],[6],[0,"\nmat4 getSkinMatrix ( ) { \n"],[1,"RENDERER_USE_JOINT_TEXTURE",110],[0," mat4 skinMatrix = WEIGHTS_0.x * getJointMatrix(renderer_JointSampler, JOINTS_0.x) + WEIGHTS_0.y * getJointMatrix(renderer_JointSampler, JOINTS_0.y) + WEIGHTS_0.z * getJointMatrix(renderer_JointSampler, JOINTS_0.z) + WEIGHTS_0.w * getJointMatrix(renderer_JointSampler, JOINTS_0.w) ; \n"],[5,112],[0," mat4 skinMatrix = WEIGHTS_0.x * renderer_JointMatrix[int ( JOINTS_0.x )] + WEIGHTS_0.y * renderer_JointMatrix[int ( JOINTS_0.y )] + WEIGHTS_0.z * renderer_JointMatrix[int ( JOINTS_0.z )] + WEIGHTS_0.w * renderer_JointMatrix[int ( JOINTS_0.w )] ; \n"],[6],[0,"\nreturn skinMatrix ; }\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[2,"BLENDSHAPE_INCLUDED",194],[0,"\n\n"],[7,"BLENDSHAPE_INCLUDED"],[0,"\n\n"],[1,"RENDERER_HAS_BLENDSHAPE",192],[0,"\n\n"],[1,"RENDERER_BLENDSHAPE_USE_TEXTURE",126],[0,"\nuniform mediump sampler2DArray renderer_BlendShapeTexture;\nuniform ivec3 renderer_BlendShapeTextureInfo;\nuniform float renderer_BlendShapeWeights [ RENDERER_BLENDSHAPE_COUNT ];\nvec3 getBlendShapeVertexElement ( int blendShapeIndex, int vertexElementIndex ) { int y = vertexElementIndex / renderer_BlendShapeTextureInfo.y ;\nint x = vertexElementIndex - y * renderer_BlendShapeTextureInfo.y ;\nivec3 uv = ivec3 ( x , y , blendShapeIndex ) ;\nreturn ( texelFetch ( renderer_BlendShapeTexture , uv , 0 ) ).xyz ; }\n\n"],[5,140],[0,"\n\n"],[4,{"t":"and","l":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_NORMAL"},"r":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_TANGENT"}},130],[0,"\nuniform float renderer_BlendShapeWeights [ 2 ];\n\n"],[5,138],[0,"\n\n"],[4,{"t":"or","l":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_NORMAL"},"r":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_TANGENT"}},134],[0,"\nuniform float renderer_BlendShapeWeights [ 4 ];\n\n"],[5,136],[0,"\nuniform float renderer_BlendShapeWeights [ 8 ];\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\nvoid calculateBlendShape ( inout vec4 position\n"],[1,"RENDERER_HAS_NORMAL",148],[0," , inout vec3 normal \n"],[1,"RENDERER_HAS_TANGENT",146],[0," , inout vec4 tangent \n"],[6],[0," \n"],[6],[0," ) { \n"],[1,"RENDERER_BLENDSHAPE_USE_TEXTURE",160],[0," int vertexOffset = gl_VertexID * renderer_BlendShapeTextureInfo.x ;\nfor ( int i = 0 ; i < RENDERER_BLENDSHAPE_COUNT ; i ++ ) { int vertexElementOffset = vertexOffset ;\nfloat weight = renderer_BlendShapeWeights[i] ;\nif ( weight != 0.0 ) { position.xyz += getBlendShapeVertexElement(i, vertexElementOffset) * weight ;\n\n"],[4,{"t":"and","l":{"t":"def","m":"RENDERER_HAS_NORMAL"},"r":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_NORMAL"}},154],[0," vertexElementOffset += 1 ;\nnormal += getBlendShapeVertexElement(i, vertexElementOffset) * weight ; \n"],[6],[0,"\n\n"],[4,{"t":"and","l":{"t":"def","m":"RENDERER_HAS_TANGENT"},"r":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_TANGENT"}},158],[0," vertexElementOffset += 1 ;\ntangent.xyz += getBlendShapeVertexElement(i, vertexElementOffset) * weight ; \n"],[6],[0," } } \n"],[5,190],[0," position.xyz += POSITION_BS0 * renderer_BlendShapeWeights[0] ;\nposition.xyz += POSITION_BS1 * renderer_BlendShapeWeights[1] ;\n\n"],[4,{"t":"and","l":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_NORMAL"},"r":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_TANGENT"}},172],[0," \n"],[1,"RENDERER_HAS_NORMAL",166],[0," normal += NORMAL_BS0 * renderer_BlendShapeWeights[0] ;\nnormal += NORMAL_BS1 * renderer_BlendShapeWeights[1] ; \n"],[6],[0,"\n\n"],[1,"RENDERER_HAS_TANGENT",170],[0," tangent.xyz += TANGENT_BS0 * renderer_BlendShapeWeights[0] ;\ntangent.xyz += TANGENT_BS1 * renderer_BlendShapeWeights[1] ; \n"],[6],[0," \n"],[5,188],[0," \n"],[4,{"t":"or","l":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_NORMAL"},"r":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_TANGENT"}},184],[0," position.xyz += POSITION_BS2 * renderer_BlendShapeWeights[2] ;\nposition.xyz += POSITION_BS3 * renderer_BlendShapeWeights[3] ;\n\n"],[4,{"t":"and","l":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_NORMAL"},"r":{"t":"def","m":"RENDERER_HAS_NORMAL"}},178],[0," normal += NORMAL_BS0 * renderer_BlendShapeWeights[0] ;\nnormal += NORMAL_BS1 * renderer_BlendShapeWeights[1] ;\nnormal += NORMAL_BS2 * renderer_BlendShapeWeights[2] ;\nnormal += NORMAL_BS3 * renderer_BlendShapeWeights[3] ; \n"],[6],[0,"\n\n"],[4,{"t":"and","l":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_TANGENT"},"r":{"t":"def","m":"RENDERER_HAS_TANGENT"}},182],[0," tangent.xyz += TANGENT_BS0 * renderer_BlendShapeWeights[0] ;\ntangent.xyz += TANGENT_BS1 * renderer_BlendShapeWeights[1] ;\ntangent.xyz += TANGENT_BS2 * renderer_BlendShapeWeights[2] ;\ntangent.xyz += TANGENT_BS3 * renderer_BlendShapeWeights[3] ; \n"],[6],[0," \n"],[5,186],[0," position.xyz += POSITION_BS2 * renderer_BlendShapeWeights[2] ;\nposition.xyz += POSITION_BS3 * renderer_BlendShapeWeights[3] ;\nposition.xyz += POSITION_BS4 * renderer_BlendShapeWeights[4] ;\nposition.xyz += POSITION_BS5 * renderer_BlendShapeWeights[5] ;\nposition.xyz += POSITION_BS6 * renderer_BlendShapeWeights[6] ;\nposition.xyz += POSITION_BS7 * renderer_BlendShapeWeights[7] ; \n"],[6],[0," \n"],[6],[0," \n"],[6],[0," }\n\n"],[6],[0,"\n\n"],[6],[0,"\nuniform vec2 scene_ShadowBias;\nuniform vec3 scene_LightDirection;\nvarying vec2 v_uv;\n\nvec3 applyShadowBias ( vec3 positionWS ) { positionWS -= scene_LightDirection * scene_ShadowBias.x ;\nreturn positionWS ; }\nvec3 applyShadowNormalBias ( vec3 positionWS, vec3 normalWS ) { float invNdotL = 1.0 - clamp ( dot ( - scene_LightDirection , normalWS ) , 0.0 , 1.0 ) ;\nfloat scale = invNdotL * scene_ShadowBias.y ;\npositionWS += normalWS * vec3 ( scale ) ;\nreturn positionWS ; }\nvoid main() { \nvec4 position = vec4 ( POSITION , 1.0 ) ;\n\n"],[1,"RENDERER_HAS_NORMAL",202],[0," vec3 normal = vec3 ( NORMAL ) ;\n\n"],[1,"RENDERER_HAS_TANGENT",200],[0," vec4 tangent = vec4 ( TANGENT ) ; \n"],[6],[0," \n"],[6],[0,"\n\n"],[1,"RENDERER_HAS_BLENDSHAPE",214],[0," calculateBlendShape(position\n"],[1,"RENDERER_HAS_NORMAL",212],[0," , normal \n"],[1,"RENDERER_HAS_TANGENT",210],[0," , tangent \n"],[6],[0," \n"],[6],[0,") ; \n"],[6],[0,"\n\n"],[1,"RENDERER_HAS_SKIN",222],[0," mat4 skinMatrix = getSkinMatrix() ;\nposition = skinMatrix * position ;\n\n"],[1,"RENDERER_HAS_NORMAL",220],[0," mat3 skinNormalMatrix = INVERSE_MAT(mat3 ( skinMatrix )) ;\nnormal = normal * skinNormalMatrix ; \n"],[6],[0," \n"],[6],[0,"\n\n"],[1,"RENDERER_HAS_UV",226],[0," v_uv = TEXCOORD_0 ; \n"],[5,228],[0," v_uv = vec2 ( 0.0 , 0.0 ) ; \n"],[6],[0,"\nvec4 positionWS = renderer_ModelMat * position ;\npositionWS.xyz = applyShadowBias(positionWS.xyz) ;\n\n"],[1,"RENDERER_HAS_NORMAL",232],[0," vec3 normalWS = normalize ( mat3 ( renderer_NormalMat ) * normal ) ;\npositionWS.xyz = applyShadowNormalBias(positionWS.xyz, normalWS) ; \n"],[6],[0,"\nvec4 positionCS = camera_VPMat * positionWS ;\npositionCS.z = max ( positionCS.z , - 1.0 ) ;\ngl_Position = positionCS ;\n }\n\n"],[1,"ENGINE_NO_DEPTH_TEXTURE",236],[0,"\n\n"],[6]],"fragmentShaderInstructions":[[0,"\n"],[2,"COMMON_INCLUDED",30],[0,"\n\n"],[7,"COMMON_INCLUDED"],[0,"\n\n"],[8,"PI","3.14159265359"],[0,"\n\n"],[8,"RECIPROCAL_PI","0.31830988618"],[0,"\n\n"],[8,"EPSILON","1e-6"],[0,"\n\n"],[8,"LOG2","1.442695"],[0,"\n\n"],[8,"HALF_MIN","6.103515625e-5"],[0,"\n\n"],[8,"HALF_EPS","4.8828125e-4"],[0,"\n\n"],[9,"saturate",["a"],"clamp ( a , 0.0 , 1.0 )"],[0,"\n\n"],[1,"GRAPHICS_API_WEBGL2",24],[0,"\n\n"],[9,"INVERSE_MAT",["mat"],"inverse ( mat )"],[0,"\n\n"],[5,28],[0,"\nmat2 inverseMat ( mat2 m ) { return mat2 ( m[1][1] , - m[0][1] , - m[1][0] , m[0][0] ) / ( m[0][0] * m[1][1] - m[0][1] * m[1][0] ) ; }\nmat3 inverseMat ( mat3 m ) { float a00 = m[0][0] , a01 = m[0][1] , a02 = m[0][2] ;\nfloat a10 = m[1][0] , a11 = m[1][1] , a12 = m[1][2] ;\nfloat a20 = m[2][0] , a21 = m[2][1] , a22 = m[2][2] ;\nfloat b01 = a22 * a11 - a12 * a21 ;\nfloat b11 = - a22 * a10 + a12 * a20 ;\nfloat b21 = a21 * a10 - a11 * a20 ;\nfloat det = a00 * b01 + a01 * b11 + a02 * b21 ;\nreturn mat3 ( b01 , ( - a22 * a01 + a02 * a21 ) , ( a12 * a01 - a02 * a11 ) , b11 , ( a22 * a00 - a02 * a20 ) , ( - a12 * a00 + a02 * a10 ) , b21 , ( - a21 * a00 + a01 * a20 ) , ( a11 * a00 - a01 * a10 ) ) / det ; }\nmat4 inverseMat ( mat4 m ) { float a00 = m[0][0] , a01 = m[0][1] , a02 = m[0][2] , a03 = m[0][3] , a10 = m[1][0] , a11 = m[1][1] , a12 = m[1][2] , a13 = m[1][3] , a20 = m[2][0] , a21 = m[2][1] , a22 = m[2][2] , a23 = m[2][3] , a30 = m[3][0] , a31 = m[3][1] , a32 = m[3][2] , a33 = m[3][3] , b00 = a00 * a11 - a01 * a10 , b01 = a00 * a12 - a02 * a10 , b02 = a00 * a13 - a03 * a10 , b03 = a01 * a12 - a02 * a11 , b04 = a01 * a13 - a03 * a11 , b05 = a02 * a13 - a03 * a12 , b06 = a20 * a31 - a21 * a30 , b07 = a20 * a32 - a22 * a30 , b08 = a20 * a33 - a23 * a30 , b09 = a21 * a32 - a22 * a31 , b10 = a21 * a33 - a23 * a31 , b11 = a22 * a33 - a23 * a32 , det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06 ;\nreturn mat4 ( a11 * b11 - a12 * b10 + a13 * b09 , a02 * b10 - a01 * b11 - a03 * b09 , a31 * b05 - a32 * b04 + a33 * b03 , a22 * b04 - a21 * b05 - a23 * b03 , a12 * b08 - a10 * b11 - a13 * b07 , a00 * b11 - a02 * b08 + a03 * b07 , a32 * b02 - a30 * b05 - a33 * b01 , a20 * b05 - a22 * b02 + a23 * b01 , a10 * b10 - a11 * b08 + a13 * b06 , a01 * b08 - a00 * b10 - a03 * b06 , a30 * b04 - a31 * b02 + a33 * b00 , a21 * b02 - a20 * b04 - a23 * b00 , a11 * b07 - a10 * b09 - a12 * b06 , a00 * b09 - a01 * b07 + a02 * b06 , a31 * b01 - a30 * b03 - a32 * b00 , a20 * b03 - a21 * b01 + a22 * b00 ) / det ; }\n\n"],[9,"INVERSE_MAT",["mat"],"inverseMat(mat)"],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[2,"TRANSFORM_INCLUDED",36],[0,"\n\n"],[7,"TRANSFORM_INCLUDED"],[0,"\n\n"],[6],[0,"\n\n"],[2,"ATTRIBUTES_INCLUDED",42],[0,"\n\n"],[7,"ATTRIBUTES_INCLUDED"],[0,"\n\n"],[6],[0,"\n\n"],[2,"SKIN_INCLUDED",58],[0,"\n\n"],[7,"SKIN_INCLUDED"],[0,"\n\n"],[1,"RENDERER_HAS_SKIN",56],[0,"\n\n"],[1,"RENDERER_USE_JOINT_TEXTURE",52],[0,"\n\n"],[5,54],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[2,"BLENDSHAPE_INCLUDED",86],[0,"\n\n"],[7,"BLENDSHAPE_INCLUDED"],[0,"\n\n"],[1,"RENDERER_HAS_BLENDSHAPE",84],[0,"\n\n"],[1,"RENDERER_BLENDSHAPE_USE_TEXTURE",68],[0,"\n\n"],[5,82],[0,"\n\n"],[4,{"t":"and","l":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_NORMAL"},"r":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_TANGENT"}},72],[0,"\n\n"],[5,80],[0,"\n\n"],[4,{"t":"or","l":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_NORMAL"},"r":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_TANGENT"}},76],[0,"\n\n"],[5,78],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\nuniform vec4 material_BaseColor;\nuniform sampler2D material_BaseTexture;\nuniform float material_AlphaCutoff;\nvarying vec2 v_uv;\n\n\n"],[1,"ENGINE_NO_DEPTH_TEXTURE",90],[0,"\nvec4 pack ( float depth ) { const vec4 bitShift = vec4 ( 1.0 , 256.0 , 256.0 * 256.0 , 256.0 * 256.0 * 256.0 ) ;\nconst vec4 bitMask = vec4 ( 1.0 / 256.0 , 1.0 / 256.0 , 1.0 / 256.0 , 0.0 ) ;\nvec4 rgbaDepth = fract ( depth * bitShift ) ;\nrgbaDepth -= rgbaDepth.gbaa * bitMask ;\nreturn rgbaDepth ; }\n\n"],[6],[0,"\nvoid main() { \n"],[4,{"t":"or","l":{"t":"def","m":"MATERIAL_IS_ALPHA_CUTOFF"},"r":{"t":"and","l":{"t":"def","m":"SCENE_ENABLE_TRANSPARENT_SHADOW"},"r":{"t":"def","m":"MATERIAL_IS_TRANSPARENT"}}},106],[0," float alpha = material_BaseColor.a ;\n\n"],[1,"MATERIAL_HAS_BASETEXTURE",96],[0," alpha *= texture2D ( material_BaseTexture , v_uv ).a ; \n"],[6],[0,"\n\n"],[1,"MATERIAL_IS_ALPHA_CUTOFF",100],[0," if ( alpha < material_AlphaCutoff ) { discard ; } \n"],[6],[0,"\n\n"],[4,{"t":"and","l":{"t":"def","m":"SCENE_ENABLE_TRANSPARENT_SHADOW"},"r":{"t":"def","m":"MATERIAL_IS_TRANSPARENT"}},104],[0," float noise = fract ( 52.982919 * fract ( dot ( vec2 ( 0.06711 , 0.00584 ) , gl_FragCoord.xy ) ) ) ;\nif ( alpha <= noise ) { discard ; } \n"],[6],[0," \n"],[6],[0,"\n\n"],[1,"ENGINE_NO_DEPTH_TEXTURE",110],[0," gl_FragColor = pack(gl_FragCoord.z) ; \n"],[5,112],[0," gl_FragColor = vec4 ( 0.0 , 0.0 , 0.0 , 0.0 ) ; \n"],[6],[0," }"]]}]}]} \ No newline at end of file +{"name":"Pipeline/ShadowCaster","platformTarget":0,"subShaders":[{"name":"Default","tags":{},"passes":[{"name":"ShadowCaster","isUsePass":false,"tags":{"pipelineStage":"ShadowCaster"},"renderStates":{"constantMap":{},"variableMap":{"28":"material_ShadowCasterRenderQueue"}},"vertexShaderInstructions":[[0,"\n"],[2,"COMMON_INCLUDED",30],[0,"\n\n"],[7,"COMMON_INCLUDED"],[0,"\n\n"],[8,"PI","3.14159265359"],[0,"\n\n"],[8,"RECIPROCAL_PI","0.31830988618"],[0,"\n\n"],[8,"EPSILON","1e-6"],[0,"\n\n"],[8,"LOG2","1.442695"],[0,"\n\n"],[8,"HALF_MIN","6.103515625e-5"],[0,"\n\n"],[8,"HALF_EPS","4.8828125e-4"],[0,"\n\n"],[9,"saturate",["a"],"clamp ( a , 0.0 , 1.0 )"],[0,"\n\n"],[1,"GRAPHICS_API_WEBGL2",24],[0,"\n\n"],[9,"INVERSE_MAT",["mat"],"inverse ( mat )"],[0,"\n\n"],[5,28],[0,"\nmat2 inverseMat ( mat2 m ) { return mat2 ( m[1][1] , - m[0][1] , - m[1][0] , m[0][0] ) / ( m[0][0] * m[1][1] - m[0][1] * m[1][0] ) ; }\nmat3 inverseMat ( mat3 m ) { float a00 = m[0][0] , a01 = m[0][1] , a02 = m[0][2] ;\nfloat a10 = m[1][0] , a11 = m[1][1] , a12 = m[1][2] ;\nfloat a20 = m[2][0] , a21 = m[2][1] , a22 = m[2][2] ;\nfloat b01 = a22 * a11 - a12 * a21 ;\nfloat b11 = - a22 * a10 + a12 * a20 ;\nfloat b21 = a21 * a10 - a11 * a20 ;\nfloat det = a00 * b01 + a01 * b11 + a02 * b21 ;\nreturn mat3 ( b01 , ( - a22 * a01 + a02 * a21 ) , ( a12 * a01 - a02 * a11 ) , b11 , ( a22 * a00 - a02 * a20 ) , ( - a12 * a00 + a02 * a10 ) , b21 , ( - a21 * a00 + a01 * a20 ) , ( a11 * a00 - a01 * a10 ) ) / det ; }\nmat4 inverseMat ( mat4 m ) { float a00 = m[0][0] , a01 = m[0][1] , a02 = m[0][2] , a03 = m[0][3] , a10 = m[1][0] , a11 = m[1][1] , a12 = m[1][2] , a13 = m[1][3] , a20 = m[2][0] , a21 = m[2][1] , a22 = m[2][2] , a23 = m[2][3] , a30 = m[3][0] , a31 = m[3][1] , a32 = m[3][2] , a33 = m[3][3] , b00 = a00 * a11 - a01 * a10 , b01 = a00 * a12 - a02 * a10 , b02 = a00 * a13 - a03 * a10 , b03 = a01 * a12 - a02 * a11 , b04 = a01 * a13 - a03 * a11 , b05 = a02 * a13 - a03 * a12 , b06 = a20 * a31 - a21 * a30 , b07 = a20 * a32 - a22 * a30 , b08 = a20 * a33 - a23 * a30 , b09 = a21 * a32 - a22 * a31 , b10 = a21 * a33 - a23 * a31 , b11 = a22 * a33 - a23 * a32 , det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06 ;\nreturn mat4 ( a11 * b11 - a12 * b10 + a13 * b09 , a02 * b10 - a01 * b11 - a03 * b09 , a31 * b05 - a32 * b04 + a33 * b03 , a22 * b04 - a21 * b05 - a23 * b03 , a12 * b08 - a10 * b11 - a13 * b07 , a00 * b11 - a02 * b08 + a03 * b07 , a32 * b02 - a30 * b05 - a33 * b01 , a20 * b05 - a22 * b02 + a23 * b01 , a10 * b10 - a11 * b08 + a13 * b06 , a01 * b08 - a00 * b10 - a03 * b06 , a30 * b04 - a31 * b02 + a33 * b00 , a21 * b02 - a20 * b04 - a23 * b00 , a11 * b07 - a10 * b09 - a12 * b06 , a00 * b09 - a01 * b07 + a02 * b06 , a31 * b01 - a30 * b03 - a32 * b00 , a20 * b03 - a21 * b01 + a22 * b00 ) / det ; }\n\n"],[9,"INVERSE_MAT",["mat"],"inverseMat(mat)"],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[2,"TRANSFORM_INCLUDED",36],[0,"\n\n"],[7,"TRANSFORM_INCLUDED"],[0,"\nuniform mat4 camera_VPMat;\nuniform mat4 renderer_ModelMat;\nuniform mat4 renderer_NormalMat;\n\n"],[6],[0,"\n\n"],[2,"ATTRIBUTES_INCLUDED",94],[0,"\n\n"],[7,"ATTRIBUTES_INCLUDED"],[0,"\nattribute vec3 POSITION;\n\n"],[1,"RENDERER_HAS_BLENDSHAPE",68],[0,"\n"],[2,"RENDERER_BLENDSHAPE_USE_TEXTURE",66],[0,"attribute vec3 POSITION_BS0;\nattribute vec3 POSITION_BS1;\n\n"],[4,{"t":"and","l":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_NORMAL"},"r":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_TANGENT"}},48],[0,"attribute vec3 NORMAL_BS0;\nattribute vec3 NORMAL_BS1;\nattribute vec3 TANGENT_BS0;\nattribute vec3 TANGENT_BS1;\n\n"],[5,64],[0,"\n"],[4,{"t":"or","l":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_NORMAL"},"r":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_TANGENT"}},60],[0,"attribute vec3 POSITION_BS2;\nattribute vec3 POSITION_BS3;\n\n"],[1,"RENDERER_BLENDSHAPE_HAS_NORMAL",54],[0,"attribute vec3 NORMAL_BS0;\nattribute vec3 NORMAL_BS1;\nattribute vec3 NORMAL_BS2;\nattribute vec3 NORMAL_BS3;\n\n"],[6],[0,"\n"],[1,"RENDERER_BLENDSHAPE_HAS_TANGENT",58],[0,"attribute vec3 TANGENT_BS0;\nattribute vec3 TANGENT_BS1;\nattribute vec3 TANGENT_BS2;\nattribute vec3 TANGENT_BS3;\n\n"],[6],[0,"\n"],[5,62],[0,"attribute vec3 POSITION_BS2;\nattribute vec3 POSITION_BS3;\nattribute vec3 POSITION_BS4;\nattribute vec3 POSITION_BS5;\nattribute vec3 POSITION_BS6;\nattribute vec3 POSITION_BS7;\n\n"],[6],[0,"\n"],[6],[0,"\n"],[6],[0,"\n"],[6],[0,"\n"],[1,"RENDERER_HAS_UV",72],[0,"attribute vec2 TEXCOORD_0;\n\n"],[6],[0,"\n"],[1,"RENDERER_HAS_UV1",76],[0,"\n"],[6],[0,"\n"],[1,"RENDERER_HAS_SKIN",80],[0,"attribute vec4 JOINTS_0;\nattribute vec4 WEIGHTS_0;\n\n"],[6],[0,"\n"],[1,"RENDERER_ENABLE_VERTEXCOLOR",84],[0,"\n"],[6],[0,"\n"],[1,"RENDERER_HAS_NORMAL",88],[0,"attribute vec3 NORMAL;\n\n"],[6],[0,"\n"],[1,"RENDERER_HAS_TANGENT",92],[0,"attribute vec4 TANGENT;\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[2,"SKIN_INCLUDED",116],[0,"\n\n"],[7,"SKIN_INCLUDED"],[0,"\n\n"],[1,"RENDERER_HAS_SKIN",114],[0,"\n\n"],[1,"RENDERER_USE_JOINT_TEXTURE",104],[0,"\nuniform sampler2D renderer_JointSampler;\nuniform float renderer_JointCount;\nmat4 getJointMatrix ( sampler2D smp, float index ) { float base = index / renderer_JointCount ;\nfloat hf = 0.5 / renderer_JointCount ;\nfloat v = base + hf ;\nvec4 m0 = texture2D ( smp , vec2 ( 0.125 , v ) ) ;\nvec4 m1 = texture2D ( smp , vec2 ( 0.375 , v ) ) ;\nvec4 m2 = texture2D ( smp , vec2 ( 0.625 , v ) ) ;\nvec4 m3 = texture2D ( smp , vec2 ( 0.875 , v ) ) ;\nreturn mat4 ( m0 , m1 , m2 , m3 ) ; }\n\n"],[5,106],[0,"\nuniform mat4 renderer_JointMatrix [ RENDERER_JOINTS_NUM ];\n\n"],[6],[0,"\nmat4 getSkinMatrix ( ) { \n"],[1,"RENDERER_USE_JOINT_TEXTURE",110],[0," mat4 skinMatrix = WEIGHTS_0.x * getJointMatrix(renderer_JointSampler, JOINTS_0.x) + WEIGHTS_0.y * getJointMatrix(renderer_JointSampler, JOINTS_0.y) + WEIGHTS_0.z * getJointMatrix(renderer_JointSampler, JOINTS_0.z) + WEIGHTS_0.w * getJointMatrix(renderer_JointSampler, JOINTS_0.w) ; \n"],[5,112],[0," mat4 skinMatrix = WEIGHTS_0.x * renderer_JointMatrix[int ( JOINTS_0.x )] + WEIGHTS_0.y * renderer_JointMatrix[int ( JOINTS_0.y )] + WEIGHTS_0.z * renderer_JointMatrix[int ( JOINTS_0.z )] + WEIGHTS_0.w * renderer_JointMatrix[int ( JOINTS_0.w )] ; \n"],[6],[0,"\nreturn skinMatrix ; }\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[2,"BLENDSHAPE_INCLUDED",194],[0,"\n\n"],[7,"BLENDSHAPE_INCLUDED"],[0,"\n\n"],[1,"RENDERER_HAS_BLENDSHAPE",192],[0,"\n\n"],[1,"RENDERER_BLENDSHAPE_USE_TEXTURE",126],[0,"\nuniform mediump sampler2DArray renderer_BlendShapeTexture;\nuniform ivec3 renderer_BlendShapeTextureInfo;\nuniform float renderer_BlendShapeWeights [ RENDERER_BLENDSHAPE_COUNT ];\nvec3 getBlendShapeVertexElement ( int blendShapeIndex, int vertexElementIndex ) { int y = vertexElementIndex / renderer_BlendShapeTextureInfo.y ;\nint x = vertexElementIndex - y * renderer_BlendShapeTextureInfo.y ;\nivec3 uv = ivec3 ( x , y , blendShapeIndex ) ;\nreturn ( texelFetch ( renderer_BlendShapeTexture , uv , 0 ) ).xyz ; }\n\n"],[5,140],[0,"\n\n"],[4,{"t":"and","l":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_NORMAL"},"r":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_TANGENT"}},130],[0,"\nuniform float renderer_BlendShapeWeights [ 2 ];\n\n"],[5,138],[0,"\n\n"],[4,{"t":"or","l":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_NORMAL"},"r":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_TANGENT"}},134],[0,"\nuniform float renderer_BlendShapeWeights [ 4 ];\n\n"],[5,136],[0,"\nuniform float renderer_BlendShapeWeights [ 8 ];\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\nvoid calculateBlendShape ( inout vec4 position\n"],[1,"RENDERER_HAS_NORMAL",148],[0," , inout vec3 normal \n"],[1,"RENDERER_HAS_TANGENT",146],[0," , inout vec4 tangent \n"],[6],[0," \n"],[6],[0," ) { \n"],[1,"RENDERER_BLENDSHAPE_USE_TEXTURE",160],[0," int vertexOffset = gl_VertexID * renderer_BlendShapeTextureInfo.x ;\nfor ( int i = 0 ; i < RENDERER_BLENDSHAPE_COUNT ; i ++ ) { int vertexElementOffset = vertexOffset ;\nfloat weight = renderer_BlendShapeWeights[i] ;\nif ( weight != 0.0 ) { position.xyz += getBlendShapeVertexElement(i, vertexElementOffset) * weight ;\n\n"],[4,{"t":"and","l":{"t":"def","m":"RENDERER_HAS_NORMAL"},"r":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_NORMAL"}},154],[0," vertexElementOffset += 1 ;\nnormal += getBlendShapeVertexElement(i, vertexElementOffset) * weight ; \n"],[6],[0,"\n\n"],[4,{"t":"and","l":{"t":"def","m":"RENDERER_HAS_TANGENT"},"r":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_TANGENT"}},158],[0," vertexElementOffset += 1 ;\ntangent.xyz += getBlendShapeVertexElement(i, vertexElementOffset) * weight ; \n"],[6],[0," } } \n"],[5,190],[0," position.xyz += POSITION_BS0 * renderer_BlendShapeWeights[0] ;\nposition.xyz += POSITION_BS1 * renderer_BlendShapeWeights[1] ;\n\n"],[4,{"t":"and","l":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_NORMAL"},"r":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_TANGENT"}},172],[0," \n"],[1,"RENDERER_HAS_NORMAL",166],[0," normal += NORMAL_BS0 * renderer_BlendShapeWeights[0] ;\nnormal += NORMAL_BS1 * renderer_BlendShapeWeights[1] ; \n"],[6],[0,"\n\n"],[1,"RENDERER_HAS_TANGENT",170],[0," tangent.xyz += TANGENT_BS0 * renderer_BlendShapeWeights[0] ;\ntangent.xyz += TANGENT_BS1 * renderer_BlendShapeWeights[1] ; \n"],[6],[0," \n"],[5,188],[0," \n"],[4,{"t":"or","l":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_NORMAL"},"r":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_TANGENT"}},184],[0," position.xyz += POSITION_BS2 * renderer_BlendShapeWeights[2] ;\nposition.xyz += POSITION_BS3 * renderer_BlendShapeWeights[3] ;\n\n"],[4,{"t":"and","l":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_NORMAL"},"r":{"t":"def","m":"RENDERER_HAS_NORMAL"}},178],[0," normal += NORMAL_BS0 * renderer_BlendShapeWeights[0] ;\nnormal += NORMAL_BS1 * renderer_BlendShapeWeights[1] ;\nnormal += NORMAL_BS2 * renderer_BlendShapeWeights[2] ;\nnormal += NORMAL_BS3 * renderer_BlendShapeWeights[3] ; \n"],[6],[0,"\n\n"],[4,{"t":"and","l":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_TANGENT"},"r":{"t":"def","m":"RENDERER_HAS_TANGENT"}},182],[0," tangent.xyz += TANGENT_BS0 * renderer_BlendShapeWeights[0] ;\ntangent.xyz += TANGENT_BS1 * renderer_BlendShapeWeights[1] ;\ntangent.xyz += TANGENT_BS2 * renderer_BlendShapeWeights[2] ;\ntangent.xyz += TANGENT_BS3 * renderer_BlendShapeWeights[3] ; \n"],[6],[0," \n"],[5,186],[0," position.xyz += POSITION_BS2 * renderer_BlendShapeWeights[2] ;\nposition.xyz += POSITION_BS3 * renderer_BlendShapeWeights[3] ;\nposition.xyz += POSITION_BS4 * renderer_BlendShapeWeights[4] ;\nposition.xyz += POSITION_BS5 * renderer_BlendShapeWeights[5] ;\nposition.xyz += POSITION_BS6 * renderer_BlendShapeWeights[6] ;\nposition.xyz += POSITION_BS7 * renderer_BlendShapeWeights[7] ; \n"],[6],[0," \n"],[6],[0," \n"],[6],[0," }\n\n"],[6],[0,"\n\n"],[6],[0,"\nuniform vec2 scene_ShadowBias;\nuniform vec3 scene_LightDirection;\nvarying vec2 v_uv;\n\nvec3 applyShadowBias ( vec3 positionWS ) { positionWS -= scene_LightDirection * scene_ShadowBias.x ;\nreturn positionWS ; }\nvec3 applyShadowNormalBias ( vec3 positionWS, vec3 normalWS ) { float invNdotL = 1.0 - clamp ( dot ( - scene_LightDirection , normalWS ) , 0.0 , 1.0 ) ;\nfloat scale = invNdotL * scene_ShadowBias.y ;\npositionWS += normalWS * vec3 ( scale ) ;\nreturn positionWS ; }\nvoid main() { \nvec4 position = vec4 ( POSITION , 1.0 ) ;\n\n"],[1,"RENDERER_HAS_NORMAL",202],[0," vec3 normal = vec3 ( NORMAL ) ;\n\n"],[1,"RENDERER_HAS_TANGENT",200],[0," vec4 tangent = vec4 ( TANGENT ) ; \n"],[6],[0," \n"],[6],[0,"\n\n"],[1,"RENDERER_HAS_BLENDSHAPE",214],[0," calculateBlendShape(position\n"],[1,"RENDERER_HAS_NORMAL",212],[0," , normal \n"],[1,"RENDERER_HAS_TANGENT",210],[0," , tangent \n"],[6],[0," \n"],[6],[0,") ; \n"],[6],[0,"\n\n"],[1,"RENDERER_HAS_SKIN",222],[0," mat4 skinMatrix = getSkinMatrix() ;\nposition = skinMatrix * position ;\n\n"],[1,"RENDERER_HAS_NORMAL",220],[0," mat3 skinNormalMatrix = INVERSE_MAT(mat3 ( skinMatrix )) ;\nnormal = normal * skinNormalMatrix ; \n"],[6],[0," \n"],[6],[0,"\n\n"],[1,"RENDERER_HAS_UV",226],[0," v_uv = TEXCOORD_0 ; \n"],[5,228],[0," v_uv = vec2 ( 0.0 , 0.0 ) ; \n"],[6],[0,"\nvec4 positionWS = renderer_ModelMat * position ;\npositionWS.xyz = applyShadowBias(positionWS.xyz) ;\n\n"],[1,"RENDERER_HAS_NORMAL",232],[0," vec3 normalWS = normalize ( mat3 ( renderer_NormalMat ) * normal ) ;\npositionWS.xyz = applyShadowNormalBias(positionWS.xyz, normalWS) ; \n"],[6],[0,"\nvec4 positionCS = camera_VPMat * positionWS ;\npositionCS.z = max ( positionCS.z , - 1.0 ) ;\ngl_Position = positionCS ;\n }\n\n"],[1,"ENGINE_NO_DEPTH_TEXTURE",236],[0,"\n\n"],[6]],"fragmentShaderInstructions":[[0,"\n"],[2,"COMMON_INCLUDED",30],[0,"\n\n"],[7,"COMMON_INCLUDED"],[0,"\n\n"],[8,"PI","3.14159265359"],[0,"\n\n"],[8,"RECIPROCAL_PI","0.31830988618"],[0,"\n\n"],[8,"EPSILON","1e-6"],[0,"\n\n"],[8,"LOG2","1.442695"],[0,"\n\n"],[8,"HALF_MIN","6.103515625e-5"],[0,"\n\n"],[8,"HALF_EPS","4.8828125e-4"],[0,"\n\n"],[9,"saturate",["a"],"clamp ( a , 0.0 , 1.0 )"],[0,"\n\n"],[1,"GRAPHICS_API_WEBGL2",24],[0,"\n\n"],[9,"INVERSE_MAT",["mat"],"inverse ( mat )"],[0,"\n\n"],[5,28],[0,"\nmat2 inverseMat ( mat2 m ) { return mat2 ( m[1][1] , - m[0][1] , - m[1][0] , m[0][0] ) / ( m[0][0] * m[1][1] - m[0][1] * m[1][0] ) ; }\nmat3 inverseMat ( mat3 m ) { float a00 = m[0][0] , a01 = m[0][1] , a02 = m[0][2] ;\nfloat a10 = m[1][0] , a11 = m[1][1] , a12 = m[1][2] ;\nfloat a20 = m[2][0] , a21 = m[2][1] , a22 = m[2][2] ;\nfloat b01 = a22 * a11 - a12 * a21 ;\nfloat b11 = - a22 * a10 + a12 * a20 ;\nfloat b21 = a21 * a10 - a11 * a20 ;\nfloat det = a00 * b01 + a01 * b11 + a02 * b21 ;\nreturn mat3 ( b01 , ( - a22 * a01 + a02 * a21 ) , ( a12 * a01 - a02 * a11 ) , b11 , ( a22 * a00 - a02 * a20 ) , ( - a12 * a00 + a02 * a10 ) , b21 , ( - a21 * a00 + a01 * a20 ) , ( a11 * a00 - a01 * a10 ) ) / det ; }\nmat4 inverseMat ( mat4 m ) { float a00 = m[0][0] , a01 = m[0][1] , a02 = m[0][2] , a03 = m[0][3] , a10 = m[1][0] , a11 = m[1][1] , a12 = m[1][2] , a13 = m[1][3] , a20 = m[2][0] , a21 = m[2][1] , a22 = m[2][2] , a23 = m[2][3] , a30 = m[3][0] , a31 = m[3][1] , a32 = m[3][2] , a33 = m[3][3] , b00 = a00 * a11 - a01 * a10 , b01 = a00 * a12 - a02 * a10 , b02 = a00 * a13 - a03 * a10 , b03 = a01 * a12 - a02 * a11 , b04 = a01 * a13 - a03 * a11 , b05 = a02 * a13 - a03 * a12 , b06 = a20 * a31 - a21 * a30 , b07 = a20 * a32 - a22 * a30 , b08 = a20 * a33 - a23 * a30 , b09 = a21 * a32 - a22 * a31 , b10 = a21 * a33 - a23 * a31 , b11 = a22 * a33 - a23 * a32 , det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06 ;\nreturn mat4 ( a11 * b11 - a12 * b10 + a13 * b09 , a02 * b10 - a01 * b11 - a03 * b09 , a31 * b05 - a32 * b04 + a33 * b03 , a22 * b04 - a21 * b05 - a23 * b03 , a12 * b08 - a10 * b11 - a13 * b07 , a00 * b11 - a02 * b08 + a03 * b07 , a32 * b02 - a30 * b05 - a33 * b01 , a20 * b05 - a22 * b02 + a23 * b01 , a10 * b10 - a11 * b08 + a13 * b06 , a01 * b08 - a00 * b10 - a03 * b06 , a30 * b04 - a31 * b02 + a33 * b00 , a21 * b02 - a20 * b04 - a23 * b00 , a11 * b07 - a10 * b09 - a12 * b06 , a00 * b09 - a01 * b07 + a02 * b06 , a31 * b01 - a30 * b03 - a32 * b00 , a20 * b03 - a21 * b01 + a22 * b00 ) / det ; }\n\n"],[9,"INVERSE_MAT",["mat"],"inverseMat(mat)"],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[2,"TRANSFORM_INCLUDED",36],[0,"\n\n"],[7,"TRANSFORM_INCLUDED"],[0,"\n\n"],[6],[0,"\n\n"],[2,"ATTRIBUTES_INCLUDED",42],[0,"\n\n"],[7,"ATTRIBUTES_INCLUDED"],[0,"\n\n"],[6],[0,"\n\n"],[2,"SKIN_INCLUDED",58],[0,"\n\n"],[7,"SKIN_INCLUDED"],[0,"\n\n"],[1,"RENDERER_HAS_SKIN",56],[0,"\n\n"],[1,"RENDERER_USE_JOINT_TEXTURE",52],[0,"\n\n"],[5,54],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[2,"BLENDSHAPE_INCLUDED",86],[0,"\n\n"],[7,"BLENDSHAPE_INCLUDED"],[0,"\n\n"],[1,"RENDERER_HAS_BLENDSHAPE",84],[0,"\n\n"],[1,"RENDERER_BLENDSHAPE_USE_TEXTURE",68],[0,"\n\n"],[5,82],[0,"\n\n"],[4,{"t":"and","l":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_NORMAL"},"r":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_TANGENT"}},72],[0,"\n\n"],[5,80],[0,"\n\n"],[4,{"t":"or","l":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_NORMAL"},"r":{"t":"def","m":"RENDERER_BLENDSHAPE_HAS_TANGENT"}},76],[0,"\n\n"],[5,78],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\n\n"],[6],[0,"\nuniform vec4 material_BaseColor;\nuniform sampler2D material_BaseTexture;\nuniform float material_AlphaCutoff;\nvarying vec2 v_uv;\n\n\n"],[1,"ENGINE_NO_DEPTH_TEXTURE",90],[0,"\nvec4 pack ( float depth ) { const vec4 bitShift = vec4 ( 1.0 , 256.0 , 256.0 * 256.0 , 256.0 * 256.0 * 256.0 ) ;\nconst vec4 bitMask = vec4 ( 1.0 / 256.0 , 1.0 / 256.0 , 1.0 / 256.0 , 0.0 ) ;\nvec4 rgbaDepth = fract ( depth * bitShift ) ;\nrgbaDepth -= rgbaDepth.gbaa * bitMask ;\nreturn rgbaDepth ; }\n\n"],[6],[0,"\nvoid main() { \n"],[4,{"t":"or","l":{"t":"def","m":"MATERIAL_IS_ALPHA_CUTOFF"},"r":{"t":"and","l":{"t":"def","m":"SCENE_ENABLE_TRANSPARENT_SHADOW"},"r":{"t":"def","m":"MATERIAL_IS_TRANSPARENT"}}},106],[0," float alpha = material_BaseColor.a ;\n\n"],[1,"MATERIAL_HAS_BASETEXTURE",96],[0," alpha *= texture2D ( material_BaseTexture , v_uv ).a ; \n"],[6],[0,"\n\n"],[1,"MATERIAL_IS_ALPHA_CUTOFF",100],[0," if ( alpha < material_AlphaCutoff ) { discard ; } \n"],[6],[0,"\n\n"],[4,{"t":"and","l":{"t":"def","m":"SCENE_ENABLE_TRANSPARENT_SHADOW"},"r":{"t":"def","m":"MATERIAL_IS_TRANSPARENT"}},104],[0," float noise = fract ( 52.982919 * fract ( dot ( vec2 ( 0.06711 , 0.00584 ) , gl_FragCoord.xy ) ) ) ;\nif ( alpha <= noise ) { discard ; } \n"],[6],[0," \n"],[6],[0,"\n\n"],[1,"ENGINE_NO_DEPTH_TEXTURE",110],[0," gl_FragColor = pack(gl_FragCoord.z) ; \n"],[5,112],[0," gl_FragColor = vec4 ( 0.0 , 0.0 , 0.0 , 0.0 ) ; \n"],[6],[0," }"]]}]}]} \ No newline at end of file diff --git a/packages/shader/src/ShaderLibrary/Common/Transform.glsl b/packages/shader/src/ShaderLibrary/Common/Transform.glsl index 245e7b0708..1c829ed32b 100644 --- a/packages/shader/src/ShaderLibrary/Common/Transform.glsl +++ b/packages/shader/src/ShaderLibrary/Common/Transform.glsl @@ -1,16 +1,16 @@ #ifndef TRANSFORM_INCLUDED #define TRANSFORM_INCLUDED -mat4 renderer_LocalMat; -mat4 renderer_ModelMat; mat4 camera_ViewMat; mat4 camera_ProjMat; mat4 camera_VPMat; -mat4 renderer_MVMat; -mat4 renderer_MVPMat; -mat4 renderer_NormalMat; vec3 camera_Position; vec3 camera_Forward; -#endif \ No newline at end of file +mat4 renderer_ModelMat; +mat4 renderer_MVMat; +mat4 renderer_MVPMat; +mat4 renderer_NormalMat; + +#endif diff --git a/packages/shader/src/ShaderLibrary/PBR/VertexPBR.glsl b/packages/shader/src/ShaderLibrary/PBR/VertexPBR.glsl index b2904e41c3..9a5b94cb60 100644 --- a/packages/shader/src/ShaderLibrary/PBR/VertexPBR.glsl +++ b/packages/shader/src/ShaderLibrary/PBR/VertexPBR.glsl @@ -73,10 +73,11 @@ VertexInputs getVertexInputs(Attributes attributes){ // TBN world space #if defined(RENDERER_HAS_NORMAL) && !defined(MATERIAL_OMIT_NORMAL) - inputs.normalWS = normalize( mat3(renderer_NormalMat) * normal ); + mat3 normalMat = mat3(renderer_NormalMat); + inputs.normalWS = normalize( normalMat * normal ); #ifdef NEED_VERTEX_TANGENT - vec3 tangentWS = normalize( mat3(renderer_NormalMat) * tangent.xyz ); + vec3 tangentWS = normalize( normalMat * tangent.xyz ); vec3 bitangentWS = cross( inputs.normalWS, tangentWS ) * tangent.w; inputs.tangentWS = tangentWS; diff --git a/packages/ui/src/component/UIBatchSorter.ts b/packages/ui/src/component/UIBatchSorter.ts new file mode 100644 index 0000000000..0a7897a41b --- /dev/null +++ b/packages/ui/src/component/UIBatchSorter.ts @@ -0,0 +1,149 @@ +import { BoundingBox, Matrix, RenderElement, Utils } from "@galacean/engine"; + +/** + * @internal + * Visual-layering driven UI batching: solve visual correctness first, batching falls out for free. + * + * Think of it as stacking elements onto numbered shelves (depths): + * - Non-overlapping elements share shelf 0 — free to cluster regardless of material. + * - Overlapping + batch-compatible — share the same shelf, still cluster. + * - Overlapping + batch-incompatible — bumped one shelf higher (drawn on top). + * + * `depth` is a global tag, not a spatial group: distant elements at the same visual layer + * share the same depth and get clustered together. Once depth is assigned, sort by + * (depth, material, texture, hierarchyIndex) — visual order is locked, batching is the + * by-product of materials clustering within each depth band. + * + * Overlap detection is accelerated by a 10×10 spatial grid (bucket size = canvas longest + * edge / 10), pruning O(N²) checks to ~O(N). + */ +export class UIBatchSorter { + // Spatial-hash is fastest when cell size ≈ typical element size (one element per cell). + // UI elements typically span ~10% of the canvas → 10×10 grid. + private static readonly _gridDim = 10; + + private static readonly _entries = new Array(); + private static readonly _grid: GridCell[][] = []; + // Interleaved (x, y) cell coords touched in the previous frame + private static readonly _dirtyCells = new Array(); + private static readonly _localBoundsPool = new Array(); + private static readonly _worldToLocal = new Matrix(); + + /** + * Reorders `elements` in place for optimal batching. + * @param elements - in hierarchy order (depth-first traversal); mutated in place + * @param canvasWorldMatrix - reduces world bounds to canvas-local for precise overlap + * @param canvasLongestEdge - canvas-local longest edge in pixels + */ + static sort(elements: RenderElement[], canvasWorldMatrix: Matrix, canvasLongestEdge: number): void { + const count = elements.length; + if (count <= 1) return; + + const gridDim = this._gridDim; + const gridSize = canvasLongestEdge / gridDim; + const entries = this._entries; + const grid = this._grid; + const dirtyCells = this._dirtyCells; + const localBoundsPool = this._localBoundsPool; + const worldToLocal = this._worldToLocal; + Matrix.invert(canvasWorldMatrix, worldToLocal); + while (entries.length < count) entries.push(new SortEntry()); + + // Allocate grid once, reuse forever (each cell must be a real [], not a sparse hole) + if (grid.length < gridDim) { + while (grid.length < gridDim) grid.push([]); + for (let i = 0; i < gridDim; i++) { + const row = grid[i]; + while (row.length < gridDim) row.push([]); + } + } + + // Clear only previously-used cells (no full sweep) + for (let k = 0, n = dirtyCells.length; k < n; k += 2) { + grid[dirtyCells[k]][dirtyCells[k + 1]].length = 0; + } + dirtyCells.length = 0; + + for (let i = 0; i < count; i++) { + const element = elements[i]; + const localBounds = (localBoundsPool[i] ||= new BoundingBox()); + BoundingBox.transform(element.component.bounds, worldToLocal, localBounds); + const materialId = element.material.instanceId; + const textureId = element.texture ? element.texture.instanceId : 0; + + // Clamp to grid range; out-of-bounds elements collapse to edge cells + const minCellX = Math.max(0, Math.floor(localBounds.min.x / gridSize)); + const maxCellX = Math.min(gridDim - 1, Math.floor(localBounds.max.x / gridSize)); + const minCellY = Math.max(0, Math.floor(localBounds.min.y / gridSize)); + const maxCellY = Math.min(gridDim - 1, Math.floor(localBounds.max.y / gridSize)); + + // Find the deepest overlapping prior, and whether that shelf has any incompatible occupant + let maxDepth = -1; + let maxDepthIncompatible = false; + for (let cellY = minCellY; cellY <= maxCellY; cellY++) { + for (let cellX = minCellX; cellX <= maxCellX; cellX++) { + const cell = grid[cellX][cellY]; + for (let j = 0, m = cell.length; j < m; j++) { + const other = cell[j]; + if (!UIBatchSorter._rectOverlap(localBounds, other.bounds)) continue; + const otherDepth = other.depth; + const otherIncompatible = other.materialId !== materialId || other.textureId !== textureId; + if (otherDepth > maxDepth) { + maxDepth = otherDepth; + maxDepthIncompatible = otherIncompatible; + } else if (otherDepth === maxDepth && otherIncompatible) { + maxDepthIncompatible = true; + } + } + } + } + + const entry = entries[i]; + entry.element = element; + entry.hierarchyIndex = i; + // Share the deepest shelf if compatible; bump up one if blocked by an incompatible occupant + entry.depth = maxDepth < 0 ? 0 : maxDepth + (maxDepthIncompatible ? 1 : 0); + entry.materialId = materialId; + entry.textureId = textureId; + entry.bounds = localBounds; + + for (let cellY = minCellY; cellY <= maxCellY; cellY++) { + for (let cellX = minCellX; cellX <= maxCellX; cellX++) { + const cell = grid[cellX][cellY]; + if (cell.length === 0) dirtyCells.push(cellX, cellY); + cell.push(entry); + } + } + } + + // @ts-ignore — Utils._quickSort is @internal + Utils._quickSort(entries, 0, count, UIBatchSorter._compareEntries); + for (let i = 0; i < count; i++) elements[i] = entries[i].element; + } + + private static _rectOverlap(a: BoundingBox, b: BoundingBox): boolean { + return a.min.x < b.max.x && a.max.x > b.min.x && a.min.y < b.max.y && a.max.y > b.min.y; + } + + private static _compareEntries(a: SortEntry, b: SortEntry): number { + return ( + a.depth - b.depth || + a.materialId - b.materialId || + a.textureId - b.textureId || + a.hierarchyIndex - b.hierarchyIndex + ); + } +} + +type GridCell = SortEntry[]; + +// materialId/textureId/bounds are flattened from RenderElement to avoid +// multi-hop property access in the hot inner loop and the sort comparator. +class SortEntry { + element: RenderElement; + hierarchyIndex = 0; + depth = 0; + materialId = 0; + textureId = 0; + bounds: BoundingBox; +} diff --git a/packages/ui/src/component/UICanvas.ts b/packages/ui/src/component/UICanvas.ts index 9e5b33c405..b9c2cb8834 100644 --- a/packages/ui/src/component/UICanvas.ts +++ b/packages/ui/src/component/UICanvas.ts @@ -11,15 +11,16 @@ import { MathUtil, Matrix, Ray, + RenderElement, Vector2, Vector3, assignmentClone, deepClone, dependentComponents, - ignoreClone, - CloneUtils + ignoreClone } from "@galacean/engine"; import { Utils } from "../Utils"; +import { UIBatchSorter } from "./UIBatchSorter"; import { CanvasRenderMode } from "../enums/CanvasRenderMode"; import { ResolutionAdaptationMode } from "../enums/ResolutionAdaptationMode"; import { UIHitResult } from "../input/UIHitResult"; @@ -62,7 +63,10 @@ export class UICanvas extends Component implements IElement { _isRootCanvas: boolean = false; /** @internal */ @ignoreClone - _renderElement: any; + _renderElements: RenderElement[] = []; + /** @internal */ + @ignoreClone + _batchedRenderElements: RenderElement[] = []; /** @internal */ @ignoreClone _sortDistance: number = 0; @@ -307,11 +311,10 @@ export class UICanvas extends Component implements IElement { const { engine, _realRenderMode: mode } = this; const { enableFrustumCulling, cullingMask, _frustum: frustum } = context.camera; const { frameCount } = engine.time; - // @ts-ignore - const renderElement = (this._renderElement = engine._renderElementPool.get()); + const renderElements = this._renderElements; + renderElements.length = 0; const virtualCamera = context.virtualCamera; this._updateSortDistance(virtualCamera.isOrthographic, virtualCamera.position, virtualCamera.forward); - renderElement.set(this.sortOrder, this._sortDistance); const { width, height } = engine.canvas; const renderers = this._getRenderers(); for (let i = 0, n = renderers.length; i < n; i++) { @@ -342,6 +345,15 @@ export class UICanvas extends Component implements IElement { renderer._prepareRender(context); renderer._renderFrameCount = frameCount; } + + const batchedRenderElements = this._batchedRenderElements; + batchedRenderElements.length = 0; + const { x: refX, y: refY } = this._referenceResolution; + UIBatchSorter.sort(renderElements, this.entity.transform.worldMatrix, Math.max(refX, refY)); + (engine as any)._batcherManager.batch(renderElements, batchedRenderElements); + for (let i = 0, n = batchedRenderElements.length; i < n; i++) { + batchedRenderElements[i].subDistancePriority = i; + } } /** @@ -384,6 +396,12 @@ export class UICanvas extends Component implements IElement { Utils.cleanRootCanvas(this); } + // @ts-ignore + override _onDisable(): void { + this._renderElements.length = 0; + this._batchedRenderElements.length = 0; + } + /** * @internal */ diff --git a/packages/ui/src/component/UIRenderer.ts b/packages/ui/src/component/UIRenderer.ts index 59a2fc434c..82af6480bd 100644 --- a/packages/ui/src/component/UIRenderer.ts +++ b/packages/ui/src/component/UIRenderer.ts @@ -1,5 +1,5 @@ import { - BatchUtils, + VertexMergeBatcher, Color, DependentMode, Entity, @@ -113,19 +113,19 @@ export class UIRenderer extends Renderer implements IGraphics { } // @ts-ignore - override _canBatch(elementA, elementB): boolean { - return BatchUtils.canBatchSprite(elementA, elementB); + override _canBatch(preElement, curElement): boolean { + return VertexMergeBatcher.canBatchSprite(preElement, curElement); } // @ts-ignore - override _batch(elementA, elementB?): void { - BatchUtils.batchFor2D(elementA, elementB); + override _batch(preElement, curElement): void { + VertexMergeBatcher.batch(preElement, curElement); } // @ts-ignore - override _updateTransformShaderData(context, onlyMVP: boolean, batched: boolean): void { + override _updateTransformShaderData(context, onlyMVP: boolean): void { // @ts-ignore - super._updateTransformShaderData(context, onlyMVP, true); + this._updateWorldSpaceTransformShaderData(context, onlyMVP); } // @ts-ignore diff --git a/packages/ui/src/component/advanced/Image.ts b/packages/ui/src/component/advanced/Image.ts index b8ca6ffe55..b364a2e303 100644 --- a/packages/ui/src/component/advanced/Image.ts +++ b/packages/ui/src/component/advanced/Image.ts @@ -4,7 +4,6 @@ import { ISpriteAssembler, ISpriteRenderer, MathUtil, - RenderQueueFlags, RendererUpdateFlags, SimpleSpriteAssembler, SlicedSpriteAssembler, @@ -236,16 +235,14 @@ export class Image extends UIRenderer implements ISpriteRenderer { } this._dirtyUpdateFlag = dirtyUpdateFlag; - // Init sub render element. const { engine } = context.camera; - const subRenderElement = engine._subRenderElementPool.get(); + const renderElement = engine._renderElementPool.get(); const subChunk = this._subChunk; - subRenderElement.set(this, material, subChunk.chunk.primitive, subChunk.subMesh, this.sprite.texture, subChunk); - if (canvas._realRenderMode === CanvasRenderMode.ScreenSpaceOverlay) { - subRenderElement.shaderPasses = material.shader.subShaders[0].passes; - subRenderElement.renderQueueFlags = RenderQueueFlags.All; - } - canvas._renderElement.addSubRenderElement(subRenderElement); + renderElement.set(this, material, subChunk.chunk.primitive, subChunk.subMesh, this.sprite.texture, subChunk); + renderElement.subShader = material.shader.subShaders[0]; + renderElement.priority = canvas.sortOrder; + renderElement.distanceForSort = canvas._sortDistance; + canvas._renderElements.push(renderElement); } @ignoreClone diff --git a/packages/ui/src/component/advanced/Text.ts b/packages/ui/src/component/advanced/Text.ts index 99824a8e3d..b534253a9a 100644 --- a/packages/ui/src/component/advanced/Text.ts +++ b/packages/ui/src/component/advanced/Text.ts @@ -7,7 +7,6 @@ import { FontStyle, ITextRenderer, OverflowMode, - RenderQueueFlags, RendererUpdateFlags, ShaderData, ShaderDataGroup, @@ -350,23 +349,24 @@ export class Text extends UIRenderer implements ITextRenderer { } const engine = context.camera.engine; - const textSubRenderElementPool = engine._textSubRenderElementPool; + const textRenderElementPool = engine._textRenderElementPool; const material = this.getMaterial(); - const renderElement = canvas._renderElement; + const renderElements = canvas._renderElements; + const priority = canvas.sortOrder; + const distanceForSort = canvas._sortDistance; const textChunks = this._textChunks; - const isOverlay = canvas._realRenderMode === CanvasRenderMode.ScreenSpaceOverlay; + const subShader = material.shader.subShaders[0]; for (let i = 0, n = textChunks.length; i < n; ++i) { const { subChunk, texture } = textChunks[i]; - const subRenderElement = textSubRenderElementPool.get(); - subRenderElement.set(this, material, subChunk.chunk.primitive, subChunk.subMesh, texture, subChunk); + const renderElement = textRenderElementPool.get(); + renderElement.set(this, material, subChunk.chunk.primitive, subChunk.subMesh, texture, subChunk); // @ts-ignore - subRenderElement.shaderData ||= new ShaderData(ShaderDataGroup.RenderElement); - subRenderElement.shaderData.setTexture(Text._textTextureProperty, texture); - if (isOverlay) { - subRenderElement.shaderPasses = material.shader.subShaders[0].passes; - subRenderElement.renderQueueFlags = RenderQueueFlags.All; - } - renderElement.addSubRenderElement(subRenderElement); + renderElement.shaderData ||= new ShaderData(ShaderDataGroup.RenderElement); + renderElement.shaderData.setTexture(Text._textTextureProperty, texture); + renderElement.subShader = subShader; + renderElement.priority = priority; + renderElement.distanceForSort = distanceForSort; + renderElements.push(renderElement); } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7bd5d4d336..d052455a06 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -46,13 +46,13 @@ importers: version: 18.19.64 '@types/webxr': specifier: latest - version: 0.5.22 + version: 0.5.24 '@typescript-eslint/eslint-plugin': - specifier: ^6.1.0 - version: 6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1)(typescript@5.6.3) + specifier: ^8.58.1 + version: 8.59.2(@typescript-eslint/parser@8.59.2(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1)(typescript@5.6.3) '@typescript-eslint/parser': - specifier: ^6.1.0 - version: 6.21.0(eslint@8.57.1)(typescript@5.6.3) + specifier: ^8.58.1 + version: 8.59.2(eslint@8.57.1)(typescript@5.6.3) '@vitest/coverage-v8': specifier: 2.1.3 version: 2.1.3(@vitest/browser@2.1.3(@types/node@18.19.64)(@vitest/spy@2.1.3)(typescript@5.6.3)(vite@5.4.11(@types/node@18.19.64)(sass@1.81.0)(terser@5.44.1))(vitest@2.1.3))(vitest@2.1.3(@types/node@18.19.64)(@vitest/browser@2.1.3)(msw@2.6.5(@types/node@18.19.64)(typescript@5.6.3))(sass@1.81.0)(terser@5.44.1)) @@ -66,7 +66,7 @@ importers: specifier: ^13 version: 13.6.9 eslint: - specifier: ^8.44.0 + specifier: ^8.57.1 version: 8.57.1 eslint-config-prettier: specifier: ^8.8.0 @@ -81,8 +81,8 @@ importers: specifier: ^8.0.0 version: 8.0.3 lint-staged: - specifier: ^10.5.3 - version: 10.5.4 + specifier: ^16.4.0 + version: 16.4.0 nyc: specifier: ^15.1.0 version: 15.1.0 @@ -146,6 +146,9 @@ importers: '@galacean/engine-shader-compiler': specifier: workspace:* version: link:../packages/shader-compiler + '@galacean/engine-ui': + specifier: workspace:* + version: link:../packages/ui dat.gui: specifier: ^0.7.9 version: 0.7.9 @@ -187,7 +190,10 @@ importers: version: link:../packages/shader-compiler '@galacean/engine-toolkit': specifier: latest - version: 1.5.3(@galacean/engine-ui@packages+ui)(@galacean/engine@packages+galacean) + version: 1.6.0(@galacean/engine-ui@packages+ui)(@galacean/engine@packages+galacean) + '@galacean/engine-toolkit-stats': + specifier: latest + version: 1.6.0(@galacean/engine@packages+galacean) '@galacean/engine-ui': specifier: workspace:* version: link:../packages/ui @@ -814,10 +820,20 @@ packages: peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + '@eslint-community/eslint-utils@4.9.1': + resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + '@eslint-community/regexpp@4.12.1': resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + '@eslint-community/regexpp@4.12.2': + resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + '@eslint/eslintrc@2.1.4': resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -829,64 +845,64 @@ packages: '@fastify/deepmerge@1.3.0': resolution: {integrity: sha512-J8TOSBq3SoZbDhM9+R/u77hP93gz/rajSA+K2kGyijPpORPWUXHUpTaleoj+92As0S9uPRP7Oi8IqMf0u+ro6A==} - '@galacean/engine-toolkit-auxiliary-lines@1.5.3': - resolution: {integrity: sha512-92PgvXoVHp+5gk9Eril5OFxCILBT+jBaRCvEKiMUntdlfZtPrMstpnHaibgeWgLHoHGmEUG5Uei7kujyY9XTqw==} + '@galacean/engine-toolkit-auxiliary-lines@1.6.0': + resolution: {integrity: sha512-wwQj28bXUGYiv7V9/ZgW8RPL8UULS5nFpBOr1ucqrqSTLMbedPcVXfuShyesFnB4QNRGCKR9pHCKrhLlYhpaeA==} peerDependencies: - '@galacean/engine': ^1.5.0 + '@galacean/engine': '>=1.6.0-0' - '@galacean/engine-toolkit-controls@1.5.3': - resolution: {integrity: sha512-SNTaCLF6rolBzSyKLwS+MUEZLpkksaQnYjhBvAnFpWUd9lR6llL8sdI5/DJZtaK6cyxiw+eA2MMCN75Cxn38OQ==} + '@galacean/engine-toolkit-controls@1.6.0': + resolution: {integrity: sha512-qqbxHStb+SsRjKAOol6m42KYC2Ma0GaiZ8zWOBjq8plCcZQNenX22u01ViAiqh+pbYcLqkslNuE3R20pPi53Eg==} peerDependencies: - '@galacean/engine': ^1.5.0 + '@galacean/engine': '>=1.6.0-0' - '@galacean/engine-toolkit-custom-material@1.5.3': - resolution: {integrity: sha512-Pw/No07qNlf/RNPP9G/8nTmE2t75ge0UmuFT7rcXYrhe3CoBpureN9rEwm1TnFkWbGcothV6cLN3U6wDD/hf8w==} + '@galacean/engine-toolkit-custom-material@1.6.0': + resolution: {integrity: sha512-spUDhH35ZvD1yivJmzRorgIt2RGXXN8IGelqFRQEtt4nsph/0LuqddRrSI6o0NiEjEsWy6IvkzinQU4WXZvIbg==} peerDependencies: - '@galacean/engine': ^1.5.0 + '@galacean/engine': '>=1.6.0-0' - '@galacean/engine-toolkit-framebuffer-picker@1.5.3': - resolution: {integrity: sha512-N4bp+c8Ess9FOnKHvml8OERspOffZTYI5UYQ9LP/0ftDTnYXqgPPQ5Hx55I/nQ6mgDgOqZW6d+wUeH1gZIH9jA==} + '@galacean/engine-toolkit-framebuffer-picker@1.6.0': + resolution: {integrity: sha512-lWaO7o+ehvtHttJdgwcG9Ix0eJFUBOzsO8kFc6RQp4aZ/IP6FS/SqGD2erRCicQeDnoIdMszW7xY2GGc8xrfMg==} peerDependencies: - '@galacean/engine': ^1.5.0 + '@galacean/engine': '>=1.6.0-0' - '@galacean/engine-toolkit-geometry-sketch@1.5.3': - resolution: {integrity: sha512-I2yQr8FSlw82JdaLHqQ8hU8pJ9rgmc2IL75NOWPVarwDwJaJeDA3uSPWNInXlFrh1MlGK1FyCMSka/XtyVotlw==} + '@galacean/engine-toolkit-geometry-sketch@1.6.0': + resolution: {integrity: sha512-wYcjzJ80eO8ekOpCZRW78jUsiE5GKGtmrWWMa6v8p+HNugFu0X9UfyomTtTx3SuImvNb/TpP2O+KZ4ZW4RXmww==} peerDependencies: - '@galacean/engine': ^1.5.0 + '@galacean/engine': '>=1.6.0-0' - '@galacean/engine-toolkit-gizmo@1.5.3': - resolution: {integrity: sha512-TpgtUsfazVaOBbwYy1pKcZsEBK09IYvYA0lI7nSWinAqpxC0LTKsBwhU/icOd9jyowGbT2Dyi4oGYj+FeLYIfw==} + '@galacean/engine-toolkit-gizmo@1.6.0': + resolution: {integrity: sha512-a5y4NACFnBsKweNcFe9VKn9ttxSuFZnNBJCcLNcWED1+Botk1xsW+2xwS3dcGhWf7GHx+nuZ4HCq4MeCLbozNQ==} peerDependencies: - '@galacean/engine': ^1.5.0 - '@galacean/engine-ui': ^1.5.0 + '@galacean/engine': '>=1.6.0-0' + '@galacean/engine-ui': '>=1.6.0-0' - '@galacean/engine-toolkit-lines@1.5.3': - resolution: {integrity: sha512-Skx4KvxxUoJXhIBNdus5HSYnGfXgu8beNzgg9GBiFr7yiGFbFdmWGt/a9df5djP/E7MPGEdNS8gOlB8KpKg9nQ==} + '@galacean/engine-toolkit-lines@1.6.0': + resolution: {integrity: sha512-QowKaRXAQPjvU21Xg+GoRpzbFcuuKrKoOcKjmC/qtFF8NF8GaeBOFhUbGPNt3ztrssDPJ474Soau8ZtqH42P5g==} peerDependencies: - '@galacean/engine': ^1.5.0 + '@galacean/engine': '>=1.6.0-0' - '@galacean/engine-toolkit-navigation-gizmo@1.5.3': - resolution: {integrity: sha512-zE7L00TzjQqE++npzzoj4g1DKlxro9IxRiZtlnwMV+xI5L63DsqT1ISHQf5ZwuctusRI9nGjdkAmKXeHK2hcig==} + '@galacean/engine-toolkit-navigation-gizmo@1.6.0': + resolution: {integrity: sha512-m307kTSWwQCHiCHa/1fIWTGtytc1bLZIFkGrRQCLrj2dGiKDqK6VaC2Jdsnm6i2Exv2FJMmkGkYPrpi6xOwj9Q==} peerDependencies: - '@galacean/engine': ^1.5.0 + '@galacean/engine': '>=1.6.0-0' - '@galacean/engine-toolkit-outline@1.5.3': - resolution: {integrity: sha512-CoLdhb5HjKaDpCxCEoxrWbajbwGIGUARibXI9ZbSu578+9Y662622xgidiifxA3HuUoEq+/YI3SliXhfh20BEw==} + '@galacean/engine-toolkit-outline@1.6.0': + resolution: {integrity: sha512-GrRZGb3B5Np35HlSVX08au9lUIQv30Yn+UPbz5tDongaIe//i7FFDpXnUC53NMfQgnySwxmjTBF8zFQtSQAsug==} peerDependencies: - '@galacean/engine': ^1.5.0 + '@galacean/engine': '>=1.6.0-0' - '@galacean/engine-toolkit-skeleton-viewer@1.5.3': - resolution: {integrity: sha512-mBqEjm4NmDIuzyleR7nt5QjXIBaChQU7do6/yCTz1D7a5YeCK3F+4BoFNPg3PwM1TXymK+LOwixZYD9V6/oILg==} + '@galacean/engine-toolkit-skeleton-viewer@1.6.0': + resolution: {integrity: sha512-kxzt4OHF0y+S3Zr6Bu/qDjzqGn7+rwK6fdewlwIlSOstYjLQ4jS/RgOFFPAvF5E8O9B9wIWkyreFXG2DPJTg9A==} peerDependencies: - '@galacean/engine': ^1.5.0 + '@galacean/engine': '>=1.6.0-0' - '@galacean/engine-toolkit-stats@1.5.3': - resolution: {integrity: sha512-bPGiFy4/zHcJitLHSUgd8xi0EP5ndqfwkR/HsYOvkYea5TD2MPYXI7DMlR8UopwhmHBd7TML0X7A1ppx74g9DA==} + '@galacean/engine-toolkit-stats@1.6.0': + resolution: {integrity: sha512-63LLxTWg15xR000jbtEONnK6lBBMylvl5m+3VqqC7b09YAuMWlm9CuPfaM8dlbctOYT6nmPu9bpQiq3JfdgtWg==} peerDependencies: - '@galacean/engine': ^1.5.0 + '@galacean/engine': '>=1.6.0-0' - '@galacean/engine-toolkit@1.5.3': - resolution: {integrity: sha512-Koefdezvft7DG1IhHDW5BXUoUp2JCQl8WJrBa/tgXR5/T20jXntzV7Ryz3jN5v0HNoOT4IhmYBBwtaxpS6KUHg==} + '@galacean/engine-toolkit@1.6.0': + resolution: {integrity: sha512-XBVMJd5WA73z25nQKF3P9GydYqjGVDWIrHzH7LjkgK5g5Yre2BLVxlRnMZAu5iW95PPt0riWwqcu+8BLm+3Fgw==} '@humanwhocodes/config-array@0.13.0': resolution: {integrity: sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==} @@ -1419,9 +1435,6 @@ packages: '@types/estree@1.0.6': resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} - '@types/json-schema@7.0.15': - resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} - '@types/keyv@3.1.4': resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==} @@ -1446,78 +1459,77 @@ packages: '@types/responselike@1.0.3': resolution: {integrity: sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==} - '@types/semver@7.5.8': - resolution: {integrity: sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==} - '@types/statuses@2.0.5': resolution: {integrity: sha512-jmIUGWrAiwu3dZpxntxieC+1n/5c3mjrImkmOSQ2NC5uP6cYO4aAZDdSmRcI5C1oiTmqlZGHC+/NmJrKogbP5A==} '@types/tough-cookie@4.0.5': resolution: {integrity: sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==} - '@types/webxr@0.5.22': - resolution: {integrity: sha512-Vr6Stjv5jPRqH690f5I5GLjVk8GSsoQSYJ2FVd/3jJF7KaqfwPi3ehfBS96mlQ2kPCwZaX6U0rG2+NGHBKkA/A==} + '@types/webxr@0.5.24': + resolution: {integrity: sha512-h8fgEd/DpoS9CBrjEQXR+dIDraopAEfu4wYVNY2tEPwk60stPWhvZMf4Foo5FakuQ7HFZoa8WceaWFervK2Ovg==} - '@typescript-eslint/eslint-plugin@6.21.0': - resolution: {integrity: sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==} - engines: {node: ^16.0.0 || >=18.0.0} + '@typescript-eslint/eslint-plugin@8.59.2': + resolution: {integrity: sha512-j/bwmkBvHUtPNxzuWe5z6BEk3q54YRyGlBXkSsmfoih7zNrBvl5A9A98anlp/7JbyZcWIJ8KXo/3Tq/DjFLtuQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^6.0.0 || ^6.0.0-alpha - eslint: ^7.0.0 || ^8.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + '@typescript-eslint/parser': ^8.59.2 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/parser@6.21.0': - resolution: {integrity: sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==} - engines: {node: ^16.0.0 || >=18.0.0} + '@typescript-eslint/parser@8.59.2': + resolution: {integrity: sha512-plR3pp6D+SSUn1HM7xvSkx12/DhoHInI2YF35KAcVFNZvlC0gtrWqx7Qq1oH2Ssgi0vlFRCTbP+DZc7B9+TtsQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - eslint: ^7.0.0 || ^8.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/project-service@8.59.2': + resolution: {integrity: sha512-+2hqvEkeyf/0FBor67duF0Ll7Ot8jyKzDQOSrxazF/danillRq2DwR9dLptsXpoZQqxE1UisSmoZewrlPas9Vw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/scope-manager@6.21.0': - resolution: {integrity: sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==} - engines: {node: ^16.0.0 || >=18.0.0} + '@typescript-eslint/scope-manager@8.59.2': + resolution: {integrity: sha512-JzfyEpEtOU89CcFSwyNS3mu4MLvLSXqnmX05+aKBDM+TdR5jzcGOEBwxwGNxrEQ7p/z6kK2WyioCGBf2zZBnvg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/type-utils@6.21.0': - resolution: {integrity: sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==} - engines: {node: ^16.0.0 || >=18.0.0} + '@typescript-eslint/tsconfig-utils@8.59.2': + resolution: {integrity: sha512-BKK4alN7oi4C/zv4VqHQ+uRU+lTa6JGIZ7s1juw7b3RHo9OfKB+bKX3u0iVZetdsUCBBkSbdWbarJbmN0fTeSw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - eslint: ^7.0.0 || ^8.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/type-utils@8.59.2': + resolution: {integrity: sha512-nhqaj1nmTdVVl/BP5omXNRGO38jn5iosis2vbdmupF2txCf8ylWT8lx+JlvMYYVqzGVKtjojUFoQ3JRWK+mfzQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/types@6.21.0': - resolution: {integrity: sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==} - engines: {node: ^16.0.0 || >=18.0.0} + '@typescript-eslint/types@8.59.2': + resolution: {integrity: sha512-e82GVOE8Ps3E++Egvb6Y3Dw0S10u8NkQ9KXmtRhCWJJ8kDhOJTvtMAWnFL16kB1583goCWXsr0NieKCZMs2/0Q==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@6.21.0': - resolution: {integrity: sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==} - engines: {node: ^16.0.0 || >=18.0.0} + '@typescript-eslint/typescript-estree@8.59.2': + resolution: {integrity: sha512-o0XPGNwcWw+FIwStOWn+BwBuEmL6QXP0rsvAFg7ET1dey1Nr6Wb1ac8p5HEsK0ygO/6mUxlk+YWQD9xcb/nnXg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/utils@6.21.0': - resolution: {integrity: sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==} - engines: {node: ^16.0.0 || >=18.0.0} + '@typescript-eslint/utils@8.59.2': + resolution: {integrity: sha512-Juw3EinkXqjaffxz6roowvV7GZT/kET5vSKKZT6upl5TXdWkLkYmNPXwDDL2Vkt2DPn0nODIS4egC/0AGxKo/Q==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - eslint: ^7.0.0 || ^8.0.0 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/visitor-keys@6.21.0': - resolution: {integrity: sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==} - engines: {node: ^16.0.0 || >=18.0.0} + '@typescript-eslint/visitor-keys@8.59.2': + resolution: {integrity: sha512-NwjLUnGy8/Zfx23fl50tRC8rYaYnM52xNRYFAXvmiil9yh1+K6aRVQMnzW6gQB/1DLgWt977lYQn7C+wtgXZiA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@ungap/structured-clone@1.2.0': resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} + deprecated: Potential CWE-502 - Update to 1.3.1 or higher '@vitest/browser@2.1.3': resolution: {integrity: sha512-PQ2kLLc9q8ukJutuuYsynHSr31E78/dtYEvPy4jCHLht1LmITqXTVTqu7THWdZ1kXNGrWwtdMqtt3z2mvSKdIg==} @@ -1632,14 +1644,14 @@ packages: ajv@6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} - ansi-colors@4.1.3: - resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} - engines: {node: '>=6'} - ansi-escapes@4.3.2: resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} engines: {node: '>=8'} + ansi-escapes@7.3.0: + resolution: {integrity: sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==} + engines: {node: '>=18'} + ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} @@ -1648,6 +1660,10 @@ packages: resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==} engines: {node: '>=12'} + ansi-regex@6.2.2: + resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} + engines: {node: '>=12'} + ansi-styles@4.3.0: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} @@ -1660,6 +1676,10 @@ packages: resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} engines: {node: '>=12'} + ansi-styles@6.2.3: + resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} + engines: {node: '>=12'} + anymatch@3.1.3: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} @@ -1686,10 +1706,6 @@ packages: array-ify@1.0.0: resolution: {integrity: sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==} - array-union@2.1.0: - resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} - engines: {node: '>=8'} - arrify@1.0.1: resolution: {integrity: sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==} engines: {node: '>=0.10.0'} @@ -1698,10 +1714,6 @@ packages: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} - astral-regex@2.0.0: - resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} - engines: {node: '>=8'} - at-least-node@1.0.0: resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==} engines: {node: '>= 4.0.0'} @@ -1709,6 +1721,10 @@ packages: balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + balanced-match@4.0.4: + resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} + engines: {node: 18 || 20 || >=22} + binary-extensions@2.3.0: resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} engines: {node: '>=8'} @@ -1723,6 +1739,10 @@ packages: brace-expansion@2.0.1: resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + brace-expansion@5.0.6: + resolution: {integrity: sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==} + engines: {node: 18 || 20 || >=22} + braces@3.0.3: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} @@ -1820,13 +1840,13 @@ packages: resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} engines: {node: '>=6'} - cli-cursor@3.1.0: - resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} - engines: {node: '>=8'} + cli-cursor@5.0.0: + resolution: {integrity: sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==} + engines: {node: '>=18'} - cli-truncate@2.1.0: - resolution: {integrity: sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==} - engines: {node: '>=8'} + cli-truncate@5.2.0: + resolution: {integrity: sha512-xRwvIOMGrfOAnM1JYtqQImuaNtDEv9v6oIYAs4LIHwTiKee8uwvIi363igssOC0O5U04i4AlENs79LQLu9tEMw==} + engines: {node: '>=20'} cli-width@4.1.0: resolution: {integrity: sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==} @@ -1852,13 +1872,13 @@ packages: colorette@2.0.20: resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} + commander@14.0.3: + resolution: {integrity: sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==} + engines: {node: '>=20'} + commander@2.20.3: resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} - commander@6.2.1: - resolution: {integrity: sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==} - engines: {node: '>= 6'} - commondir@1.0.1: resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==} @@ -1955,6 +1975,15 @@ packages: supports-color: optional: true + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + decamelize-keys@1.1.1: resolution: {integrity: sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==} engines: {node: '>=0.10.0'} @@ -1967,9 +1996,6 @@ packages: resolution: {integrity: sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA==} engines: {node: '>=4'} - dedent@0.7.0: - resolution: {integrity: sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==} - deep-eql@5.0.2: resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} engines: {node: '>=6'} @@ -2018,10 +2044,6 @@ packages: resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} engines: {node: '>=0.3.1'} - dir-glob@3.0.1: - resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} - engines: {node: '>=8'} - doctrine@3.0.0: resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} engines: {node: '>=6.0.0'} @@ -2051,6 +2073,9 @@ packages: engines: {node: '>= 8.6'} hasBin: true + emoji-regex@10.6.0: + resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==} + emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} @@ -2064,14 +2089,14 @@ packages: end-of-stream@1.4.4: resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} - enquirer@2.4.1: - resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==} - engines: {node: '>=8.6'} - env-paths@2.2.1: resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} engines: {node: '>=6'} + environment@1.1.0: + resolution: {integrity: sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==} + engines: {node: '>=18'} + error-ex@1.3.2: resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} @@ -2260,6 +2285,10 @@ packages: resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + eslint-visitor-keys@5.0.1: + resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + eslint@8.57.1: resolution: {integrity: sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -2303,9 +2332,8 @@ packages: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} - execa@4.1.0: - resolution: {integrity: sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==} - engines: {node: '>=10'} + eventemitter3@5.0.4: + resolution: {integrity: sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==} execa@8.0.1: resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} @@ -2325,10 +2353,6 @@ packages: fast-diff@1.3.0: resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==} - fast-glob@3.3.2: - resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} - engines: {node: '>=8.6.0'} - fast-json-stable-stringify@2.1.0: resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} @@ -2349,6 +2373,15 @@ packages: picomatch: optional: true + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + file-entry-cache@6.0.1: resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} engines: {node: ^10.12.0 || >=12.0.0} @@ -2427,13 +2460,14 @@ packages: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} + get-east-asian-width@1.6.0: + resolution: {integrity: sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==} + engines: {node: '>=18'} + get-intrinsic@1.2.4: resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==} engines: {node: '>= 0.4'} - get-own-enumerable-property-symbols@3.0.2: - resolution: {integrity: sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g==} - get-package-type@0.1.0: resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} engines: {node: '>=8.0.0'} @@ -2476,11 +2510,12 @@ packages: glob@10.4.5: resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me hasBin: true glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} - deprecated: Glob versions prior to v9 are no longer supported + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me global-agent@3.0.0: resolution: {integrity: sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==} @@ -2506,10 +2541,6 @@ packages: resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} engines: {node: '>= 0.4'} - globby@11.1.0: - resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} - engines: {node: '>=10'} - gopd@1.0.1: resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} @@ -2570,10 +2601,6 @@ packages: http-cache-semantics@4.1.1: resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==} - human-signals@1.1.1: - resolution: {integrity: sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==} - engines: {node: '>=8.12.0'} - human-signals@5.0.0: resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} engines: {node: '>=16.17.0'} @@ -2587,6 +2614,10 @@ packages: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} + ignore@7.0.5: + resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} + engines: {node: '>= 4'} + immutable@5.0.2: resolution: {integrity: sha512-1NU7hWZDkV7hJ4PJ9dur9gTNQ4ePNPN4k9/0YhwjzykTi/+3Q5pF93YU5QoVj8BuOnhLgaY8gs0U2pj4kSYVcw==} @@ -2631,6 +2662,10 @@ packages: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} + is-fullwidth-code-point@5.1.0: + resolution: {integrity: sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==} + engines: {node: '>=18'} + is-glob@4.0.3: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} @@ -2645,10 +2680,6 @@ packages: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} - is-obj@1.0.1: - resolution: {integrity: sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==} - engines: {node: '>=0.10.0'} - is-obj@2.0.0: resolution: {integrity: sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==} engines: {node: '>=8'} @@ -2664,10 +2695,6 @@ packages: is-reference@1.2.1: resolution: {integrity: sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==} - is-regexp@1.0.0: - resolution: {integrity: sha512-7zjFAPO4/gwyQAAgRRmqeEeyIICSdmCqa3tsVHMdBzaXXRiqopZL4Cyghg/XulGWrtABTpbnYYzzIRffLkP4oA==} - engines: {node: '>=0.10.0'} - is-stream@2.0.1: resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} engines: {node: '>=8'} @@ -2683,10 +2710,6 @@ packages: is-typedarray@1.0.0: resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==} - is-unicode-supported@0.1.0: - resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} - engines: {node: '>=10'} - is-windows@1.0.2: resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==} engines: {node: '>=0.10.0'} @@ -2813,18 +2836,14 @@ packages: lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} - lint-staged@10.5.4: - resolution: {integrity: sha512-EechC3DdFic/TdOPgj/RB3FicqE6932LTHCUm0Y2fsD9KGlLB+RwJl2q1IYBIvEsKzDOgn0D4gll+YxG5RsrKg==} + lint-staged@16.4.0: + resolution: {integrity: sha512-lBWt8hujh/Cjysw5GYVmZpFHXDCgZzhrOm8vbcUdobADZNOK/bRshr2kM3DfgrrtR1DQhfupW9gnIXOfiFi+bw==} + engines: {node: '>=20.17'} hasBin: true - listr2@3.14.0: - resolution: {integrity: sha512-TyWI8G99GX9GjE54cJ+RrNMcIFBfwMPxc3XTFiAYGN4s10hWROGtOg7+O6u6LE3mNkyld7RSLE6nrKBvTfcs3g==} - engines: {node: '>=10.0.0'} - peerDependencies: - enquirer: '>= 2.3.0 < 3' - peerDependenciesMeta: - enquirer: - optional: true + listr2@9.0.5: + resolution: {integrity: sha512-ME4Fb83LgEgwNw96RKNvKV4VTLuXfoKudAmm2lP8Kk87KaMK0/Xrx/aAkMWmT8mDb+3MlFDspfbCs7adjRxA2g==} + engines: {node: '>=20.0.0'} locate-path@5.0.0: resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} @@ -2843,13 +2862,9 @@ packages: lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} - log-symbols@4.1.0: - resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} - engines: {node: '>=10'} - - log-update@4.0.0: - resolution: {integrity: sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==} - engines: {node: '>=10'} + log-update@6.1.0: + resolution: {integrity: sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==} + engines: {node: '>=18'} loupe@3.1.2: resolution: {integrity: sha512-23I4pFZHmAemUnz8WZXbYRSKYj801VDaNv9ETuMh7IrMc7VuVVSo+Z9iLE3ni30+U48iDWfi30d3twAXBYmnCg==} @@ -2915,10 +2930,6 @@ packages: merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} - merge2@1.4.1: - resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} - engines: {node: '>= 8'} - micromatch@4.0.8: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} @@ -2928,14 +2939,14 @@ packages: engines: {node: '>=4.0.0'} hasBin: true - mimic-fn@2.1.0: - resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} - engines: {node: '>=6'} - mimic-fn@4.0.0: resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} engines: {node: '>=12'} + mimic-function@5.0.1: + resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==} + engines: {node: '>=18'} + mimic-response@1.0.1: resolution: {integrity: sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==} engines: {node: '>=4'} @@ -2944,13 +2955,13 @@ packages: resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} engines: {node: '>=4'} + minimatch@10.2.5: + resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==} + engines: {node: 18 || 20 || >=22} + minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} - minimatch@9.0.3: - resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==} - engines: {node: '>=16 || 14 >=14.17'} - minimatch@9.0.5: resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} engines: {node: '>=16 || 14 >=14.17'} @@ -3057,10 +3068,6 @@ packages: resolution: {integrity: sha512-Yic4bZHJOt9RCFbRP3GgpqhScOY4HH3V2P8yBj6CeYq118Qr+BLXqT2JvpJ00mryLESpgOxf5XlFv4ZjXxLScw==} engines: {node: '>=4'} - npm-run-path@4.0.1: - resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} - engines: {node: '>=8'} - npm-run-path@5.3.0: resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -3089,14 +3096,14 @@ packages: once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} - onetime@5.1.2: - resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} - engines: {node: '>=6'} - onetime@6.0.0: resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} engines: {node: '>=12'} + onetime@7.0.0: + resolution: {integrity: sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==} + engines: {node: '>=18'} + opener@1.5.2: resolution: {integrity: sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==} hasBin: true @@ -3132,10 +3139,6 @@ packages: resolution: {integrity: sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ==} engines: {node: '>=8'} - p-map@4.0.0: - resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==} - engines: {node: '>=10'} - p-try@2.2.0: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} @@ -3217,6 +3220,10 @@ packages: resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} engines: {node: '>=12'} + picomatch@4.0.4: + resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} + engines: {node: '>=12'} + pify@3.0.0: resolution: {integrity: sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==} engines: {node: '>=4'} @@ -3238,9 +3245,6 @@ packages: engines: {node: '>=18'} hasBin: true - please-upgrade-node@3.2.0: - resolution: {integrity: sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==} - postcss@8.4.49: resolution: {integrity: sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==} engines: {node: ^10 || ^12 || >=14} @@ -3384,9 +3388,9 @@ packages: responselike@1.0.2: resolution: {integrity: sha512-/Fpe5guzJk1gPqdJLJR5u7eG/gNY4nImjbRDaVWVMRhne55TCmj2i9Q+54PBRfatRC8v/rIiv9BN0pMd9OV5EQ==} - restore-cursor@3.1.0: - resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} - engines: {node: '>=8'} + restore-cursor@5.1.0: + resolution: {integrity: sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==} + engines: {node: '>=18'} reusify@1.0.4: resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} @@ -3452,9 +3456,6 @@ packages: run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} - rxjs@7.8.1: - resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==} - safe-buffer@5.1.2: resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} @@ -3487,6 +3488,11 @@ packages: engines: {node: '>=10'} hasBin: true + semver@7.8.0: + resolution: {integrity: sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==} + engines: {node: '>=10'} + hasBin: true + serialize-error@7.0.1: resolution: {integrity: sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==} engines: {node: '>=10'} @@ -3531,17 +3537,13 @@ packages: resolution: {integrity: sha512-pEjMUbwJ5Pl/6Vn6FsamXHXItJXSRftcibixDmNCWbWhic0hzHrwkMZo0IZ7fMRH9KxcWDFSkzhccB4285PutA==} engines: {node: '>=4.2'} - slash@3.0.0: - resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} - engines: {node: '>=8'} - - slice-ansi@3.0.0: - resolution: {integrity: sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==} - engines: {node: '>=8'} + slice-ansi@7.1.2: + resolution: {integrity: sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==} + engines: {node: '>=18'} - slice-ansi@4.0.0: - resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==} - engines: {node: '>=10'} + slice-ansi@8.0.0: + resolution: {integrity: sha512-stxByr12oeeOyY2BlviTNQlYV5xOj47GirPr4yA1hE9JCtxfQN0+tVbkxwCtYDQWhEKWFHsEK48ORg5jrouCAg==} + engines: {node: '>=20'} source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} @@ -3596,10 +3598,6 @@ packages: strict-event-emitter@0.5.1: resolution: {integrity: sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ==} - string-argv@0.3.1: - resolution: {integrity: sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==} - engines: {node: '>=0.6.19'} - string-argv@0.3.2: resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==} engines: {node: '>=0.6.19'} @@ -3612,16 +3610,20 @@ packages: resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} engines: {node: '>=12'} + string-width@7.2.0: + resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} + engines: {node: '>=18'} + + string-width@8.2.1: + resolution: {integrity: sha512-IIaP0g3iy9Cyy18w3M9YcaDudujEAVHKt3a3QJg1+sr/oX96TbaGUubG0hJyCjCBThFH+tFpcIyoUHUn1ogaLA==} + engines: {node: '>=20'} + string_decoder@1.1.1: resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} string_decoder@1.3.0: resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} - stringify-object@3.3.0: - resolution: {integrity: sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==} - engines: {node: '>=4'} - strip-ansi@6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} @@ -3630,14 +3632,14 @@ packages: resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} engines: {node: '>=12'} + strip-ansi@7.2.0: + resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==} + engines: {node: '>=12'} + strip-bom@4.0.0: resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==} engines: {node: '>=8'} - strip-final-newline@2.0.0: - resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} - engines: {node: '>=6'} - strip-final-newline@3.0.0: resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} engines: {node: '>=12'} @@ -3702,10 +3704,18 @@ packages: tinyexec@0.3.1: resolution: {integrity: sha512-WiCJLEECkO18gwqIp6+hJg0//p23HXp4S+gGtAKu3mI2F2/sXC4FvHvXvB0zJVVaTPhx1/tOwdbRsa1sOBIKqQ==} + tinyexec@1.1.2: + resolution: {integrity: sha512-dAqSqE/RabpBKI8+h26GfLq6Vb3JVXs30XYQjdMjaj/c2tS8IYYMbIzP599KtRj7c57/wYApb3QjgRgXmrCukA==} + engines: {node: '>=18'} + tinyglobby@0.2.10: resolution: {integrity: sha512-Zc+8eJlFMvgatPZTl6A9L/yht8QqdmUNtURHaKZLmKBE12hNPSrqNkUp2cs3M/UKmNVVAMFQYSjYIVHDjW5zew==} engines: {node: '>=12.0.0'} + tinyglobby@0.2.16: + resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==} + engines: {node: '>=12.0.0'} + tinypool@1.0.2: resolution: {integrity: sha512-al6n+QEANGFOMf/dmUMsuS5/r9B06uwlyNjZZql/zv8J7ybHCgoihBNORZCY2mzUuAnomQa2JdhyHKzZxPCrFA==} engines: {node: ^18.0.0 || >=20.0.0} @@ -3738,11 +3748,11 @@ packages: resolution: {integrity: sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==} engines: {node: '>=8'} - ts-api-utils@1.4.0: - resolution: {integrity: sha512-032cPxaEKwM+GT3vA5JXNzIaizx388rhsSW79vGRNGXfRRAdEAn2mvk36PvK5HnOchyWZ7afLEXqYCvPCrzuzQ==} - engines: {node: '>=16'} + ts-api-utils@2.5.0: + resolution: {integrity: sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==} + engines: {node: '>=18.12'} peerDependencies: - typescript: '>=4.2.0' + typescript: '>=4.8.4' ts-node@10.9.2: resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} @@ -4030,6 +4040,10 @@ packages: resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} engines: {node: '>=12'} + wrap-ansi@9.0.2: + resolution: {integrity: sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==} + engines: {node: '>=18'} + wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} @@ -4065,6 +4079,11 @@ packages: resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} engines: {node: '>= 6'} + yaml@2.9.0: + resolution: {integrity: sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==} + engines: {node: '>= 14.6'} + hasBin: true + yargs-parser@18.1.3: resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==} engines: {node: '>=6'} @@ -4477,8 +4496,15 @@ snapshots: eslint: 8.57.1 eslint-visitor-keys: 3.4.3 + '@eslint-community/eslint-utils@4.9.1(eslint@8.57.1)': + dependencies: + eslint: 8.57.1 + eslint-visitor-keys: 3.4.3 + '@eslint-community/regexpp@4.12.1': {} + '@eslint-community/regexpp@4.12.2': {} + '@eslint/eslintrc@2.1.4': dependencies: ajv: 6.12.6 @@ -4497,69 +4523,69 @@ snapshots: '@fastify/deepmerge@1.3.0': {} - '@galacean/engine-toolkit-auxiliary-lines@1.5.3(@galacean/engine@packages+galacean)': + '@galacean/engine-toolkit-auxiliary-lines@1.6.0(@galacean/engine@packages+galacean)': dependencies: '@galacean/engine': link:packages/galacean - '@galacean/engine-toolkit-custom-material': 1.5.3(@galacean/engine@packages+galacean) + '@galacean/engine-toolkit-custom-material': 1.6.0(@galacean/engine@packages+galacean) - '@galacean/engine-toolkit-controls@1.5.3(@galacean/engine@packages+galacean)': + '@galacean/engine-toolkit-controls@1.6.0(@galacean/engine@packages+galacean)': dependencies: '@galacean/engine': link:packages/galacean - '@galacean/engine-toolkit-custom-material@1.5.3(@galacean/engine@packages+galacean)': + '@galacean/engine-toolkit-custom-material@1.6.0(@galacean/engine@packages+galacean)': dependencies: '@galacean/engine': link:packages/galacean - '@galacean/engine-toolkit-framebuffer-picker@1.5.3(@galacean/engine@packages+galacean)': + '@galacean/engine-toolkit-framebuffer-picker@1.6.0(@galacean/engine@packages+galacean)': dependencies: '@galacean/engine': link:packages/galacean - '@galacean/engine-toolkit-geometry-sketch@1.5.3(@galacean/engine@packages+galacean)': + '@galacean/engine-toolkit-geometry-sketch@1.6.0(@galacean/engine@packages+galacean)': dependencies: '@galacean/engine': link:packages/galacean - '@galacean/engine-toolkit-gizmo@1.5.3(@galacean/engine-ui@packages+ui)(@galacean/engine@packages+galacean)': + '@galacean/engine-toolkit-gizmo@1.6.0(@galacean/engine-ui@packages+ui)(@galacean/engine@packages+galacean)': dependencies: '@galacean/engine': link:packages/galacean - '@galacean/engine-toolkit-custom-material': 1.5.3(@galacean/engine@packages+galacean) - '@galacean/engine-toolkit-framebuffer-picker': 1.5.3(@galacean/engine@packages+galacean) + '@galacean/engine-toolkit-custom-material': 1.6.0(@galacean/engine@packages+galacean) + '@galacean/engine-toolkit-framebuffer-picker': 1.6.0(@galacean/engine@packages+galacean) '@galacean/engine-ui': link:packages/ui - '@galacean/engine-toolkit-lines@1.5.3(@galacean/engine@packages+galacean)': + '@galacean/engine-toolkit-lines@1.6.0(@galacean/engine@packages+galacean)': dependencies: '@galacean/engine': link:packages/galacean - '@galacean/engine-toolkit-navigation-gizmo@1.5.3(@galacean/engine@packages+galacean)': + '@galacean/engine-toolkit-navigation-gizmo@1.6.0(@galacean/engine@packages+galacean)': dependencies: '@galacean/engine': link:packages/galacean - '@galacean/engine-toolkit-controls': 1.5.3(@galacean/engine@packages+galacean) - '@galacean/engine-toolkit-custom-material': 1.5.3(@galacean/engine@packages+galacean) + '@galacean/engine-toolkit-controls': 1.6.0(@galacean/engine@packages+galacean) + '@galacean/engine-toolkit-custom-material': 1.6.0(@galacean/engine@packages+galacean) - '@galacean/engine-toolkit-outline@1.5.3(@galacean/engine@packages+galacean)': + '@galacean/engine-toolkit-outline@1.6.0(@galacean/engine@packages+galacean)': dependencies: '@galacean/engine': link:packages/galacean - '@galacean/engine-toolkit-skeleton-viewer@1.5.3(@galacean/engine@packages+galacean)': + '@galacean/engine-toolkit-skeleton-viewer@1.6.0(@galacean/engine@packages+galacean)': dependencies: '@galacean/engine': link:packages/galacean - '@galacean/engine-toolkit-stats@1.5.3(@galacean/engine@packages+galacean)': + '@galacean/engine-toolkit-stats@1.6.0(@galacean/engine@packages+galacean)': dependencies: '@galacean/engine': link:packages/galacean - '@galacean/engine-toolkit@1.5.3(@galacean/engine-ui@packages+ui)(@galacean/engine@packages+galacean)': - dependencies: - '@galacean/engine-toolkit-auxiliary-lines': 1.5.3(@galacean/engine@packages+galacean) - '@galacean/engine-toolkit-controls': 1.5.3(@galacean/engine@packages+galacean) - '@galacean/engine-toolkit-custom-material': 1.5.3(@galacean/engine@packages+galacean) - '@galacean/engine-toolkit-framebuffer-picker': 1.5.3(@galacean/engine@packages+galacean) - '@galacean/engine-toolkit-geometry-sketch': 1.5.3(@galacean/engine@packages+galacean) - '@galacean/engine-toolkit-gizmo': 1.5.3(@galacean/engine-ui@packages+ui)(@galacean/engine@packages+galacean) - '@galacean/engine-toolkit-lines': 1.5.3(@galacean/engine@packages+galacean) - '@galacean/engine-toolkit-navigation-gizmo': 1.5.3(@galacean/engine@packages+galacean) - '@galacean/engine-toolkit-outline': 1.5.3(@galacean/engine@packages+galacean) - '@galacean/engine-toolkit-skeleton-viewer': 1.5.3(@galacean/engine@packages+galacean) - '@galacean/engine-toolkit-stats': 1.5.3(@galacean/engine@packages+galacean) + '@galacean/engine-toolkit@1.6.0(@galacean/engine-ui@packages+ui)(@galacean/engine@packages+galacean)': + dependencies: + '@galacean/engine-toolkit-auxiliary-lines': 1.6.0(@galacean/engine@packages+galacean) + '@galacean/engine-toolkit-controls': 1.6.0(@galacean/engine@packages+galacean) + '@galacean/engine-toolkit-custom-material': 1.6.0(@galacean/engine@packages+galacean) + '@galacean/engine-toolkit-framebuffer-picker': 1.6.0(@galacean/engine@packages+galacean) + '@galacean/engine-toolkit-geometry-sketch': 1.6.0(@galacean/engine@packages+galacean) + '@galacean/engine-toolkit-gizmo': 1.6.0(@galacean/engine-ui@packages+ui)(@galacean/engine@packages+galacean) + '@galacean/engine-toolkit-lines': 1.6.0(@galacean/engine@packages+galacean) + '@galacean/engine-toolkit-navigation-gizmo': 1.6.0(@galacean/engine@packages+galacean) + '@galacean/engine-toolkit-outline': 1.6.0(@galacean/engine@packages+galacean) + '@galacean/engine-toolkit-skeleton-viewer': 1.6.0(@galacean/engine@packages+galacean) + '@galacean/engine-toolkit-stats': 1.6.0(@galacean/engine@packages+galacean) transitivePeerDependencies: - '@galacean/engine' - '@galacean/engine-ui' @@ -5017,8 +5043,6 @@ snapshots: '@types/estree@1.0.6': {} - '@types/json-schema@7.0.15': {} - '@types/keyv@3.1.4': dependencies: '@types/node': 18.19.64 @@ -5043,99 +5067,102 @@ snapshots: dependencies: '@types/node': 18.19.64 - '@types/semver@7.5.8': {} - '@types/statuses@2.0.5': {} '@types/tough-cookie@4.0.5': {} - '@types/webxr@0.5.22': {} + '@types/webxr@0.5.24': {} - '@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1)(typescript@5.6.3)': + '@typescript-eslint/eslint-plugin@8.59.2(@typescript-eslint/parser@8.59.2(eslint@8.57.1)(typescript@5.6.3))(eslint@8.57.1)(typescript@5.6.3)': dependencies: - '@eslint-community/regexpp': 4.12.1 - '@typescript-eslint/parser': 6.21.0(eslint@8.57.1)(typescript@5.6.3) - '@typescript-eslint/scope-manager': 6.21.0 - '@typescript-eslint/type-utils': 6.21.0(eslint@8.57.1)(typescript@5.6.3) - '@typescript-eslint/utils': 6.21.0(eslint@8.57.1)(typescript@5.6.3) - '@typescript-eslint/visitor-keys': 6.21.0 - debug: 4.3.7 + '@eslint-community/regexpp': 4.12.2 + '@typescript-eslint/parser': 8.59.2(eslint@8.57.1)(typescript@5.6.3) + '@typescript-eslint/scope-manager': 8.59.2 + '@typescript-eslint/type-utils': 8.59.2(eslint@8.57.1)(typescript@5.6.3) + '@typescript-eslint/utils': 8.59.2(eslint@8.57.1)(typescript@5.6.3) + '@typescript-eslint/visitor-keys': 8.59.2 eslint: 8.57.1 - graphemer: 1.4.0 - ignore: 5.3.2 + ignore: 7.0.5 natural-compare: 1.4.0 - semver: 7.6.3 - ts-api-utils: 1.4.0(typescript@5.6.3) - optionalDependencies: + ts-api-utils: 2.5.0(typescript@5.6.3) typescript: 5.6.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.6.3)': + '@typescript-eslint/parser@8.59.2(eslint@8.57.1)(typescript@5.6.3)': dependencies: - '@typescript-eslint/scope-manager': 6.21.0 - '@typescript-eslint/types': 6.21.0 - '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.6.3) - '@typescript-eslint/visitor-keys': 6.21.0 - debug: 4.3.7 + '@typescript-eslint/scope-manager': 8.59.2 + '@typescript-eslint/types': 8.59.2 + '@typescript-eslint/typescript-estree': 8.59.2(typescript@5.6.3) + '@typescript-eslint/visitor-keys': 8.59.2 + debug: 4.4.3 eslint: 8.57.1 - optionalDependencies: typescript: 5.6.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@6.21.0': + '@typescript-eslint/project-service@8.59.2(typescript@5.6.3)': dependencies: - '@typescript-eslint/types': 6.21.0 - '@typescript-eslint/visitor-keys': 6.21.0 + '@typescript-eslint/tsconfig-utils': 8.59.2(typescript@5.6.3) + '@typescript-eslint/types': 8.59.2 + debug: 4.4.3 + typescript: 5.6.3 + transitivePeerDependencies: + - supports-color - '@typescript-eslint/type-utils@6.21.0(eslint@8.57.1)(typescript@5.6.3)': + '@typescript-eslint/scope-manager@8.59.2': dependencies: - '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.6.3) - '@typescript-eslint/utils': 6.21.0(eslint@8.57.1)(typescript@5.6.3) - debug: 4.3.7 + '@typescript-eslint/types': 8.59.2 + '@typescript-eslint/visitor-keys': 8.59.2 + + '@typescript-eslint/tsconfig-utils@8.59.2(typescript@5.6.3)': + dependencies: + typescript: 5.6.3 + + '@typescript-eslint/type-utils@8.59.2(eslint@8.57.1)(typescript@5.6.3)': + dependencies: + '@typescript-eslint/types': 8.59.2 + '@typescript-eslint/typescript-estree': 8.59.2(typescript@5.6.3) + '@typescript-eslint/utils': 8.59.2(eslint@8.57.1)(typescript@5.6.3) + debug: 4.4.3 eslint: 8.57.1 - ts-api-utils: 1.4.0(typescript@5.6.3) - optionalDependencies: + ts-api-utils: 2.5.0(typescript@5.6.3) typescript: 5.6.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/types@6.21.0': {} + '@typescript-eslint/types@8.59.2': {} - '@typescript-eslint/typescript-estree@6.21.0(typescript@5.6.3)': + '@typescript-eslint/typescript-estree@8.59.2(typescript@5.6.3)': dependencies: - '@typescript-eslint/types': 6.21.0 - '@typescript-eslint/visitor-keys': 6.21.0 - debug: 4.3.7 - globby: 11.1.0 - is-glob: 4.0.3 - minimatch: 9.0.3 - semver: 7.6.3 - ts-api-utils: 1.4.0(typescript@5.6.3) - optionalDependencies: + '@typescript-eslint/project-service': 8.59.2(typescript@5.6.3) + '@typescript-eslint/tsconfig-utils': 8.59.2(typescript@5.6.3) + '@typescript-eslint/types': 8.59.2 + '@typescript-eslint/visitor-keys': 8.59.2 + debug: 4.4.3 + minimatch: 10.2.5 + semver: 7.8.0 + tinyglobby: 0.2.16 + ts-api-utils: 2.5.0(typescript@5.6.3) typescript: 5.6.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@6.21.0(eslint@8.57.1)(typescript@5.6.3)': + '@typescript-eslint/utils@8.59.2(eslint@8.57.1)(typescript@5.6.3)': dependencies: - '@eslint-community/eslint-utils': 4.4.1(eslint@8.57.1) - '@types/json-schema': 7.0.15 - '@types/semver': 7.5.8 - '@typescript-eslint/scope-manager': 6.21.0 - '@typescript-eslint/types': 6.21.0 - '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.6.3) + '@eslint-community/eslint-utils': 4.9.1(eslint@8.57.1) + '@typescript-eslint/scope-manager': 8.59.2 + '@typescript-eslint/types': 8.59.2 + '@typescript-eslint/typescript-estree': 8.59.2(typescript@5.6.3) eslint: 8.57.1 - semver: 7.6.3 + typescript: 5.6.3 transitivePeerDependencies: - supports-color - - typescript - '@typescript-eslint/visitor-keys@6.21.0': + '@typescript-eslint/visitor-keys@8.59.2': dependencies: - '@typescript-eslint/types': 6.21.0 - eslint-visitor-keys: 3.4.3 + '@typescript-eslint/types': 8.59.2 + eslint-visitor-keys: 5.0.1 '@ungap/structured-clone@1.2.0': {} @@ -5298,9 +5325,9 @@ snapshots: jsonparse: 1.3.1 through: 2.3.8 - acorn-jsx@5.3.2(acorn@8.14.0): + acorn-jsx@5.3.2(acorn@8.15.0): dependencies: - acorn: 8.14.0 + acorn: 8.15.0 acorn-walk@8.3.4: dependencies: @@ -5308,8 +5335,7 @@ snapshots: acorn@8.14.0: {} - acorn@8.15.0: - optional: true + acorn@8.15.0: {} aggregate-error@3.1.0: dependencies: @@ -5323,16 +5349,20 @@ snapshots: json-schema-traverse: 0.4.1 uri-js: 4.4.1 - ansi-colors@4.1.3: {} - ansi-escapes@4.3.2: dependencies: type-fest: 0.21.3 + ansi-escapes@7.3.0: + dependencies: + environment: 1.1.0 + ansi-regex@5.0.1: {} ansi-regex@6.1.0: {} + ansi-regex@6.2.2: {} + ansi-styles@4.3.0: dependencies: color-convert: 2.0.1 @@ -5341,6 +5371,8 @@ snapshots: ansi-styles@6.2.1: {} + ansi-styles@6.2.3: {} + anymatch@3.1.3: dependencies: normalize-path: 3.0.0 @@ -5366,18 +5398,16 @@ snapshots: array-ify@1.0.0: {} - array-union@2.1.0: {} - arrify@1.0.1: {} assertion-error@2.0.1: {} - astral-regex@2.0.0: {} - at-least-node@1.0.0: {} balanced-match@1.0.2: {} + balanced-match@4.0.4: {} + binary-extensions@2.3.0: {} boolean@3.2.0: @@ -5392,6 +5422,10 @@ snapshots: dependencies: balanced-match: 1.0.2 + brace-expansion@5.0.6: + dependencies: + balanced-match: 4.0.4 + braces@3.0.3: dependencies: fill-range: 7.1.1 @@ -5517,14 +5551,14 @@ snapshots: clean-stack@2.2.0: {} - cli-cursor@3.1.0: + cli-cursor@5.0.0: dependencies: - restore-cursor: 3.1.0 + restore-cursor: 5.1.0 - cli-truncate@2.1.0: + cli-truncate@5.2.0: dependencies: - slice-ansi: 3.0.0 - string-width: 4.2.3 + slice-ansi: 8.0.0 + string-width: 8.2.1 cli-width@4.1.0: {} @@ -5552,11 +5586,11 @@ snapshots: colorette@2.0.20: {} + commander@14.0.3: {} + commander@2.20.3: optional: true - commander@6.2.1: {} - commondir@1.0.1: {} compare-func@2.0.0: @@ -5653,6 +5687,10 @@ snapshots: dependencies: ms: 2.1.3 + debug@4.4.3: + dependencies: + ms: 2.1.3 + decamelize-keys@1.1.1: dependencies: decamelize: 1.2.0 @@ -5664,8 +5702,6 @@ snapshots: dependencies: mimic-response: 1.0.1 - dedent@0.7.0: {} - deep-eql@5.0.2: {} deep-is@0.1.4: {} @@ -5706,10 +5742,6 @@ snapshots: diff@4.0.2: {} - dir-glob@3.0.1: - dependencies: - path-type: 4.0.0 - doctrine@3.0.0: dependencies: esutils: 2.0.3 @@ -5736,6 +5768,8 @@ snapshots: transitivePeerDependencies: - supports-color + emoji-regex@10.6.0: {} + emoji-regex@8.0.0: {} emoji-regex@9.2.2: {} @@ -5747,13 +5781,10 @@ snapshots: dependencies: once: 1.4.0 - enquirer@2.4.1: - dependencies: - ansi-colors: 4.1.3 - strip-ansi: 6.0.1 - env-paths@2.2.1: {} + environment@1.1.0: {} + error-ex@1.3.2: dependencies: is-arrayish: 0.2.1 @@ -5930,6 +5961,8 @@ snapshots: eslint-visitor-keys@3.4.3: {} + eslint-visitor-keys@5.0.1: {} + eslint@8.57.1: dependencies: '@eslint-community/eslint-utils': 4.4.1(eslint@8.57.1) @@ -5975,8 +6008,8 @@ snapshots: espree@9.6.1: dependencies: - acorn: 8.14.0 - acorn-jsx: 5.3.2(acorn@8.14.0) + acorn: 8.15.0 + acorn-jsx: 5.3.2(acorn@8.15.0) eslint-visitor-keys: 3.4.3 esprima@4.0.1: {} @@ -6003,17 +6036,7 @@ snapshots: esutils@2.0.3: {} - execa@4.1.0: - dependencies: - cross-spawn: 7.0.5 - get-stream: 5.2.0 - human-signals: 1.1.1 - is-stream: 2.0.1 - merge-stream: 2.0.0 - npm-run-path: 4.0.1 - onetime: 5.1.2 - signal-exit: 3.0.7 - strip-final-newline: 2.0.0 + eventemitter3@5.0.4: {} execa@8.0.1: dependencies: @@ -6042,14 +6065,6 @@ snapshots: fast-diff@1.3.0: {} - fast-glob@3.3.2: - dependencies: - '@nodelib/fs.stat': 2.0.5 - '@nodelib/fs.walk': 1.2.8 - glob-parent: 5.1.2 - merge2: 1.4.1 - micromatch: 4.0.8 - fast-json-stable-stringify@2.1.0: {} fast-levenshtein@2.0.6: {} @@ -6066,6 +6081,10 @@ snapshots: optionalDependencies: picomatch: 4.0.2 + fdir@6.5.0(picomatch@4.0.4): + optionalDependencies: + picomatch: 4.0.4 + file-entry-cache@6.0.1: dependencies: flat-cache: 3.2.0 @@ -6147,6 +6166,8 @@ snapshots: get-caller-file@2.0.5: {} + get-east-asian-width@1.6.0: {} + get-intrinsic@1.2.4: dependencies: es-errors: 1.3.0 @@ -6156,8 +6177,6 @@ snapshots: hasown: 2.0.2 optional: true - get-own-enumerable-property-symbols@3.0.2: {} - get-package-type@0.1.0: {} get-stdin@8.0.0: {} @@ -6255,15 +6274,6 @@ snapshots: gopd: 1.0.1 optional: true - globby@11.1.0: - dependencies: - array-union: 2.1.0 - dir-glob: 3.0.1 - fast-glob: 3.3.2 - ignore: 5.3.2 - merge2: 1.4.1 - slash: 3.0.0 - gopd@1.0.1: dependencies: get-intrinsic: 1.2.4 @@ -6327,14 +6337,14 @@ snapshots: http-cache-semantics@4.1.1: {} - human-signals@1.1.1: {} - human-signals@5.0.0: {} husky@8.0.3: {} ignore@5.3.2: {} + ignore@7.0.5: {} + immutable@5.0.2: {} import-fresh@3.3.0: @@ -6369,6 +6379,10 @@ snapshots: is-fullwidth-code-point@3.0.0: {} + is-fullwidth-code-point@5.1.0: + dependencies: + get-east-asian-width: 1.6.0 + is-glob@4.0.3: dependencies: is-extglob: 2.1.1 @@ -6379,8 +6393,6 @@ snapshots: is-number@7.0.0: {} - is-obj@1.0.1: {} - is-obj@2.0.0: {} is-path-inside@3.0.3: {} @@ -6391,8 +6403,6 @@ snapshots: dependencies: '@types/estree': 1.0.6 - is-regexp@1.0.0: {} - is-stream@2.0.1: {} is-stream@3.0.0: {} @@ -6403,8 +6413,6 @@ snapshots: is-typedarray@1.0.0: {} - is-unicode-supported@0.1.0: {} - is-windows@1.0.2: {} isarray@1.0.0: {} @@ -6539,38 +6547,23 @@ snapshots: lines-and-columns@1.2.4: {} - lint-staged@10.5.4: + lint-staged@16.4.0: dependencies: - chalk: 4.1.2 - cli-truncate: 2.1.0 - commander: 6.2.1 - cosmiconfig: 7.1.0 - debug: 4.3.7 - dedent: 0.7.0 - enquirer: 2.4.1 - execa: 4.1.0 - listr2: 3.14.0(enquirer@2.4.1) - log-symbols: 4.1.0 - micromatch: 4.0.8 - normalize-path: 3.0.0 - please-upgrade-node: 3.2.0 - string-argv: 0.3.1 - stringify-object: 3.3.0 - transitivePeerDependencies: - - supports-color + commander: 14.0.3 + listr2: 9.0.5 + picomatch: 4.0.4 + string-argv: 0.3.2 + tinyexec: 1.1.2 + yaml: 2.9.0 - listr2@3.14.0(enquirer@2.4.1): + listr2@9.0.5: dependencies: - cli-truncate: 2.1.0 + cli-truncate: 5.2.0 colorette: 2.0.20 - log-update: 4.0.0 - p-map: 4.0.0 + eventemitter3: 5.0.4 + log-update: 6.1.0 rfdc: 1.4.1 - rxjs: 7.8.1 - through: 2.3.8 - wrap-ansi: 7.0.0 - optionalDependencies: - enquirer: 2.4.1 + wrap-ansi: 9.0.2 locate-path@5.0.0: dependencies: @@ -6586,17 +6579,13 @@ snapshots: lodash@4.17.21: {} - log-symbols@4.1.0: - dependencies: - chalk: 4.1.2 - is-unicode-supported: 0.1.0 - - log-update@4.0.0: + log-update@6.1.0: dependencies: - ansi-escapes: 4.3.2 - cli-cursor: 3.1.0 - slice-ansi: 4.0.0 - wrap-ansi: 6.2.0 + ansi-escapes: 7.3.0 + cli-cursor: 5.0.0 + slice-ansi: 7.1.2 + strip-ansi: 7.1.0 + wrap-ansi: 9.0.2 loupe@3.1.2: {} @@ -6665,30 +6654,29 @@ snapshots: merge-stream@2.0.0: {} - merge2@1.4.1: {} - micromatch@4.0.8: dependencies: braces: 3.0.3 picomatch: 2.3.1 + optional: true mime@2.6.0: {} - mimic-fn@2.1.0: {} - mimic-fn@4.0.0: {} + mimic-function@5.0.1: {} + mimic-response@1.0.1: {} min-indent@1.0.1: {} - minimatch@3.1.2: + minimatch@10.2.5: dependencies: - brace-expansion: 1.1.11 + brace-expansion: 5.0.6 - minimatch@9.0.3: + minimatch@3.1.2: dependencies: - brace-expansion: 2.0.1 + brace-expansion: 1.1.11 minimatch@9.0.5: dependencies: @@ -6802,10 +6790,6 @@ snapshots: pify: 3.0.0 optional: true - npm-run-path@4.0.1: - dependencies: - path-key: 3.1.1 - npm-run-path@5.3.0: dependencies: path-key: 4.0.0 @@ -6862,14 +6846,14 @@ snapshots: dependencies: wrappy: 1.0.2 - onetime@5.1.2: - dependencies: - mimic-fn: 2.1.0 - onetime@6.0.0: dependencies: mimic-fn: 4.0.0 + onetime@7.0.0: + dependencies: + mimic-function: 5.0.1 + opener@1.5.2: {} optionator@0.9.4: @@ -6905,10 +6889,6 @@ snapshots: dependencies: aggregate-error: 3.1.0 - p-map@4.0.0: - dependencies: - aggregate-error: 3.1.0 - p-try@2.2.0: {} package-hash@4.0.0: @@ -6968,6 +6948,8 @@ snapshots: picomatch@4.0.2: {} + picomatch@4.0.4: {} + pify@3.0.0: optional: true @@ -6989,10 +6971,6 @@ snapshots: optionalDependencies: fsevents: 2.3.2 - please-upgrade-node@3.2.0: - dependencies: - semver-compare: 1.0.0 - postcss@8.4.49: dependencies: nanoid: 3.3.7 @@ -7129,10 +7107,10 @@ snapshots: dependencies: lowercase-keys: 1.0.1 - restore-cursor@3.1.0: + restore-cursor@5.1.0: dependencies: - onetime: 5.1.2 - signal-exit: 3.0.7 + onetime: 7.0.0 + signal-exit: 4.1.0 reusify@1.0.4: {} @@ -7223,10 +7201,6 @@ snapshots: dependencies: queue-microtask: 1.2.3 - rxjs@7.8.1: - dependencies: - tslib: 2.8.1 - safe-buffer@5.1.2: {} safe-buffer@5.2.1: {} @@ -7239,7 +7213,8 @@ snapshots: optionalDependencies: '@parcel/watcher': 2.5.0 - semver-compare@1.0.0: {} + semver-compare@1.0.0: + optional: true semver@5.7.2: {} @@ -7249,6 +7224,8 @@ snapshots: semver@7.6.3: {} + semver@7.8.0: {} + serialize-error@7.0.1: dependencies: type-fest: 0.13.1 @@ -7284,19 +7261,15 @@ snapshots: skip-regex@1.0.2: {} - slash@3.0.0: {} - - slice-ansi@3.0.0: + slice-ansi@7.1.2: dependencies: - ansi-styles: 4.3.0 - astral-regex: 2.0.0 - is-fullwidth-code-point: 3.0.0 + ansi-styles: 6.2.1 + is-fullwidth-code-point: 5.1.0 - slice-ansi@4.0.0: + slice-ansi@8.0.0: dependencies: - ansi-styles: 4.3.0 - astral-regex: 2.0.0 - is-fullwidth-code-point: 3.0.0 + ansi-styles: 6.2.3 + is-fullwidth-code-point: 5.1.0 source-map-js@1.2.1: {} @@ -7350,8 +7323,6 @@ snapshots: strict-event-emitter@0.5.1: {} - string-argv@0.3.1: {} - string-argv@0.3.2: {} string-width@4.2.3: @@ -7366,6 +7337,17 @@ snapshots: emoji-regex: 9.2.2 strip-ansi: 7.1.0 + string-width@7.2.0: + dependencies: + emoji-regex: 10.6.0 + get-east-asian-width: 1.6.0 + strip-ansi: 7.1.0 + + string-width@8.2.1: + dependencies: + get-east-asian-width: 1.6.0 + strip-ansi: 7.2.0 + string_decoder@1.1.1: dependencies: safe-buffer: 5.1.2 @@ -7374,12 +7356,6 @@ snapshots: dependencies: safe-buffer: 5.2.1 - stringify-object@3.3.0: - dependencies: - get-own-enumerable-property-symbols: 3.0.2 - is-obj: 1.0.1 - is-regexp: 1.0.0 - strip-ansi@6.0.1: dependencies: ansi-regex: 5.0.1 @@ -7388,9 +7364,11 @@ snapshots: dependencies: ansi-regex: 6.1.0 - strip-bom@4.0.0: {} + strip-ansi@7.2.0: + dependencies: + ansi-regex: 6.2.2 - strip-final-newline@2.0.0: {} + strip-bom@4.0.0: {} strip-final-newline@3.0.0: {} @@ -7460,11 +7438,18 @@ snapshots: tinyexec@0.3.1: {} + tinyexec@1.1.2: {} + tinyglobby@0.2.10: dependencies: fdir: 6.4.2(picomatch@4.0.2) picomatch: 4.0.2 + tinyglobby@0.2.16: + dependencies: + fdir: 6.5.0(picomatch@4.0.4) + picomatch: 4.0.4 + tinypool@1.0.2: {} tinyrainbow@1.2.0: {} @@ -7488,7 +7473,7 @@ snapshots: trim-newlines@3.0.1: {} - ts-api-utils@1.4.0(typescript@5.6.3): + ts-api-utils@2.5.0(typescript@5.6.3): dependencies: typescript: 5.6.3 @@ -7606,7 +7591,7 @@ snapshots: vite-node@2.1.5(@types/node@18.19.64)(sass@1.81.0)(terser@5.44.1): dependencies: cac: 6.7.14 - debug: 4.3.7 + debug: 4.4.3 es-module-lexer: 1.5.4 pathe: 1.1.2 vite: 5.4.11(@types/node@18.19.64)(sass@1.81.0)(terser@5.44.1) @@ -7699,7 +7684,7 @@ snapshots: '@vitest/spy': 2.1.5 '@vitest/utils': 2.1.5 chai: 5.1.2 - debug: 4.3.7 + debug: 4.4.3 expect-type: 1.1.0 magic-string: 0.30.12 pathe: 1.1.2 @@ -7760,6 +7745,12 @@ snapshots: string-width: 5.1.2 strip-ansi: 7.1.0 + wrap-ansi@9.0.2: + dependencies: + ansi-styles: 6.2.1 + string-width: 7.2.0 + strip-ansi: 7.1.0 + wrappy@1.0.2: {} write-file-atomic@3.0.3: @@ -7781,6 +7772,8 @@ snapshots: yaml@1.10.2: {} + yaml@2.9.0: {} + yargs-parser@18.1.3: dependencies: camelcase: 5.3.1 diff --git a/tests/src/core/2d/text/TextUtils.test.ts b/tests/src/core/2d/text/TextUtils.test.ts index 2db75b4125..54a5a57820 100644 --- a/tests/src/core/2d/text/TextUtils.test.ts +++ b/tests/src/core/2d/text/TextUtils.test.ts @@ -359,7 +359,7 @@ describe("TextUtils", () => { ); expect(result.width).to.be.equal(23); expect(result.height).to.be.equal(135); - expect(result.lines).to.be.deep.equal([' ', ' ', 'W', 'or', 'ld']); + expect(result.lines).to.be.deep.equal([" ", " ", "W", "or", "ld"]); expect(result.lineHeight).to.be.equal(27); wrap1TextRenderer.enableWrapping = true; diff --git a/tests/src/core/Animator.test.ts b/tests/src/core/Animator.test.ts index 044312c943..d160f186ea 100644 --- a/tests/src/core/Animator.test.ts +++ b/tests/src/core/Animator.test.ts @@ -350,7 +350,7 @@ describe("Animator test", function () { animator.play("Walk"); class TestScript extends Script { - event0(): void { } + event0(): void {} } const testScript = animator.entity.addComponent(TestScript); @@ -792,8 +792,8 @@ describe("Animator test", function () { animator.animatorController = animatorController; class TestScript extends StateMachineScript { - onStateEnter(animator) { } - onStateExit(animator) { } + onStateEnter(animator) {} + onStateExit(animator) {} } const testScript = state1.addStateMachineScript(TestScript); diff --git a/tests/src/core/Camera.test.ts b/tests/src/core/Camera.test.ts index be1c0b9923..0892400f07 100644 --- a/tests/src/core/Camera.test.ts +++ b/tests/src/core/Camera.test.ts @@ -118,7 +118,7 @@ describe("camera test", function () { // get enableHDR expect(camera.enableHDR).to.eq(false); // @ts-ignore - expect(camera._isIndependentCanvasEnabled()).to.eq(true);// Because sRGB pass + expect(camera._isIndependentCanvasEnabled()).to.eq(true); // Because sRGB pass // set enableHDR camera.enableHDR = true; expect(camera.enableHDR).to.eq(true); @@ -420,14 +420,14 @@ describe("camera test", function () { camera.nearClipPlane = 1; camera.farClipPlane = 255; const cloneCamera = camera.entity.clone().getComponent(Camera); - expect(cloneCamera.isOrthographic).to.eq(camera.isOrthographic) + expect(cloneCamera.isOrthographic).to.eq(camera.isOrthographic); expect(cloneCamera.nearClipPlane).to.eq(camera.nearClipPlane); expect(cloneCamera.farClipPlane).to.eq(camera.farClipPlane); expect(cloneCamera.renderTarget).to.eq(camera.renderTarget); expect(cloneCamera.shaderData).to.not.eq(camera.shaderData); // @ts-ignore expect(cloneCamera._globalShaderMacro).to.not.eq(camera._globalShaderMacro); - }) + }); it("destroy test", () => { camera.destroy(); diff --git a/tests/src/core/CloneUtils.test.ts b/tests/src/core/CloneUtils.test.ts index 79fb05fdfa..e583d6d8ab 100644 --- a/tests/src/core/CloneUtils.test.ts +++ b/tests/src/core/CloneUtils.test.ts @@ -1,12 +1,4 @@ -import { - Entity, - MeshRenderer, - Script, - Signal, - assignmentClone, - deepClone, - ignoreClone -} from "@galacean/engine-core"; +import { Entity, MeshRenderer, Script, Signal, assignmentClone, deepClone, ignoreClone } from "@galacean/engine-core"; import { WebGLEngine } from "@galacean/engine"; import { describe, expect, it } from "vitest"; @@ -553,7 +545,9 @@ describe("Clone remap", async () => { const parent = rootEntity.createChild("parent"); const script = parent.addComponent(SignalScript); let called = false; - script.onFire.on(() => { called = true; }); + script.onFire.on(() => { + called = true; + }); const cloned = parent.clone(); const cs = cloned.getComponent(SignalScript); diff --git a/tests/src/core/Entity.test.ts b/tests/src/core/Entity.test.ts index 0a428f4b60..c7bb4adbaf 100644 --- a/tests/src/core/Entity.test.ts +++ b/tests/src/core/Entity.test.ts @@ -4,7 +4,7 @@ import { PhysXPhysics } from "@galacean/engine-physics-physx"; import { WebGLEngine } from "@galacean/engine"; import { beforeEach, describe, expect, it, vi } from "vitest"; -class TestComponent extends Script { } +class TestComponent extends Script {} describe("Entity", async () => { const engine = await WebGLEngine.create({ canvas: document.createElement("canvas"), physics: new PhysXPhysics() }); @@ -568,7 +568,9 @@ describe("Entity", async () => { const entityGrandsonClone = entityChildClone.children[0]; // @ts-ignore expect(entityChildClone.transform.instanceId).eq(entityGrandsonClone.transform._getParentTransform()?.instanceId); - expect(Quaternion.equals(new Quaternion(0.7071067, 0, 0, 0.7071067), entityGrandsonClone.transform.rotationQuaternion)).eq(true); + expect( + Quaternion.equals(new Quaternion(0.7071067, 0, 0, 0.7071067), entityGrandsonClone.transform.rotationQuaternion) + ).eq(true); }); }); @@ -655,8 +657,8 @@ describe("Entity", async () => { it("addChildAfterDestroy", () => { class DestroyScript extends Script { - onDisable(): void { } - onDestroy(): void { } + onDisable(): void {} + onDestroy(): void {} } DestroyScript.prototype.onDisable = vi.fn(DestroyScript.prototype.onDisable); DestroyScript.prototype.onDestroy = vi.fn(DestroyScript.prototype.onDestroy); @@ -871,4 +873,4 @@ describe("Entity", async () => { expect(order).toEqual(["C", "B", "A"]); }); }); -}); \ No newline at end of file +}); diff --git a/tests/src/core/PolyfillAudioContext.test.ts b/tests/src/core/PolyfillAudioContext.test.ts index e13738ec6b..117c9553fc 100644 --- a/tests/src/core/PolyfillAudioContext.test.ts +++ b/tests/src/core/PolyfillAudioContext.test.ts @@ -9,7 +9,7 @@ describe("Polyfill", () => { (window as any).webkitAudioContext = class MockWebkitAudioContext { state = "suspended"; - constructor() { } + constructor() {} decodeAudioData(arrayBuffer: ArrayBuffer, successCallback: Function, errorCallback?: Function) { setTimeout(() => { diff --git a/tests/src/core/Shader.test.ts b/tests/src/core/Shader.test.ts index 543e6ce8cc..5f4902de40 100644 --- a/tests/src/core/Shader.test.ts +++ b/tests/src/core/Shader.test.ts @@ -24,8 +24,7 @@ shaderCompiler._includeMap = ShaderFactory.includeMap; // @ts-ignore Shader._shaderCompiler = shaderCompiler; -const makePass = (name = "Default") => - new ShaderPass(name, [], [], ShaderLanguage.GLSLES100); +const makePass = (name = "Default") => new ShaderPass(name, [], [], ShaderLanguage.GLSLES100); describe("Shader", () => { describe("Custom Shader", () => { diff --git a/tests/src/core/particle/ParticleTextureSheetAnimation.test.ts b/tests/src/core/particle/ParticleTextureSheetAnimation.test.ts index 250ba08537..934d1f1082 100644 --- a/tests/src/core/particle/ParticleTextureSheetAnimation.test.ts +++ b/tests/src/core/particle/ParticleTextureSheetAnimation.test.ts @@ -1,50 +1,52 @@ - import { Camera, ParticleRenderer, Scene } from "@galacean/engine-core"; import { Vector2 } from "@galacean/engine-math"; import { WebGLEngine } from "@galacean/engine"; import { beforeAll, describe, expect, it } from "vitest"; describe("TextureSheetAnimation Test", () => { - let engine: WebGLEngine; - let scene: Scene; - let renderer: ParticleRenderer; - - beforeAll(async function () { - engine = await WebGLEngine.create({ - canvas: document.createElement("canvas") - }); - - scene = engine.sceneManager.activeScene; - const rootEntity = scene.createRootEntity("root"); - - const cameraEntity = rootEntity.createChild("Camera"); - cameraEntity.addComponent(Camera); - cameraEntity.transform.setPosition(0, 0, 10); - - renderer = scene.createRootEntity("Renderer").addComponent(ParticleRenderer); - engine.run(); - }); - it("Tiling", () => { - const textureSheetAnimation = renderer.generator.textureSheetAnimation; - textureSheetAnimation.tiling = new Vector2(2, 2); - expect(textureSheetAnimation.tiling).to.deep.include({ x: 2, y: 2 }); - // @ts-ignore - expect(textureSheetAnimation._tillingInfo).to.deep.include({ x: 0.5, y: 0.5, z: 4 }); + let engine: WebGLEngine; + let scene: Scene; + let renderer: ParticleRenderer; - textureSheetAnimation.tiling.set(1, 1); - expect(textureSheetAnimation.tiling).to.deep.include({ x: 1, y: 1 }); - // @ts-ignore - expect(textureSheetAnimation._tillingInfo).to.deep.include({ x: 1, y: 1, z: 1 }); + beforeAll(async function () { + engine = await WebGLEngine.create({ + canvas: document.createElement("canvas") }); - it("Clone", () => { - const textureSheetAnimation = renderer.generator.textureSheetAnimation; - textureSheetAnimation.tiling = new Vector2(4, 4); - const cloneTextureSheetAnimation = renderer.entity.clone().getComponent(ParticleRenderer).generator.textureSheetAnimation; - expect(cloneTextureSheetAnimation.tiling).to.deep.include({ x: 4, y: 4 }); - // @ts-ignore - expect(cloneTextureSheetAnimation.tiling._onValueChanged).to.not.equal(textureSheetAnimation.tiling._onValueChanged); - // @ts-ignore - expect(cloneTextureSheetAnimation._tillingInfo).to.deep.include({ x: 0.25, y: 0.25, z: 16 }); - }) -}); \ No newline at end of file + scene = engine.sceneManager.activeScene; + const rootEntity = scene.createRootEntity("root"); + + const cameraEntity = rootEntity.createChild("Camera"); + cameraEntity.addComponent(Camera); + cameraEntity.transform.setPosition(0, 0, 10); + + renderer = scene.createRootEntity("Renderer").addComponent(ParticleRenderer); + engine.run(); + }); + it("Tiling", () => { + const textureSheetAnimation = renderer.generator.textureSheetAnimation; + textureSheetAnimation.tiling = new Vector2(2, 2); + expect(textureSheetAnimation.tiling).to.deep.include({ x: 2, y: 2 }); + // @ts-ignore + expect(textureSheetAnimation._tillingInfo).to.deep.include({ x: 0.5, y: 0.5, z: 4 }); + + textureSheetAnimation.tiling.set(1, 1); + expect(textureSheetAnimation.tiling).to.deep.include({ x: 1, y: 1 }); + // @ts-ignore + expect(textureSheetAnimation._tillingInfo).to.deep.include({ x: 1, y: 1, z: 1 }); + }); + + it("Clone", () => { + const textureSheetAnimation = renderer.generator.textureSheetAnimation; + textureSheetAnimation.tiling = new Vector2(4, 4); + const cloneTextureSheetAnimation = renderer.entity.clone().getComponent(ParticleRenderer) + .generator.textureSheetAnimation; + expect(cloneTextureSheetAnimation.tiling).to.deep.include({ x: 4, y: 4 }); + // @ts-ignore + expect(cloneTextureSheetAnimation.tiling._onValueChanged).to.not.equal( + textureSheetAnimation.tiling._onValueChanged + ); + // @ts-ignore + expect(cloneTextureSheetAnimation._tillingInfo).to.deep.include({ x: 0.25, y: 0.25, z: 16 }); + }); +}); diff --git a/tests/src/core/physics/MeshColliderShape.test.ts b/tests/src/core/physics/MeshColliderShape.test.ts index 3daa37ed94..9506569526 100644 --- a/tests/src/core/physics/MeshColliderShape.test.ts +++ b/tests/src/core/physics/MeshColliderShape.test.ts @@ -31,11 +31,7 @@ class CollisionScript extends Script { * @param indices - Optional triangle indices * @returns A ModelMesh with readable data */ -function createModelMesh( - engine: WebGLEngine, - positions: number[], - indices?: number[] -): ModelMesh { +function createModelMesh(engine: WebGLEngine, positions: number[], indices?: number[]): ModelMesh { const mesh = new ModelMesh(engine); const vec3Positions: Vector3[] = []; for (let i = 0; i < positions.length; i += 3) { @@ -107,11 +103,7 @@ describe("MeshColliderShape PhysX", () => { const meshShape = new MeshColliderShape(); const meshMaterial = meshShape.material; // Ground plane at y=0, CCW winding -> normal +Y - const mesh = createModelMesh( - engine, - [-10, 0, -10, 10, 0, -10, -10, 0, 10, 10, 0, 10], - [0, 2, 1, 1, 2, 3] - ); + const mesh = createModelMesh(engine, [-10, 0, -10, 10, 0, -10, -10, 0, 10, 10, 0, 10], [0, 2, 1, 1, 2, 3]); meshShape.mesh = mesh; groundCollider.addShape(meshShape); @@ -265,9 +257,10 @@ describe("MeshColliderShape PhysX", () => { const meshShape = new MeshColliderShape(); const meshMaterial = meshShape.material; meshShape.isConvex = true; - const mesh = createModelMesh(engine, [ - -1, -1, -1, 1, -1, -1, 1, 1, -1, -1, 1, -1, -1, -1, 1, 1, -1, 1, 1, 1, 1, -1, 1, 1 - ]); + const mesh = createModelMesh( + engine, + [-1, -1, -1, 1, -1, -1, 1, 1, -1, -1, 1, -1, -1, -1, 1, 1, -1, 1, 1, 1, 1, -1, 1, 1] + ); meshShape.mesh = mesh; meshShape.isTrigger = true; triggerCollider.addShape(meshShape); @@ -417,11 +410,7 @@ describe("MeshColliderShape PhysX", () => { staticCollider.addShape(meshShape); // Update mesh - const mesh2 = createModelMesh( - engine, - [0, 0, 0, 2, 0, 0, 0, 2, 0, 2, 0, 0, 2, 2, 0, 0, 2, 0], - [0, 1, 2, 3, 4, 5] - ); + const mesh2 = createModelMesh(engine, [0, 0, 0, 2, 0, 0, 0, 2, 0, 2, 0, 0, 2, 2, 0, 0, 2, 0], [0, 1, 2, 3, 4, 5]); meshShape.mesh = mesh2; expect(staticCollider.shapes.length).toBe(1); @@ -695,11 +684,7 @@ describe("MeshColliderShape PhysX", () => { expect(meshShape._nativeShape).toBeNull(); // Re-enable with new mesh - const mesh2 = createModelMesh( - engine, - [0, 0, 0, 2, 0, 0, 0, 2, 0, 2, 0, 0, 2, 2, 0, 0, 2, 0], - [0, 1, 2, 3, 4, 5] - ); + const mesh2 = createModelMesh(engine, [0, 0, 0, 2, 0, 0, 0, 2, 0, 2, 0, 0, 2, 2, 0, 0, 2, 0], [0, 1, 2, 3, 4, 5]); meshShape.mesh = mesh2; // @ts-ignore expect(meshShape._nativeShape).not.toBeNull(); diff --git a/tests/src/core/physics/PhysicsScene.test.ts b/tests/src/core/physics/PhysicsScene.test.ts index d514abf337..bc215b1315 100644 --- a/tests/src/core/physics/PhysicsScene.test.ts +++ b/tests/src/core/physics/PhysicsScene.test.ts @@ -748,18 +748,11 @@ describe("Physics Test", () => { const halfExtents = new Vector3(0.5, 0.5, 0.5); const direction = new Vector3(0, 1, 0); const orientation = new Quaternion(0, 0, 0, 1); - nativeScene.boxCast( - sweepCenter, - orientation, - halfExtents, - direction, - 100, - (sweepUuid: number) => { - innerSweepCalls++; - innerSweepUuids.push(sweepUuid); - return false; // skip everything in inner sweep - } - ); + nativeScene.boxCast(sweepCenter, orientation, halfExtents, direction, 100, (sweepUuid: number) => { + innerSweepCalls++; + innerSweepUuids.push(sweepUuid); + return false; // skip everything in inner sweep + }); return uuid === shapeA.id; }, outerHitFn diff --git a/tests/src/core/resource/ResourceManager.test.ts b/tests/src/core/resource/ResourceManager.test.ts index 54d058a4f0..61c62d7319 100644 --- a/tests/src/core/resource/ResourceManager.test.ts +++ b/tests/src/core/resource/ResourceManager.test.ts @@ -78,7 +78,6 @@ describe("ResourceManager", () => { }); }); - describe("load asset", () => { it("not found", async () => { try { diff --git a/tests/src/loader/GLTFLoader.test.ts b/tests/src/loader/GLTFLoader.test.ts index 6ad52fc919..08201a400f 100644 --- a/tests/src/loader/GLTFLoader.test.ts +++ b/tests/src/loader/GLTFLoader.test.ts @@ -393,7 +393,7 @@ beforeAll(async function () { afterAll(() => { @registerGLTFParser(GLTFParserType.Schema) - class test extends GLTFSchemaParser { } + class test extends GLTFSchemaParser {} }); describe("glTF Loader test", function () { diff --git a/tests/src/loader/PrefabResource.test.ts b/tests/src/loader/PrefabResource.test.ts index cc0636e1e9..24088c2932 100644 --- a/tests/src/loader/PrefabResource.test.ts +++ b/tests/src/loader/PrefabResource.test.ts @@ -546,7 +546,15 @@ describe("Prefab instance overrides", () => { instance: { asset: 0, overrides: { - removedComponents: [{ path: [], selectors: [{ type: "MeshRenderer", index: 0 }, { type: "MeshRenderer", index: 2 }] }] + removedComponents: [ + { + path: [], + selectors: [ + { type: "MeshRenderer", index: 0 }, + { type: "MeshRenderer", index: 2 } + ] + } + ] } } } @@ -760,10 +768,7 @@ describe("Cross-prefab $component ref", () => { const outerPrefabData: PrefabFile = { version: "2.0", refs: [{ url: "deep-entity-nested.prefab" }], - entities: [ - { name: "outerRoot", children: [1], components: [0] }, - { instance: { asset: 0 } } - ], + entities: [{ name: "outerRoot", children: [1], components: [0] }, { instance: { asset: 0 } }], components: [ { type: "EntityRefScript", @@ -809,10 +814,7 @@ describe("Cross-prefab $component ref", () => { const outerPrefabData: PrefabFile = { version: "2.0", refs: [{ url: "deep-comp-nested.prefab" }], - entities: [ - { name: "outerRoot", children: [1], components: [0] }, - { instance: { asset: 0 } } - ], + entities: [{ name: "outerRoot", children: [1], components: [0] }, { instance: { asset: 0 } }], components: [ { type: "DiceScript", diff --git a/tests/src/loader/RenderTargetLoader.test.ts b/tests/src/loader/RenderTargetLoader.test.ts index 543f33e91c..805c791392 100644 --- a/tests/src/loader/RenderTargetLoader.test.ts +++ b/tests/src/loader/RenderTargetLoader.test.ts @@ -67,14 +67,16 @@ describe("RenderTargetLoader", () => { depthFormat: TextureFormat.Depth, antiAliasing: 1, autoGenerateMipmaps: false, - colorTextures: [{ - mipmap: false, - isSRGBColorSpace: true, - filterMode: 1, - wrapModeU: 1, - wrapModeV: 1, - anisoLevel: 4 - }] + colorTextures: [ + { + mipmap: false, + isSRGBColorSpace: true, + filterMode: 1, + wrapModeU: 1, + wrapModeV: 1, + anisoLevel: 4 + } + ] }); const rt = await engine.resourceManager.load({ url, type: AssetType.RenderTarget }); diff --git a/tests/src/rhi-webgl/GLRenderTarget.test.ts b/tests/src/rhi-webgl/GLRenderTarget.test.ts index 1f4a0be195..51940d5e13 100644 --- a/tests/src/rhi-webgl/GLRenderTarget.test.ts +++ b/tests/src/rhi-webgl/GLRenderTarget.test.ts @@ -41,5 +41,4 @@ describe("GLRenderTarget", () => { renderTarget.destroy(); }); }); - }); diff --git a/tests/src/shader-compiler/PrecompileABTest.test.ts b/tests/src/shader-compiler/PrecompileABTest.test.ts index 03b9c0a677..f9269fd9ca 100644 --- a/tests/src/shader-compiler/PrecompileABTest.test.ts +++ b/tests/src/shader-compiler/PrecompileABTest.test.ts @@ -10,7 +10,14 @@ * 6. Full .shaderc round-trip: JSON stringify → parse → create ShaderPass → WebGL compile */ -import { Shader, ShaderFactory, ShaderLanguage, ShaderMacro, ShaderMacroCollection, ShaderPass } from "@galacean/engine-core"; +import { + Shader, + ShaderFactory, + ShaderLanguage, + ShaderMacro, + ShaderMacroCollection, + ShaderPass +} from "@galacean/engine-core"; import { ShaderCompiler } from "@galacean/engine-shader-compiler"; import { ShaderMacroProcessor } from "@galacean/engine-core/src/shader/ShaderMacroProcessor"; @@ -111,7 +118,6 @@ describe("Precompile A/B Test: Live vs Precompiled", async () => { // @ts-ignore Shader._shaderCompiler = shaderCompiler; - // ═══════════════════════════════════════════════════════════ // A/B 1: GLSL Source Identity // ═══════════════════════════════════════════════════════════ @@ -201,7 +207,7 @@ describe("Precompile A/B Test: Live vs Precompiled", async () => { ); // @ts-ignore - const program = shaderPass._getCanonicalShaderProgram(engine, macroCollection); + const program = shaderPass._compileShaderProgram(engine, macroCollection); expect(program.isValid, `Pass "${pass.name}" should compile to valid WebGL`).toBe(true); } } @@ -319,7 +325,7 @@ describe("Precompile A/B Test: Live vs Precompiled", async () => { ); // @ts-ignore - const program = shaderPass._getCanonicalShaderProgram(engine, macroCollection); + const program = shaderPass._compileShaderProgram(engine, macroCollection); expect(program.isValid, `.shaderc round-trip pass "${pass.name}" should compile`).toBe(true); } } @@ -537,7 +543,7 @@ describe("Precompile A/B Test: Live vs Precompiled", async () => { pass.tags ); // @ts-ignore - const program = shaderPass._getCanonicalShaderProgram(engine, macroCollection); + const program = shaderPass._compileShaderProgram(engine, macroCollection); expect(program.isValid).toBe(true); } } @@ -567,7 +573,7 @@ describe("Precompile A/B Test: Live vs Precompiled", async () => { pass.tags ); // @ts-ignore - const program = shaderPass._getCanonicalShaderProgram(engine, macroCollection); + const program = shaderPass._compileShaderProgram(engine, macroCollection); expect(program.isValid).toBe(true); } } diff --git a/tests/src/shader-compiler/PrecompileBenchmark.test.ts b/tests/src/shader-compiler/PrecompileBenchmark.test.ts index 5c46413bbd..00f67d4ab0 100644 --- a/tests/src/shader-compiler/PrecompileBenchmark.test.ts +++ b/tests/src/shader-compiler/PrecompileBenchmark.test.ts @@ -2,7 +2,14 @@ * Precompile Benchmark — performance comparison between old and new paths */ -import { Shader, ShaderFactory, ShaderLanguage, ShaderMacro, ShaderMacroCollection, ShaderPass } from "@galacean/engine-core"; +import { + Shader, + ShaderFactory, + ShaderLanguage, + ShaderMacro, + ShaderMacroCollection, + ShaderPass +} from "@galacean/engine-core"; import { ShaderProgram } from "@galacean/engine-core/src/shader/ShaderProgram"; import type { ShaderInstruction } from "@galacean/engine-design"; import { ShaderCompiler } from "@galacean/engine-shader-compiler"; @@ -366,5 +373,4 @@ describe("Precompile Benchmark", async () => { console.log(`\nRuntime evaluator: ${rtResult.avg.toFixed(3)}ms avg`); }); }); - }); diff --git a/tests/src/shader-compiler/ShaderValidate.ts b/tests/src/shader-compiler/ShaderValidate.ts index 3522f30f9c..cbe34aa730 100644 --- a/tests/src/shader-compiler/ShaderValidate.ts +++ b/tests/src/shader-compiler/ShaderValidate.ts @@ -1,4 +1,12 @@ -import { Engine, Shader, ShaderFactory, ShaderMacro, ShaderMacroCollection, ShaderPass, ShaderLanguage } from "@galacean/engine-core"; +import { + Engine, + Shader, + ShaderFactory, + ShaderMacro, + ShaderMacroCollection, + ShaderPass, + ShaderLanguage +} from "@galacean/engine-core"; import { ShaderCompiler } from "@galacean/engine-shader-compiler"; import { expect } from "vitest"; @@ -64,7 +72,7 @@ export function glslValidate( }); // @ts-ignore - const shaderProgram = shaderPass._getCanonicalShaderProgram(engine, macroMockCollection); + const shaderProgram = shaderPass._compileShaderProgram(engine, macroMockCollection); expect(shaderProgram.isValid).to.be.true; }); }); diff --git a/tests/src/ui/UIBatchSorter.test.ts b/tests/src/ui/UIBatchSorter.test.ts new file mode 100644 index 0000000000..a5cd3b9b71 --- /dev/null +++ b/tests/src/ui/UIBatchSorter.test.ts @@ -0,0 +1,180 @@ +import { UIBatchSorter } from "@galacean/engine-ui/src/component/UIBatchSorter"; +import { BoundingBox, Matrix, Quaternion, Vector3 } from "@galacean/engine-math"; +import { describe, expect, it } from "vitest"; + +function rect(minX: number, minY: number, maxX: number, maxY: number): BoundingBox { + return new BoundingBox(new Vector3(minX, minY, 0), new Vector3(maxX, maxY, 0)); +} + +function fakeElement(materialId: number, textureId: number | null, bounds: BoundingBox): any { + return { + component: { bounds }, + material: { instanceId: materialId }, + texture: textureId === null ? null : { instanceId: textureId } + }; +} + +const identity = new Matrix(); + +function countBatches(elements: any[]): number { + if (elements.length === 0) return 0; + let batches = 1; + for (let i = 1; i < elements.length; i++) { + const a = elements[i - 1]; + const b = elements[i]; + const at = a.texture ? a.texture.instanceId : 0; + const bt = b.texture ? b.texture.instanceId : 0; + if (a.material.instanceId !== b.material.instanceId || at !== bt) batches++; + } + return batches; +} + +describe("UIBatchSorter", () => { + it("empty input is a no-op", () => { + const elements: any[] = []; + expect(() => UIBatchSorter.sort(elements, identity, 200)).to.not.throw(); + expect(elements.length).to.equal(0); + }); + + it("single element is unchanged", () => { + const elements = [fakeElement(1, 1, rect(0, 0, 10, 10))]; + UIBatchSorter.sort(elements, identity, 200); + expect(elements.length).to.equal(1); + expect(elements[0].material.instanceId).to.equal(1); + }); + + it("non-overlapping interleaved buttons cluster by material", () => { + // 4 (bg, txt) buttons, non-overlapping → optimal: 2 batches (all bg, all txt) + const elements = [ + fakeElement(1, 1, rect(0, 0, 100, 100)), + fakeElement(2, 2, rect(10, 10, 90, 50)), + fakeElement(1, 1, rect(200, 0, 300, 100)), + fakeElement(2, 2, rect(210, 10, 290, 50)), + fakeElement(1, 1, rect(0, 200, 100, 300)), + fakeElement(2, 2, rect(10, 210, 90, 250)), + fakeElement(1, 1, rect(200, 200, 300, 300)), + fakeElement(2, 2, rect(210, 210, 290, 250)) + ]; + UIBatchSorter.sort(elements, identity, 200); + expect(countBatches(elements)).to.equal(2); + }); + + it("overlapping batch-compatible elements stay in one batch", () => { + const elements = [ + fakeElement(1, 1, rect(0, 0, 100, 100)), + fakeElement(1, 1, rect(50, 50, 150, 150)), + fakeElement(1, 1, rect(80, 80, 180, 180)) + ]; + UIBatchSorter.sort(elements, identity, 200); + expect(countBatches(elements)).to.equal(1); + }); + + it("identical-material overlap preserves hierarchy order", () => { + const e0 = fakeElement(1, 1, rect(0, 0, 100, 100)); + const e1 = fakeElement(1, 1, rect(0, 0, 100, 100)); + const e2 = fakeElement(1, 1, rect(0, 0, 100, 100)); + const elements = [e0, e1, e2]; + UIBatchSorter.sort(elements, identity, 200); + expect(elements).to.deep.equal([e0, e1, e2]); + }); + + it("incompatible overlap forces strict hierarchy order", () => { + const e0 = fakeElement(1, 1, rect(0, 0, 100, 100)); + const e1 = fakeElement(2, 2, rect(0, 0, 100, 100)); + const e2 = fakeElement(3, 3, rect(0, 0, 100, 100)); + const elements = [e0, e1, e2]; + UIBatchSorter.sort(elements, identity, 200); + expect(elements).to.deep.equal([e0, e1, e2]); + }); + + it("transitive overlap (A-B, B-C, A∩C=∅) keeps hierarchy", () => { + const e0 = fakeElement(1, 1, rect(0, 0, 100, 100)); + const e1 = fakeElement(2, 2, rect(50, 0, 150, 100)); + const e2 = fakeElement(3, 3, rect(120, 0, 220, 100)); + const elements = [e0, e1, e2]; + UIBatchSorter.sort(elements, identity, 200); + expect(elements).to.deep.equal([e0, e1, e2]); + expect(countBatches(elements)).to.equal(3); + }); + + it("isolated clusters batch independently", () => { + // (A,B) overlap at left, (C,D) overlap at right; A,C share material; B,D share material + const elements = [ + fakeElement(1, 1, rect(0, 0, 100, 100)), + fakeElement(2, 2, rect(0, 0, 100, 100)), + fakeElement(1, 1, rect(200, 0, 300, 100)), + fakeElement(2, 2, rect(200, 0, 300, 100)) + ]; + UIBatchSorter.sort(elements, identity, 200); + expect(countBatches(elements)).to.equal(2); + }); + + it("rect spanning multiple grid cells still detects overlap", () => { + // canvasLongestEdge=200 → gridSize=20; A (400×400) spans 20×20 cells + const elements = [fakeElement(1, 1, rect(0, 0, 400, 400)), fakeElement(2, 2, rect(200, 200, 300, 300))]; + UIBatchSorter.sort(elements, identity, 200); + expect(elements[0].material.instanceId).to.equal(1); + expect(elements[1].material.instanceId).to.equal(2); + }); + + it("complex 2x3 button grid yields 2 batches", () => { + const elements: any[] = []; + for (let r = 0; r < 2; r++) { + for (let c = 0; c < 3; c++) { + const x = c * 200; + const y = r * 200; + elements.push(fakeElement(1, 1, rect(x, y, x + 100, y + 100))); + elements.push(fakeElement(2, 2, rect(x + 10, y + 10, x + 90, y + 50))); + } + } + UIBatchSorter.sort(elements, identity, 200); + expect(countBatches(elements)).to.equal(2); + }); + + it("rotated canvas: world AABBs reduce to canvas-local for precise overlap", () => { + // Inflated world AABBs of a rotated canvas would falsely overlap; canvas-local recovers truth + const cosA = Math.cos(Math.PI / 6); + const sinA = Math.sin(Math.PI / 6); + const worldRectFromLocal = (lx0: number, ly0: number, lx1: number, ly1: number): BoundingBox => { + const xs = [lx0, lx1, lx0, lx1]; + const ys = [ly0, ly0, ly1, ly1]; + let minX = Infinity, + maxX = -Infinity, + minY = Infinity, + maxY = -Infinity; + for (let k = 0; k < 4; k++) { + const wx = xs[k] * cosA - ys[k] * sinA; + const wy = xs[k] * sinA + ys[k] * cosA; + if (wx < minX) minX = wx; + if (wx > maxX) maxX = wx; + if (wy < minY) minY = wy; + if (wy > maxY) maxY = wy; + } + return new BoundingBox(new Vector3(minX, minY, 0), new Vector3(maxX, maxY, 0)); + }; + + const elements: any[] = []; + for (let r = 0; r < 2; r++) { + for (let c = 0; c < 3; c++) { + const x = c * 200; + const y = r * 200; + elements.push(fakeElement(1, 1, worldRectFromLocal(x, y, x + 100, y + 100))); + elements.push(fakeElement(2, 2, worldRectFromLocal(x + 10, y + 10, x + 90, y + 50))); + } + } + + const canvasWorldMatrix = new Matrix(); + const q = new Quaternion(); + Quaternion.rotationAxisAngle(new Vector3(0, 0, 1), Math.PI / 6, q); + Matrix.affineTransformation(new Vector3(1, 1, 1), q, new Vector3(0, 0, 0), canvasWorldMatrix); + + UIBatchSorter.sort(elements, canvasWorldMatrix, 200); + expect(countBatches(elements)).to.equal(2); + }); + + it("missing texture treated as id 0", () => { + const elements = [fakeElement(1, null, rect(0, 0, 50, 50)), fakeElement(1, null, rect(100, 0, 150, 50))]; + expect(() => UIBatchSorter.sort(elements, identity, 200)).to.not.throw(); + expect(countBatches(elements)).to.equal(1); + }); +}); diff --git a/tests/src/ui/UICanvas.test.ts b/tests/src/ui/UICanvas.test.ts index d9eca198d6..aa8f70e866 100644 --- a/tests/src/ui/UICanvas.test.ts +++ b/tests/src/ui/UICanvas.test.ts @@ -294,7 +294,7 @@ describe("UICanvas", async () => { // @ts-ignore expect(cloneCanvas._isRootCanvas).to.eq(true); - const cameraNeedClone = canvasEntity.createChild('camera').addComponent(Camera); + const cameraNeedClone = canvasEntity.createChild("camera").addComponent(Camera); rootCanvas.renderCamera = cameraNeedClone; const anoCloneEntity = canvasEntity.clone(); const anoCloneCanvas = anoCloneEntity.getComponent(UICanvas); diff --git a/tests/src/ui/UIEvent.test.ts b/tests/src/ui/UIEvent.test.ts index 4630ce25ed..982173e0a2 100644 --- a/tests/src/ui/UIEvent.test.ts +++ b/tests/src/ui/UIEvent.test.ts @@ -129,7 +129,6 @@ describe("UIEvent", async () => { target.dispatchEvent(generatePointerEvent("pointermove", 2, left + 5, top + 5)); engine.update(); - expect(script1.enterCount).toBe(1); expect(script1.exitCount).toBe(0); expect(script1.downCount).toBe(1); @@ -160,11 +159,9 @@ describe("UIEvent", async () => { expect(script3.upCount).toBe(0); expect(script3.dropCount).toBe(0); - target.dispatchEvent(generatePointerEvent("pointermove", 2, left + 5, top + 5)); engine.update(); - expect(script1.enterCount).toBe(1); expect(script1.exitCount).toBe(0); expect(script1.downCount).toBe(1); diff --git a/tests/src/ui/UIInteractive.test.ts b/tests/src/ui/UIInteractive.test.ts index 646cd19e3a..3889666fd8 100644 --- a/tests/src/ui/UIInteractive.test.ts +++ b/tests/src/ui/UIInteractive.test.ts @@ -1,7 +1,16 @@ import { Camera, PointerEventData, Script, SpriteDrawMode } from "@galacean/engine-core"; import { Color, Vector3 } from "@galacean/engine-math"; import { WebGLEngine } from "@galacean/engine"; -import { Button, ColorTransition, Image, ScaleTransition, Text, UICanvas, UIGroup, UITransform } from "@galacean/engine-ui"; +import { + Button, + ColorTransition, + Image, + ScaleTransition, + Text, + UICanvas, + UIGroup, + UITransform +} from "@galacean/engine-ui"; import { describe, expect, it, vi } from "vitest"; class ClickHandler extends Script { @@ -40,7 +49,7 @@ describe("Button", async () => { const canvasEntity = root.createChild("canvas"); canvasEntity.addComponent(UIGroup); - const commonTextEntity = canvasEntity.createChild("commonText") + const commonTextEntity = canvasEntity.createChild("commonText"); const commonText = commonTextEntity.addComponent(Text); // Create button @@ -55,7 +64,6 @@ describe("Button", async () => { text.color.set(0, 0, 0, 1); const button = buttonEntity.addComponent(Button); - it("Set and Get", () => { // Click let clickCount = 0; @@ -135,7 +143,7 @@ describe("Button", async () => { const cloneButton = cloneButtonEntity.getComponent(Button); const cloneTransitions = cloneButton.transitions; const cloneTransition = cloneTransitions[0]; - expect(cloneTransition.target).to.eq(cloneButtonEntity.getComponent(Image)) + expect(cloneTransition.target).to.eq(cloneButtonEntity.getComponent(Image)); const cloneTransitionOne = cloneTransitions[1]; expect(cloneTransitionOne.target).to.eq(cloneButtonEntity.findByName("Text").getComponent(Text));