From 0b6cf9aae4ae0fdd708e522126a5fc5babae306b Mon Sep 17 00:00:00 2001 From: Dmitrii Zolotov Date: Sat, 3 Oct 2026 09:41:37 +0300 Subject: [PATCH 01/34] fix: Keep a tipped liquid inside its glass, and colour its drops A tipped tube's liquid stood out through the glass along its long sides: its meniscus was the upright tube's, by distance from the axis, lifted straight up off a wall that leans. Tipped, the meniscus is now the flat wall's, by distance from the glass and with its mean taken out so it adds no liquid, and the liquid mesh keeps every lifted point inside the vessel. Drops are drawn the colour of what is dissolved in them, rather than near white, and as spheres of forty-two points. --- ARCHITECTURE.md | 2 +- README.md | 2 +- packages/education/chemlab/lib/src/bench.dart | 16 ++- .../education/chemlab/test/goldens/bench.png | Bin 1936077 -> 1936077 bytes .../lib/src/geometry/liquid_shapes.dart | 110 +++++++++++------- .../test/geometry/liquid_shapes_test.dart | 48 +++++++- .../lib/src/fluid/free_surface.dart | 16 +++ .../lib/src/fluid/liquid_body.dart | 49 +++++++- .../lib/src/fluid/particle_fluid.dart | 11 ++ .../test/fluid/mixture_test.dart | 6 +- site/content/quickstart.md | 2 +- site/content/reference/testing.md | 8 +- 12 files changed, 209 insertions(+), 61 deletions(-) diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 2627251b2..fde253cc2 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -2691,7 +2691,7 @@ storage. |---|---| | Style | `dart format` | | Analysis | `flutter analyze` clean across the workspace, no warnings | -| Unit tests | **11340 tests** across 43 packages and 10 applications | +| Unit tests | **11341 tests** across 43 packages and 10 applications | | Structure rules | 35, `dart run tool/structure.dart`, the first CI step | | CI | GitHub Actions over `tool/ci.sh`, on `ubuntu-latest`, with no graphics card | diff --git a/README.md b/README.md index d468a8dd9..8cdb4b03d 100644 --- a/README.md +++ b/README.md @@ -158,7 +158,7 @@ Or one package at a time: (cd packages/flutter3d_physics && dart test) # plain Dart, no Flutter needed ``` -There are 11340 tests across forty-three packages and nine applications. The +There are 11341 tests across forty-three packages and nine applications. The only ones that need a GPU are the Impeller half of the golden set. The other half is rendered by the software backend, which is what makes 90 scenes checkable in a headless run. diff --git a/packages/education/chemlab/lib/src/bench.dart b/packages/education/chemlab/lib/src/bench.dart index 504820e26..1aa825b62 100644 --- a/packages/education/chemlab/lib/src/bench.dart +++ b/packages/education/chemlab/lib/src/bench.dart @@ -439,9 +439,11 @@ final class Bench { /// The colour of [layer]: light through [fade] of it, every dye in it /// taking its share by Beer and Lambert. - Color colourOf(LiquidLayer layer) { + Color colourOf(LiquidLayer layer) => _colourOf(layer.concentrations); + + Color _colourOf(Map concentrations) { final absorb = Vector3.zero(); - layer.concentrations.forEach((dye, c) { + concentrations.forEach((dye, c) { final mu = _dyes[dye]; if (mu != null) absorb.addScaled(mu, c); }); @@ -833,6 +835,7 @@ final class Bench { /// The streams drawn, one per pouring vessel, and the drops. final Map _streams = {}; final Map _drops = {}; + final Map _dropColours = {}; /// Moves everything on by [seconds], and says whether anything still /// moves, so the caller knows to ask for another frame. @@ -974,15 +977,22 @@ final class Bench { node.visible = mesh.triangleCount > 0; }); world.particles.forEach((medium, fluid) { + // The colour of what is in them, as a solution's is: the drops off + // a pour of copper sulphate are blue, not the near white they were. + final colour = _colourOf(fluid.concentrations); final node = _drops.putIfAbsent(medium, () { final made = MeshNode( _upload(particleMesh(const [], 0.0005)), - liquid(Vector3(0.9, 0.95, 1.0), depth: 0.001), + liquid(_rgb(colour), depth: 2.0 * fluid.spacing), name: 'drops', )..castsShadow = false; scene.add(made); return made; }); + if (_dropColours[medium] != colour) { + _dropColours[medium] = colour; + node.material = liquid(_rgb(colour), depth: 2.0 * fluid.spacing); + } if (fluid.count > 0) any = true; _swap(node, particleMesh(fluid.positions, 0.5 * fluid.spacing)); node.visible = fluid.count > 0; diff --git a/packages/education/chemlab/test/goldens/bench.png b/packages/education/chemlab/test/goldens/bench.png index fa03e0669c0563e7ad6cb998a542a09762f3d69b..80bc35ea40f91d57056dc4bf72a06890898118ce 100644 GIT binary patch delta 7604 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 delta 8034 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 UHFoxY(a(Ete=xcDttIjQ2A|gca{vGU diff --git a/packages/flutter3d_core/lib/src/geometry/liquid_shapes.dart b/packages/flutter3d_core/lib/src/geometry/liquid_shapes.dart index cba50af59..28551c745 100644 --- a/packages/flutter3d_core/lib/src/geometry/liquid_shapes.dart +++ b/packages/flutter3d_core/lib/src/geometry/liquid_shapes.dart @@ -151,6 +151,15 @@ MeshData _layer({ final bottomCut = >[]; // How far the surface stands off the top plane over a point on it. double lift(Vector3 p) => surface ? body.surfaceAt(p) - upper : 0.0; + // Lifted along up, a point on a wall that leans is lifted off it: kept a + // hair inside the glass instead. + Vector3 within(Vector3 p) { + final shape = body.shape; + if (shape is! RevolvedVessel) return p; + final at = shape.wallDistance(p); + if (at == null || at.distance < -1e-5) return p; + return p - at.normal * (at.distance + 1e-5); + } List<_P> clip( List<_P> polygon, @@ -190,7 +199,7 @@ MeshData _layer({ // four nanometres out at six centimetres, and a test tighter than // that left the wall's edge behind the cap it should meet. (up.dot(v.p) - upper).abs() < 1e-6 - ? (p: v.p + up * lift(v.p), n: v.n) + ? (p: within(v.p + up * lift(v.p)), n: v.n) : v, ]; final first = builder.addVertex(position: lifted[0].p, normal: lifted[0].n); @@ -207,7 +216,16 @@ MeshData _layer({ previous = next; } } - _cap(builder, topCut, up, surface ? lift : null, body, upper, rings); + _cap( + builder, + topCut, + up, + surface ? lift : null, + body, + upper, + rings, + within: within, + ); if (lower.isFinite) { _cap(builder, bottomCut, -up, null, body, lower, 1); } @@ -223,14 +241,19 @@ void _cap( double Function(Vector3)? lift, LiquidBody body, double height, - int rings, -) { + int rings, { + Vector3 Function(Vector3)? within, +}) { if (segments.length < 3) return; final loops = _loops(segments); final helper = normal.x.abs() < 0.9 ? Vector3(1, 0, 0) : Vector3(0, 0, 1); final e1 = normal.cross(helper)..normalize(); final e2 = normal.cross(e1); - Vector3 raise(Vector3 p) => lift == null ? p : p + normal * lift(p); + Vector3 raise(Vector3 p) { + final up = lift == null ? p : p + normal * lift(p); + return within == null ? up : within(up); + } + Vector3 shade(Vector3 p) { if (lift == null) return normal; // The surface's slope, by central differences in the plane. @@ -471,11 +494,30 @@ MeshData jetMesh(Jet jet, {int sides = 14}) { return builder.build(); } -/// Particles drawn as small icosahedra of [radius] round [positions], in -/// the world. +/// Particles drawn as small spheres of [radius] round [positions], in the +/// world: an icosahedron split once, forty-two points, round enough at the +/// size of a drop that its outline does not show its faces as the twelve +/// points of a bare icosahedron did. MeshData particleMesh(List positions, double radius) { + final (points, faces) = _sphere; + final builder = MeshBuilder(VertexLayout.standard); + for (final centre in positions) { + final base = builder.vertexCount; + for (final v in points) { + builder.addVertex(position: centre + v * radius, normal: v); + } + for (final f in faces) { + builder.addTriangle(base + f.$1, base + f.$2, base + f.$3); + } + } + return builder.build(); +} + +/// A unit icosahedron split once: each face into four, the new points +/// pushed out onto the sphere. +final (List, List<(int, int, int)>) _sphere = () { const t = 1.618033988749895; - final ico = [ + final points = [ Vector3(-1, t, 0), Vector3(1, t, 0), Vector3(-1, -t, 0), @@ -489,37 +531,23 @@ MeshData particleMesh(List positions, double radius) { Vector3(-t, 0, -1), Vector3(-t, 0, 1), ].map((v) => v.normalized()).toList(); - const faces = >[ - [0, 11, 5], - [0, 5, 1], - [0, 1, 7], - [0, 7, 10], - [0, 10, 11], - [1, 5, 9], - [5, 11, 4], - [11, 10, 2], - [10, 7, 6], - [7, 1, 8], - [3, 9, 4], - [3, 4, 2], - [3, 2, 6], - [3, 6, 8], - [3, 8, 9], - [4, 9, 5], - [2, 4, 11], - [6, 2, 10], - [8, 6, 7], - [9, 8, 1], + const faces = <(int, int, int)>[ + (0, 11, 5), (0, 5, 1), (0, 1, 7), (0, 7, 10), (0, 10, 11), // + (1, 5, 9), (5, 11, 4), (11, 10, 2), (10, 7, 6), (7, 1, 8), // + (3, 9, 4), (3, 4, 2), (3, 2, 6), (3, 6, 8), (3, 8, 9), // + (4, 9, 5), (2, 4, 11), (6, 2, 10), (8, 6, 7), (9, 8, 1), ]; - final builder = MeshBuilder(VertexLayout.standard); - for (final centre in positions) { - final base = builder.vertexCount; - for (final v in ico) { - builder.addVertex(position: centre + v * radius, normal: v); - } - for (final f in faces) { - builder.addTriangle(base + f[0], base + f[1], base + f[2]); - } - } - return builder.build(); -} + final middles = <(int, int), int>{}; + int middle(int a, int b) => middles.putIfAbsent(a < b ? (a, b) : (b, a), () { + points.add((points[a] + points[b])..normalize()); + return points.length - 1; + }); + final split = [ + for (final (a, b, c) in faces) + ...() { + final ab = middle(a, b), bc = middle(b, c), ca = middle(c, a); + return [(a, ab, ca), (b, bc, ab), (c, ca, bc), (ab, bc, ca)]; + }(), + ]; + return (points, split); +}(); diff --git a/packages/flutter3d_core/test/geometry/liquid_shapes_test.dart b/packages/flutter3d_core/test/geometry/liquid_shapes_test.dart index dae3dbeff..3882fdcf7 100644 --- a/packages/flutter3d_core/test/geometry/liquid_shapes_test.dart +++ b/packages/flutter3d_core/test/geometry/liquid_shapes_test.dart @@ -43,12 +43,18 @@ MeshVessel _box(Vector3 size) { Vector3(xx, yy, zz), ]; const quads = >[ - [0, 1, 2, 3], [4, 7, 6, 5], - [0, 4, 5, 1], [1, 5, 6, 2], [2, 6, 7, 3], [3, 7, 4, 0], + [0, 1, 2, 3], + [4, 7, 6, 5], + [0, 4, 5, 1], + [1, 5, 6, 2], + [2, 6, 7, 3], + [3, 7, 4, 0], ]; return MeshVessel( positions: p, - indices: [for (final q in quads) ...[q[0], q[1], q[2], q[0], q[2], q[3]]], + indices: [ + for (final q in quads) ...[q[0], q[1], q[2], q[0], q[2], q[3]], + ], rim: [p[4], p[5], p[6], p[7]], ); } @@ -79,7 +85,10 @@ void main() { test('so does liquid in a vessel that is any mesh', () { final box = _box(Vector3(0.04, 0.05, 0.03)); final body = _body(box, 2e-5, turn: Matrix3.rotationZ(0.4)); - expect(_enclosed(liquidMeshes(body).single.mesh), closeTo(2e-5, 2e-5 * 0.01)); + expect( + _enclosed(liquidMeshes(body).single.mesh), + closeTo(2e-5, 2e-5 * 0.01), + ); }); test('oil on water is two meshes, each its own volume', () { @@ -110,7 +119,36 @@ void main() { } expect(jetMesh(jet).triangleCount, greaterThan(0)); final dots = particleMesh([Vector3.zero(), Vector3(1, 0, 0)], 0.001); - expect(dots.vertexCount, 24); + // Two spheres of forty-two points. + expect(dots.vertexCount, 84); expect(_enclosed(dots), greaterThan(0)); }); + + test('a tipped tube keeps its liquid inside its glass, meniscus and all', () { + // Mutation: lift the surface along up with the meniscus of the radius, + // as for a tube standing, and the long sides of a tipped tube's liquid + // stand out through the glass. + final tube = RevolvedVessel([ + for (var i = 0; i <= 8; i++) + Vector2( + 0.0075 * math.sin(i / 8 * math.pi / 2), + 0.0005 + 0.0075 * (1 - math.cos(i / 8 * math.pi / 2)), + ), + Vector2(0.0075, 0.09), + ]); + final body = _body(tube, 6e-6, turn: Matrix3.rotationX(1.2)); + for (final layer in liquidMeshes(body)) { + final mesh = layer.mesh; + final stride = mesh.layout.floatsPerVertex; + for (var i = 0; i < mesh.vertexCount; i++) { + final p = Vector3( + mesh.vertices[i * stride], + mesh.vertices[i * stride + 1], + mesh.vertices[i * stride + 2], + ); + final at = tube.wallDistance(p); + if (at != null) expect(at.distance, lessThan(2e-5), reason: '$p'); + } + } + }); } diff --git a/packages/flutter3d_physics/lib/src/fluid/free_surface.dart b/packages/flutter3d_physics/lib/src/fluid/free_surface.dart index dcd6a9378..52751d513 100644 --- a/packages/flutter3d_physics/lib/src/fluid/free_surface.dart +++ b/packages/flutter3d_physics/lib/src/fluid/free_surface.dart @@ -64,6 +64,22 @@ final class FreeSurface { /// The surface's area, square metres. double get area => _grid == null ? 0.0 : _grid!.count * _grid!.cell2; + /// [f] averaged over the surface as it is laid out, by its cells, and the + /// layout it was averaged over: what a caller keeps it by. + ({double mean, Object? layout}) meanOf(double Function(Vector3 point) f) { + final grid = _grid; + if (grid == null || grid.count == 0) return (mean: 0.0, layout: null); + var sum = 0.0; + for (var i = 0; i < grid.count; i++) { + sum += f(grid.point(i)); + } + return (mean: sum / grid.count, layout: grid); + } + + /// The layout the surface has now: a new object whenever it is laid out + /// again. + Object? get layout => _grid; + /// How much liquid the waves hold above the plane, cubic metres: nought, /// since no mode but the flat one has any, and that one is never kept. /// For a test to hold the surface to. diff --git a/packages/flutter3d_physics/lib/src/fluid/liquid_body.dart b/packages/flutter3d_physics/lib/src/fluid/liquid_body.dart index dc6a138de..3efd0f048 100644 --- a/packages/flutter3d_physics/lib/src/fluid/liquid_body.dart +++ b/packages/flutter3d_physics/lib/src/fluid/liquid_body.dart @@ -432,10 +432,19 @@ final class LiquidBody implements JetReceiver { /// How far the meniscus stands over [point] (vessel frame) above the flat /// surface of the same volume — up at a wall the liquid wets, down at one - /// it does not, nought on average. For a round vessel, the exact - /// Young–Laplace surface for its radius at the surface ([TubeMeniscus]); - /// for another, the flat wall's ([wallMeniscus]) by distance from it. + /// it does not. For a round vessel standing upright, the exact + /// Young–Laplace surface for its radius at the surface ([TubeMeniscus]), + /// nought on average. Tipped, the surface cuts the glass in a long oval + /// and is no longer a surface of revolution about anything: the flat + /// wall's ([wallMeniscus]) by how far [point] is from the glass. Measured + /// by the distance from the axis there, it climbed the long sides of a + /// tipped tube by the radius's meniscus and stood out through the glass. double meniscusAt(Vector3 point) { + final shape = this.shape; + if (shape is RevolvedVessel && _up.y < 0.999) { + if (volume <= 0.0) return 0.0; + return _wallRise(shape, point) - _tippedMean(shape); + } final m = _meniscus(); if (m == null) return 0.0; final r = math.sqrt(point.x * point.x + point.z * point.z); @@ -452,6 +461,38 @@ final class LiquidBody implements JetReceiver { /// How deep [point] (vessel frame) is under the surface. double depthAbove(Vector3 point) => height - _up.dot(point); + double _wallRise(RevolvedVessel shape, Vector3 point) { + final at = shape.wallDistance(point); + if (at == null) return 0.0; + return wallMeniscus(medium, math.max(-at.distance, 0.0), _g); + } + + /// The wall's meniscus averaged over a tipped surface, taken out of it so + /// that, like the upright one, it moves liquid about and adds none: left + /// in, a tube tipped half a radian drew a fortieth more than it held. + /// Kept until the surface is laid out again. + double _tippedMean(RevolvedVessel shape) { + final layout = surface.layout; + if (!identical(layout, _tippedFor) || _tippedG != _g) { + _tippedFor = layout; + _tippedG = _g; + _tipped = surface.meanOf((p) => _wallRise(shape, p)).mean; + } + return _tipped; + } + + Object? _tippedFor; + double _tippedG = double.nan; + double _tipped = 0.0; + + /// The most the meniscus stands above the flat surface anywhere. + double _meniscusPeak() => shape is RevolvedVessel && _up.y < 0.999 + ? math.max( + wallMeniscus(medium, 0.0, _g) - _tippedMean(shape as RevolvedVessel), + 0.0, + ) + : (_meniscus()?.peak ?? 0.0); + /// Menisci already solved, by the radius they were solved for, in steps of /// a hundredth of it; and the medium and gravity they were solved under. /// @@ -520,7 +561,7 @@ final class LiquidBody implements JetReceiver { // nothing to ask the rim. final edge = shape.lip(_up); if (edge != null && - height + surface.reach + (_meniscus()?.peak ?? 0.0) < edge.height) { + height + surface.reach + _meniscusPeak() < edge.height) { return Spill.none; } var flow = 0.0; diff --git a/packages/flutter3d_physics/lib/src/fluid/particle_fluid.dart b/packages/flutter3d_physics/lib/src/fluid/particle_fluid.dart index ccf8aaafc..79bd15d9b 100644 --- a/packages/flutter3d_physics/lib/src/fluid/particle_fluid.dart +++ b/packages/flutter3d_physics/lib/src/fluid/particle_fluid.dart @@ -137,6 +137,17 @@ final class ParticleFluid { /// Cubic metres here: every particle and the bank. double get volume => _x.length * particleVolume + _bank; + /// What is dissolved in the particles, as concentrations over all of + /// them: for drawing them the colour of what they are. + Map get concentrations { + if (_c.isEmpty) return const {}; + final sum = {}; + for (final c in _c) { + c.forEach((k, v) => sum[k] = (sum[k] ?? 0.0) + v); + } + return {for (final e in sum.entries) e.key: e.value / _c.length}; + } + /// Cubic metres handed to receivers so far. double get received => _received; diff --git a/packages/flutter3d_physics/test/fluid/mixture_test.dart b/packages/flutter3d_physics/test/fluid/mixture_test.dart index e4dc01c2c..0fd97c3d1 100644 --- a/packages/flutter3d_physics/test/fluid/mixture_test.dart +++ b/packages/flutter3d_physics/test/fluid/mixture_test.dart @@ -48,8 +48,12 @@ void main() { final body = _tube(FluidMedium.water, 5e-5); body.pour(2e-6, medium: FluidMedium.oil); var oil = 0.0, water = 0.0; + // Tipped well past where it starts to run: at 1.2 rad the glass came to + // rest at its lip with a film of oil still in it once the meniscus of a + // tipped surface was the wall's, so neither the order nor the amounts + // were what was being tested. for (var i = 0; i < 3000; i++) { - body.place(Matrix3.rotationX(1.2), Vector3.zero()); + body.place(Matrix3.rotationX(1.3), Vector3.zero()); final spill = body.step(1e-3, gravity: Vector3(0, -9.81, 0)); if (spill.medium.name == 'oil') oil += spill.flow * 1e-3; if (spill.medium.name == 'water') water += spill.flow * 1e-3; diff --git a/site/content/quickstart.md b/site/content/quickstart.md index 9dac63652..ba0875a52 100644 --- a/site/content/quickstart.md +++ b/site/content/quickstart.md @@ -91,7 +91,7 @@ tool/ci.sh # shaders, analyze, every test (cd packages/flutter3d_physics && dart test) # plain Dart, no Flutter needed ``` -There are 11340 tests across 43 packages and twelve applications, and only about thirty need a GPU: the Impeller half of the golden set. The other half renders through the software backend, so ninety scenes stay checkable in a headless run. +There are 11341 tests across 43 packages and twelve applications, and only about thirty need a GPU: the Impeller half of the golden set. The other half renders through the software backend, so ninety scenes stay checkable in a headless run. ## Your own application diff --git a/site/content/reference/testing.md b/site/content/reference/testing.md index d89d101c1..32f1f61d4 100644 --- a/site/content/reference/testing.md +++ b/site/content/reference/testing.md @@ -1,10 +1,10 @@ --- -description: Four independent golden sets, mutation-checking every new test, determinism and snapshots, and why only about thirty of 11340 tests need a GPU. +description: Four independent golden sets, mutation-checking every new test, determinism and snapshots, and why only about thirty of 11341 tests need a GPU. --- # Testing -11340 tests across 43 packages and nine applications, counted the same way the `the document says how many tests there are` rule does: a scan of every `test(`/`testWidgets(` call. The rule holds `ARCHITECTURE.md` §13, the README and this page to the answer. The README went on saying 1242 across thirteen packages for as long as nothing compared it with anything. About thirty need a GPU; the [architecture](/core/architecture/) is what keeps the number that low. +11341 tests across 43 packages and nine applications, counted the same way the `the document says how many tests there are` rule does: a scan of every `test(`/`testWidgets(` call. The rule holds `ARCHITECTURE.md` §13, the README and this page to the answer. The README went on saying 1242 across thirteen packages for as long as nothing compared it with anything. About thirty need a GPU; the [architecture](/core/architecture/) is what keeps the number that low. | Package | Tests | | Package | Tests | |---|---|---|---|---| @@ -12,7 +12,7 @@ description: Four independent golden sets, mutation-checking every new test, det | | | | `flutter3d_mesh` | 599 | | | | | `apps/flutter3d_modeler` | 1750 | | `flutter3d_sim` | 691 | | `pad_input` | 67 | -| `flutter3d_lab` | 15 | | `flutter3d_core` | 771 | +| `flutter3d_lab` | 15 | | `flutter3d_core` | 772 | | `flutter3d_lti` | 26 | | `apps/flutter3d_lab_pendulum` | 7 | | | | | `apps/flutter3d_lab_incident` | 13 | | `flutter3d_game_shooter` | 340 | | `flutter3d_audio_core` | 55 | @@ -40,7 +40,7 @@ description: Four independent golden sets, mutation-checking every new test, det | `flame_flutter3d` | 140 | | `apps/flutter3d_showcase` | 88 | | `flame_multiplayer` | 9 | | `flame_multiplayer_dashwire` | 3 | -The rows sum to 11313 rather than 11340: the remaining 26 live in `packages/*/example/test`, which the count includes and this table does not, among them the two seeds a new project starts from, `packages/flutter3d_app/example` and `packages/flutter3d_game/example`. +The rows sum to 11314 rather than 11341: the remaining 26 live in `packages/*/example/test`, which the count includes and this table does not, among them the two seeds a new project starts from, `packages/flutter3d_app/example` and `packages/flutter3d_game/example`. `flutter3d_samples` is not in the table and has no `test/` at all: it is test data with two path constants over it, and other packages' decoder tests are what exercise it. `flutter3d_conformance` is missing for a different reason: it is invoked as a script harness rather than through `flutter test`, so it does not surface in a grep of `test(` calls either. See below for what that cost once. From 35feb5141ecbcd0a4d80ef16e7e4c4156ba3e976 Mon Sep 17 00:00:00 2001 From: Dmitrii Zolotov Date: Sat, 3 Oct 2026 10:00:25 +0300 Subject: [PATCH 02/34] feat: Colour the solutions by what they absorb, and drops as drops MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Each labelled solution's colour now comes from Beer-Lambert with its molar absorption coefficients at about 610, 550 and 465 nm and the strength on its label, A = εcl, rather than from a swatch: permanganate at 0.02 mol/L is nearly opaque in a tube, copper sulphate a deep clear blue, dichromate orange, nickel chloride pale green, hydrochloric acid clear. Particles that touch are drawn as one drop of all their liquid, so a stream breaking up shows drops of its own size, not millimetre dots. --- packages/education/chemlab/lib/src/bench.dart | 98 +++++++++++++++++- .../education/chemlab/test/bench_test.dart | 17 ++- .../education/chemlab/test/goldens/bench.png | Bin 1936077 -> 1936077 bytes .../lib/src/geometry/liquid_shapes.dart | 14 ++- 4 files changed, 121 insertions(+), 8 deletions(-) diff --git a/packages/education/chemlab/lib/src/bench.dart b/packages/education/chemlab/lib/src/bench.dart index 1aa825b62..7b046a934 100644 --- a/packages/education/chemlab/lib/src/bench.dart +++ b/packages/education/chemlab/lib/src/bench.dart @@ -256,7 +256,9 @@ final class Bench { surfaceCells: 24, wallThickness: glassThickness, ); - if (!white) _dyes[vessel.name] = _absorbance(vessel.dye); + if (!white) { + _dyes[vessel.name] = _measured(vessel) ?? _absorbance(vessel.dye); + } world.bodies.add(vessel.liquid); vessel.shadow = MeshNode( @@ -428,10 +430,42 @@ final class Bench { // --------------------------------------------------------------- colour - /// Each dye's absorbance per metre at unit concentration: what makes it - /// its colour over [fade] of it. + /// Each dye's absorbance per metre at unit concentration — the strength + /// on its label. final Map _dyes = {}; + /// Molar absorption coefficients, L·mol⁻¹·cm⁻¹, of what the labelled + /// tubes hold, at about 610, 550 and 465 nm, where the eye's red, green + /// and blue lie: read off published spectra of the aqueous ions, good to + /// a few tens of percent, and enough to tell which solutions light goes + /// through and which it does not. Copper(II) absorbs the red end weakly + /// (its band peaks near 810 nm), permanganate the green very strongly + /// (peaks at 525 and 545 nm), dichromate the blue (450 nm), nickel(II) + /// little anywhere (395 and 720 nm), and hydrochloric acid nothing. + static const Map molarAbsorption = { + 'HCl': (0.0, 0.0, 0.0), + 'CuSO4': (4.5, 1.2, 0.2), + 'KMnO4': (150.0, 2300.0, 450.0), + 'K2Cr2O7': (0.2, 2.0, 250.0), + 'NiCl2': (1.1, 0.6, 0.8), + }; + + /// [vessel]'s absorbance per metre from [molarAbsorption] and the + /// strength on its label, A = εcl in base ten: null for glass with no + /// label or a solution not in the table. + static Vector3? _measured(Vessel vessel) { + final solution = vessel.solution; + final eps = molarAbsorption[vessel.name]; + if (solution == null || eps == null) return null; + final molar = double.tryParse(solution.note.split(' ').first); + if (molar == null) return null; + // ln 10 for base e, a hundred centimetres to the metre. + final k = math.ln10 * molar * 100.0; + return Vector3(eps.$1 * k, eps.$2 * k, eps.$3 * k); + } + + /// What makes [colour] the colour of [fade] of a liquid: for the glass + /// with no label, whose solution is only a colour. static Vector3 _absorbance(Color colour) { double mu(double c) => -math.log(c.clamp(1e-3, 1.0)) / fade; return Vector3(mu(colour.r), mu(colour.g), mu(colour.b)); @@ -994,12 +1028,68 @@ final class Bench { node.material = liquid(_rgb(colour), depth: 2.0 * fluid.spacing); } if (fluid.count > 0) any = true; - _swap(node, particleMesh(fluid.positions, 0.5 * fluid.spacing)); + final drops = _clusters(fluid.positions, fluid.spacing); + _swap( + node, + particleMesh( + [for (final d in drops) d.centre], + 0.0, + radii: [ + for (final d in drops) + math + .pow( + 3.0 * d.count * fluid.particleVolume / (4.0 * math.pi), + 1.0 / 3.0, + ) + .toDouble(), + ], + ), + ); node.visible = fluid.count > 0; }); return any; } + /// [positions] gathered into drops: particles nearer each other than + /// one and a half spacings are one drop, drawn as one sphere of all their + /// liquid. A stream that breaks into drops two and a third of its width + /// across was drawn as a scatter of millimetre dots, each a particle. + static List<({Vector3 centre, int count})> _clusters( + List positions, + double spacing, + ) { + final n = positions.length; + final parent = List.generate(n, (i) => i); + int root(int i) { + var r = i; + while (parent[r] != r) { + r = parent[r]; + } + return parent[i] = r; + } + + final reach2 = 2.25 * spacing * spacing; + for (var i = 0; i < n; i++) { + for (var j = i + 1; j < n; j++) { + if (positions[i].distanceToSquared(positions[j]) < reach2) { + parent[root(i)] = root(j); + } + } + } + final sums = {}; + for (var i = 0; i < n; i++) { + final r = root(i); + final s = sums[r]; + sums[r] = s == null + ? (sum: positions[i].clone(), count: 1) + : (sum: s.sum..add(positions[i]), count: s.count + 1); + } + return [ + for (final s in sums.values) + (centre: s.sum / s.count.toDouble(), count: s.count), + ]; + } + // -------------------------------------------------------------- shadows /// Who casts [vessel]'s shadow: the engine's photons, or this bench's card, diff --git a/packages/education/chemlab/test/bench_test.dart b/packages/education/chemlab/test/bench_test.dart index 0cafa5411..96b78a085 100644 --- a/packages/education/chemlab/test/bench_test.dart +++ b/packages/education/chemlab/test/bench_test.dart @@ -244,10 +244,25 @@ void main() { to.liquid.pour(1e-6, concentrations: {orange.name: 1.0}); final mixed = bench.colour(to); // Half of each: each dye's absorbance at half strength, added. - final expected = math.sqrt(blue.dye.r * orange.dye.r); + final expected = math.sqrt(bench.colour(blue).r * bench.colour(orange).r); expect(mixed.r, closeTo(expected, 0.01)); }); + test('a solution lets light through as its strength and absorption say', () { + // A = εcl: 0.02 mol/L permanganate takes nearly all the green out of + // three centimetres, 0.5 mol/L copper sulphate only half of the blue, + // and hydrochloric acid nothing. Mutation: colour them by the label's + // swatch instead, and every solution is equally see-through. + final kit = cpuTestDevice(width: 8, height: 8); + final bench = Bench(kit.device); + Vessel named(String n) => bench.vessels.firstWhere((v) => v.name == n); + expect(bench.colour(named('KMnO4')).g, lessThan(1e-3)); + expect(bench.colour(named('CuSO4')).b, greaterThan(0.4)); + expect(bench.colour(named('CuSO4')).r, lessThan(0.05)); + expect(bench.colour(named('K2Cr2O7')).b, lessThan(1e-3)); + expect(bench.colour(named('HCl')).r, closeTo(1.0, 1e-9)); + }); + test('a pour drawn at uneven frames still pours half', () { // A browser's frames are anything from a 90th to a 30th of a second. // Mutation: stamp the glass's place with the liquid's own clock, and diff --git a/packages/education/chemlab/test/goldens/bench.png b/packages/education/chemlab/test/goldens/bench.png index 80bc35ea40f91d57056dc4bf72a06890898118ce..91d368070bc74f26adc85581e958364b66f7a9bc 100644 GIT binary patch delta 169035 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 delta 169318 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 positions, double radius) { +/// +/// [radii], when given, is one radius a sphere, in place of [radius]. +MeshData particleMesh( + List positions, + double radius, { + List? radii, +}) { final (points, faces) = _sphere; final builder = MeshBuilder(VertexLayout.standard); - for (final centre in positions) { + for (var i = 0; i < positions.length; i++) { + final centre = positions[i]; + final r = radii?[i] ?? radius; final base = builder.vertexCount; for (final v in points) { - builder.addVertex(position: centre + v * radius, normal: v); + builder.addVertex(position: centre + v * r, normal: v); } for (final f in faces) { builder.addTriangle(base + f.$1, base + f.$2, base + f.$3); From 428251622b5f2540097be96b6317225f4efc6b15 Mon Sep 17 00:00:00 2001 From: Dmitrii Zolotov Date: Sat, 3 Oct 2026 10:03:50 +0300 Subject: [PATCH 03/34] fix: Mirror the glass in the tabletop; make its shadow as faint as glass The tabletop reflected the liquids and labels but not the glass round them, a choice made while the glass was nearly invisible. The glass's tint is what one surface lets through, and light crosses four surfaces of a tube: at 0.96 an empty tube's shadow let through seven tenths of the sun. It is nearly white now, and Fresnel alone darkens the shadow's edges. --- packages/education/chemlab/lib/src/bench.dart | 10 ++++++++++ .../education/chemlab/lib/src/glassware.dart | 14 +++++++++++--- .../education/chemlab/test/goldens/bench.png | Bin 1936077 -> 1936077 bytes site/content/education/chemlab.md | 3 +-- 4 files changed, 22 insertions(+), 5 deletions(-) diff --git a/packages/education/chemlab/lib/src/bench.dart b/packages/education/chemlab/lib/src/bench.dart index 7b046a934..c3c625404 100644 --- a/packages/education/chemlab/lib/src/bench.dart +++ b/packages/education/chemlab/lib/src/bench.dart @@ -286,6 +286,16 @@ final class Bench { ..receivesTranslucentShadows = false ..lightChannels = _vesselChannel, ); + // The glass in the tabletop too: it was left out while it was nearly + // invisible, and once it was not, the liquids stood in the mirror + // with nothing round them. + vessel.mirror.add( + _mirrored( + vessel.glassNode.mesh, + _reflection(albedo: null, colour: Vector3(0.995, 0.999, 0.997)), + vessel, + ), + ); final foot = vessel.foot; if (foot != null) { final hexagon = DeviceMesh.upload( diff --git a/packages/education/chemlab/lib/src/glassware.dart b/packages/education/chemlab/lib/src/glassware.dart index 257a6f238..f702c6081 100644 --- a/packages/education/chemlab/lib/src/glassware.dart +++ b/packages/education/chemlab/lib/src/glassware.dart @@ -178,9 +178,17 @@ Material glass() => Material( // what it does not reflect (see `g_pane` in the engine), so its alpha // weighs what it reflects and adds. At 0.22 an empty tube was a ghost; at // one, with every reflection whole, the glass read heavier than the - // liquids in it. Halfway is what the bench is lit with. The tint is - // laboratory glass's faint green-grey. - baseColor: Vector4(0.96, 0.985, 0.975, 0.55), + // liquids in it. Halfway is what the bench is lit with. + // + // **The tint is what one surface lets through, so it is nearly white.** + // Light crossing a tube meets four surfaces, in and out of each wall, and + // a shadow takes this colour at each; at a green-grey 0.96 that made an + // empty tube's shadow let through seven tenths of the sun, where a + // millimetre of laboratory glass absorbs next to nothing and loses about + // four percent to reflection at each surface, which the Fresnel term + // already counts: some 0.85 in all, and darker only at its edges, where + // the sun meets the glass edge-on. + baseColor: Vector4(0.995, 0.999, 0.997, 0.55), roughness: 0.03, alphaMode: MaterialAlphaMode.blend, doubleSided: true, diff --git a/packages/education/chemlab/test/goldens/bench.png b/packages/education/chemlab/test/goldens/bench.png index 91d368070bc74f26adc85581e958364b66f7a9bc..86ca3d5f47da1603bde031d76e1ce57cc204bcf8 100644 GIT binary patch literal 1936077 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

-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

waPK_m2IuZNBO>U-B&CgHo>H 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 I|M1WM0bK-|+5i9m literal 1936077 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

g@M5mD&T`80|GF9}`yNt(}(SA$e$C$S=qb$PdU5 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

Y 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 %(#hKl&y0WQ7hke)5L(lYWGh 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 W{_78a3jh86yMO%cKi_`; Date: Sat, 3 Oct 2026 10:34:57 +0300 Subject: [PATCH 04/34] fix: Lean and lift a glass smoothly, so a small lean spills nothing The tilt slider set a glass's lean at once, and its lift jumped by centimetres the frame a tipping glass first came over a neighbour. The liquid felt jolts of several g, its surface turned over, and a tube leaned a tenth of a radian further emptied itself in a step. The slider now asks for a lean; the hand eases towards it and lifts first, both with no jolt at the start or the end. Also pours briskly, so the stream is wide enough to reach the clean tube whole, and lets a tool read the bench's frames through ext.flutter3d.render. --- packages/education/chemlab/lib/main.dart | 8 +- packages/education/chemlab/lib/src/bench.dart | 144 +++++++++++++++--- .../education/chemlab/test/bench_test.dart | 20 +++ 3 files changed, 147 insertions(+), 25 deletions(-) diff --git a/packages/education/chemlab/lib/main.dart b/packages/education/chemlab/lib/main.dart index d1011d659..ed6b2ed03 100644 --- a/packages/education/chemlab/lib/main.dart +++ b/packages/education/chemlab/lib/main.dart @@ -119,6 +119,12 @@ class _BenchScreenState extends State @override void initState() { super.initState(); + // The frame the bench draws, pass by pass, for a tool attached to it + // (`ext.flutter3d.render.*`), as the games have it. + registerRenderExtensions( + () => _ready?.renderer, + timeout: const Duration(seconds: 20), + ); _open(); } @@ -312,7 +318,7 @@ class _Controls extends StatelessWidget { const Text('Tilt'), Expanded( child: Slider( - value: vessel.tilt.clamp( + value: vessel.leanTo.clamp( -bench.maxLean(vessel), bench.maxLean(vessel), ), diff --git a/packages/education/chemlab/lib/src/bench.dart b/packages/education/chemlab/lib/src/bench.dart index c3c625404..b0c20672c 100644 --- a/packages/education/chemlab/lib/src/bench.dart +++ b/packages/education/chemlab/lib/src/bench.dart @@ -62,6 +62,18 @@ final class Vessel { /// How far it leans, in radians, and about which horizontal axis. State. double tilt = 0.0; + + /// How far it is asked to lean, and how fast it is turning towards that: + /// [Bench.step] brings [tilt] round to it as a hand would. + double leanTo = 0.0; + double _turning = 0.0; + double _aim = 0.0; + + /// How high the hand holds it out of the row, and how fast that is + /// changing. + double _raised = 0.0; + double _rising = 0.0; + double _raiseAim = 0.0; Vector3 leanAxis = Vector3(1, 0, 0); /// How far it is lifted out of the row to lean, from nought, standing in @@ -547,14 +559,13 @@ final class Bench { /// footprint, its underside there has to clear that vessel's top by a /// millimetre. A vessel leaning away from its neighbours is hardly lifted; /// one leaning over a row of tubes goes over their mouths. - double _clearance(Vessel vessel) { - if (vessel.tilt == 0.0) return 0.0; + double _clearance(Vessel vessel, [double? at]) { + final tilt = at ?? vessel.tilt; + if (tilt == 0.0) return 0.0; final turn = Matrix3.zero() - ..setFrom( - Quaternion.axisAngle(vessel.leanAxis, vessel.tilt).asRotationMatrix(), - ); + ..setFrom(Quaternion.axisAngle(vessel.leanAxis, tilt).asRotationMatrix()); final top = vessel.glass.map((p) => p.y).reduce(math.max); - final sideways = math.sin(vessel.tilt).abs(); + final sideways = math.sin(tilt).abs(); var lowest = double.infinity; for (final p in [...vessel.glass, ...?vessel.foot]) { for (var k = 0; k < 24; k++) { @@ -595,25 +606,94 @@ final class Bench { /// the way the camera looks, so it leans in the picture — after lifting /// it out of the row ([step] lifts and lowers it). The glass turns at /// once; the liquid keeps level and follows late, as liquid does. + /// + /// **Asked, not set.** [step] turns the glass to [angle] as a hand would, + /// smoothly. Set at once, the glass jumped a frame's worth of lean and + /// lift, the liquid felt a jolt of several g, its surface turned over, and + /// a tube tipped by ten degrees emptied itself in one step. void lean(Vessel vessel, double angle, {Vector3? across}) { if (busy) return; final limit = maxLean(vessel); - vessel.tilt = angle.clamp(-limit, limit); - if (across != null) { + vessel.leanTo = angle.clamp(-limit, limit); + if (across != null && vessel.tilt == 0.0) { final flat = Vector3(across.x, 0, across.z); if (flat.length2 > 1e-9) vessel.leanAxis = flat..normalize(); } // One vessel in the hand: leaning this one puts the last one back. - if (vessel.tilt != 0.0) { + if (vessel.leanTo != 0.0) { for (final other in vessels) { - if (identical(other, vessel) || other.tilt == 0.0) continue; - other.tilt = 0.0; - _place(other); - _castBy(other); + if (!identical(other, vessel)) other.leanTo = 0.0; } } + } + + /// How quickly a hand brings a glass round to the lean asked of it: the + /// lean asked is first eased ([_aimRate]), and the glass turns towards + /// the eased aim critically damped ([_handRate]), so it gathers speed + /// from nothing and sheds it to nothing, a third of a second or so. + /// Turning straight at the lean asked, critically damped alone, it took + /// all its angular acceleration in the first instant; a tube asked for + /// 0.8 rad felt three metres a second squared at once and threw a third + /// of what it held over its lip. + static const double _aimRate = 6.0; + static const double _handRate = 8.0; + + /// Raises or lowers [vessel] towards [height] for [seconds], eased as a + /// turn is; says whether it moved. + bool _ease2(Vessel vessel, double height, double seconds) { + if (vessel._raised == height && + vessel._raiseAim == height && + vessel._rising == 0.0) { + return false; + } + final pieces = (seconds * 240).ceil().clamp(1, 32); + final dt = seconds / pieces; + for (var k = 0; k < pieces; k++) { + vessel._raiseAim += _aimRate * (height - vessel._raiseAim) * dt; + final pull = + _handRate * _handRate * (vessel._raiseAim - vessel._raised) - + 2.0 * _handRate * vessel._rising; + vessel._rising += pull * dt; + vessel._raised += vessel._rising * dt; + } + if ((height - vessel._raised).abs() < 1e-6 && vessel._rising.abs() < 1e-5) { + vessel + .._raised = height + .._raiseAim = height + .._rising = 0.0; + } + return true; + } + + /// Turns [vessel] towards [Vessel.leanTo] for [seconds]; says whether it + /// moved. + bool _turn(Vessel vessel, double seconds) { + if (vessel.tilt == vessel.leanTo && + vessel._aim == vessel.leanTo && + vessel._turning == 0.0) { + return false; + } + final wasUpright = vessel.tilt == 0.0; + final pieces = (seconds * 240).ceil().clamp(1, 32); + final dt = seconds / pieces; + for (var k = 0; k < pieces; k++) { + vessel._aim += _aimRate * (vessel.leanTo - vessel._aim) * dt; + final pull = + _handRate * _handRate * (vessel._aim - vessel.tilt) - + 2.0 * _handRate * vessel._turning; + vessel._turning += pull * dt; + vessel.tilt += vessel._turning * dt; + } + if ((vessel.leanTo - vessel.tilt).abs() < 1e-5 && + vessel._turning.abs() < 1e-4) { + vessel + ..tilt = vessel.leanTo + .._aim = vessel.leanTo + .._turning = 0.0; + } _place(vessel); - _castBy(vessel); + if (wasUpright != (vessel.tilt == 0.0)) _castBy(vessel); + return true; } /// Puts [vessel]'s glass where its lean and lift say: turned about its @@ -632,7 +712,7 @@ final class Bench { lowest = math.min(lowest, turned.y); } } - final lift = _ease(vessel.lift) * _clearance(vessel); + final lift = vessel._raised; final y = vessel.at.y - lowest + lift; vessel.body ..setRotation(turn) @@ -704,6 +784,9 @@ final class Bench { : Vector3(1, 0, 0); from ..tilt = 0.0 + ..leanTo = 0.0 + .._aim = 0.0 + .._turning = 0.0 ..lift = 0.0 ..leanAxis = axis; _transfer = _Transfer( @@ -717,10 +800,17 @@ final class Bench { } /// How long each part of a pour takes: up, over, and back; the pour - /// itself is as long as the hand takes, about two seconds. + /// itself is as long as the hand takes, about a second. + /// + /// **Briskly, as a chemist pours half a tube.** Over two seconds the + /// stream ran a millimetre across, and a thread that thin parts into + /// drops some forty widths down, about five centimetres: the clean tube + /// filled by dripping. At four times the flow the stream is twice as + /// wide, and since how far a stream falls before it parts grows as its + /// width to the power one and a half, it reaches the surface whole. static const double _rise = 0.45; static const double _over = 1.2; - static const double _pourTime = 2.0; + static const double _pourTime = 0.8; static const double _back = 1.4; /// The world's up seen from glass leaning [tilt] towards its local +z: @@ -887,13 +977,19 @@ final class Bench { var moving = false; for (final vessel in vessels) { if (identical(vessel, _transfer?.from)) continue; - // Lifted out of the row while it leans, put back when it does not. - final wanted = vessel.tilt != 0.0 ? 1.0 : 0.0; - if (vessel.lift != wanted) { - final change = seconds / 0.6; - vessel.lift = wanted > vessel.lift - ? math.min(vessel.lift + change, wanted) - : math.max(vessel.lift - change, wanted); + // **Lifted out of the row before it leans, and put back after.** The + // height it must clear its neighbours by is taken for the lean it is + // going to as well as the one it has, so the hand rises first; and + // the rise is eased as the turn is. Taken for the lean it had, the + // height jumped by centimetres the frame the tipping glass first came + // over a neighbour, and the jolt threw nearly all it held out. + final need = math.max( + _clearance(vessel), + _clearance(vessel, vessel.leanTo), + ); + final rose = _ease2(vessel, need, seconds); + vessel.lift = need > 0.0 ? 1.0 : 0.0; + if (_turn(vessel, seconds) | rose) { _place(vessel); moving = true; } diff --git a/packages/education/chemlab/test/bench_test.dart b/packages/education/chemlab/test/bench_test.dart index 96b78a085..4d99b1028 100644 --- a/packages/education/chemlab/test/bench_test.dart +++ b/packages/education/chemlab/test/bench_test.dart @@ -316,4 +316,24 @@ void main() { } check(bench.scene.root); }); + + test('leaning a tube within its limit spills none of it', () { + // The hand turns and lifts it smoothly to the lean asked. Mutation: set + // the lean at once, or lift it by the height the lean it had needed, + // and the jolt turns the surface over: a tube asked for a tenth of a + // radian more emptied itself in one step. + final kit = cpuTestDevice(width: 8, height: 8); + final bench = Bench(kit.device); + final tube = bench.vessels[1]; + final start = tube.liquid.volume; + for (final lean in [0.05, 0.1, 0.2, 0.0, 0.8, 1.2, 0.0]) { + bench.lean(tube, lean, across: Vector3(0.35, 0, -0.94)); + for (var i = 0; i < 150; i++) { + bench.step(1 / 60); + } + expect(tube.tilt, closeTo(lean.clamp(0.0, bench.maxLean(tube)), 1e-3)); + } + expect(tube.liquid.volume, closeTo(start, start * 1e-9)); + expect(bench.world.jets, isEmpty); + }); } From 907ecd55a4f9e7adf00c49aba3c7ec520356267b Mon Sep 17 00:00:00 2001 From: Dmitrii Zolotov Date: Sat, 3 Oct 2026 12:11:11 +0300 Subject: [PATCH 05/34] fix: Let photons land on the bench, and pour at the flow the hand wants The tabletop cast no shadow, so it was not in the shadow map the engine's photons search for somewhere to land; they found nothing and were lost, and every solution threw the same grey shadow. It is in the map now. The hand tipped to where the tube held the next eighth of a second's worth less, which on a tube nearly on its side stood the surface a fraction of a millimetre over the lip and ran a trickle. It now tips to where the lip's weir runs the flow it wants, and a tube pours half in about a second with a stream that reaches the clean tube whole. The liquid meshes are thirty-two by twenty-four, which halved what a pour's frame cost. --- packages/education/chemlab/lib/src/bench.dart | 76 +++++++++++++++--- .../education/chemlab/test/goldens/bench.png | Bin 1936077 -> 1936077 bytes 2 files changed, 65 insertions(+), 11 deletions(-) diff --git a/packages/education/chemlab/lib/src/bench.dart b/packages/education/chemlab/lib/src/bench.dart index b0c20672c..c7ac96e79 100644 --- a/packages/education/chemlab/lib/src/bench.dart +++ b/packages/education/chemlab/lib/src/bench.dart @@ -12,7 +12,8 @@ import 'package:flutter3d_physics/flutter3d_physics.dart' RevolvedVessel, VesselVolumes, fallTime, - overCircularLip; + overCircularLip, + circularWeir; import 'package:vector_math/vector_math.dart'; import 'glassware.dart'; @@ -355,8 +356,12 @@ final class Bench { name: 'bench', ) ..setPosition(0, -0.002, 0.06) - // A floor casts nothing. - ..castsShadow = false + // **In the shadow map, though it shades nothing below it.** The + // engine's photons, bent through a liquid, land on whatever the + // map holds under them; with the tabletop left out they found + // nothing, were lost, and every solution threw the same grey + // shadow, clear acid as dark as permanganate. + ..castsShadow = true // Its own channel: the sun reaches every channel, and the fill // only the glass. ..lightChannels = _benchChannel, @@ -834,6 +839,46 @@ final class Bench { return 0.5 * (lo + hi); } + /// The lean at which [vessel], holding [volume], runs [flow] over its lip: + /// where the surface stands over the lip by the head a circular weir + /// needs for it. Found by halving, from the lean where it starts to run. + static double _tiltPouring(Vessel vessel, double volume, double flow) { + final lowest = _tiltHolding(vessel, volume); + if (flow <= 0.0) return lowest; + final radius = vessel.lip.z; + double short(double tilt) { + final up = _upAt(tilt); + final lip = vessel.shape.lip(up); + if (lip == null) return 0.0; + // By secants from the lip, which the surface is a little over. + final head = + vessel.shape.surfaceNear(up, volume, lip.height + 1e-4) - lip.height; + // The flow that head passes, straight from the weir, rather than the + // head that flow needs, which is a search of its own inside this one. + final passes = circularWeir( + head: head, + radius: radius, + tilt: tilt, + g: 9.81, + steps: 90, + ).flow; + return flow - passes; + } + + var lo = lowest; + var hi = math.min(lowest + 0.8, 2.6); + if (short(hi) > 0.0) return hi; + for (var i = 0; i < 14; i++) { + final mid = 0.5 * (lo + hi); + if (short(mid) > 0.0) { + lo = mid; + } else { + hi = mid; + } + } + return 0.5 * (lo + hi); + } + static double _ease(double t) { final x = t.clamp(0.0, 1.0); return x * x * (3.0 - 2.0 * x); @@ -913,18 +958,19 @@ final class Bench { most * _ease((time - start) / 0.6) * math.min(1.0, math.sqrt(remaining / (0.8 * most))); - // Ahead of the liquid, not behind it: tipped to where what the glass - // holds below its lip is what is in it less the next eighth of a - // second's worth, so that much stands over the lip to run. A hand - // that answered the flow it saw was always late, and a glass this - // small, nearly on its side, empties in the time it takes to notice. + // Ahead of the liquid, not behind it: tipped to where the lip runs + // what the hand wants, by the same weir the liquid runs by. A hand + // that answered the flow it saw was always late; one that tipped to + // hold the next eighth of a second's worth less stood the surface a + // fraction of a millimetre over the lip of a tube on its side, where + // its whole length spreads it, and the clean tube filled drop by drop. final target = math.max( - _tiltHolding(from, from.liquid.volume - wanted * 0.12), + _tiltPouring(from, from.liquid.volume, wanted), t.spill, ); t.hand += (target - t.hand).clamp(-2.0 * seconds, 2.0 * seconds); tilt = t.hand; - if (remaining <= 1e-10 || time - start > 3.0 * _pourTime) { + if (remaining <= 1e-10 || time - start > 3.0 * _pourTime + 2.0) { t ..poured = time ..end = tilt; @@ -1038,7 +1084,15 @@ final class Bench { .._drawnTilt = vessel.tilt .._drawnLift = vessel.lift; final meshes = vessel.liquid.volume > 0.0 - ? liquidMeshes(vessel.liquid) + ? (() { + final m = liquidMeshes( + vessel.liquid, + segments: 32, + rows: 24, + rings: 8, + ); + return m; + })() : const []; // As many nodes as layers. while (vessel.layers.length > meshes.length) { diff --git a/packages/education/chemlab/test/goldens/bench.png b/packages/education/chemlab/test/goldens/bench.png index 86ca3d5f47da1603bde031d76e1ce57cc204bcf8..d256e9b5541f1c03079a8c9590bb8f3bcde9cafd 100644 GIT binary patch delta 148688 zcmbrncU)E1(mwtnDhP+OH;GZy#MryWs8NH7QDfKGTcWYoRC`P;9PAYVQ5Hx?6cq$f z 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

q%M z?bKa-J9by!k20)oR)=n)r6b3#_BHM?z>>61d5$(ZxrS;SdsTil_HCK=@u&8&T{-cx z8CbRxlx#O}i5PYuFIW!c<6xyiTaFcB&vuKxF2-5CczqOdr~vQBdv^odwv=Sc=A1am zhgp~#GE=gajhD0qFU$IQBP8Y17hRGx=S5lb$#7XS=Osy)`?{=I@V=x3d4pk=Ob)$H{J)f)NrkwUb0cVy1PGXkb}1C|dN)fjGJN4M_@LhDdR_}&a(OC@hJdY@u+B)6L1+@Rk`&`U4P)tpY#H&8d?S!yoOxvWOk zAR8+t7ZeSlk%(MSG&hEY!XeN|&D>NhC^HV3q>zkQdsO)^8IR89TPfkNhr@FcB`P;r zqVX#e0FmiM#j+orXV0BJrE!he*60odra8>*HgL-^f*To|`};Rfog|K_?_EY$_4>=k zi+*K|=tTt6D8^A`zHEHtGZh|Tq^njyx!h9QevDD$(eA>jqq+wRtzm3Kd5u)6cU zX{c%cGf}u0RaL#;=%+@_g0(6*ol)J%M=jW>Ck=nK;7K^Bst=-0 z_=i7ux30bNy5ae-8gtt0p!P;%jZYp9Pu{4S&A^!At7+qn4_$#F(Kt2fUFkn~C`{ESG%W+RX&5v8x`+Y6F^J;h3vrL$ z9Gi&qnjPel*JsQ0nR8|Ag!grd&#)I?0`(iA=^tT`;pFk}d?51|p#ZW7oUA4<1t}9W zPi-6|S33wCJPdq01{`bv=AAAHmh)x7a-lp}E>+laxiVNT;`$5RJF^k*!+Q<`7k3pW zNkLJWsBi?h7riHOb6=I{St9^bFG}>s&)egykrF%SHHn+=dRLNwgSqL%!37dI(E<*- zWs|mnUb7~o;tbUa{w=mg8;KINQjOgGb7XHaKyi0mGZXH>l0oP86hFa`JoU7 z!?M>%L{5@KTN!ve%sabR9_8;(b;nnYMTBv+-TvlvFwWI@irhFKt-@}%9S*y1Fy5gyY6TO zJa~2rXDqVI& zIvS;nIGoWy1-tX|1tjjUoB1uY-MJ`t@7&fA3#K`epRs7&@xbX5Wq_W{w_*7c`5$W& zY0sWH)d1u?jdA2DkU|^_uzMef-VQ0-cpv!$brA4hR98FT{v}5U=;pDDi$SLcE>{mG*-JrCtA}I0R>b zw0&}pw0mNfwC(dTWQIJ~w)aQ4_(=Cp`*RDOh24FLxRI%QO}7!z2$|uh(OSr7Nj9qGpbesM)W8g}L65#8q=7HzPxmg60Fx zd?4P9V-#L%nPdRcd;n({C!3&jfV`=IH^5ocbbpDO(HDPcjI0j8A!ukZosBh4i!&3} zXLd!QMyG-;I2mO7CMf}wmF=mKP5ZY<<%C1X89suI_878ckJf3as;`xb16ySyAdc`x zXyY%++yEyr&>%K@y#}EOB#V=q**wjLGM9>;X7qiXL=I{D!4MZ?uwhuUC~zRE%nc7Mn{hZRpo+{>vlFMP{##EI~CR3v}%`6H|Dfb zx0fMlu=?AlMqAZpF8C5G$Ciy(t(DgZeB(|(qwQmi7}!G4u}>kejY->( zWQg>ZN{U6XWzbw$(M{onaO7l_(2YgMKiy#3l*H4aYmCrh7ti2a9cEku1?abDp7NoC zaCPB`bb7STpF4w&^OxlItsAJuWV89NQI++T6vJ~{fm7wn$~Gbpf$}H2DyNh$bk9fj zePq)-`tR#dRI_U*)3*2Gmmh?wc^Gc9dO#RXE7-Xo*>!vI%iw@4seyI4NmA2GkPA_O zT9;g)Nrr?*rK1)x73h*CS!hSP22I{ppeA)mASF$f2D(r^9ta{8lmkInm$<3`Hsns=P2s362|pl9B9B5&qE7gnEQvZNVTng1E;&bjGjokRGmhEKanfl- zoLI=q^LZgoyq=Gfc0;43-E&dW_L*>LJ0wKf3<{JsV+O92*8P@9>!%k=>!&`G)<7Rm zpigU{PiufqYamb?jBNol?P)qb{Sg8JGo<&hnKEX==koc|7ztC;J~Li(*)f0>jj@2F zb?Fik7NyG+**o{irw8luLqAxHhHsZf*lFkOC+)m^rL9}qw6~-UuA7eh-mFg-z&g#* z1|#8T_^4Oi@H3pFOGg35P53nq5m_W9g;*|GYqi6^GBp^%PgsTNIAACfj0h04kCr7M z=)?xHr6A3sZd3;Wc7o;G+93HuU7&owD?onO9VkEOF+l#bD^R}M86@X7Crd^;`Y^4W zCsCihBN4O5NaRe{aET!PfKo+%JY3^X%x7;m!cQ`+%81{#2lV`0q9%C(dLWZ2-e6LI zq$z+Qz)#fF&JsDj7qD%JM1TICB*jKZYJQI7mZCud99^kJS=va| zD@~%Zz@`8q=@HDJB@NGp&L9-?#Srt;WeJf;4+(&*9-*u%CQ_9+(E)Z6|@N@!Z1?PO|TginjW z^E-^TFmr=`F1sYe_ILf98}S}F5`TST|8Yb(>EB|tZhn3q_z->gjCQhA1Ubhpa2RGx zFb9}b&@{s8;fy~4qwE|ytX;hf&U5=F(napeMRc$I(;t41b{CaW2wS`mzpS{p2*0$c z6ytR0#>U_yQ-$|xpgM5is2n_aOkBHn*CTmtkCdY|em<&a(lg7D zwSYbwiFx2XnW)Y~I%M5`lo0NaBIJ+7B;-m+RE9>Z#fT3t2>@yZqyexpWN~1o2CcPncF#pi8!fTYdT1OZRy?1L7SADJ(h8{MIbgZ8>bpQ%JvCQaJuzE6 z0al&>s@5<9+khE)ff1Pis_sK($e_`)W#+t4NlR}F56ZeUbbMOHP^C(WhkYLsX!y4v za4lK3TvY`kF!RC0kL0-*M&a0^zHr6&)JWxRb`+u%QHZG28sgd3bc^vHBaw>P8FX#^ zYV122sp#$}Ng@#=N%}S1_XXLRlApRp3X+1QFbPdTQ-WMlx;6-?6@;|6AfQ%|Yy)ws z%L;dU=;zNik$Vb5U3JXej>S<%`zoP9S$-Ey8I*(4z2L%PfElmc*pWtNU*>T zmzygI>1%cPFgZ)<#EkVw)<`YRf*(Fl8+iFOSdd^sWI>f6K-(Jj$es&_<;d;Ra^n6M za_0AFsQdkOIrpb)a_V=Nr2ghfsXMb@HtpO7XW0gcL2^fUH$+*(0U4og6V2v1cCaw3FY;e z`JTG53(Tj*ReHd887*qlUB(L@>Q)Y{tJT+y$5qG}xRXNmz>dosV@zQ%a8T{;P-9RF zHQ}b!M)`%A?Ndjd6e0hh$Q-W=qtI?l+&u$mdv~7e#jhxX57TN*B zWwA!@hratp<;KD@e^-Okt?L)HpL-uz4{HXPLY9@4CApX$f=^)~9Pq%4($W$zCOX}1 z>|xJ1mIoX>upho~95H|HG|q{;q#4r9n>Xc$Km7qj1~z&wc9h&a$<4#jc#yoj0{m`V zyZ8-Mlj}F+m)dSzkIwPMTU-rUwuRfeCi?M^K6K;hxyg^nJ{Ss zR@C~L2x(26c{WPpO{-@jF-A%&e9v=8sI(d!I7U1Nt`N`ui@=)ZOPjuPq&)(N2GS=w z4V)o^0X8dw6Lgq#@7_H+TRA5?OI#tL=;#pOq)Mn2@x}|T<@)8)BB+Yomkt$oC^jgPc~@SbK#3M>g3V)SE?B@KOH zva>vB>y-OAU~c;mA@Vim+ua( zmxu)uC1%bm5;J>*#LRk8T+y?Jl$AYf3F zeIx>gTEvvj5;pZQ37hepL@k|(bI-wypa*d&YfxU8AhE~|V|g&M91_q-lvxkVBSSWX zOH-(HSaI3qD69o$mB0~I3D&d~#@c=`q?6y^7?K~5ulbkTa^sswtyPzfA6`w@R&2K?YZEHo^&fLA)H;g2ni-nDf}#tZC+ z120lYE9+tPP#S)&MTudmerb63CnZLEzpwAvP0}8WY`1+wjg3V{;{)(wz|bLE7*TF* zJDQx)NsqM&7wkbDY_!v259+)E5~l1NWUwfOojXl3Gc(-ymIEw8^9tbG1~<84Q$v)x z!V3;}I6Du}1f&y)4aC3w`YZYNn{V*Lu-3Csf|reQyzE@bf@EZ7OGXB|!DL|X!gV^X zGct3u@cr4qx1u6cj%{RZE$e2%r0ezp%XVsuZ=LobWk^~k0JjL~TWn-}=JXjv9WUrJ z2u__m0~2wNWagA=z;i{cLx+PzS-f%$fGq)IJS0vQuZTgKRJ0x!uS6~Cia1%aa@`e3jpbYD=I2+8}RG^fHGZ1y%QxpUI-Ll*N|1>HE5-@8x){TyViq(#dC0o zO`3)PzzAd@Rh~m*ARt!5Fg_a&;0uLwFzVJbLo1L_;sVxn@c7Qg(8HI4BrM0&WZy4!&;#tSjL8;yt_l}GLl(C5!4NHFS zz`i|l;mk3d<_=F_!yz29Q-jnW)N2+(ITg<7O^pi@1xb$&LSlNLhPxcVT>*GkadM!h zU7J9=NV&G8qr#prR|J@Yad>BIko*aT;9mf5e>)F|ySqyM`nxsqxBH>;!&TImF8fr% z=8T2S=Nc_>pNx{#pS~iA3*V8Hz&Vl+IATaKYEl~*f410=MrZ@90n)-D5tF>E`fHVlQ5NA=HdK)=phHR9EsU4*IKKr?*tQFpS96DlbLn6^2`=+dlVZ>>6)0}6L? z?+*3H9K@(ot^?}8(ONdrv*xusbBz%#R8l*$?Tc=Qlw%Bnk=?rsX~N9DLbiiuY3|Ws zYWKfXqf3n5?D3^ri)>lq9aCbu3x_%z=#?P1gkUP+04$)205eENe?`{@96w!59@8+Yv`pNy-$U$U{(~F$kOjFFp9)6d2DrHx7F?f} zD|Nf}10eJ8hic$tuSb@}1!S1qk~_C=Ay#<}_;(SOZ3Dda_!*Q3g@nb+s-Q?&x*|lD zEDw>zkR{7QF;c>`ELnkr7?wj;pnLZ6NMK?Vu94&P02Jd!I>)q`Z|E0z0*(OgVf0KgD!UhnDvatTtVz(MjsQp#a`6(C zu+iw}TD)|b21J5lZef|Q@G1+(oHD=vt+zjrzWtt&ZvMT+w*%bpW@l;d4R>4N&zLn&nDF}M`1j?5iPPa?$GO-z`n>^(H%AcE{qi~v6uy4m zCAY62_<`;%dul6X6H-76GE*ciDO%P<1xZpgBq~snF{Z=>$vPaTw+<(^5*pJW8LNZ9 z1_LDrEHEF?SORNwBUs=zSfCAHe7E5r`|->w`Tka#{O#*7`OBB6A3{6Zu=x`ue9kzD zp6ePbaSM=55j0owu`t(#E`(dXot7w!6hdAEd|u&zys$~8gd(#dWb&gDJndNtnU5p! ziYugU_g=Yt8UGQK_4>6hZ~((;WF+j8jpZfiW4}gX*Q}O^xEMGnA|R0x789iqw1RwV`**YO5;y0-iD`~W}*W|O~(gEE81YCU*lOg<|Ib~nI7F> zhBL!|yWQyKa^9oAPf&vpwRr#jf4nBT+24OKx)G1a*97&x!r!}$bONRrupVdweDi5( zN}{5pA$a6b9HU+Of-fQ>qx3g<9T^p+Upx1sV`9)_BTpmI&fWX8s?e$=5~Zqi2)qgq z<(4!e6oe?2nMn%BZd&Mm0%lfGu?>Bu%8;jknvEP6d}3wQuv-g3)oOHE=og3v+_(;> z;`OV@{73l}a>wY{FGmgHh7Cx&fvvl49US%1*xOv;vLYY^NEHk{4wS`c(&~(hoY%a! z3@1@Kua^es_bpn6pK$@U;*;~l6|)iTD|VuPEe;n#E3#+a43}P`LQ(u4ill}RxV*x| zXBgy#2=PGylQ}$EtP#=DVMGLqK?9`Miwl8FpU7LkStzSQKx5DZhWkOj3n2L%;Ep}*x ztWI2yn)VfNP>q-V1BaqE^eIFPAJc5j^6MrBk{l>LU~Z<>MJ&Ir?&g1aI01Euc6fab zmdB_gw=r&Kbvt*yT^baeZEHUOtPy-j|V>a`Lbo+=F&DWylYJLpU`BiW(In zQK5kn6$a5`(1X{w7aeB5j>dH)z8@JHB(dQ(q>Sb!p5jJ^^wv4glKc9P(U{t`5)w**dm zUV`SlE775d9l&|QM8Z?2z>1-|ceR%XB{H|KVA~_@KaB*%qwu3{#fr>Domd<;fM|eq zm;{8lkg*G~$Hoi$=7VqOH>?T{lEBaqi3Ov}*;FL^QIB)!$6IpcuXka9-jRzx+|r@Q zn6>L9BpI&xwE(45kS>K0aOFzFNb=<#gE{g(zmMbgItQ=E#o9OtO8e0=aqd-rMtx_LzX%+7{qt$=j^>?B?V*FHS2paAP&0p%2y1MhI=CCbq0!aH-i z0jUp+N$%FJK$^t_=F$=#Q3i}e{9z+TzUKWrxCqx`(L_bVZyJn4bOVAx#8v^mXvewu zWhHP8dGN`^JoZwEJPzsol1uuI36McJZseu67RWmjm&n59=xvPNW-7Bls@|$Wt?RCRI#cD3 z-|?hA)|1&08AfI3EFgJyyr-<5_~PsdIf}CBt(z+)D>DrM?$S^P8&oCkz-n8!!{`Ke z8;Kch(}ZOBY>=Lxho_ndQuYbDF->@HB3xy!$-p5mAW%6(dOtZ(9_!r?8TtdH&y$0s z|Da)@qb}?&8+2|1k7di>P^puMckSGX@cJ=CvQEj3D@fIY+`I~ua|>Tzcj3#mOK0#V zoFsP$uEEU}lAjCW4Z;uy?&5;J2L}a85F{{=5+ngwU(OhS*Q@ZF?<4Z1!H(UUiL(F@ z3b?-`NPYm~eY-zJ{_LDHItw33ZcndZj_mqGuFQvl(?tvxb&2$sE@2!GX(U{Fe zp6qsn3{KoTC#Sx-D7#M{k$o4SiC-L%^;jd3Foj%+utk$$W~RhQ@H&{B5CR&ngK@TW z&{~Wsc%2k0VMz%feumPt^2Bi_ke`rUdk>(jaq4i>Qa^ledNzZ)Ga%5TF(A;Z(FE0Y zXeZjCud9E%V3B^W+(PX`7U}}CbBhpO1i8yV3NtpB3|wbr7fM!65df|bV1~X8n|Z7X5@j|aBNmCM zL|a|03F>?Tz{cDz_SoY&i-pLhrA_=?kq&GWx)H8ef0Lb^oNB4O+#J}*IMV}+GY}BW zPY&Zuox6wtFxDM8+cKB7E*GtU_YD}f2%fd%v~mW9zClhLMMLN9HBx}Mek9aJhbL)GE?utjFBwmLU>lQUYO52m)rW&i zgoGo@BvV$xoF;ZnnmS8<{oypUM4F7_V5Z7%Cx0v-&;A@|*efY0slr)|0VvifthZ#UO9RBq6-$6mEpFToN*8uQ8H^}5cM&om9%ym~dd5eJ9J%2k1& zkr0f_G4k~)2w^MCMPf!07KjK!Ac`deqr`CPlv3oFEsruE7Gx z#>r@9BPA(ejRbr)T>|D!k$}0Aa6L_e7S5K?l}jZSlej)Dhn=vbz8<+fsDilz2%^{( zEvZ+adwIQmA9h{GKfxSqrX{kBgk^K_3CNlX4aMO;L7L`r1K@+yBdzr1a8#~bDJy}g zuE=npPn;wnLXd%=0JE|f5ZJVLvuv*4AyvC~NcDbXavek#7mi1YNkNb@5$0h6xYwGv zArcIKT<{tQ#!wiikx6jDrDp2=n%%hQl|BNu8WkH>q1*=I2c3K;h2vFO96;j%sVQci@03 z?}h>UK8#RLWXxAzFg!gSRJnUwh28^yYkLIv*^Puc-cXe-Pibr?&}C1Ox_S2M&R)7b$V^@o@g6AYz!U6SrtIvY(nR zB?R9*h6!bnHoSm31>)SKqi9Xbe{fsf_-}a40;Rm%Yz=@kPy?|Caan7B z4h*A3OO^vHK!O%6vB}S(rDRG35xTGsPIjMF0}!NT}>hXariY9+EAeT`TFb>aL;ZLWX!&HGG4 zu}P2~(Nv@jo)}e%CGcvf4g}4!cu+3`*I+&qPExT{wF zXuPH-{MKyiaZ^niZgz4p!+>gkZsIEiA_sReb zRDHq$Rev4WLKHTd;1FySFy_d47Ag?#@MhAZnGauZ5#rO#(PHOy=ChOE@Ejc`j&0kD z?oR;N^8nhr?J#vt4JvVirTaSD7891X4Ve#<4ri;fh5lA5xE?$a%;DI== z?a|o=m+O;B*CZzD*g}2*Dt{1LD8kvqB}hCg+k`+7&a&Q&9#4G21NR@;k3)-hfk2NcVi4sv=ofq`v> z+i7!ovFxbcD0N%WA{rj@3rF{Q!uZBMMp1wME0T{FOhnDZ)Ro9?9+2YO(&M&zd$ZNu z#T9=ApYjVp*omVDaVTCjK4H3cUXmcw@~7@ECP9YXvW!}QPaFjIPH1!_+8W2{+=DD+ zz2~8$*9M$wQG}GH5}a~TT8$K$noY6+9bz|D)!=Yga9{A=O7P$+;05hel_h z*qrb}LxgT;vJLXnK*)+!n4o2_bb~<9gTpbxU_q0T^0`EF3Z3 z*cklB^r=T_PDOtXd(DvU5Cxbp&-gt1KCo>1L5@RJXK2oy5 zo3oJ^SY41Mb$toUun%&4k@LkCCC9o@NAPGgt5aO|L5!AH8>aM&JC99DmR7@adV z`dU8T7lr!{pCw0#I`Dg6OPvn!ZRygxH69jql<;>6m5~kFRN1PR3ArAZ#%g>zKCpzu z1ihO1IvpsJgFU<)SX+!F=TdmZH{rap3g{z8zTSwXSXsSEYU{SjK6uWL;**}l%$|fh z7h~=5N6fm1l&iw%R-4z-Om3m_LVa7R1=rxZ#E#oawSLvNb*skhRwe(z>a6@HK@C6m zGTW*t5mxKg_P=n6o3irWYWk+mw%V#s|7dkkJ)X4;^~8@xn+Z+!?VET8G|uSH=YLDv z<}_ID8Cc2`PA^M6`4q^0c~aY@3ul477m(G5Ck36nrOst~bx^m1yjrNa-ey-9w$%Ig znD)$d>7+GtTjgs;InV1FR3e|PoX9@rb_&HShH~ny6t)$&QI>tN+b4y~kFTBkTr*_g zP8}>W6uC9KxbIei88Q{Rs; z)7s_U85^lG&28+E)HwV5_Abh69vSbg54U-?@?FDr7xf#!#S*Ax)+Y(G$=NsvE6aUwZ82Il{t6_ zb%FSw8u+mBv5w%n9`8Mh|B?5!K2j&ULMa<~;Rs$|cYoHK*VKWr=Hs=^EHmOE74nh! zhT7lT>Zz)iSj|;Zo;6D){Q#w9aH4iz2lIGy)qAViUfqAz*Gv7*&uXWhD6l$_4122Y zI{NlhRRvJc>h4hDtY@s2J~Sel{>zB)PPu1ve67*026b~=-F8I6ZHa4-1)oi$hQkSf zf`>a0`pvYq-ngoA(@e{C`_?s-E+MX@$7}Z1dYhpMZm;&%3YrX-48eHs%cg35+pger zn~k>L{I*_jEHB>zKe^46SwKLw#(t}f<3_a}qII8dqBX5gxu~)mvTa4~s3Y8NDC`r7 z@^dwCq}j1!HFUWeB?#1QN3XRmtI=3JE^4iNTV*mbbM{Dp`8f(;Do}H40K#=>W68x$ zTFD*Lainoub;P-+w_R-+*p(bkEc6@jWxd;Cm(^i!@aEz75d*hp=PI5$y#{bWXu)D~ zUpJ1x*HaL^jbdz2-aSn}*AcYHJPMuS7RmORq`-7sI*RTnxmISk;%g<=%5BqQLb?{T zc_lhAc6c4vH{3$K<30Pn{e9{oWQhKOtM~={qn9D)p-Gf;khAz;rx2e%4z7NN9~2{$ zUHv)G^iyp{V@>~GPqU4$tt<5G*oyo>zk7Z}<<%a3xY@qMVx~)hBjp|zvvb|}8XhhE zNb!Aba$>xNMSTh}5ejwGxjqd5ICWZOJZe5)d*e~_BTx0sBhbB{u0!pxm9|i`hog7a zxPDMJ&;B5@Q-3g@OYMa~~&V zt0T12`3!7b$j@#on0kAh>E{hU5snVFb?qisfI4@~%T&{mi>N~U&6enjjYR{qlHx2d z&E?z+j0=kXmBTe5o{Om+2U)n$PB*hIY%Vgsy1n>W1?;##v*Y=YbX^(F{)qAIc0dIP94KLvMe(rR{_ zVB19EE%y(4iN3>s;x;Kes|p{}vnO*r8goM!3WYciPwU7@^}|TBi}HHdY_3`xm=^DW zW-mXsioJ9ZOVC;W_GYG5e1-t7nrF2g(YWh5HX(Pj2a3|T`!(4OFXNiO5Q?R?4m3Yh zNiLx8pC($ZehYQrGSy2J<82C-ss>|@c+I7&#Q|y7h3VQbcz@jQ<sr42zLD*B23CtcRP3)5=9fGG;G4xH&QPy5Ev};cY6n$r(u; zg?0tcx?uSSmy=#vSaif|;xsXv*W_c4U>!=$e0ykT4?Ka!hNj}3sJYgK7@&>>f*gMkfVBN)r$A`tp5cw_X)+zP-k!Ej? zlgb!nKBf8_W;c~M&}{Cf{S8=e4(Pf;SS61_h%aXpXn5ln___0^m_`c_BtoV-Fv@&J zeZ9l<^0pa~&4R9zK&#PH;WmF`G-mwypWqcA@F;!}zBF%PTPU|xkIuf2ws5!0Q{_|f z(c?yA`PYs%`(r^}!U|I!^=7Bq<}aC(JoKGg*VXiBv!}}IZnmjSec9aBQgx~Z^%%Mb z#=z_!%>HWHGV3jM_A#q-E0{a>vQ__g+32qNj6=Vg*{kqnG7XDq<4iA)8)_kd?V($G z;dE4me9P@vv*oLNp44Qzl1WmzXvokXESjc_9^EK_R1Tx3qn?)jrgGJ8G5~p0oayD_ z{6n}n8b|lSu@?~5gpFd2c-7RRuB)pB;_(AAz+|&yZ|5&mz(^*dr*^~blc;rj++uAi7SYGOEqHhPd8KI$yJqK2MxSAW3=b!2kBgd8TI{TfaGvwvJ;2 zCvU3b4|LmKjr`1fQzcHe{94dUO*T>bnfZ7-Fyo^zfltF&KfG_By78GgQH@$}4N%qD zR=e7z^UXhbK1_a~l9$0DbGi$sq7!UD|81tf@|xk-!TvH~8=k$-Dmb?j`azSrtukM1 zoRoIp1)19cnsET?){Y^Eb*U;=0rvk?0-rPd4=qPfJDH}rXLqgEDn2?+343F2KpQl= z97_?q|Jl?)tL&*!q5bg*-zYWPcoT#jP=>$0rdmx10B?YQS>M(eZSU8_Y35Z>xFV>` zmH2Zc2#qtRgCjOJ)8n%VAB(fblLhE&uuU?|ntR5`l7>gsAHKnDjmOp%y0sP49>H@57-ICW>`4 z%?|B|zucQ`+*J!3e0`NyjxUl3CzwXb5o1Jv9rk^@fPqNQzv-n`vh2{?2Z|`JkJagn+?D z?n89ua~>RlW~I(EJNBnGRno+A1Diu-94@S>4z;QVi6Avw)cAC>(=6^>TGNnKgHY}^ zw^M|3MIqIyZd5JK6%9emm0Pu_<)l8m$GIXEK88okgE+Whu{k~FN!?C2ySL^3WefH% z_5Ebi^4YtO?M@HL{{3iuic^mc*Q*zIz(AX@!)*S@WtwDa0(lIS>)FnZhd|Gx+f!iA z=RtK~2R8mI8NjhNnKbaAVEocj^~uCNuNMJ-(5+sz3o^~-t(D(y(9|owzP;77KOx36 z>O-ry$_w`$O4V!Om`|>IRH+N#z#)gRH%$N)RsH6gU63u1SYq~U%?V_33JgxQyTp9f z1)8csAExP5RD|u_vj@*)Gv>_p@A5>Q;$laKh={h&SL+Yakmd&7%Xy@aSkEKo()L3& zK}OD5lX>HO^0f<-sxS12YmPk3T2CxOROF;gEv4H`DSZJ5{+I314%_3C!QN)vfkdhnTO@npk(h8R@dB%K47Isb-`Iv zg+8JNW`O8_u){1@|GET2w_lz4I%emhT3N?wx^}VFW2fl?tOj9*F%#c5YFqaQMC1{A zzV4{qhs{TQ7;2;oflg6Q$hY^^pAVb9e3 zWRck1Y&S4$0OUz9$Z0pkw;K!6&&9^kY<9{_0ypna=K`<|SVzsy4;?z71_lCv#ve6X zdK^(795vq@NJlL#y7Nb2^t(rmg6`M6NA)?2@ibWCNp<0<`GOkoFl@qq-8X$|pFUX)QIiCy=gzf!CL2qpILnYc&hnC-eJ>t2-erm z3ue#p4@#`aBivI0m!kGlLs#g2ym0=UmWyAUN1DZ1{DWtK3Fu{rDcV_QdvDy)FZI+# zbC62vk9z%}hb+UzO=-*Ktva8!>BxT9bg66E!M=$+DGGCfg-_Z3i+P~}Y=(E!=7?oF zQJDT5M(~)A%Q@LlY>V#5hPlIOC|!Wwbvm#^EOSqc9&w0(YJbUm(&MOl{*u{K1Q?qda2rtpUzwen*Wt<5)v8Qff7A#mpavRJ z04sW{N547}d}jVIM#|a{LI~rdT;+7(@gCuYhl3HOj=+0Md)9fV_Ne^soBm#irNQIR z-k0{MUb~Oo;i^jP0k=U$4{YGc_sw@a_9&0PnvW{EZ$A0RHO3fJkFC}aRb6bgP}SdK z3YLCtCJ|t2TYh7XXst&4h{sye&+4ky+yl&GKljH@L5#nol7EDvjht(GKE>QCMha-j z(Aea)Q!C&kyOVp~Llw^Nel(w%!KF+&eX;?L%!62iJM^Z_2hELLqYY4ph(iRT5cZp* zjV5b!BDe!gdKR3G9Rw}(FJ{N~JL|S;Chi_p)>mdv7pB5a5Z$C7FV7$1H0aZTISp9Y znoYX_htt5cHF`95)olmM+OJ&*4wCB;>zvbZ-~gJ>BWe8rl2w`M%ZeOkxpHEhQN8g$ zW;>5V>cjsr-}gADs{RMtI9cy(_vpf*b#QJ|k4LNM~^3uT~JvrK=&GSA%%`W|Dc1V2)d-m87R!cvw?^Af} z2k}X3x7WJYcZC}3ZFTIZpD|FM$lr8Z#kn`$P&eRt%U75ULgPlu&mXV8r&qt$02^m$ zfKaFj+0kf%e~qDgp~taRB0MwBQT}-v+N@i_YgL=uw>i>v#jj2iT=3uqa z$LgjIHUs;=>SH~PhuOYyi|nFC4n%lvYmM(9l?O=Cj!j?=o!Q6Y5TJ=!+VVKh6xq^b(`fp(A7Xn-ZiI@{w;E@6m+ zAbj9%ak*#0tpn~E;Fd>-pl_Q-KZOsNgwQ$8Op`^x4WWknrAB@CKB~D5CW#Y6yMo+i z9~`Z_ckjU@9I+?lC??~C8r8$u;dT3(O-oZPrgcba_< z$d9_%!+J*f9fM;LO3>2dc&&d=>r)TaZ<_VG>i3g5R1J8<`a~^x2}n~l#IKL?f6;1F zd$5Jo;z&%8+3m%jg2l4J>Iye?s}M3M;5s_K4>SROip@A^`B&Q zabY%DICLJ(4>_}XX9gX0cI6B1U77b!90N%PFtXtRXOlDQ?98+f^{l(;sh)8SWOnwD z4obK!LT1M~%)j@8DYs{I7g3G62LB{wH}dCq@7$(N^tU>r2`eXfGe|49Wj)E5V0)55 zTrqKkFKQnrm|MHvPY7|?(y4{KuN`h!d3AL=Fu}XErZt?POA~Q&+ILLr!gvz*m>k1o z9%|z8R>$m3Z$4EE ztsH>z-A6!5Z%(jqI@=&@{KFEgQMH{1TN^ypTiD>?vOJA_1;M0q{ebuX8V==r5>wRT z40tDdwDj<|IzGnAc}@l=>-bT0!hoqxmZ{Z{6GD4IEgWI_zwUOZ@L(4T`6YQKIcFW@ zzoDFd;+&pF*(Uqd)e%;2k80&H((2!RqgG{X-cVnj#C%}?UMvixHrfwOjUS1v64}P4 zN*-x-^#Z2@xwqFn*T3378Q^v2FL+pYMp|#{wO>1I6n?+DHWg3jr>TJakkOVG0)$EP zvG&6s#WQ>+!5X8yUb4p2LLa(ei}(?INYkVL^2K7>9XL{xhycnD)UC1DhX8Qx+d465 z1Z0pS_Sjr(<4=#X`V8Yn!beM?J-ipnPm`724I zH4gOMq|-d%Acld!v$yq>=!3-=wq@vrsfrKQGy&hqb72k)b7OuHwsj-i`G@4H%6Q8f z=}A;O1M}?UL3Qsf>m8b8ZE8o4w@eRJH6L>~eS(#z=1j1L)((5yO84w{>pG({PQt+d z*O)rV>ZS5LeA~Hb0q{U4juhHm6k-(T#@XTVjQsl`0Y+k%U#DLQdG zs;*WYCR>jWXM5O<8_9B!%mu_^#uZ&so<=a;=9#>Q+{YIci!rpdcwE03Z7z}RilEeC2GM= zOwhhExPEU>wFay6Qvp=2`5?3drdjhmJ+CnHiHWWk)W9D>i65v{!>4%Xt%-oNb5I}# z!}^tSH;3e)Jjcwj{!S54*2wK_f7L|ybV#!k-XY^w=6 zWI{a{G2gbWMt#2u&-m*};EQ1f3Dw+$k&ov#FvbW1en))R4=4i-PJp3)?;97 zP#Ifo^fnJQqV0FsZDiAyb8J7VisR@df8sVv-zt4VHHcNwdZu53zF6)jdQX9-(8h3> zFn4g0H3!_9+h(}>ZWXwS%mt=D9cQ)tkVXdo1nC(YSZ%6+>BEnrXOE^QJDRfp0;>?v zLKW1Ev&ZAY=t`j_$l2p^bc(F>?5WTI%j#ig*V~y+_Dt#W+RJuk6EgKwHHq6tq#aIJ}G=W4aIj8QwPNAMk<``p2)z}iN|6967 z6Lp%-F4YtPNeDQt?2%932_1q&IhyZOME26>v!;ujv5<;#RTXP>@*~jc>7#23dlsh; z)K__2#N+v4mGy9E;w02i<0Y?~yjDHZv8!S}drd6`+v0q&_k}ZGJc5$*wF}(-3;1Dm zUW7XXOPd+cG-?}H@qcQYJCR5yt7+xxq)wJvExVCOlT={T9z&?{NmRnr!*<80{yf%S5{gEoHo-} zLT`{d{+1eh0l#D9VXKpmo`MEW1-i~~Y*1s)0MCXELG^MG-r9?)_pKLIoBOD4el-KX z|6f0VYM%Yjw`FZuhE?ss75{KEENyil6V4}R>*!FsD$Du}mh|(!k0T=0!AG?|YB z;_K~kLiwjb1xA)wo^72+#IZrW7;AOIj!pvW-oSb8vqQ9Ke4Nsc?f}AQbcygB3Fb4G zqH>GjR6e>=oz}u-3uh3lH>T0iE82)e+js_ry zS%5t{t9$!4^;oGjaxB`mI7^z#x(3DvRfv?0kt9BPk|$@=;8G?yH*Vc<^4XOGKqFOM zYW4RxtL~Iq>(tZP9opB1Z?txMsP5%>h`|0qwE^YUFi-XWv~?xmRaJL>UJ?i-FUd>D zJ@?+1gd{|T3JHmh3rJWjs92WB%!p%@#i>&p6~*rZ8?=N{5tvRbF3sO+M;TdM3YzuZ z7=w@yAPFiVF9<4ABeB{}ktOi?O|3Tb`<;`U#I}6jdH21%g>(MWfEtwqu`wh%Wa`USR`?wdCj(4e>=2|tFlLmjjaX{oQ9zrE zu3YC4gv?-sP_{GHPl%f`AJbvN#Hbb&$geTa=F5I2S}FH&&mZaUvvMnj%ZA~Q^|XEU z*N}xQ0rqob|=~dlUls1n(I_4Nsr=^NzY@}#^w5?T|4qD-nMo4=n z4_d2YWH$t^SJrObp~*X_fjM&_5D*Hek#eY2C07=!WC`^_8K-qaBHh^sTWE5xHL|!3 z?zdSac0Sic&npD(5CaSWp8{GhNaC7DA=^+z zzH1D9E`RE_E|c5~)|e!N6=DX2FEfr=S@4|iJZ5E- zvOa4l`ozXcMxA(Nled~#!{N%8cD_horYJjZ`-vEPagkx30Ao(X;Ciwo$rK~X_jOG}(l7DQ%nLtB+if*o~bo~ z@0MpmsK(gPXI(jwU}B~3`%(05B3DESX{r*SwgD^b}9{z}HDkcx$g*`-?+lW7;Z-8WRBKHW-y}hh=sYy;{-K;XJ45L{7%2 z@CaRsEPsws#S)5DA@8PG^J}0TLXfG>$kSW%%GQ;UyLn8!jS9xDj&RTL4!JzS9A49D&p2*P{8^ zdghGVo6*S*r{i!CrY6BcbMu&-n-6y?u@E)W2^TFD&weTBU^)Mutz=)ilPy)J?Kt^G zn%Wu*`Bu3?ZI*>4>Jq71f>t6t+%HS6K&8`+&!DCs`MJuKWluPk6#kc;C!t-o?OjM$ ze;7@R3DLx{>gv(>dHCvBva%ipqZ5l&q3kGy>Ax-;5bBV10Te1$W$R{qKSzqZsK$$_ z3P7HE08hjf1L-W@Z9!Wkbuk4G`@AV^$ZWjwH9O=PbtbN~dH~2sMFcOuQwz%TtsafI z3T+xucQZc+;m1YXU{S|ZgUsvEP+JX2PzO@yGNg_x@dvUu*BTw}V|6igG;wY49f4ls zxO`(Hn4%g;O>B&W_C1=?L^i9(Ip{xv*G-_VW^Akt$&`0M|18DuV}5iYS`aHIviI+4 z(v{atkOI$g9?C~T4OXG7&$DNGTXNOCL3y`TCCG>ZwMDM)w%iKnYCl6kpqga$P@B%oi@9T`(sE0ZT<)|LS> zJza`eAIJv4lqnjpgTOUFW;}H-V8SF5uLQIPHln!9W$?Ec!lJ!PKo2pMF|2pPUai4q zYj$p%(BBB?lbZqZm-#+usVH61a!x8TR<5cFw!0IYn?#c&8k0(CUOMcSnSLb*eFCO8RVEq9<;2jz~T z<#bKVlp9?95iFTCU0E8goL8b{vzF5XFx9ZE)5J<|m@1jB6T29==>6(79JUl#ge?S? zCSbsovYSYyx?tX?j)i^LX#;loc5PKq!;pQKC%cczCyMYPdo50K*>qRx3Q`_W*%bbTTqbe;8C%Ut4bikkDZC{JZ7jh+6FZ(*hL<%DTtV z_;BD9ESQ{9^+J&LW)wy}uhLPf3a&B5;)itY3r|a|o08{&1O&*2oXFGi?}h_kLt+u4 z`q$&ql8OdI+8Y?JLdtl(+S6`{ufZ7y=h~00(nx9Ei`EyFGZ#EYL571fdqN>eDXR57 z{u>XJ+elf3Z?B2xOA6S|~05l0LP~Vj^5tNGm%YEvc zESm)tUDg0@S#m$%)cG@niB{aNUcfC$JKT|me#VtU&ToyXxOnQ{lOJ@+(Ryh9u5vYH z&SBHrO$kn>CKGG1Ln%%*3c={lr7&X0WZ(%NUxh+=FE2?OD=XG0C$LvGu2GYw6`=wgO<>mzD^P{s-fA#an~ zL9R%VmU5LYf83;UZq&UlKrd0u86O-BM{eZ)NcUV?eDWMbGeoM6Qw!g;#F0M0U`!ojkqll)CNV+jA@Y?LG9B2vbtT)ZdQ)B_&-!j zQ1-Qee0R5D*Nf`$%S%c@*LT$80VJI`NZdouP@WLQhnJPY;r2hL|29e{7vO98Aw1w$ zMoOd{Xg-&P51*cfUw*etjao!cfJG{V06ToROdAP@2l_1~fDrzU0UV%Q%u@qes6eP- z2pO&+Y|9PLs+?SEk#Ac;MwuE52vH2#_^iqw-vl@?TThdSH6zUK?0jWc|634)#P*&@ z1Ouj86<8-xvea(Hfk5{wTg z&Id8wQ9cC`h6hkMg;|PP5yPPdrH~VRZqP6qq$D%dh5Carhe3lgwz|6hCn)^=@<$w?L{QKBmP;Ge!{XX=v~|UsiV|$@TTBNapv!s>VY|^7{}Kc)cFD z2NfW|+lL6Ges@O{ywEod@!p<#l_B3mAtQ&Kk|*}5LZ5ViDl~<#aDw#`(3CWqh-clW zPio+4aY6?1_?)7VKD*YG1EB+-_bE=P^?dVr4*7BP6W$?EN|Id7^F7!K*|w?`p23VwD7Xjum$90K zoec~yaS+^z_q{y_R3sq#x>cO_@FDeOBEd0A?r8eh4To;UhN&o~N90WlEA#oT$m@DU0Q=w5|QM*%mQ=sx-JghdU zKoq`@rJEM<8HO$?12}4-3FkGHIUHpJBGbKEruv~h83l^(p<{>Bn3$Q(ecrabwr*7y zBdMPQYnxZt56Ot%s3~6Y3AG?WuA>#?Qv=aob4p#wBPNjY6R!DtJU)bFa)H6RxemSt zXQ`}GGCQpUsz5F>zR_JQCp3;ZF=em?jKPj+0mbrG+N`u>*akI{x;}$6Xc~)I5@EGH~gfG>>1i7yUZ$CaOoGe>rh2ti2kUM8@0RV^{ zFa~OP>~Hz3L(+Ox;SIy~t2t5Q#q8ZbD>b=Zy5NGTf0oA}eyp#Ue|J@57X?QO8IA?(ff<+5W2}=qi5&YiQX^A*eerb*%_Uhjqu6BY`lwy?3ngL zl3HfNI>L4X2fS6;_T89N7>kafQ@Qp%BXs40tbEhXkVoIdckqxVB^OnKS2@luPfq0f zC)y8j$;ykUO;~dgMn-9o9Uqj;QsC)_t@b2&LF@$YrDFS;EScMiU&$=CFY(Gs?YAb$ z!ku_Mc_*5a@R08PaFZR$5^IxP=;57Z0lnqwJM4SCtXJ%(ljE77X~&GN>Tdf+?=KO% zHd%k-?Ow)&UbgR)BM0zo#;11Bn|sjS7L=+l9JJR2oHQ>vYIh~e^Ut}Hy_8e-hd&5J zrE{Y59T|1bPL^r8Zk}xY+DY^l-t7EeAhxpsk+K3O5511~YQ;QfU4}e!#!;Sik25bu ziprc!@5g1%=H$wV4eBd*K1h;>o^o?5HzF>TbJ~rQ@f)3!GG>#LB{`d%g>rWp63H7| zom6?C&&l_iH#vDp`ZOor@09ZoJ4Lc3HY4awsC4E9WNNt+@*Wdsd6N7*#hon^_d7?u zuXZ>S=A|^^UMp>IPugL5x4{(6?Q?ATZ4{flz0bKWBj(USd2*tQ>6k6f`1pnhEFZ5? z_TA&S^1rqC&--t6^SvvR-I_ome}%u+*i^lCTbPCw)jT=7-!{g0f{Q z&ayt!T_)>RyXo@vYB#mA-?_@0mgSBQO7_>zD0%9FGfQUP=jKSyqnS6#mXgeIQn)B% znOyFMQSJT%XN>H-+?_0MG&?~#d%3$s4xV);$Qu*go8(9fe&EbmXO!1J(S0l+857-1 zc`@JJC0*y8bZ=>ayE9Q*K5-^^`BUAzSUES%4at&hccl04#qQqGvB$ewya_kD(SY>d z`WT$4h|0+4ZbMKdu)u708 zGr|SZ^M3dS>A4-emJ=8LPw6?1WB2?xjOk{pK$7Q9xQ^uf+FmR<9iXD*3OCLB{#)*b zQ8)q;!5gu0K;tIw?pAk0Fczbmy)Qc5l{{dlw>;{u4@y@Sa8kG$dtUpa@F*{($8ArR zGo5adytpcyBdhbn*LgF~x*^Oi|D`+DTXEjKGAKRQ;qy;r;+ro$?c#nhtKAXuVx@bn zOxy0J$h?O^jwKJfao(@~;=U4)zQyjO!Ox(o@)%O0?ANbfw*LPCoS4^1 delta 150701 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

  • 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�$emTu!B8=y3%s)JHQF5W03zH8ZNh9MjC;ZIL z31_Nqos7=aL7pH`wXq(4JE6YF!gh5s!d0&l1-C`(+7v|)uEuD?o>P{=ze<^DWbJzQ3LpEFW`wxT~ zWhI9s)BKXI#-Qh_cF#8qN z#{V+bR>XB>aKFId_J5835r))gUS-b6Fa(2A(6(v#*;~2C=C5v`S1m zeELKJ2tUS308?P}ATFU~2hU5_aY=cNJ{g$pIx-_{ zt4~xnzzr`vP3@edCgHM<#w0QJE<}G;9j4>cjpw>r{2TNn|2mQRANZHHPGnr7`gb40 ztET2(24{pC)Yo|T+4Ir9xc%6s--NzK6OXWN7&tW$V`JvZnM6hBrCv}VppLsbEW zWFd{o9aehD_{#U2syw}oIVx@p;wgEy@ro+`4UBuw8=X`5qmKHYc(hObk2nAL4TDsE zEphiytv*79p;LXs?Ckw}jjU}^YGlmG@qo|9_TC!| z-XRfUyvxEuC-t}&UK-Zgcsm~>QMy)ZRd^J~!_PpPT-pNj#s|(RO5(+=AFRQuBxew^ z*HELCJ14GOJhKZYvL|CwZybuf1Z$qt&A0XH`bHj4=!TLWVY_V)JsTwj8V)=ZupV~0ej@E-CZLvH^iXfKHBw_SDDHK2E0Q{KD`x&nh zsrz(J8B{@^$T<cc>Qj05{5dv6%Vu56P05FRi?(u&Ff)5&}v)oY9~OC>Hx7#5B( z2B}lt(1{2>Q@t_Pce7tB9Q@46D^3LoPIVVO1qa>fXD0A?y%({M_5c zxJwivN!@&>#8)nz*@441IH{_79YvG1qlYzbBCZ=k2B&v6YpC}>Gc|+0#}Itqio?fl z=DSRm-mS$q>Ltb^ApGQ1!?Tt{lBCue(~LGxvL^i^$VZCVlV>ifq0@{$Z=RIpn{#wy z6{GBfidywd^ET{VF(fbc!y$4+LjUTbV8K$=dHw z!(a6HK!rsbFKRIx5EL$xF&>+N_B+mG--$haAt31bKTUo5y2En^5Vl{wRRwK`+! z%yxBUrqR&DW;`8JvqHdlA?nwes4ms(2tsN$%Q!#W3O2G{8G~)H9c*B|A_g1Gq>Bu; z&;(3vMz9^sk;8`(Y;d?zBb6j=50JFL)pBU-63O+SD|vp?^1IFkr?y9)NndA;)3`O< z>Xk-e0<4I<5$ZFzs`^CF3eMJt&M~%CuThFQApCtcT8O%P?{&s2&7Hu|K>==J^YV?W zE(FCUxpX#M&Ys3;(2^3`B?BY6dQ4HJwLn5Xj}Zo?*=8d(?V#yJ!Sy_{q3X2&hjRYX z6%C8078xy@I04`g4%H%G<8!?~P(Lp+T2#}os!ofI@eO&M=x6?jflt6RQ>hzMq}50= zO%n4um9^N30a6WZQS6KXD-NI~kFdfza36VjMk{)n**4m9e#MW2A7TTSM^}w*-MO zZ5A2F3WQ;!tWjazd-qfKmso+YXqozTi80`12ExUt6$pf>QoKWrTxzt^eB-m!=9{FY znr|2kMSJHW7%=So&dsNO*1@EmBy=Zf+CfD8G3{8 z?J}coFH0Kgq>ZxB=A0eLu?UD1B>uN`;hDp(&Rn=!!8xb!eugZRORh+DW0~=`+YI&V zGUK{yYLMKR79=;Pqve8Yrj8l8F`K-EW%Ck4h4~#FonnT{nms!IyWk%uXBaAbQl)^Q zf{xRi>^w<{2$2JUF4^b1Oybwilf-q?C3Wot$zC@`a@LKITv(rn5h`l%a*V8t^fla7 z!gAwvw?*pYa$}`x>xX~sz!klac;ar-ZzW+-8^wT%;^N(N4&p&*P=gL@Tyw!ib?h?^`Tc9DU?|3CTNUVH~#{`(S z>DRSILp8|xHKZb!lwIB|H;XY8{&-gY`gKNkx9S(K(En7Y*BdRHGcT(Mq)G+nC^@}9 zdU%(PdovFw%BTk)l4aPsQkx`2>rTbJIX92ym8p*z1i(axf*eMx9=}CHF zshsqJ(1M@xCb}G(4oXCI0iiV%)e02&bZ9}v4bY*LEis8lbV{~yrAJfM(`D3aNP65F zyc3Q1bA(a#6uqeJe>Yy$g}Qju9lA1%Hu(oX$tOZg1>CoESB{ z>NrGmHDU^D4VdCK2t)kUBp;*6v*)1eHu@ONI)Zd?u~G}Yu5WFLdlBqjuE3_4@cS<2 z5PyiVzhI;t2*SvZc|L25T;TgWawYojkl zS2FyZG^#;WtCDFHmSa^WEy1q=>?U+7HMwb(x1gdL$aLz9G^2ivX|ib9D%l$mYIsBD z#oO$rhKCyOJrliIZ3<<;(TogeUJ-QV+YoeEHxO{;L2Y!vm1#?4uw31XfJ?^p9T=y) z@fQPyz)MCAO?V7Am1;@AAQauTO$qr|nP>eG;e}cO=a8Kyym?{9doG3>zf?C(Rxn+h z#AKxE|Hh)?Yr2_GhZ=?`aoC%~bQfKy`61Mb7-~y*O3A`-DP6E#%I1Y>Q>1)$h+Kz6 zygmc8hjkq^NGiNBHPBj<18d0*bSK|HP4VU=)p)xR>NZhjZ#U|@O;N?$jYh6eDF;86 z&Bp>imXIIOTvG&oyozRE%ifQ@BweNr#U!J#tb zs=w|rnl1QA6Y*E_(+^*1ck}eggE&WyUp-sb5cWKkSJ_s*x(Yp8wCvC{yR5D138{Il zuB_bD^z0{B&V|Uy6Dj$wy+$9mm#*u#2csRu4OJ3py!pCCyq2X(D6oANd8B@cG@8~% zpO;0{L<*8P`o6kG8I$X;0Vs@FoC#3i932}JDv9~kxs5@ET^ktaq4K%or8+v8 zpYIShYa3Mwo3)KLqm!Y9LD+NBW!^emC3N5jJ&au&J%AN}!EK?tWGW655Gy!Kj#$BY zlnoj;!<7VooC$)tYpcv9#`C?jo2oHH6FGWwrq5nbnHc^DB4=luP2@_Vje+i%fPh?) z6kbdUSL0)h=2Oo_Zy&zFtJ~bp9yzCgskt4x+E;gISLJrV zjm7D<#tu;nVvRNSUiXiMtR}DTM(jsO zF~J5{P&z;Vr&!}PH`lUVQuLXUD{J@2rH#>YZcCh;f=hcO3YdWJlXLip9L~s;RHT(D zn-@!>Yqlh;nJoKOjFI?HM@Y=#!4mZeFyZ5VvS(gjiJ0A6cFpRA)k754Zmhktdq~ur z?h-qBz5evst}+4UA1M_5&5m);ZYcv`CiM|{{Cgsc~b4D~3l3bz&q zdvO*jxA0VcEq^GAz zN@|K;$;nBQgq4_>D5-cYKM(UluU^6hu#e==KYeShpTE_K0OW}L=|?Ok1;8OD2E-u; zlj!E3JdrG8Z(rLc<(COaK3b3PJYuD8ArN7~u40~GE%ew@$1q=jbwxnBRkT(#AYJm6 zs|2Lu2lIWBsbfx_xuA_(OULN`CRLhZyxNesQ<*$iDh0`cqi57hP{Ylwl-&Lxu?t_M z69`HgNKQ-Al&fK>Mt|43Kmt~V^aNm0#k7Wsv6FNZUnx$QEFf{fA{H@$sMpWJDlKY& zUyZOdeqqAV49e@H->aM_Qg^L#?9}}S25651$xj{~_v=45Ll=3MoW%sv?DAGt*!l!QaHxMJD~Z zM5p9jTM8YJb3mty8`SL#?Sd@Jtc0Ar|h5GT@vPXm&EzqB^fLAlOB?Wm9emgI+kU; zTZf3YsE5_iQMs#ZZ*)&M#`g=VZMM;H5WDZImX8T%EFU8YqKT)^vaH9^W)_~%0#?X= zd^9a{y3Y|NLD6vC5AKtkL-|saACqnTpK1#p-oLGJs31Sj!mZ47ja?K;T*NTvan(IN zBTavdLW(OTC0VbeBw$=pq9v@3^7KNPgKz5J`Nr$-IW7l*jXkI*PNd`9G;z!y`IL_q zR>ZM;JQq;1T6q;1&Fb?~f!oEj6F1-!2~`n$olJ11(ubH-C`aj=PzE?*}L05 zvvU(V^#ru_L5DFrH&f#ng%@$mazs?t2IG}k7JAj!$Ync?L@5WkY~`gDnT=YN$_on2 zR$lBXX$ItKIU?BtE-0^$=A@y0Ia_wet9OnX{ptsXDNI0|r*VslibRl_tk5tGhF`>V~zjAm^s6%|yLt*FYkwZic?W^eCeV*ZC1V(lp< zJAg-#3p5@*IA(acCuASe30r6)Rn%_v0er?<1SKt-*aCgrsQo5f5F}+Tx*>Lw#$7M; zm25n2ysp&~J2IPV<-J zQ!y}ix}W4t_m!MkzLGiDPcl9Uko2Y7Bz<+Lq;1+I>A^9Q5s8!~C09-+a+-g-9NxT0 z(tYMg%G$}2ylR{zt{5qa%ZEzB(t&bdNq?A`3;RjjCw(Pues77zik{a~qUQD#HM6@$ zG@_Zcx=P68uCir(7uh(bv#cA@N!D-;?Op3kxd^I6bDSAg?K1vq_P$Qq#E zbUmYmEj0Pt*Gb;)ZE`4XuVkd8=SQD19#(5g>y@hNN7%45gUU*aWVUvrckcdEV%=g*)+^m9wOLBUbIQPEMoIkqm<9089_qQ{Qo>YejD z^gNfFMH?Z)cnHeswWGmAab}&%was1#I1F0C=d5h4Q%TnR>GZM(;ARm4ag!8Z03e>g zl{>eu;~(=7vQilrS7%VdSwIL-v_X(Nr5mN(|0?0&9X}=EG!S-xf+G;lUY#WoajMM~ zqu-lB+jr}pIQF}>>u9B(toCc0N`+l9+776YYA84I@YRetwp2rdEUGP*R6~|Yo4B%d zZiLP*A=PAW4DR7CBKVNmVPUOej`Q}hgRx0Vq}GW z3$pbaF!EeXfbzd;W2B?m%4jXqR<<3kGCEwr)NH`WokMY*(*oS#7Ns6uHN2ip$j(-8 z7a5H^>pmT%lN+t$A+}(%OEg-rLA2Ss21*Dxy(^z0qy96S_p8{Sj5c^;<+ZE)y3KI_{PMoa-D0EwaT$yn;0NhC-}>S zalUe9>_#~@dcEY2S}TV~t&zi{*UF*MYvj<_wURwz(%D=CII$CLV}!0!0HjU~e zegNYw0OM`=3qvM$kuV#KcR`-+fh3ItAjiyt9G%ro_EC~zQIZ~!ZE+g?PcuslkIsW7XU#ClSvyK{){m1MpDB{#J4>?t7fQyq z&m<+(Pm)!*q$M1bT(o>#h3CnJK3saBHa5h8uO45b-usu&(Z%2BjJaG*JL+!cFDW%1 zKj-xW<^VYbF((HmiaLn;XCf>Xj5__=&p_6%ap3IS*;87NCPRlNs)U9yOKG&4b6hjdup#xKS=gPo4v~lu>JfqHb%$uPP`zTJ=jNGzJ}49pTy-LJaw=Zwg~TA;HQh1P;^IG>dSZ&b5;KBQBCzcYSe3T z4#%{J06rmyWx~=-0DG#mwIyx~?Ja7F+nGr@(7Qt7TJn~!ImvlFFQ>?ECFYI$C(v9} z&)zkf)gW~5iY-v@-8H=G2Z!%Qx8%pVSNSR1kRrB@ib+F_D60=TEDP@%wLC2m+fvv0 ze7A(ijHhfuo^t5gy-!8GuP>5%o--OdVX7=rZug8q-8Evbuw6n6v7c78*Pv>PbjA%; z8!`@=_Q!HICV;!nwrerlrf+yXprOjVhXat6k`{1HNej5X8u<#=2=&R>eg`pM-no8;Ummz)}b!Sut| z>Qy*=jd0};UoH6~)<_=qT&Ki6w3kF#Xx61=I(OPw_*n> z6O9*F*)>Y*=lCY}>r08$Sj+6Sd{9SOPShUUQ9i?8M&w>i^adrYhqU&=548!)4>aLF zrju+1f&;}}5=>1EDBnJ*tL%U--$iW=INwc&!G?5dY{Gi1b{e`vYIm1?FjMzIZtsVo z%9Q|9mFwVwUXp-ykOi5AeNdF?i{&MWi$9Wsi~CCgERX$5hRXhBBVppU94GOsrb^t} zxpDyA5Q#x9-5qi0K%5kyTE-~>9L|6qUNvnekN31P=c^t$W?hVBM@x@q0RC9q#q`Vj z!ti>oHpjYgyxWi8e`&9;)Z%B%*Io29wH*L|Q)4}_Tzj9ydmG=0{XasbUoR`x{saL$ z5!nybH-S7gEk*kej!!}FmB7!!PUYha$+n*p^!d41jr12=Y+#udG;mLyJTCX|-K2C^ z#_vA=)!S791(q5 z&g+}Z8oj0B-!fbGwJiWKJo7#$GtTYg0U6^ss*^`lJ#RPAL@ z?WGl}oiq@mzW5Q&20?mP%03B&5wQ&e8QcA2wCzY!wNj&NqqTw)$PM5DEP5ZlC=rnd zG#99tpN!W#rGv_E;yBEG7_B8Z!E#daP|`h$HjR@Z7y|;M)luzNK1Im~Mn>_%?NTyd z{q-kfnOa;7(YN$xqpquL>}Dw$1IQn_QO=FnASZ{el_Nt|Nx|TilFv2hGs(lAi~aE6 z&m?Ei3OO`*g=7y}F4@?#xQ48dOsuS-pGnp*tl=vqYXsKF)si&|3zU!v!LBI*Vm))3 zk7UdMCCu}KY9}Rp8YpRN!z699lGM;xNsmpHOi)5j98PbqoF!+LPm&8uM#<$xL*xo7 z(pNwSm*)18^QbhPh6X-9y{qI-?kwpOJ4?d2juJbjqwF5lLBdCNkdWaWBoHfLXnXMk zMQj|>UVMghkPU;|%lg5c+RNHO?PU$1d=>a%6&|m|&b0!xumbyX?8^cBpJK0ED)Udq zyRJ_`57ukez5<`OoL@_7z*-4vSjq2=zi>6y8c@Vq{1EFw6B|GiE;ukg6#JkGUkLuq zpo`5A{r(XB0osM>qMev+92+#{!T7qXtnxZj+tru`jf6P{A< z?;pc73RkJoQZ0_gS^O_HVuEhTcbLwJInNDM+)m>KwS-qd;D&(~>ST)hn96fX)*z+D z?hW(f9~*(sG>0Cx$%2HTFKx5;AHD;Dz@^cbxv7!=ZM^RSTaYy@zr|(@vIZ8Jh46R! z6wCc-6`l>jo@qdOI+x{OlPy@abJii;^URfe`X*HB!(Kq(K_ z_!>VD>Fi5T+ZTGq=h5RwtYN@cI1G3b2w?-r1A~20eS1)DwGQwOhp%q2%WtJT!m=J) z)jEC-iG*K6BH{Nay}b2pbgxIs;lk7UFCmjKuh4AbDelAeWJ2%|Z3q^BRPlK13Z7NTd-CJtkRN|BEDo`= z3-!VOHC}yO-!gqVFOk9?!sl`bsNC6FWLy~3m@JwYz z{m)4+Xd2=B>$3PK?|^IC;0%iQtW36#W&mn_ z!{iDwkW0uw&M*VnIbX{BReU?M_RGjY%IqEn<{{bt_+1{-9j%P8jUpG~_Qe?W0metil?)NoD4nxxuvKo;8lU+7%A2|q|L zWF*{gU@sr*FV{x<%9T+Y<^1psa(dW0IW}aq936~C+d(U(04sOk3cYd$ESH>t%jM93 zPbC{GbHFma()%xybUaSON*`$LX@fqMv_W`07&}(_&=u;zzl_&i>EqW*I=Crq>IO+e zx{^BAS5iSusi3CRb=%Pl0czSFC+Tr%lATc?X)$qLVv-_LLK-Djr7#@#xepQV43wozzKkCU%m{@f{@%6qPi#gB--#H@btwjqadU{A#>D zVH-GV3uwY09JLv{FF0xwD8vV}Pi+v6DHK3l=*jHmGl{xz= zJYP9L-TBpM@gg4K*=P9Z%7N;Q-;5Ts@wxcEtC2Q2^rR_j7zzSh!%;B6a*gUL8^?Nz z--I5rbxLmuo8>LL7Yvm6Wy2+D)mX`NO+m$Cj^qa}mi#b?hu!`dUx5*`skq-X?`VGV zZ^oz9cq;Ar2BZOp3aq{IIlS#jjm)>zyl2dw9=bOI`9aCGD_ZxbrKyvqS;s}w$H@aM zG$+Das9yOz^9h7cPEM44`_Pmgy<7I|*@4HAU=Q45edRR3{Vq(R2l6x4b=WcmM{?xS zxkxDosNcqIRRndmgg!u}5-r&;;t!&^Ms+puS+hYMnny%$7)oWAx8j5zDE3H>3VqhB z_X5Ei>$`8%(o4nwW#pOF)HHXG7AnjiM!hy+3^!UskAU0||MOhD{-Oi}t8U-Efpn!( z_|xvO+AJ)9W}B;p$2O2Vz>Zz(ee9NTU-@zU^;JIZe4Zu*{rPw5S`2}2PEYFdd$f+| z?_uCkHPh?m&EdH+>C+79GlM3PO1^9~Xi(pq)lcAaKMS{+77)9wG(r8Pn%Skcmi)8Q zWX8%&3D}v39x{wWoML)5N7Ji>?u@kIc!=FZ)=r<>;}Kl8V!Q$AA6wmQ(}#Y3BS-kt z2Koa(|98TFFopkAOZZ18DEAtscW0>M$WOHwR1`kka_|2a;eRD$Ji0F^{I_6Gl-aB! zE1Y!i>D-rXVU@F`l?Yb!WdQq9 z=SP$ytP9eZZj8g=po^Hmo!jf}y|C4II@%Ao#!hl3;iW!d7z{K(NhEVNLqNjWW{Gl zPG+GbMaN3if{7A0ca$8MHAIqT_LsD2eUYu8D{V@5$)4;f*^|0-kweHbvL|%XD-%$j zft3a*PsK_a(_RwCbdZG6?PWhQkhqcUB?c>UM0?qzf@_-1TW$ro2LRapu{Hz9{jmFD z-vl7vh@DFVzIss8Z22sZUAfgV-%@RAnKfKYREYACmDBrxn3E@t>0T77Z;EevL0Zj2;nUY~6g+XB7*9JVEiG9NCd5k&Fg-GI zm+aoXT_Sb`%dVYR+_Cg??7Me|$w6FdUr>-Cw{Knr-rtv*1bbePa^Wnl5Wj-K&)0kb z_80{QHO>L%Jb&}(230(;{`M+u2hkGJO8$n$0sI^i1Ha~836Ghw?CXb9al3Ib)e#lu zVK%O%y&x#|@4k7c%4&JEW*q?cwf$m*s7L>1xt7L{^T+ebr_96XNCwcyr>CpKP6}XCf)ojySD{dR|ISENa{%HH;C`-2(eNN|}9e01MxRrYy^P?Bg zc*c6|E@ZlO%-5S)R{zsNdkd`o`REXC2!#!FS8?skx+<@Z`C7v#jeZF1oe=1ei{w~p z9Q&aw|8=$Rz?NZ`F1`7XgBXOApj5Zl%r~2|P;1F*0J&X^t&r6*!R)kC8``6gzxOq> z-CMaQBwqt}iY~*R@sE)UuE+}DzDh$!{rpel;bvX4jSD5zn_NKPTi7)k1Br>qcd*|f z0$16I#(d75X#Mog*PQkFq#(IB3D2?a+UpMX+Z=C(zl$YYb-b?Gz_n3MjrEZeV_kA= z%mz6!c7qg*Md^0j2FV@2UJg&(AUTs=k~3|i9GbC74$avthZbzXbR&XN!nBRl4flU*~1!yz9ekyE@Sc5)wyhvjhq)<*)okVN<*N#i<6(s2GU zmeRVT#$e*`LC9;a1EbnwL2d(!x10~y9>LEyL!2v+19n5;EUx0r)Lu!9)GwxTjAt{ zOzbM*Q@Y7+^ykFD%Rd0mK520u6so->b9p~Gw6eeCtQvrWh=b)Y4kYHG-7n8IR`NDY z!nt0|Cfzz;@`IO20Vc*2?17Q94=NL8M;>x~UOCS@M_7d|dt{EM(*BS$TxzJa&gNm& zJ-~F&hi%`@O~uW{(c@tUP@mVsC`x;|zmlK)rWyE*>KI^ps6OxEkFF-t-I-9WwX2YKDo&7-55HV}_WOFZD*p24HIfhdDE^7N?J zg>y>?e8oUqic0*Mr>>6V`mX;`8AHr zrk#7GNKI>MdOyFDn42MeRc2GOsRg;z*R~B`p|AVVhEGs`YYND14NskrJMFU!@q_U~ zfgRtnHhNZ)%^JSt0?DYZKUZ={w2$g*%W($0e`EuRA zq1w~TY~8Xs2Ix2bLw!vYzN}F=9w)RhzN%&I)~e^6+O^b@wq}jmRN92%oyoY<1qvC5 zDU|2iW@p?O{elIdt1oDnF+SVgmf>fyDVJJtlTAM zHtdnpo1@XLctDQhptGI{fH_wCfs}zWM@jIsA?Ww(FX0otWas!^qQ>=*-DAqZk4UZfvjtbRQsZ^@5_KF$NPGW$J(Llr~tjJ;QWH0tTKt?V#w4EsIyMU5h zJBGBwYA@UE6$Z2n#p4j{!B|09fmquH)xsZmuoaSZi+a?;tY6I+`01;ph54S#g;%*Y z!ur?*mwYquGhk##2?TzIPUx)bq>-qN#-qh0VLlF&Eb1j`JVUaqk7VIw$RV^4=B&V} zGPF9g+;z$uMe23|uWeTgR6urHCJuoezEhfX9JnZoj zp{aTsAhT?bh?1FeKM`VarTl&0IyU!*26XK{_1;7yw++jiw}xqW9#K^ZqlvLX38Mn) zc+X>O^J90^0p-!o^y+g2WBV?`{?+M~JZ`I|?b+N@^BU@}Cd zIF3-=+nb#`yC{I^b~sLlb=<@f%yx&PRSCr{cQ8L-mS_WHi^^(mHtu%Z63csRvAh{L z4za9peEBZ9vLsxJQ2i{1%W(}ZN6DNJDaDD~Qtfgm_fc@7TQ7t10j$6LLWRqry#Iw} z#+4n+SKY>|;0|U-7hwGER6zOE5V;E+zc(E_7p~0H3-=1$;llmRyf*JPuDiU2S@pLt z(Tw*u-&l-k+c;p);n~+#?v`Rs0^VfLtH&X{6Fis;(a(WO`yyi`VEPCNm^=stK5sOS z^buFk*q#zH+Ec|73(?*wjB{f1-baxgt~aC_J9KwSen5ZeOxD%g(K0_^3Fooh3Io_>e3{P5fl z!kONOuf6*L`DuIyz`oc5^bdr34u!1WiN?o0(_CG3OU!;Axcp9Jb#4!A$BZ)E?w#GzJWr#S1QMj9s;u{xYuEoDp|W6 zRLj;PTR2QY)=;}G_So$Lb?}AV*mvW_J$ov5evd1P>e6dK# zs(flo-v06jIBvy{aerFY7Zn%l8Z1WeDGLj2iCWG0Tr*yv%9Cj;GC&{dP%mw=fLwm3 z_z&2QdV>1zUS@|nqmraG3Y?^zsrcHBp@;Fkt}C}(P)^)gkNVAdm?>Pv$jmt;nxS^3 z)3Mf@Raol~{Y_O#uvybq{w*x!ug#WEaJ11fTdFqJIK!p?Ncq?9WA^I}hS3H)80P9z z(!V&641*4vDxEc!^k=DatCs#`n7AwEYbtXD{vQhanC=$W*cN-KZLybx(uf%@mm(MA z5Yb)?(kQq7`C)@RYN=CQY8xP&8xju(QKtZKW0(T;=!?#_h3RIknjjkz4_p|vafbQo zv-HH|QyuINupb2DDH`%HN_cQBH2?xsW0J87I+5zRx zeJ2zeY>9-C;Hx3$JLXdszfTZ6&rHjNs(zAR0AWsqD^iV3A)YEZF zC~FB$3oTL8v&>h<6WOsa67Z0X>_m4Wdk!bd;H)IYelEcJC6bEk$Xe+$M#_w90Ov+rUXOOyZhjazt_JuOq)|4FLz{{8z(=X$GJV?H-^p8;Lsxe z0X!NFx)l93j@uxuzHEZ5yj`lB{nSELJgt|7ikn&3b^U*~scs=!r-c1-S9 zt`_OWI~LijpX@&WA8<-5(^GaUzAk| z=Iq6Xd!d#-#@Iyw*^8}7T?F%4^A>6_@6fqB+E&^*M?dwbVz#Yd(i~l!mR75ZlP+NR z_zbYX)9FH&?!B#RI{qMCP*MAl0+!$o0`mjas+swscX>JP5KD^w!`z|B$sGc5c-_t& zt_HD*1*KD%Ij1$UFOc%h4OP?#!I=da@0~eksPTloxlC+;aQvB zSR86W4vMpdvgb&%>j#xdgFc_m1VT5iz-edFV7E{Dp@niY+9%nyk~Y$8){5|+598;^ z6A6Q5{9IYFOB+AMIOJ43U;R4LJmYp#ofu^fcVV2)s@-x0lf*A>!sv``@p3Z!pd7{M zj9j2I$IZn8L7wj7JEE&>9??bohj)?ytSx}SZG=KVVh~m^ zAUVWdq1Z!VsDxn;tFmu@%YLB(mmPe@9%|!rs5;&cf)i*P2o&bp2BfxjJ_cF?nYI0b z$6K65bjI3-A0-e!RxlBIR7VLP+eso&?To_VPo6P4FxOKOfzmwZsgJtz7|~(}sjUGX z*+6YIc#Qdy+cGtAjM<_yd>9;Kuk>Ls-G|VuXHiav4}(d~flJUfvRVqX4-*a>=78kq zrgCf=X0+82QiQO zWV(D_j#@}Dun`{2*LT(fH!ZbHkp1>9)G`3}OAWGCD>;Fd;7c#&5!CWmP}iTAt)BuD z1{aPO;S|RC?YI#+9hmc!TGlGrQp5z=@4vynrpj&sE5P;Z`x<1w} z$B@Q*dk|6yVBbEq>(^~?W9VIjB@TO4gCEPa1jR=W?x?>_G225RTl%>|0P7D@AX`G1 zpX>-@z2iAw<2U*oXv)8U$Vyzt2rX6iSC7|gI?(#{mnv+k*}!``Ty47B?Z=~g9KyHx zFwPZ3%imyjm~;FGP8?y?XX~INoB_BN*kZS>@?WN!o!wjE8xUxxz+!iW99EvwOs}Rp zcE`%BxeN6~TB{|{5z6R6vEA|XJMemnHkgJ6*G6wqD1Rb;+KX|7vfY6WFNTdM&KwX& zDASAi1Qxjl*HVD%bhFh2{R_dhY?_+%Zx(HVIAaQ^y|8zgwrMD$Y10%1e}qNxY>Vh^ zy|qnq1?}mMh&~;IxFGHkH!AccnDAom5KaC4kx}_2=oPmphNg z??}R}ms%+AQoUxFof~R_9Q`EF@-?R)WzP(=aeMZkMBqZzgsek)hQilhe$M|)$-|8H zyo5t?w5pDF*$#XDUuT%D-CP%ZqviD0I61KccODT-lXLZ$!FVX$^%MHb`mtWJepD~n zFtP^@Ms~wlpRVGA=Cn;*04z3j`vC&kG#7xig$r=VK8tPG1A(D|*n^&0!Pave$>9T_ za-`E(c>`nbGm6>h$vyl2CC>a8ZvHtY4H=+$D^vNCcgc;Rdx zuCOvjYbzrcRz@CXlIEd>BR}Lb$=~S%DoW@i5J*=A@pRou#>#>>1jhmFk| zPvKK6Fzcw*Tg{i$)-@<_>|TIcg@#kK98=Tsv88Pv$e%Q{0#bjpp!LV^pliQ^pL+QO zN`Fx>Dt21ZRLfOJRmjo`WVMl0BPbBnLDp#el+kE5;U2?1I`kd<5vHFcqJQt?$xOg3 zro$Eo04g^EKGy?2*TINb19`eeP58uYR-fKCJ@C80;hRP1D7qLfCjg_@ua~O0A!Z#< zLM0(oLnh&qI@E&7s*p)Jry-L&5mL)L^|v{--=`w2rF<6QH&y90JoO0Z+QB5U>R+(^ zOa4w}1e$NO(%;FFvqU+I)>-X;RvK$K@AwJbl3(fWowF<3bE)XUh%;hHmgzMC^ zzleD1C{=zV)G}40{ezaA z4=Vs`m?VGHcq4 z@bJPSaX|v6rq@(ier5}fQ^$QGwNR>fe?30si$~DCU(7+DhjZBnjLZzB+4?<_EW778*k$%ShfX}D&HIiNhi6SG-Uv1a23%zYqx|krN28`K zG?h@5TMaBNbcL1ouCdbU+%{p^*j3bdl?Ilo>bwMm*oHda~(3MIUzn(&Y1bZj6f z$D*28mrXUlm+(ELc;^V%F-zrmO04>;%N+U=DQ1^!;UyRG;cB3d`N6=d0^Su}*<5Z5 zcs8K27M__*B;j>e^p=15l=`p`=-1h8Z-h5@2# zdu>6OCNFm7usi3{DkbOF?~${hoKvKnU5V)8Am!vqcHRlu9~~#_$Mpl{^v1-i9+-IL zi6i=5a0auptO3=m;{wgB$Kt^nnkFs~gAdlmLG4^<$ZjW_2DU|UvKW$6<|E^uaj(%P=|23lCg4v*a@o z%pXBR??-D&Kjdy!YKVsD8R_VT(8WZ;_GGX-grRqk2X|-v_}x97SX{n%6p6)N^c3!_ zuwm>Z0pwui2;3dQAX)6gX|{bBYPkeE8!sXmG+-Op~UCv-XRTM7Aui~co%UD;HWS!qFspq03;p~1%xR@aauH;KX@o71L zLrMp6>t^!VB9Of3b&a}-0rLU+sxN%XnOhT0bLLD zD>g)1BK|;IVuVNCTHk{qenj0Ebz&8E5h|a(^e92Fmdw(GUicg~C&jKa>*IT#3N&A> z#{q_HeItuhNhbhf5C>+fkvgNW7(%-=nmOzY!^tchH^<60toHB2Yd$b#Nrf^mc6USu|Au98qXPQY1A5K7~r>f|u9j-6~^egF>*{mvR!e-AR- zxh!A2m7Q`-`qXMBCq+2S@ikDGS(Nkqt1pPqMCN;%TUe}%|kztW|5{@B5wm^t$o zqor|}bnMbyQ%sB2RWlY)jLW{XMbEisrh*Gxn6WsgkgN>Gq8*2ZXbAZSZr7AEV)R7o zf+Ksv*wb!1M-q$~KSdV85Q>Q0&+?^CG0ja)WV5d2;(7?eNxDIbym}$IGG4#gHe8^FJ4STsd5oUV1LZz5w zgZzeM!-G;6Nj4||pYa3P1nrY!B%An5$xY3}dGj1O5ECyxF#Xq$?j`F+c9%87x`JrB z;NX8J>vSbr!g(%-!v?I=o9$#h_+tb3fTZKXPU7(ae{AFn8}Y&>y+Ai z&W^7OK$^tLLI{Zkjqp3icM=jyB#4Ek)4o|<<>1_Ik_2vHR+EawtcKi@xzO5`Te#WF zZL#VTZnmDlrW###wVG;lkEK&~t>{^IoG5S$Cim0Z&)YN=PShO9+qO{hL+M1ZsRmBe z{zyH5;Bdjo{7d0xNVQtDr?n^Z9r|i^n~jw#(X8{jRZnEX!P;U)^6~uxmAxBB4Rn^_ zWF6S~{6}m5>HE(ClXv9Sjf+x{mm&vnMlKGQ#6?5C@;OLf5q&|vVVbUX_Q&J*fat{yH+mJlm}Z*ky(57D0jgJ`sP}e+K)v_gD*{AUp;y;9nK+qw zN#2xXlFWL)-#+I^0y{JBkHtRcUNv;D)_4C_+pN-5LPQ;I@KjEq_gZ>?lA%+CK#Zuz zux>?CfoIHiiID$~6v2LH5FrKUG2Pet#all5%oH3r6-|wfgY$2RbJ8m~JL_wpDGR$+0Zy*zObwX20`)b?@&BW)Sf=QL3Qp~h@s@c%i^#%J&+z_K7QWh?1k3n- zsGBkTedo%w0RF;I#Hqz6Sl;?HLb>)phzK4D&j!`3l5#nJ{ya(`TBPyZc_~KYWqvBg z`NgD3QNUTa4K&WVM@!?;NR+&X%cTS1a@7H`roAzVmOek@nB9(zuno`}+VDinGVPc* z-ny}g7=_VNZ+YEH1#%Ngq=RZ?LjXQf`&FXlZ5u0gE~9dXHK7+!L*ERBGzKM0ZA_L_ z(vjy?s-Y+ui79d%s=*7Y!9xY9;K<>`sTlM|OH7GDpkH0X@4CX=VD7Z}ABzW853F?T zo>*>Cckc_#aZ*cv`v*1RMV_>Hrq0>*SYg8s%nuT6IHpW(yuXRFbF|y(L2jlRKQ2Y zy3ObWv$(w0v%JjoGN*x>8=RP=f3@#pYsF<13!Y3=T7sMRN^>Qjww+ADttX7 zP^BFU!ViIuA7ri6hS>a&DrG6~+K}_)cVq(G+ z4pV+aILw%{K+Q6vaM*WX1eHUIN*A+et!ogU@g_2rq7o8=XDQ9VjPg1Z{u`PB;i%5c z2Q`D4`A`#Rbj{ENY+TkggPKBf0Nvm9wb(2)<)JcD2?!&-%q{?xURDBPnOsKCZ6!Le z@cz-3u0|qi$shTb!hhb&xAb}*F(z$xzGeLLkPh0hP)k4Cam08z?u@2VAJ7PlM)?^U zfw^f8vdJ!~kP89F=)NaAwX*O_)F97 zK)JXJ|CgOXa&3E%+<>)i4MHCP2Dn2zU}BBdzrZr`xtrSD0?P@cK&}^9KDB`u7ZLDc z*A-{0)qogPsl`&3UxgXC^-^8eEM=wTavZfj-q`wkE}ek(dkjuN8p91SB@%+>0;li7 z6%gR+ik0MW!)nrl1feNefakoio1c9g|EL5v=n#l*t#HsG1|wzSkflh#mOdFgTQ~pb#WfgJpj^9fK_k%DPdY|RbRoMJ7##xVRtGx7&!>(CFj@k}U#7dF-CR<{<0sRfICK zC~z#wl|i58&_+q$xgv2 z189O>+8Iq6{IMY|LoetcaCkatfs&%}lkHW#Cg;`bB}GeB z1Zkh47xD{>u&*ms=T=dtF^a_5dZwx9;dftYGio8B2?J;dJvXsL*q*B=WJ%Ud16 zEJI?&=W;chp#p=QPza{kM}reyBhb_FL7nB5*YmR_BC}I`Xmjc;3vH_YNEaGNU;MDp z(+3@53@Rz*0bo#h4!ReaF&6@ZZkA&CA&t{o>DL_|C= zk+dCY1w?)r{ZWx00};eT{yw5YVd827vc^9zvb^xBqaG0|bey7n+-O-lnF)ot`j7&n z^oYrXGS8JrCal5qm~H_dlpa+e;8S@fSSnNE6hW>vTH;=?bP|O0plKUpv5P*MY57@C z10G#TXTn4)y@**cD%@kr2tCY08PUm$?{WP-_yPO=HxCd3zKK6nMCS6&f*BgZIgkqt zf0xYqze{@E-z2^E?~+#YH`w1L)m*`h-#9?6`7FCRlb zJcN9pWPptL=7AJ{_ecu9xvyA4hEO`>L1K_2x$v&Kd;mij>gl*AnU~tNvn>{vy$sj1 z-nfkF{5q+sEK^odQHo(rFh~ae1(%nVD0fo^Kl!7+67DDuQ*yX(rI9E6IP!$SZ%PP5 zTD6IANxlpQNob@=-}$);Bz@=RD3ItdL9*f*sPvtK#|W8unc5py zAa8ZC!J~QKUXiPgL|KD@m)@bQ28V$cof`sd3dk642q-@If>D5wGh|F=M!I^OZ-UnA z2+-X@moO$a?Aqs~xH4|y)E{b%pI~G|-W5x4+y9i3ptA4_id2CpQ&~(kl?7{5am~X| zX3U1Nz!--WpRX4JB|0t{TCNa3T_%Pnam$jY-kMjhV9NqI&6m{>95!{KWUG<8;8ul# zlF6FdOoZxH7JQxD;J7suvbJ_hRd5(Y_nra0;A*clku*^bOjYPqA#FewQU}8!bh;?Y zXcaRoucM^^Q`yi`@WV{TavTtfS&;<=R7#rDAFbox(ogxiEoadN#NZaos;EZhUPH~R zXMB+AL^cCkUPjv7TXiRgXi3*ld7yIS|k}5#vf`SZHNnSyPQYG0@DU#`bTGBlb zV|EU}=}jjw&D~3qHoHsGdKXDveH4R>k79h-QORHFBE^`PT#4B^b)Vbh+-i)#T!X1- zYfs7bwLa3i&R5#j`u+s-iN;(f2({#!1T2%y=|hZyR_l;WBFGg>v#W*027duS^u}!6q_%L)TM? zIsYYa@|Ad|zP?rwimr%_Z~a^Lb^-;v98 z&aB4FeyO0vy>$wrelIf(*2t{vNFw$?OI_ zo!C%9#S|#!Y9=<=iS`eL$|QRnur)`qW%{i7Dh<9IT-oDzSaF3?k3*x>84ZxcJoq64 z1XPT{@0Kqt>UM2UDH#0~)9W61XijYwxS|vc!&%)G3{&4m79{ZLEJ#bl9&iOGigqfP zp^7I;!GJ4d4ONS-VBULL!m!}?hgDcil~chuYkz!TSnND#1M@JdZpMlH(mM9t|c zx*YdEv{k+kkq6cNsdSq zYL!gwcMmNCdmfVHr3WQt$w5h7Ia zoJVL;KJz^k6(()6^y;R*YOdd71D^EAGG!ohCLPF`v?GTOY)Cs|V(pko)V39dYOGdG z9-%GZ5=r6~E6v_<(&U#Ybz!MejRp@kOfyw~@xn#9*LGFzARv4j``n9-_0od4YFVLfw<43fh2Q3Q0B@N_g)J>6#wPuTV9WeMcXIX zP?9?l?Pnx|K?$s+iLPLbmCyeJ%U6N1uID@NjmJChfAsUU|8v9g;`8`^TE8cj#hWo4 z)QR&a3`3W4akoxorprq(l1M2hl`dZ(r7j%t#!@WI-9(*mnfE$mYPLu@THz|t3Re*Z z_+!LdMe=Eoxw!Ji6HCSm{TWqJvk=g(pxPJA_?ud_@Na>}+}lv02^E%~Klf|x#@JG@!;S^*+{-*%J9V* z^7fKc8L=curmTsVReKY}GXPt!!FbsDpQODK)0+6ok#_+B(mn&W}*)J2FGB0|&!t*4mv81)|1KbKLYdmU+)*2tyO zib$KOf7;AaEj10poVUcZ3-wPh(k{?HW>l@4{^^XqDg84E!iZruVTb z+vrv~jwqZr)X{O2?0ciU#|sf3ZKdEZt;-JO|W&YlCk=jq%1!yNdR5Kwnh6T{!>SZU*I5#u%vko zk_=0k>mX_K93^Ake#u?nB!w9AU%u#w)GT(9#?Rd4{4!6uw8C4iuE2S!INq!k)&}}< z<}}a0Q7ej%dEKEM`yQn;H?^woErWm7vEEPB8nmO{phNrT@6lR~YUJyCLgm`NFuA%v zLM|VSluJjW<${|g&BxD3BY_y6E>&>=VisZm0AkC<76rt6?I`I781J?bjF;pBz<9pC zTFzCMBbAXMX(YLRLZ zN2B9p2wEpMTC_OE}ktavBq-UG>d z#IWB(@bN3jH`G?qcZdLzjbD+C%|;W2ISMZwbKL|LIBW_kK1V^t z6j6!h^zW7)8~O8)Txvf68D&Z-bM4wEFrbD#a88YEcFvL+n=)kl+Dw!cfJRI5K(;*T zw+J!4#gI@~2Z3&V=jUtR{<~$cf|m(2f=jnS3%K&=b)Hq3B!lOjks)(qWW>Bk88$ae zCa;W;6+2?Y!!Jz*MoTJcwaqV}Ez9XYumvu__TX%CwjP~RB8t(uABZSqeMYKE0A~DE z)*lHTcBu63H&7Le+3_C6mAvA*4XrO`ypF?{6tAYuQoI^BaTju^$g6JO$CMBw z$CMBQrid&fdBkyp)MGTyvq3*tJ6j#c*=4Rm`s}0Sl2?hI760;>X?2Lq;2$i6trzF79Q-XH5 zNZ_W!nALwke3$Q)fTerTxV{^6Jz(>9N!Yxd51U@K7JvLY#)vOs?4GgSg~q#s z&3MP<^K!1XQW`2sFgGtx5-<$qZ0s319gQi_F{h=Vv{oYL^b@z4BgB37JK{bE+7DRs zg#J6V_#+AX{1Z8|X{@AeA18TxCP@C?2~x0VACSfiq76o@b*;o4B8Yqcf7i*{b5AS- zXFV$xpT-tjJRu^1Hm=HmFRsK`p@FhOZAGKy-6=}nLE~WxRml-OJ63uO?KZB9aES6! z#kDdUvSZ+y(s!uDD-Xw6Y^MXIH04a?wZB>_Ur=2jNOowpKViT`#&g#GD1TPjv2Geq z2iRk+__pOOJpFXs@rmpS{VigNf752@JL^LKENg=QQ`Uw2S=PgL08j+g zHW+mgoh-`{04nV{?96|rlpFj8$x)^)+S}_b?b>%p_FuhgdF>_TlB>!!rx&bmZ7zn7 zF@k>ZEmVCpl80Y|&rwS?pQ~3YkoH);s)$E87xV${Suw$?qN1{DDaPKP04*=m!h2YIJzs_Yef&?Y{cP#Em9q6< zoY;RJCgYZd%DeN!FkmD~hRlnTesdF1kCuvlNt7*r%FGgU)dB|fsI&CzfqaZM4_a$( zmKsvhXJ(2Fm>DkvW}KD*)1zUL(tAp{473lCK9hs62FM`TkQsqC89pmOM$HeBNy|gP zsAzHbNu|D$5+w7w(AgE0Bu350b)iTp4oPk(ZoXgyM|?`Q?A~|KsCS+s?~M9bhQ0m1 zYPe+MC0q9g4zYFh?Gs(k;)@8g8#G*@>=(ZrXdul&{DY%Z3W|-GoJL65#Sq~*N-zU& zifBrLty2<=g9S><%JG9zzN1hB@q|(v{we8vSNsEQhMW~+ihPTeS5!zH%8##Ns#GhG z)&>dI7Cs+ME_0;~NNW$am)2mSZH6M6I(rR7W3PV`h;}*J5$UG>kYRfI38z5o7aUN2 z?nP^F35OU2nCAQE#n)-a0C!MJ3wbU$mk(`_(sJvN7t8sDLiMuo7s9TeBdP zD^bR`VoXM=gksin02-(LQljKkk|D={F``TR64z;K#dXRWahbGQTqb@lF5_2;i#F zxW2gtE9@pZQ9DRBtnIu;oU;+<`XcXAGUn~Ha$E)a9rZ|n$`>o~6a`rc4g zgnk8cgfAV6l$K*La={$|&=Y5+As|WWFzle}Y~D-y7_bs;(ks@!HWQGomoYW3MZxj< z`Fg3t+qeSGuQ)4Ra+4E8i_#<}B3fd?qm*T26-exy-r_!En9_fz7QQbbD?gIBjX1nw z8xFVFH6A@X;}sKiF6yAyef)zEs0%`%z+-3eh?0HiMD^Pv%SJ5pSK8NaSO>ofeYYDN+<6jX zGk*dO4z^g+wrl_g*VDj2UYqypLjF@d&XsK32Jyx;)SX+c3SGpYnKYpoV^AtTUl(#J z(21axsyZmuMp~`?pNEIlLVk@YIOImKOo_#UZp7}UGj?pf1m+3aTT?QHJ>uN?wb919yIDbyrIpm3JYpZoF ziP|dWl}h+4DJ{|l{-jr5?SMUAq|6>xi>;zcQnD+=(ea_Xp);an;H=ZqXGT0)LX%|x=Fg~NaK;^BZ0{K`J4Nhfo&_Ic$u7V^>B{(STo%cVMp(EZ?XNFSZsq~n3ZX;eV z6My{;9CB5UVO1*6M53YcCIN#AiMq;DXIT@8RDg_1?r}II3W<0hP_!8dTKqro7K1U; zO+>1VSaG2Z?=>BdW>KR`w*ie=IeAhKm3Q^*0c3{ONjnC%cSI}z66fIjY9eu(v?(M` z2O1fbTrAg=$TN_LsN`*5o{}`wz@okqlO`QId_M#x4V6cw*S!ExA44`;+C#>Gk}IVJ zlq@MK)Bd}sbtDzt3);Voc=P2o#3DrL)oW09cTo?M7%wMqw1SrgrKUlZ#Re#I*MK{S zuVYcCk#vVbz2$J|aXA#?P18bpS$nTO7~&<)c#x((0Vs5dI3>qm z?os|?!(dk8F9MFbqPjsEn{*{tf9{f$-l@%XRx?nH>9AHy7>Gx2$$Ee8;YlAP_HN z;wI51ZQ|{AkTezMlgCI5Q>CgneU#;=HAwuFMP!0pCX~6AuGR0 z#UEKgN{)ooY5C?5CZ3E(xI#`MJgTqe{jaqDwzD?aHi!R3w!k(SwlNH(4Eu{tOstBa zpr=xkSg9np!^|V1xTU4QYiy`d{>N;pAvqcTRAEZsObI^d4HhfXU(ujNm_adPl=@0X zTvJ`49CB?gE@k>MG-MIl`XYVhA?R};1WMb2>DgH`&4wx3IOVSy!kf>*1z%OkE zS4dV|_qLD2*NBk;_7OlbK7MMj^qv$b!v{|_-V~b#Y0cFnFlp-_65UOJA_q9_hXRy!kaHDn*Qswx+Ll2-s+u3{f>glTSWN;e zaavleEgoWh)u!HPU79qnpimmJPRsRpCuxseCpV*)%FT%Rax;9cbO5wBL+!!9+0qd_ z1Hhe+5bF}m`CN@-R&>x_f%d%Z+h1;hqc;IteI2IYOFep%(NjJLzLK$hZ~Bh_Xa^wm zH&S?JVMh?<=xBVSvD*I~f??8Al6$(K)}b~+^)M*g306S$81yBf>K5fEUVy4k zT!hk;ms&2M4Y*mgq%%BPi7wo-B$ZEEby56`Im@+)8l;Yn6ewt~9XL^%G$=mfY>=SShJl!)+u@n5%{?Bl0&-d~Scq+&es_LHbBvcKE8j>GMlVT^BM$3KQI!dc~-}+B4s>z(+Xuo^k+UNN% z9^cVk9%apbeJg5Gw!k)r{~4w=jMj#tj8byg*Oki`lhzb=c)d8mRSf+R|m^2K4(!piIie>k_)*+^^b(-r3)`2!1g@g^& zAy<-&qpH_f4 z`6adDG`NYIfM$7WvcxC2eatx7!uVZqMgxD z141Tzl>8esLQMI`mE%(VL!#8kX*0=3`Nv}Xv6O$5f=u+WDrL@m>c4gB2Ql@ZD*VA4 zgfDIqEd);4zZ=&|w%{uC~t znj){HMuOr_i+iZQ90@!w2mNib-_PAJ54Ae_xrrklbKvTa=lnhNHNZn0{M}?fR^7DF zPpo}xPC=efhF(e`l3irj(J;hC!7sN+r1qi$)H|@12+Wh9+sga0%nDnx!Tm zn^AD9Au?6!eNIcQTey@t`AYsSFG=6zBJpbu;gBu|iCDZxLKp0ipt)Pcf959fnZ8j@ zPF;s|-ddY@Ph2hD6IP4YxX)p$#5QK7GEam=Z3u~ae!N_n2l<3+cQA^aatF6OVD2A& zrdD2i(mwc1tu|bHeF&Dpj(@a5PJX;ne8DsS(W`ZyP1q>0lg9&SQ*@wZBEFhGXTKCv zZ6aq_v+$@iEOC`{OWoC(?3Y%sxb(POMSb$acEnShr0?yLv3UrZCm7j zsZ}wN!VZsh7j_#>VHetsk6@!7Ce>4hJeka7qdrvV+s?8|b_kG8W{nE@i14VbGd^k} zjGl*dFv(y>+G=Ym6lA+|k!)m9i@xHz+r7z6g7sOU$FEJXS5^v!(#0`iN;31CwcsbE z(;(?dcaxu_cPBd;kp(xYr--Y{s!FMXRae8*3Kfd$sw%2c-FS_JpbCxB1uJ)K;{~4R ze1N_gMqf-HUC|A~EQ2%^BUe3sr^8r1j*n&PtE9XdM~k+r#yN_1NzN!xnv8*0o_xc= z>#&i?PU6%XW+&MLH*o0N3dcHmYyVutISaOmm4hZekhPJ1(lO~IeCOL}3WkB&B z$3v)2)w7d)DHVqCe&hRqrg~VE_||(_x^Qiv8E*%^WF@6#QlCi_J4puw;_VpQQn?c~ zU+zZEl{*o$Bjnua;{u`=l8tz82#s_kiL%K&@%Ff#17+ zb_&6_@i5v%uQ}~ zZjoeUqX41iywpNXHet5Y#mF?d?i(+y7%bI#2*0yEIAMC*2|2&sQ|do=k&4d_OYx!u zk~@E&q|ezcNi(<0ndw_4X6h!1nqu3CQ0#gMo3LI&#;=uNCM3tMmVhy<#Savv`9LB1 zQYC_{KCn}u?5U4d%1P3e2J&(}fwj9GH}1`q&zYa2f2~#GXZr-wlc*lMR>H=umng{3 z*vX*vG|(E^&rct$4L)*Zv!7hq0^5eU_B${YWe?h7_Jv5xfiSsn2s2P!qNT|*R(dp?IxE$IiBcYu zAw`MM9NDGXQT0 z_$Q#YPVypBT#=kKhdFgyab0{6)jo$YKDV;5GJdx8FAPj71bo4s;a9LVQa9~fV8#v!D`S^!LACm@}7_L9xIJR z?tZNk+3>dAAlyl2<)SOP+^?>XOr>PRav_;X+}76XcsagSFDawi%}w=cOJNq<@_)+z zvHCT4+u!iF!q_ld=???AOSi=WxDoRDdkey#Ttj5Y%wP~#d$QO%U=vshp7uwk(hk<2 zjK%tkanG_AOhzbmz_eiLgV5^0=^-*`W|$0_4Lv+3THae2EfZJ9;9F^O^mq!Us382v z-))iR-2?TiVCu`ZIxtn&wN)ypnvz+lvlOzHRX!?-Ir5n#CX0IvewxyjE90zY(T`do zXU*8_c1%lToRudjb(6Jvy{f5eS^2|2E31IWQg(Pmfu+S@A(==cQ<)KXy4jN3E1j<< zXVt5V7nR#9wOvYyMgP=(X$n~@mk~^5q0g-d+Z=kN|xTndBvp9$Rz7OA{bOR}nEy#RaMDBedLNTr zHfP!GbwqZ1ACX;HcY5RgIIfR#Jt})n9F^U$JtvRJ^Se$Q)qFlfaF#;YWUCp~bp}$2 zR+lhjJtO?&q=t-VQlgyl3zE15v?OGpM!33J;j}TSKw6^Gr4=~6?V-uN!{PF9UywZ9 z?kA5no|JoQa7g3|4{2NKBG&+-miY&zdF}zJo9Q4`Gxpk~blNT{nz}=BCvB6giCZOY z!e&Vszey6tZjiHM*URZK>qHx~R-!&xqb%a%)j|vV_;Y0;AFUEvFz_0LHSoig5{T;n zth%jGtN({9gyu)X^ZIJT1#b-V|9F+q0)bds@EAmRf!Xl!>m_o+28lr-?dd67CEk9A zB+b|*X|wlA=3ECfnH-S(g$Jc*iL;b^c2vq&xJtz;H>q5M^F`O$q-N7`soruzs&|}{ zs@=X)>4+g@hk~TEmur|5c|}RSf1Kn*CQEh#Y8SIhv?#@!n{M}*I<=}!RL$!H z#18cgBug@=N%K23DMv_kq7mA(4fWHUJ6Kd&f$(YpPNl5@5vvvXO!^VkthONm>#)*z zuRpGn(xfJztEs8P+prr#6)HgiVv}El0)>y6qP9CetMMDq@0o(D!T~;*zm2^$_XOO8 zFc{6@^mlK!Db7=Bnwt>DhgC4TL@U`~we~r3JWZBvkClllqU60#!(}*nD~8Mpk-qlY z7aOb}>}KhXpY$G27#ac-E5&DTM1mO=R_Q~e4m;C_D1&7Lc>*HIOSeYL5$_cID$opr ziGV6Xt@5`hoH8QR2BWpb>#e=t;Wma@#nh}KHRObG-FH8DT1;|mBbqU~Wfe(67}aAJ z0Y@T;yI%rBW7L_fpRHW0cWV4dS*!glWEG9FR(8O%t&yFDeD|ptF`d9;JXbdZblA9& zcrZQeVMHIGFd5y?ijT#x!~K%wwOaB#7fZ3{JgGiD2lJ+8$yI;7hUZqu3_uAK3`dPm z}7BC)45*K$A=|;%CpaF6>_-(lt zJQ#{}6ev0xWF3cIfzRb?k{has5ySDc6vE0%*HbwO;;8DrMNuc@9{GKkplr9TH|K?X+|1&i%-s!;)=j)!pjz~cmzy3j za^E>z9s_S*?(mndHu=cc&`)1MOMQus!Y7MyX6Hgzxj+A?+@0$zH)kD^)|nW}Y`KjK~iB!pRAX}Pu5BN zCu`*_EbikqavBy3(_k?lt(F*|FbXRz@}tj{MPLml9BQ`V_sEiyb9(nUkch zJS1srj!5eIW0JPT9aF{7wCQj{k`DVyl1H#4`9w(?Mipd$Zh1M{l&#kOubA=QyIRt6 z>kut09J%NN4cMO^NV2|B`TMQbmKR5=9Z$EJB)m6umZ7iIPU&my>r@;Ky{WxNuYY2L zwHh39^@jH5UTffU|Dh%AwT`zVLMW{6-o=dcyBtIQ0EY9Z?z741f%a+uYILc!47~+% zkS?4G&h9$?wb7+91E{ipsAw|tZ7R5_vVUE{&8OrQd<^|er@S)2!SI~|2*{*hVly7# zjY%2(lk_O3{wJ?@sCU8yu|6~PNWV*%Ffqt+jf@W0Hk^~Xx>^;;)Mb?}q3G)sEXV}H z1ncW{aOk{IYmH{-fHa7H-St8Iz-LW|iJ`@e=Ls9?w`!29tfCr`Ejl07I|2n9 z=*8bMw*nmK#W1kxvPnqrdbmn`5{0aAJ$fQdmhCtVdPK_mq{kf6BTV{E)4p`D{=yc7 z)F4dH6M`Vj7Y0cGNqUI#7vuHSPTljG;Z3XzbK+wMAmlm7J`hEyfyhS&$-DDNl`vVd zB}SaRQ_&sr02!W(DhbOMn5~@M^PeTN4GBmmP9gkk{Iv}AqG{R1vKQmDSihpemIz%A z?Jl+Y57O!!QNQwwzNlXTVY;UaOQ^vpg=tHYMwJC&BgA$Av{$_gEvz zM;A%5^ISxlXn=R)JZc`9t4sw z`udRc!M&nSAbQyE^CoCGC^K9h1P=sdM#_WG!E!hBedx9^axZcm@|CL#8uj>@B%&hlW!A-QYsB)9CHY|=i}QCg=s%C*V+0@FohV8$VFP_vTbgJcuZ=3Sj?gxFTl;n@r%{zX4_Px_)E>DYAXk*y z<7MsP9_w(;OS8WD61B#)Ypq&uSL>nY{!$S+~JpP&W9XI>C)N9o2{OblrkShS$(G?X&iLk*>0# z9;0@lj+hJ6Yee+u8`Dwzv(%$+{50-u`S;9N6vKUd{_>?}91eIFC+A$1n;kfV8QWc^ zw5rV@TQ`SpDg;FYg9=J!5DMCGck7$|fe2k}=)!|2FcE=Ov$&(qh8W>jh47&JFNa$)uH0%KML) z8?L#AWC{$;ayk=&;OohTz|K`YJ_VsPFr)XRAbc)X z)m#@WgQf=~IER!L!fOoHjYrgO$<|mz@lw&I(IhQ6RO@%Y{go1K*D$1vuMB_dWCAw| z`Pv`<)bq{v@p`D&q^v^Hb4t|FP74+Vb8gh4ZU_eVi?@(|AbAsqX|pkZQr7>o;A$Ow59GEg3dzAcZ! z2Fru+QF1?Gj68@QFSp_8ucf$S@(rp0+S>FK6gCj5EDWojSI0fP{C7Bm?mH+_edS}A zXw8qsbISXdR7q@hnuMgsiEm;grsZN*i95UF(Co&P5@TYN4ttQp+HQjc@jRrY2a!M= zY*Y528rA#XEOL`?;O@Vfhhs|N?!TISRKA$uEKg<} zmPhu746?~! z4ygkIYGGACKn1L9^cE=v3W|Y&BI4kaO_D!)ljMG)BOwbo$O0OOg>)zpVu6YzW%PPU zh9%L)td|6=30ULDthY(L5wSZvZiAemp^QWsTzwq6_2Q-=cs3Pg4>bXIe|q+IiJiMc zV&U#%Q3rE+nWLQk`~VKzb(T1|`!k3Ro;`F*5}_cHeWN8kDoJuuP;i%5E=}jJz^`4w z;ooRAM~Ljs4b5Y@^|eZP`p;j|+Qm9e`^pak)&|sBUViE7)f;l<%5|-ezjggjP9$q? znbyG@QvOX&z)q$bE3RGQ|5IEO{!<*aKVuxuEoEl(iPGT~?DlP#T8V=@3I*M9a2L`7 z5<}ZOphqw5jR5N_HlEj~N2&Dc37rvqjKMJOf*I@K&Y0SQIh?#a-Gy{UrtqAZSfEqa zwFPJMvS>n2->3vR+^&v`uE10SHANHBEDV3ql+fs|Gw9h_m1sn{_{F>XX+4jl2dhXE zilIBVJFp2v<^b-YvXUVPk_ho56;IORNR$L*z^mp(O^x<`9R5y-76y)#&Hx}3K(Lxo ztY=sA?0wS}Q7Lm1y>bJpPX8|Jd zg@uLU3aTvMsZ(Xt!U!WG1x-P!%m7jBQ5*rP*iF^`7-;<^h93Q5BH4mpE(Fj8ay);$(}IP7(RYkq$~zU4uK>5?xp3rY`TUiDm+(~-RHXC)W@i0 zpu+bl(fJX=S$t>k|5=14?Tp+~9Q<)aJ_S}7xuT{}We_+O*XTdfnm$r`Vt}fL@2)3^ z72Z=%1S+iPdV(EhX7}0H33~bAvuT=L=nRhlR%&W%6*SmX##RNr=bl}I6mYsaMHia3 zGT7SBmY1MOj=!Viczz~XZi^(#Wu9alnI##{GbJ5)*R;d4B-P1YQV-9Q6z4^f>bhFe zk0YUtlz!GJN6B;Ohn(#YsdOGH4K71)2H#M*;?+;C9v><n=!On$wKSh~mwHU{BuzLBn{@a!$pL$I{UK4PC7wtJYH_krs(3m# zUBWUkX(XMKM$n#(<3>3Q%j;|~rh^2C3)-!ZgxgRwO?192I`_a&(Lsj@+Q)Iofl^No`h&nO(#jw9S10_4^XAGy2fggjX5C689wnJt|*1jDVJ*Ryw)?WW~6Od4FL9EFx*1GWd6Ul$n_QzT$_aj=aU%epL zu$ygfzlD9bp2T1j>Xz0KYwcmD)8uK2+<~B=z<{vO)(_~>XD$Nkzx@s8)_$eZ&rCsc zqpYd{jQj?398VtI!8i+SLg8Dvai+@X9;GVM)}KZLU|_7@&XwXI}%~ODGT++|ZL^tW;-CUlFUK9Pd3O49eM{%8x5wqcRER22&3ybS3V) zV4>54L{VCVD&r|g80y1-37@OiHpijKRxcT(RH{{hugdB=fJrB#S+qdNnR1D{VER%% z#@`Fuy*YuHRUSMGu%a5N{<1Q0_sx_QJI~0Jl`#+>kuqX#1jI+U{L&s%Ii`mxLu-@` ztUziXiFv!JSf_Mbc@675(O4(xtNyX}H}!Z$Si9NEGOC zS`OM$C8wZV5>qn8KOjK-`~xH;6bDwMEKOE5Av^}slqGy6_-@F;h=J^E99=?*g2r`@ z#m~qq6-TF|iXQKMI2y@+(1YDn-9$;_ng6AmiuB+i?VPO0iSkO6Oj8Bx!UoPlLV;4TM1&trqqgRKu5I;3nEoT06v)St^9-- zDF}3we6Pj}Qg;oJ^gTl)WA6~j+1F2U9EPA8XsA>;e>zm^T!u-L`!H$t94_ZQ?c}`I z2)S_lZMk&neYxyAS}ysGlScoAQWWVSU*dn%ip<8Ze~t0PFs`Qk<~Q1)cUV<`WB_KUUeA958BI$txOE_myALapq#07{OW=wHl2fLWry}UmN5JAb@9+cHF z^Ffg8@X|9Q%#zS3R|tSd3s1Fs1Xo= znT>8Xbm)dleg*&zYE%Lm)lsR^;D?h-JTdOVIYh4R^TRj{j7r?(jf357atFid?=5qa z`%7HpA)xVS!BKfU?}$8_?JSQ0jmMBLj{%KG_5cQ;@o?%yC;S6)Ox~~T9;iWj+y*%m zJtpjvcG6?~9=QR#Hg30EgKL^3JA1+O|T9do3a#< z$(2r$vgWX)Zg!EhogR|D|AeF;^_NU<>?DHXBsVrq3e%u~3o6m?c0;bWwrgJ%SQl$k z9>eXM|D4eN^&k!>V|t>}G0D2~MM{bne#-2Fw)xc_AIFpe54|(3bN}gN@*gnY`Hw;d z?8~&ydX@g4*50l)RaghTq)Uj~+OIOL_EYH9yRz4;tTwXP@a7ENb6D*~>|W_z`S;pA zW>iq1ZOyX2{f?ewMgrQ{+MAx7EA1RTxqhuxWnuHxl|Sg(E;D&ih>3r!ye&hFhLe)a zE>=~e%!sfG3mC;V*yl4J{FLV=3XJ_eJvP0u9{WE;7|eZA?wnMo&WScb)p*n$ECm2m1*8&1-#uDgIqYnL&w zFH=_TIwO-;j);~~aNNV^&~Zl~XF$h|f@SzyTBpyRs{J>G$}bE*t=8_o9M|;EcJT9k za6JIdf6$C@8La$tguJ^TQpPWjmPK1mixd2G3L*lLTD%-N<|;>B+|=sg<{`d*{t^`( zrQ&rw{)JNT0>Xq>cQ*m#k31BXgHOc=$W2$XN}%)!OWz zoic&FJ@@zB_xZY~{;_@jRMlqmWBYvO4N3t)zE~Y?JRtY6YD43|XF`=R$6Un@=(u!qFrJiJBA!IZE;I&(QI|NDAHONrCGuDR7x3`N$jO9h)V2N9-l{ z*gVNOwpeo9*GTrseUghto2*mFZ13$S8T8PwGI^1`r!%$_} zj&_oLV7TNQ94XmO?@H#uk0s;KXvuI}D48Md@)(DE-arBKuYW@ijeUPNPfZQL`z}3T z>H}kiUbuOyL$Zr1lqV0%JR?CixN;mEqFgzT1feTebKjBq;Mr6>0No4Y1vz5SgY%i- z+Fdk#CX;jI2{nd^EwfHRNQ9$0ixj%e~pKnTO>5jDvC?$p>YKMBRtoo3dZ-!IQ&- zf3AxFxbZu5<#6M)j`4eywLu89!fwEoU#CllJHGCWWwq$=eWt{Zqbm@YuXn&XT{* zMGCigO7ZTKQpy7$kA+IPcZ`(#pOtb1=St4zNNFbWlZDlg1FZ;`-`Co|w+^awEU^CJ zrJr28s)bcpduc~1Fpb1kVSP!+TSf(yy5OL;^6=v-rh^y|69;-0oVue9z8^nqQ@w7Op3duLtW8*(ni}AK z>I^Q_NqH4{p$E3e1_Gz5(#Duhu_PpBAxxeu$8fUqQIA+Tg3`p}zL=sMj+2$LtEK7O zHL(R`$*Ns(GIb@n5b?teJvR2-%bWZ80r2&|n8ZE3v9CAQ-s&;z-POtm2@8S&fayJ% zaKSniumL0p3Rddc&5S_#Q(*D3n=w1;zXX*?-7I76Jg@D{b2LX?w9Tvh5vCB0ypnG*qo{4&ds}7wDe=$ zE+}kbMu8Q&1!x@A*~`2>PV&Y)C?3vb?qFIl9vC|q8x#5JOYNgzPX+X*}N`7q48FufIi~i;e`XcP(17yJr(_A_mI1kCv0F;y!`t8r*)2 z_~1BFx_!EQ+VLd)>{@TQ{^LoQG)wmnQxj%^0FLQ1F~Bi>9M8wOMTf)Daf)3&F@Q29 z)-HV_j))ntqXtO_aX^t2yKD~nd5UX@kDSuNi;Bg;`4#QE{k#X9;)Iz;A zIQU5O&J%KBlMOu|?s8?Nt6X1pOl~YbB5ezurG5Tk>6m*+Zq7a^w`RenJIQU@v;%Ty z+J3o>{PG?6_}j=h(6~dtJ&8MY9QwH8|d>H7lPG|+m0kQVnbM~#%+@-6irpoCTy2-SlPtwQaTAX zd508Fflb{hMbltthAEu6TZ-q|J4z`|M5$PQRH|0HOD&IY+;&nLP;J=Y7$l8I!8f=> zO1({!+EZtwIygxxV=|>Y5z`{GQCe4ATRE%V8iJ6}>>jUb{fAm#*A6uH=&21j`KFy_ zchNfSrE6dTf<4-fix^6fei5+nx((e>|E=}qmzYaH9znZ$(K_FT@&i`A(3l&hG1~AO zY&HHFTMgRxqykLO8<^UFIfSp}E6h!0H7ngV-N4h49%y>zld+}ebNcMmVzpc5j+xtk z8xsZ$b99D)zyMt&U@|J)sWLEwu2p9UR^#4uw@)#HxdVJn3Kiyf3skNa+<>OwmYk+$ zkl`;KD+<01{oYm8ZwL$s4OMNzn3BN_RiFgl&U}GtK*2dr>=_{^biJUjeLdn4*X^F%I4zzh6Hqsk zE8c;b^7-!5G6l6qqgZ=1I}{n>P_%C_`^?Ojh|t%eLcCfI9CnpOOIQ9-K%lFG+27VT zGtB_`aO?I>$to-tEgREaGtNk$4IE+qKuHH21*N0|7^1Vo;70-&0<$IX@C`5|K1i1n zX9GKVLZ)~?TDZqyN;x7&j2@X2$~ha4#+-yZ29X?jm(mu$9NqXdm z(VsRXv{ep)Oo350DCq#4sE81;0=oi~m=eO25ehAaoM=Xxfp|FwoSehTltbfK?c6m? zjH#NiL;K>Iwf9?15IxN+J>()Puv#{vDRQg7T-qL>y?)*LwpGhggNQ0}Q2$n33(44~ zE&YqNXXVE0)?Lp%k24P{uimi6yr^yYleLfL1w}xi@N+Hewsq+1@c+y{GT+Pk=b!%s z=$JA9fuld)Mh((r3u;$~+_8S}9z*#I^|R=d<&X?_AQJF{#y&OBOY^>C?e|=zmUsuT zif)dZ&YF6mnJY})bLHOJ*e_E6FnUA?u%N#H#d912!axwmk(tA_)s!*Afj{N9;j2{> zJNA6^**4{{p&ra+uI{j@E_73ydxoO$L(qY%)o|jbGjD{$rqgEaK9jq#XL7~Wb{0N3 zPL6t>kt3eQYTkRCf#1gC9&tAP!X3`L(}Bl{Phg6i3dxc+drr%=RS`03L8y$FgPuF| z-StI^mb0|=#4c9c>nU8OcX>^xt*`wjhahOLZ~D#6zPZPzukJm0WVcN|oHjT5blUyl zyx(0Aj-lY;vS@P@X5J)dYww}Z+3TM5r#9~JL&HKPJsroT!9!QqHOavv?y~5!Ro!;; z?|0wLKh=L{&NSo7k|CAXg~K)FNBSIVHQr#PKuFC%&X6c^p+yHp{lG{xmI5&U);PPU){MPZI|k$ zu^N4*B`DU&$2k*8aZ(g~08V?2+TfR9gJ0rqo2|TdsVgQ!VW(f>f}x0R@a7&%&=Ivp z3jG|E*DmyTk`kwW7@Rm%C4P&r79s&$bO4?lYa#9n4#2SH^ZMX0T=$p!gXnZZ%qQ=R%cC?E1sCW-T_b1@Ax!G4SAN-co5r4{I8%Ipo66m!tq+5A!-GlR9 zR|Yt6)(8@*!)9^KW0lm=O88`wA6W;ytR?&jopzxYkqhwt7HtWx&tdRT;kRhK`}v>n z7{<~5lh$zJO{=zQVUM3{zrTnEy(I&B46*53cs;z&Eqqs4pW%Ma=wyPC<)GY>=cCkz zDY@KSPQ}EZ7el8=;Bx!UkSP|(+m=j0LtL~xrL|K z=NDs`he6$Z$XK=?b&ZcUx9-g5vY1rg!jk}<{kTjEblb5r{7OyEz2mC7(zf9rv3F(f1NI&@#wf-_ zjfpKi6HV{--g}pFXws3Qu;^7qLB8F?6E7B^hu^TnM}#^yzkuab*+6il9~Cw zKW^{6&pF^>ueGjq-E~>XqD=1TKAP9IW}**v0_*}>V^`=7;qK6VOf)Ed6m$eM3kkZh zS7wOx8WSYlMhD2iSDZ59ZGV}7vzk|WC#uQcxxe6Cvu=ZU`}j#();1U->9T5_ue|r+ zXBvy?*Jt z3)2#$D15mbSlJE0-&gjnL<|<1qBjD>V~cQI1YHPS2uFVGtzKg)LuB~RlGzd#A%7x8Y^)r)&@`je^k}!3c1S-z^3pp$L$Ef zWqA5eR@H#2=jgoANDcZHQ`g=efIh*V@)+zbhE7bkaouTML_U5&ziDj-1bzL((18GY zrV#OThhWGi{0E^h3Bq#{Bsw=qw&rC@HbDOhs>yF%xhU5zo|B8^$E6nJsjBFJoG2)i zvTXpB%$`9jEHm>`CbsywpCJuny>V`#dx30=+`v6rCEXeMcXy*mcX`~-vy-Dd8mTzJk+W13Cjt=cWySI>U` zJYp4q4L|)JWEL&hPhICQ1Dh>hN0(kmX5cGwxw4e}9pwP|REi5J;`(?N!Q)T~x7-bf2GhJf66}owcL~hBK zsY?_N1pr*5A@G3Lty-*JsLARv7PVYsBLTIzhIAioiRUP4KrmWj*xGYclyu`g#L^Mc z?M1fM2ocW_fzrL-D5rEA=`GzyZjkOH)=1BhtEBe}E99xsE9CjtSINZBePlyGqMGtI z_t%_(n@}CJ(I5RQK9?6pzpTCNPd+tRd)Nul8k+l9@N2^`p}2dmet_tnTHE*3o_r0O zj**zHshXD)qF+b*3!*Xm5WfVdrofrv)GyjaT#NxT<8x0|lI%`EgSA9|*+ZS+ukUw5 z7vR1Cny|f-uuZsz-klsK2a#Y>u`gH7o-C7H+i~7o^hzlNFE4VwD@87dF5ZaVH`q?NBovNzJo<3lAeD??&Z6Of3qRbqh3o1vp$O4=e(gzQ8J z;5t4fQPOiW;Ls|NO2G9U4cC^Zo+&r??%fi#)AFW7s7e2DA2blGyCJbA;kFNVvtOr% zOGOp`1G6(uLIAa4@Zv`RYBz67)=-;+@`>wLF3UG{x8%WXoD+5CtlX?dhr&~pa^?65 zxqw8o)2LId+yk1Fvs3nGY?m~QZ)$vsq{bynS}d#%I890>E|b!?mdKGemq^)bi=`a> zn#$47|M+;w*acGI0?zlU5) zykCiX{+=rE_v%-cOU)ar2vVd3XLS6Bb( zKDN#LD5+W$jbQO+Iki&t{MEfnQ=DjeFt?~={IBjSnzyTzJJ)OE&W+QSs0ue@oZEfX zwWrZrwfw7lOZCMVqrH<6P%9ex-<;qLo!@g>4GkqV>^ndUTCcg8-cG5fJtVC!#r;+zMR}g?&d;o;D z9MK`P`#fD!iGs6J$kI6hq=vs4t`53E7!b8tvt44z976(a6YWG%;~N=9H_Lxw74vc@ zuyz9`&qLG-e54gasm#eK*n2?5G%`jxeRE`uZ|EpoB zT@3^KMCXJt;lM)R-RN-OUl;@$_}2}!u9gmyt}kqY1WVVE0n&AZQ@RfKfoznn&#i;3 zkuJklNY`hVNtb6ALobxBL+4A6ZqLq>?!)Fu@8R>MKQ{g0ID+DXDc%wsnZoWcYPn&& zp!^#f&7HxakrJ>eN*^7@f>iR_zTmZN$X5@N07!ylx1LW*w+7myQ+K@f`1P)Q-*vA+ zbBhIS zv@N`+?1k)s6l}F*7j!;E11Lar&$bK=z6G1t%buXgve%CZEN>!#1rbVsX5ogH5wWCp zB6Nuy#6s_PG-wuv!Uc^wszUJE{VRKe$3mcsmiLD9qPG+*>5K?vZ^>EMTQU~(mXvwD zC2?+V*)qGg#Ley_F|+&1=Gpxudd@(JMjP+wC9g>AnvW$bIYCkoAdW{?JtZzJQQ`p3 zu@i`*E(9ft5Rj~ui zCdz9F+{67k7={}%4#yZ~OGFMecz#o-+V6z#7eHx63ayR>KOmaO>_IjHV172)rv}Si z%p2LMT?{r8C0LS)68|g=v~iD?KFQ(Z$|D;S596~eIVEn=i!j4Z%%f(z)H3>?0FoCj z)XLQ>IA0M70X!S{%B6F19-&J%RA*rheZVA?nw=t}grKPb6JS{noMfk}eT}=LF&!al zp1aZA$xL#dagmRlxacjrKqIpNi`meG#~fJyxzKbUY?C#RwSL>7!A6}8HD1Sk^wvF+ zlD$tBu1%6RzSt~7e-{QQ4aGT8n@|?I2^12B{ELBrN`Fg6_{|1h`bwAK-oQ(5>GIrq z$Xej!D#!}yGIXhQ@megMhb)9%2t8lAKspbZhkMA7xzg1OGIXwn(q7Nclc!)uje2vL zOq%VKn1mb&Ln+Qoi;zoxAlWGgAzH%+-%#(z z>-&m@03dr8uqUXn1or)-(kOJZmClFg8)8NDQOMsJCr%aT2k`D-sI(D%9 zy_$XkC85=BhcVQ-8Ni#kBS$JK(B}I5dHMDpY*IkseOzln6CL~dUM=7er$XL6eMW9q zfq+(=k}r=Qm-C2lSD@W#IU3j;$;#76m>ju9RCt^ug~jOu8xOs_NJ@Z)rQ;Sz>6m$P zc=S9u^3uF7gk5RM$DnHfeW`Hvo`gU36wL0**H%a+vO=nn0ay*RJ3V2&oI#Ch?FW89 zxd1u;Nsyc;%8@T>jeERy;Ztx&Am0Ub$irCBDOye~-7F_p#>oi+-o^wZTO={rqGY6} z5!t*6c;o##6*t0Rs0kO$)~cqvVWQ)R-GXnAe|&dhry7zg*jetywU zy1fAGa}Hl8U7lYforkRi_$`;t0Kd*dmq@1}i!=as8Vulrbb4lvOJ+;wXJ+Gi7KD1X z7z16`gK-b(>@^18yE)ty%85x})&rN8~oM>2i(LVaBO0RTWrik}=#b3**&NIDv@HPB`D zJ>D-(^^=lRBB-D219BEA5LOV>f&@R=mAYAWBt**2;5m}-^FC_q-#|Uf%cx};kF2$E zvTfCP)Zsfvqy5SolDT?Gp0G% z4phrOs;Q?2PAk>HFO51<)Q-N!v(9+SV9!mKTwDOgYI!6wp3kR z1=3fA)*e-IuC_)lg9wrolBM3fenks0(k6)f1tf?}6kw-2x+jT+MaWEGZGjfVm3bx_ zi;ef}Msj-r(j;(-W&W-Lt$AGl-?($n9%PxzXXJg?m z-0!x;e-AXoe=mfZ_q&l)P=xqYmV7chT3&c3M4oyj5FH9FOzb>-t#o>BrE~-ocJx{_ zUpfw60GTHppP37pBc6k1OGk+3pjnoFdX~QSbZHN054>l|Y^^D&JqnA-g{`gQKsM~9U< zb?xoay)3Q18ETAkB8`g-kQn;z2cPMbuPhvTa{%FOLReY4pB&3{%JED;smOBTL~Kh} z{F^?3_xU+~{xE*-5FlpM%hIM1e`Hkqv5PRCdAN=?TVze{96d)VcmXd zDtnmW>6WGr4>Ni@BeD}TLZ;{C%gw7-G?IOL&oYv2Hh3S%#cK=6E@&hpntcVvs5P!1 zo`ci^`N$g2!k~uSfq{MdT&(tukjP1=%EsA3PVM*`jja|*30CoG*Xrr_0dBAAOt9Gj8L}Q5Z3Iu=aA7nb3S*?w~ zRujhn_eVA)XL-3V}(?h_^ATp5GyMUeDv; z31rFZp@YSip-TP+tYYMZ^;OQQ%Huk{ia2uthpVyh>Py6Ks_@reJdYzQj{|#-muvhX zPopsQ!WQPlFy`NqXws-9$GdvP;&zr{d&2Sr!gWW!MvThO&j+~Xqn;~Ia<}C-` z)6&7wkdcv~vL!wt3z98c;I>Fc{53mwr)2HeCz}(1Mc{C&eSldoZdYp#w;h^zl@D!U z)oP7Vg|gZS&gZ`mdO!35^eQ@lzI6v+vm8X*xqUKyakPy6&>1cRU+3wIA<_lbZKoHU z;_>`O@qpvcF?6Lkyq1ai%tA2-%@Y&lHYWI)F>t1(pQ4^A26VmP-ktY+ou31KnZ&Qb z;B{WJrPuRw#S0$o_b08F_$0*SpNNc6%ilG|EB|pwfh!tkH2x$g46R#Xf<8BLwDuCx zq$NBt!tK$yhZaZ2?&8s@hdAIJ)Pno}FU{5zu?ec>cvzk6GEQ^$)i);S?&7Q0BL_Jn zQuZNtrwn|oJOdg3kdpwg%4|QW$wlG_m_CV=b~1=C0l`C@r%Yt?1Gn^vU&bX5;bqMM9qI$A{V|T(aS%UIB#^&Oi7k4 ze#<0mawiF$)KNmI8_E>iL&BzZme8rt(>hx+y{m)*)Cg#yvj<7|!m$#y7TvN_(vSnR zQ_}Y2O2%H~_!Q+yRx!4=oc;Ndy?^I#bur#7+Mz#4z)Ri}j`M=(>6daAX`e%a_VtD!frK6eQ_K_pVi zVzbjwkAqSwgs~Z0q5N0626{%SW{E}D2zvMMdfoYRYU*-?Y{$J~yz04ke;JyK#7OG! zsZs+!i#`eYlR%aFiZRoDYN(u^7Ah5!0#Mo=#TuHDcCQ-6Zf#NYCHLxX!VaaV4ug$h z>cPjRp{D;YVi?nB8~;)#S{h5$xjDw`s_29XK%=KxJ`jd$ z(Mja~Kl($5RwXyzG+H)Rf9nsPW`pAxHGZPeRsG+u(HscfOlh_f4y{UndpZI1arVEf zqa3P(*~7-J66R-bUcaPi7yWiLaWy3FKvuZjMTj+GEVrR)3rMtmeQf_&6->X%5MFGCap9rh48*46khQ%T2|{=)$9DHLd(MpvNopmwa{ zCyir`=q337YR}e4brn0hp`aJkc@JV^+tEHgD|@G;rf+v@_=}CtK-=Ur36DyZO=yH3 zgytlHp~(`Adh^Y3uoDnW3yPo_n+7OMw;<6M_b_KyYv0~ZXqvDEfIiYRKp|joO#lvE z2q=*?frp{Xpvz@7Bsu%21V$f~bxs_4{pKXZPmmha8%G~?MU1&4x=nkG+9c+P05PBU z6Jyv0aras+?t_=KaJaq|1ysi*&6p9eOXk^fFGSA0yAdFh-x4%UB8H$+T3r zCTGJ@hs9lz>ZiF{Irtj6+bO^yq3{eK@O+-1T+a8Cs|9{?eUG2q-0PA;>;CF)Ke>qa zYw@`%eE!JxSV>c0LmOvHfyxmQ-(7&mzN9u>_UlR;ZK(*isC@>oNA<>FcGYoo22hf?_M;C<8# zW)#q;r}HII_+PXKez*fX-)+A(Oc~)N(PIj|1|{T0UB@H6ed~rixW|Ir2f7XP*Izx< zS?}a$`T09_buCV<)0HW#QlSryM3O*9Ta?v|=W9`@&pfO1=fDMV5DfgarKKZ|p|ZME za<`+hD7`@9wr+z9C_|jVN#Yx*#M?hXd{Ayo@e52uU{s;xGF_Z1a*EN@2?$#aPuyzf zF2L3v=pyL-kVAm2BO0<+2UW=Gph{UCTmv~H;R#i`k?@p-=uG)uwDfx|TDqb~S;uj) z;y{U!fy3B3pxbeW5u2nvJm2k}^_F%+)=0a-E2Qnyi>2+r`O;>&`N~ZI+Q~gBaw;zz7_wf%mwzfD3tpFyxnpG0tQTA|Nn2if0GbKf0eV59nN$$Uq5ZqHjCmRw137tYQC3G6VY#P7}02VsEn}p2l zFCp_rN%$I^c#@PN>F~wS-b^jX0f2$a0gG}DRXd zEGpd2lPXxk6%*65cC12%O#%#EyU2~S6uA_E}`zz@MIzy(~|AXTB$jX`gs z5LGic0GAV>MbV%I;38=8CpV=7w9>Z#4pR{BtI+iAYfvYP!rhdw09tkGf2V_#^_^jO zsbfw!tU4{nKYwz==GQ697VYoisfx~T_) zk$63Bkf{MzcvK>2c~&2}Nc?zsAI9o;-{35+@8yT@zn5Km z_DddYyKUP6P}{d5(F%^oygaxSAUk*FX(=c`lwmIqWM(P}%Nv;!eGH&d0Xc~P!YRCV z0xav86znMhj_lJo5|0DcB4e^q$dV!co07#h$ifo;O^K3`lP}?TZw=0{TjQfZjFO<8 zDYyVj^38zI`46MfHy7+^hh|7*N2~n-FPa&F6$KrGoRZa>&Ok26n$T;qChV33#a|P@ zO-V9wTAVI*?1}bM9Z}wBj*gZNNVseNLWHy%8Lp+x@K9;6DntU* z^d-g{&Q)vH!N*TOzvb(X-I6T+sB50Tcoo{4zbX9(dTDo-hYM^7Gz62j9Xz$PY40H| zTDwbYXkNE&=g_)Es}5ST?ma#+L$e@)4b$$J82#Lcmt^=0W1RHrYya6ypixr#b{wv; zMLXp8B>G8F5)8j&9PR@HvJ8N8oW^60uQn1d0dQ`BCDj%C%C`WPA4`4ZPh~#x=Q3~k z%hAWe`=5^Z%9r~Qo>SlyYv)SH;&)`z-0`w$w(~^^o;4DPGYU7OHQIzPdA}ZP;$S$2 zOlk$NX%A^vuS2J_2GF#ZkSQIsgiZzcOapHqG+FfAqFQ2X2tW>+0U<~(3ZfDsKgFckf?u}HW|hrS>&iz?x>8- z#ysWaZ?rC1x7=9LLKS72ruyt>qpf<72ud@}4T$6!Xd1&co4F4ww1Ig>(5ZK=e`^(P zvuL}%fcqPjm1LMsSN#Y4?Up~wD&^LhY~Vk3R-46x7`NofId#JB4z$JSV`n``HqIl- z$;r~bE+Pu)iG?DT?ZuO0*g6ioXFq#}ZuJXt%X#xUa+vSoKl)Ct&7wPmsVG3vrie6g5}Q;iIxM2C*7p4URu>N6t+K{@tE~1;06YP! zywOJ+#d@oJQUOmWfPhb)Fty5;zO8&&C#zt*(O_GpnNJn2!GZ$HWwSaY{t=}z zZ)Jjv{Ww>5Tq|$T{!&{D0OCsuUskcm0N|NJ_mi}r^7z-2*~u;@(uF$ zW02z;yJ*@uwS7S$9qj1APig z_rs~bT|)8ugBGTM-vB8BQfYFL#gNU=H`M@ch%hek{x{9n^=H9`{K$kL{`g(|eSxXb z5`@TXNNSu!rzWfWenzK8_wL?M6}Lcm+COQ2r0$j(rt&%p7x;%w&5k9>PUA&4w5Kz= zmOSz|{?$yywnd%;@TQ#_H5sfZ_JGl*A3(=8rO0;b&8f#ZU(Eed3z9&L_U9o_tUM1s z)Sz&q^Ao@SPGyE09i0!fGo3B{Iavb_(>WBYl}UQmZeU85toPj_t2f3$;w=HbtOC9`NrYB;lLrAs8(W9PeZo@X(=-pr3y+9OPx<7ga5j7sku*-vvppm;A(Yq*L67`%Amwf#5em(t7wN zY4tp0M5weJfemV8gr#xaLgR{4S`6LrDu89Rw0vfnw1T&&^`QCEcFuOR%Iy`$`%lW3#Vh#rOhld^Ozc1k&u<>WgFrU!;4H4*_K|EtILv z^OdW6eB~h!<`3XMKbLO=s%(&7PkGD#oc57lYklOG%Uk7_^Fb0F8Z1FeaA@*^*N|^8 z8tGauqCXQa7Q6}ntHcCR{q9if zfe;aqb^wufA4l)2S_Fk|*2uZg2}XafH!7zLGot_!{z+Tz^z22dc~U3FRU9 zrGd#V5TY5S&8gq=9$x|tKt=7-M>~bH_`i_E@Rv zkO?g5o{7FT&+J9d`lt88r;UGFtCjtX(dy9(7-P$4;m378!XKL({YwtV8ZV;Be!1C9 z8G&Y(CUgsZrMe{HHpOB(PjH7!F+a!R@+BjS>Trl}N_lq$)|AkZmJ zY-6bzKts~Eoj_M+aE3fs^>RDflC;{;5 z!H$3jqp#(N5NSC)2xQ7Bt)7FuH*~eM^I9S%GFy8*H%p!#`PzJ$i~h3N@Hdi_au?%n z##k$zdC3Trhew3V8W5(8e9XRreC&Vt$K45&&tg(Ky(=grTw7ire>P2q4jZK*k0C%p z9!)*MU26?@1|Sb`2bj}v2NTcM^A@f^m--Bu0U|}XBgBn{vz>WdUrd<=(i$f>E}xat zRcIUPtSOhWedv^&nIM@7XrvS7D+xH;DG?30k|KR2Inqbc&~`TiP?!w}%#HKWWGf#K zSV#y=_L0LNSrsH%fWN!&Dg6i&@2}MxnNg66-4 zoP==_y>Og3H!pfkVpe=0@!ktir=JFg_%is8Xwq4tVb2A5!GJnTI!F+FOF@Vg22AZM z{_-WpML#G{s8&zuixwc zbQ7>NAQ5nd9ueeB6hCk-LK$JslK+G}-{fbkH~sJ-ivHnb;2(ZbKvI+hsm(a{I6-b9 zY3S00bLwFlN!Ok0BwfksK^bNd_|^daUya6%YLAtu;tb5Qm3NS%u-BhC z3K_;Yyk1%|G}EYQrtVL|j{?AqR#x*yp7DN1bpCjDRcAomd{y^H&s z$m==_bUOsZ%axGucoa&aIrTb!S-s9F&Q|8b{%P zawlWhfsurCBq>ElN1;;R7t~Dc$%l&|E#K%tplS)A;<;|DaI?x|w@v=4ms@4Fh)@>osyq^z;_ZC!T&z!qh-bDw1w*XMggP04@+Po!IE}<>( z8Gg_E*W{}^SETL+GK??4`Qki`?vJ^c4=P5sMg>dsCSTbcLh+H1_B+jh#blHk*tnjIAk)Y5Pz9#T40@9?m0HgL0f|4l#lRJw4lwRUD%}bo~ zCrF6zT8$Ccv4nXvUmf~oUA=lijvYUOW0SUFH%yd>&2SF|2f^hTEKZ1jC{EN14Uxbw zfENHPI3nyrl$-&VB$|Km7AY`SI5uvP z_+p1=$v+B=-EOUbF=8>Q67^?)V@XMuy~dxKwY`5+?|d%Lwd!#QlW0*DJWd}Sf^isK z1+F#!5U|JpkkN#BQQx>cPPXAk&C|3S-V=TJ+JDpEx?b1s;b&3BtdwQIxr|$0s@1yIQ;{}*AM;9QqXe%z9Y{5R4^Q3 z%GLxJ@Cn!}5>Y6NYif$pxC2@Qa7s_lhHJb4c*C5igR(QfSdvqBpwtCPbSRSDv8%`l zzxNL9e7}gyfx0`0Io`XY<$m2AfX#L7h^J$oNmUscnLx?}9I=RKtA8+X2Fn!PlUA+u zw)7fHuXO2Ezq!YI`rcdg`@pHlIA@MH!;vH!l_b*^hRe$zg~;GHkta1a5YD9l@jw-j z1IYo#=m;@UfNnq>NEmRu6eOObe55mK$a{@kB+me6UY>x?`g1l&QrdRiBekNU0`uUG z#+e@&tw6e)&2~BD4}d$@I)8Z{djrmKhf6jtE*7pdpyryjvJ#%AEv0a$@MhKOwQw}8 z1J-U9zkpy_?-MMfN25l+Dg&Q+4k5UK(xqEp@$A%79G>09a3FsG{wKriA||dKp51ht zkF7AR7r>J~W%^u=K5I7y=xVXk)kw5MXyV?jD{}w#W2w7&31{bAM>W@#vr=7w)3xDc z$$$qZesj2l1o}#_zmIGR@Nwz?ejkL-1Uh{r!09VN&_t{Z^x(dMu-wlT8|25+8S=N9 zVEL+MmxSQ`z*Tc4VCf_YSvggre4I-q6CQ>b=PC)9 zpZH82CO)%Y7ylJVKtP*yR$*{bef8iLmISO7mnQn$ym1K=s~Vn}{_;Ss{^6cn z`Qu%rz2`^(_?9ys3}QOcV0Y%sX;ty6ho^e5RrI>iv83p@@o^LN=%CT04W>39IU(??2dW() z?|pdIaYrGpxxmq-UHAMnu**7a$ND@6&Hg!k47BTa;5GGG6^ve!NZR#~(Zc!ooyR}n zdW~7|JPngfj2)C{D<&r=X%CDK0FK-JMsJMhMjtKfHn3~|Ms1I*UB3Z+HaEz6jI^KA zUn41#11=(S?Z+R!k<4woH7Gh&QkukVK?00R5)w(x(!sjGq_Y?)+=ZwiirDiDB@?|A z;}bBivEOIp^1u_6JRU63nFcpu;6Fem*qvL~k)l-%&s?c)v(GP`595{nz#nU5^JQd6 zeEb$C&KAJDaR%aBZv=*{2O@5;G_F^!#ywwi$;#F1aLxDeSs>`jbzo#0Q8t!dC_&Lh z;u~6wrl09DXK9#BoE##f-w%;tzYCV9Uk{Q2U}pW0{oenT02%PIj|_Twojm)>lgo85 z@7+&V$h@VnDdJPn(#fg=IDwi9Hbe&ksu|Y}$I~?OHJ8TDMf!F7<`t=|D3@J`fG2E4 zK}c{g5fI;QtxBsgo^%octrz&U>4#s3w%&<44?YWR?wvuAK(+ZO{(c{sPp=^TeUwH< za%qb~7SOkDV1t9=r6X=T{aKXpNM~k<&k85W6V0J+;ySy>Wcuic147PY# z8GL8gkX`kA7>$pPdCPalw#ZM%!Zpc^fR8Z5$GKJ_1AQbj15Jp6063Gp#Cy_U=t1H= zd5CPB{H$!8HcB?md_{cbe+Uk~P&P-$%Knlvpx|XWTYE+?37yKrrFjpW9{Pbx->*Ys z3;gBR!O5ztj_VA*0$JIb(rUId%$L>eS|fJ}xZsN!oWI4oMH5xlz@8QwA-qW8W5%}$J z5Sy=o!(GvJH3yMWPWOFGOpI&Jml+YXJgchPEqh&}EQUsWii+7P z{z3So{DY9}h0dfK17*&FIg2HHa{`WvLHglNv{gZP z_xSN+I`x(qbmxZpOQ?s3^Y)F)dMZ#8D5-BD5BM6WqqU(O*6DFuVc>A+*${d?pl1CB zh)Y}0gX!Vxqe&Q{XG@q5-1$DTKgCB*z;|^HDGXNuLr0M}d9Em4E*D43<^7vSB3(C4 zvbXJ$*k~MHvTT-kFPdV>;%VZ$VxIV~TPdMH>;!n+cp?PB6o$5HI}!At`%Tno5@7CQ zbv}TuyM0whzFB;6th^LnjcnZ!m4?S^K>NzoYc$mJajqm2hOAzXaLC4u$f5(tRBk;17Li{Y?u~JGPtEw+FuPgsP>W|+VK?xD7X?%uuzmQ$@A zV$98A!h^;PSKY*(0V)eKf(t3;Q=;$ZP?I6hSLW292w0@&2Xq) z%w{e9P~a2rkgtLZeI??D^o*DfDA zqwdt6x4m$B?LZQ(b{7n(6ennGQoA9AK^ly2M$hl!{v2 zsHi9`SRb|Ly3wCt()<~L5+G#)+;eVpAG@Gj7vdSBpNG%15bp|;^;3XO?`YX@%E z%p^(Kkttbwz|r^blHzhCJ>mR-V(e`DkCw_o)J>FDpj9*E2&D8FGA~OH${u72vwLa@ zs=kgNM;g!JqpmNgZocX%oU8grVdM}I+h?!?c?5AYi9XsjN! zM>@b*H?yaD*UfC9=Kc&?68p2!f>_c_t^XOe4Q{>oWA1AG7DqePVw9tm^DZ!ye?R;D zGx3?FAZhsfxzah9T;1z8cx#)*2Lz6e9D05tA|qkH#B19pGb3GRSM!ia7TmIx6<2)G zfy2V%FAtX?PJi^clpn9q4G(CJ+^b`LRGpLmz>~*l9WxIs;R?4>o*rsH2VGD+3YA?B zHABD(&&gpH0t0dI3}L13K<$csLM6+PtvZ$+dZqJ=hK7ZSKPZh&cWAb(Tn$Go?U|K& zwZogE>4FnB3=Y~|hn}l&_O9F*j!a2(=!k{CeJfHGa!>?-YPg)dBH6aH2(BlzYutrY z*`0-`e@1>S(xoWun8?Fzh=EoU9rRHKOfgUE=Cz9&czUef7#Y03C9o@aHCAd!}7ur#IH`bE~-Dt&tU4udUa7jnguB!0;VNjnbny)4!C`G;(mp0Safjd>@_}XJ?F}0k;1J;SmJs-TB7?mp4m3gm zAkyJk-i1Q3qHSAH9+x183R0vrKNBZ7;FLHtCEXAI-TvJ;IsgsAj~ql!ER4e&=8oRmFnX}A2Gb0@VA54XaNNn6VP>|Pr zDv1b{QFDu8lO=mupTx|ls6eA|$QdLK(t5g$B~5qh!~1t3&<~&=+*K={FrReVS&F2Z z+~>;Bw3MBzv$MH`v1vnConh^V*sNi@GqGA%Y3ObOJ7pV|IzuX?&6_b?me(2CzJbAD zAMm^Q1z-r_a0X@eaRx(zV32@q<{+thI~>DV*nG3m&O8s3ea~)mOTifJK}$x;?%gQz zhZNu>4holXzFx}kvmmz4Wz0imsmUhzXu;HKDQD4<-ONbW(pB>1g`PeNTS_9F2xf z;beL_7#9va{U`D8MkH*Bg&t4BqV@}up|=H+xzNNs@I)hoV$}bsHM*2!H8{ z{&{-1qm4Ro4oP?ZEgVfz#)J;;Y5hG~s6Vg6y2IYux*dH7*4L($f;D^8?4%00O4~j{ zhH%@B*qsMF?`W;A^}wI{)g;6HL(7LkL!D2-9vVG7>}zqc7WL)lw1sBt8}P;4LxJUe zY@>DH#&>Vu&~m?y+Xcv>`mBTL<@}17Gdvl}+E?v4$_2>~&kbxtY`eh)$yBmjpaF%8 ztzo&8ZtH;s$$3v<89g;83pF=>>%4HQ^#`xH|2p|g*`A1P-*>wf9naS*f)ws$Jt)ID zI5Y&Z7YlJOjw;oQ5}z$7;DX!>MuG(ivG-LjNVf1`j}d-RZvMMK>sgd~<d2At zM>eKC&VALGj5;#C7{>HSq$--T*E?VixJvHED1Y@ zDQHO*?v~dyzG(3^Iy*%$FVXfTf2Iu>QlJ_599?H&!>UW7on?9;AA~) zkrZx~*Kyt$wH7Q-`*r)CwpAVEx2u#pXn&`k-`DiBdVp(gF??45WuS4$zx=6@( zuA$8VH(rj>WmxQNX>|%N!jovHfaM3*BK{t{ex82|uFvA@odYtRJ70qXmhrrK4e4&Z zVBI|aK#g{E)!kMV6U=@kjT~n16O3C7QoCoG-PMWyU@1kbv1DVj9CKCdBg7sUs3=+7 z(LB>s6=ph`soxJq_~E{%qoXQ%&7-~QJ{i%F9uvW;SG{d^P-EV5bWvW-`EC!hiIe+k z19QXne=<}-i`uftf2;YLe%PSPdZF*ri@c}^N4nv@*rkgKt=9J!s zy=r_f({y70<=$)UzZR8dD-uXXN@v<&sS*Vuw7*to20&DZVE;x+6dWAqQ*!i)S* zuhg7^oYeXkoxf4I5j`lIzm)z}R&TN@D z0sAdiox0c$+vuejY@@e+Mwb}>8HhLHjh1TUBePxNAji|{#3a1=-m6&XmtOT~uCmI( zB=k=`_z_DtVlbAo*Yo%#@0~K6d2*Y!UFQ5wcd?_wqph+JfkFjtH2XEiRIr!TLsSf6 z3!&Kas^NZ0I!B1BJjJ6~_Uond@B1m|t<@%rS@X!A!uDwIqx1=rkyG}8P_ZwA-Xgg= z3X7Xt%c!teb@eize4=o#dT*@Rd91xT+AF3IKg|u1tA(bbO{ov#8*#$g{%WoWe0%PV zJq9q{miZudo`{`Ca$64=2aR(d33HFenw}=MzFI=F-U2OMtJ)4V`#00x+Uiqk{5Z3- zTGrTX)ydw!IH|44Z|#4#QT%Im>0x#7;@YsfdC|Tkv!P(hsslsK&j)g=;v}rQb5$?) zdzj>0^!Hr%?9m*IpDkAIsu#zYeVYKi?$xOk6HQMKFaiesDcTf=ISx*sG7v*~$0h(oFp{>* z7vXS+@yRpVxU*`n8Y}=}2S-=?&tZ-?BmyM#Wo4z99je7UW|yA!mfmoS=gi_gwR(Sw z+2w6}4mPy4S%S#Ur8M~YKXEQw`#in@{&&u^{Wv+U2K3N&nZbNkSzZW~)V^c3_F#yXNaHA48Ig?d9mKGT#N}mqwbc8^a*Fq$=Mv zN2s5FF*}at4B>{W=`gTH&j=fH^yY{e0o+v4lPdMbY2(Rn^1 zDx8k~C99{Iom*nz$1E^UtDaj)FgknmRz15p#;W%79qmC&Ji4l^Fxd3%!m+g99qG|g z_1J(xeQJ^UoXWatc6j3MO*LsUpg&@f*&1Vqw$?AI6BEs5A8S7lkc0g&IbwW-e3V>{ zHZNyO5!%4q>gk}eomE^=1Z#VNS#;V3@*UOdi_N}E$+9)JyG(3+oGps?!Ye}lu^WEO z0`L)g9n$vaf6KMViLwWK3ftdl^BRCis_>XsTc-7QsHCA;fjF{qD>XZfcs!6;k{Hx; zHiss0z_qck)LyvKE?eU|QMTe4=U`KOlZ(LKjoMAV+D{VdOp)<2J$d9-Tjiu_=u zD7TH6QvEhsV+6){6+Cm?M6;usGugF4HvypDzpeIcG<(m7C&gxe)U+hXsm{ZO=HQXJ z5j(lu*gb0pPKl($VkgArXxvHla&vhd>G0t0Y_mP>98vG=#8>z{8D6C?yv;UFjNW70 z>9O;~?!3>nR#aF}KcY0+h}n9lcA=`h?D;wqMF|m{c+6iQALQRdcFTT*>`zExRsfrE zsdhDH({}bMrSkzRRsCtPiB>*7=47>D32bK{AG1eGtVM3$5LNUoo^1KIfVs0+#Vrxo z;*N{8sP3njSd_~h5noGzE(vW&4Dk|w@TlQ6)ZyCFFcxzzpx~oVhsl?Nx6<1 zw0d=+-=5v7%{yj)^Ts_X_x$oU(9$B3ooXcf8?EaiWr z%#|$@!|+i68h+@$W2Abp+%Z7KhG7N*+L|kW!LHLU$@Ego51DO&T<>r%Dy%Y_w1h8$ zECflQ>isdMqkBWYgdQcNE!)}V)+lvRbxCHc5A0RM;Ujp{o~XovCX_WCE)JRP`up$D z$F9EQtg8DIxZ$QJW7RH5Hrqdi^Z~G2%|V!2L|lb`LI-{HP!`!sM#XxY9{ufMvvlyZ#M7sc)&PlatyP)x{4c?g=ke(>ZMY%t9q~0 zY~Bc-0QDYu#?lmXco*9+|56+1=)q524X#R#3ItU*Q%tiJ%^z#oRC3u2RRdCC^!okN zbsiyzQ;jW5iIJ)!dDU}uEF_uQn_$u>t^t^=1Td|qj+%e4g;&UZDW@}EFz{b0M9h8 zaUnt2FPXNerVyYJ97W<<{buCafwUh8>#CT8^I!Bn3>e;9jKzjykX&;7xYg{QO}Z!? z#REK07z=VAyii4O4;5-xG~LhEVzf*Ygy{5E#^Qlo0Ho!$qU(qW4BUmdU13B!HzgIh zcveZW*~P6!^~{IUa9j-*#k)0FEfX=)O=;fVxUT$rIZU-I-+V)rBjDMX1Ex;qn~=-&D7%#r-3eTiFvxuK^)Ylal{>$k3}_wq2X80Dtwoh1C! ziyO^$ZM1nn6IYuF%Qj-o9)f3sg(4PcT4iXwCU8=0&zN4FuD#CM6E5o-uIfspULqAr z&k2n4f2>sQb^kUWxYyb9fh)B?Cxzu4v^F(sBItpyAM^eD4yY9+__F(OvMdLTwk1ir=}#miRHGv=CjkatqcL|rd-t>2 zP@YvyO3eNK-UXriU8#Avt&PLf*yA3SVnhZXHs4g2Zh%}w z95yGkItM>?E&fAbaf#az(}{84=J4WD9jSUg0}}b(Gma-!`|e8)`kMJH8D9OO z&|4R*Ef)atvwZdqH9K=0M!OPv_NeJ|^B$>z3pK<>cJ8$k?e&=-!502j%#8V z2Vuu{8sS!tM7~M>bn-;G9t=9$?FB+jxMF#*?&Oxx{2NHqgHGn@7$^&mlO6HsvQP zD)4v?>&=E%6X!oSupMgDH|EnSpo7DFqPSRje}gUHNGXq|QmMF}*$`&9*AQw5GkhYP zri?x^SBfPRbiZ->Hk`@~f6`IH(_YSCW49OtPqebg^_5G?^INlLdj<)37@$j6t2e&I zBih`{(N(4N0wBbFYkuH%O#S5-*tLSU+~EB=;CN0IZAZka=+8*}TJxP5+Xw-&lIGu= zV_I2H@^}xtJLV7`9VRc>^i{wJ{%JxiF~?v_;5KrX+k#7@^$fTv98In~eqP&Nd^v^p{%7;~S$yVv&b4RYK*BRFEh*KTI zHP;O>OM5wV;?T7t0yS2ZZjQdd|KGbg#!j@yf%E-Vg<0 zYv4iHL%b(hQybB8Q^h{vX#Sc7FI*37XlOn5dac(9UUz9i(Bo~ONN=rt{DrFS2}j4_ zSS5VmTp?DX9>AU$gV(qbFsZMmxtP+M zX~tE6PE~t{*+I{L_^GJ1s2|%q-hPWu_{!yrSjF(q;OUkeLRL7Q?oP~V`^o4vwCk_&i*?*1LTAh^wl*9UPq|vcKeiz>N#6`A{j0 z8u5SwG8(%X_sNrJ%zd^72dMyHFpKpWD(Yo-$B>rVgMOW{7&Rjj_I19yqr2NFb=uuA zrp4o_`REtCHFhYb;(=n1XH^!^1_bu1`VE2Ys9OHrY+2I9bOg6jX@g-cYVg@I*wKMk zhP$0*tAlNp|N5IAj(*M95&)HNszXo5Q%-9dU()@ePU9SfW98*w6sQLQRpi4Zq%?fk zeE6Kg_B1A>{C7Ah274?;$}kQJBx*n&KXz+c2^)k$L3O{6P!bJV~*rb~f zo*_$nf>kk$h-+s6C?*f=*6A;FzF>yyU6q67+EqE2geM*daTI?fnPg>UlT#R-YBjo- zt8Y_|pVO z=Yfn0Fos2sEw62DuL_37&)3#sLsM;rIJ!7dyLkEH1>LBHtK>_FO?~Wrm`%WHU`%pQ z4!bI_- zM-Hj8_@W)ykPtKoLezn%8&5d8f9^sj?&0?KKy>1QD+1*zKU#+7g%~H;^ju6lfs##} zsd*R?-4;C5gTezmDBLEnvX*!`IyQ!9`nrmp!T>{fM|c;SG&aln|-K{<2~9j(Fj`S1@@TpYB1RsHtaWA*7VkP3Bc3~bsq?_e6Y z9_#4aBM-}$t+QF?!IS3ME|*Zxrwg{E-W}^0tYW5s7cQI%XG`>0N3SMUSh#$Oqmw%B zof(Y}|2P3p zPoo(layK;BB)vZe(T}@Ub(!cG^#XxS+hTaoRWP2lL*)STUkm@kp<+3St-X1-+C0(G zaf1D@L2$Uk>WAH62jL{g1h*%;)?}Qlxv}K{Jtnx{uR3@;98OMu%MGHpXuy}1#n%A3 z09$%FU^%iNBoA1-69dKmen-nVP(1XZ5`QuxHHf|GCBfx@dkU9=&QM`y3Vfbc`l%~a z)21HY?3K|`6}*FyzIV;hv@uw~DfRyfyYld=$~!$bfg~h13nbrn?zssh0R;*s1UpVE z6#{mlT9$|%qXjf{>a-JCYM&MhqE{UqsMZ!+CqG<3Mj`AH$Z|pwAc3p|A&{U*^#KG+ zJ5!ZJJDuvZnfLv^dy-)P7@p^F?#*&@&ToBx>$x;fElBk1vu_@gS<7JlRvgn|X)IGI z^2mI3R=Q>(36r@(Eh@Vey7X?5x{i91z%LbeH{YRNNR+oqRYrKQIUrh)`wa?s>^gm? zY!N_IrzFjQDr8Sl!z0)<#bAO4%pPPMUt_)>OtpbD%QHg)X$BKMxB``E!2Ik!>njWv z7ezX(;H5@Ts^Ha%Z{PD=FxjqS3K1S$|g-Osb%uR zI_UV}od5vm?^9olr2^)T!;M6it2nQqL@iB}!aju4jio4lmIQz=pkRs8SqfG@U7eAb z172Oz864#quAX<$*&)dfs6{scmVsa7%~2p7#?*|FcO%<$ZIT1|V;~431++@brUz8` z)~H$;9sm*ePJgI6H6iIp9vU?Qzjz+nkNyXFfHtkDQdZ0_*Sqht*wg%24c9|+j<>yc(-aTi|^4uFvzC5-}wSh^89l+y$iwRx>f4Sv#4MG!NMtD+lyz2 z*a@@S36sm?_>ePSN6n@@*n>ZnGX;OXWVIRR0dfu~#se>v65DjnxT)2#>P#`I0 z-u>>Ncja*y=p@??XlmQ?+>06MF{j(4X(?EGypR~+VJO&wXP`}2yJ7F<{n)|R!VXku zjoKV@?yThQRKF^#Lo(Ud!dz-$D#2k$#*Ty8q#9n!X2<*KqiSlR{IV1uId=~J%-&L{ z@EhyYR25|^yRWSBk%<^4Rq12E8m3stL%Kb_CNJ&LDR*p8c{6A}EiSa`NhtmQU-y}bv*bLj zrY_@ZY;tSp!O;r))Q$$^9#5M7O18oI{fkshyCQ(?&4c}ygX-xwCqN@n#Ac<3#k+24 z+^#al;GM1g*n~kBEcWqef&gdfU99F(XA|V>&%jE18=YjSCp zXth$)U_E`0$Mb1;KnA%@hZ{`_foXYqG_r?qn04)K<*(vvTV>w{HC976EDEeNql457 zk~Q^XrL<3Xn;Q1{BcHB@j!%0*O`PmM=zwRIXgM&*C+cyghQiNqk@SWslxJU1#hJtg zc<^z3Lw_fb;u(;W6&9Y)l)bNRk>LCACf|4w?mTZ}C{4ansgt}XUQ`u8g2Z@4gY}0b z_dbx+SB;Rj`ejv|C>P7sBpuf*6Q8#%H?@~7> z%8l77D;B>@XQQOC3V{BDYW4MT9X^c*odap^I|mvRnYm4=3=61j?9yqfP$y5wqcuu@ zm*gkO8NnPrcnGO#R4YNk?Rap2-|)n;F5mCm!J#tLevrH+$&G^m$yuwQb6}Q$PQ;8< zAxI=_uC6LOqsByh;+iz$0I_}I@@#DmBN;xUgXevCegU6y=0A9r9^ZfXEX@nI@zeCs zS?u1u%VfqFcd{k!(@+0wGGc6x!idgw#>O!2Hg+fKRR`>jZS$7KrxER)@Ki#&wJxWS z6=QhB6nwk<-cxI&zr@YR*$ zX-14D3`d}PUyGV{Cs{z_LH2N*sH3gP%&AhEx1;9jOFoTU4<@aD!_m}(pfujChsoIKdOWIq zD(efhIL7J>Y6M+t^oYVFxL4y^!zIY7kowHN@NAciU=bV)Xgl($^pd1*IVevqP$8@d zx5~guISZz28#(~5%1o9Y8d4GV%Lg^M+LSYJ9N|`#q*!6H{IF-f_N4HP8Xedti_fUc zZ=%x}0GJ)fOo5rCFGQN1oGioh!`UOnlt~YIix_bjkV_*2l9HS~FzMY`N46ay$eXQz zE$^K{Ix8j@oz`i&@P60)m*Cz0rus!N8N$on8iHD6u`X@}#(88xC|!b=)XkFFf=~H2 z;L4!v%2R#H37nAimsIwGE0^Cfc`lNz4dX~88v&$Gwyj&N*|wmB_G7zIc#d>4@kj8< zJ2NDs{iu|{WtA}zQ63=6py?PY$5l}}RzbF9`el_JfynYP)!ebjc}^p~5YGyTEdx6m zCH?_3cn6+wAdh0piW3h$)0W?3nv;c7E+J(zy)hDRV?`#uW=U&-hyf%9hM3fOzr6dj zN(gf*q#e^BtX{MnI@o^(TdAy%_5N~MT?op)DkMV;?ks)=e$a?-MxR;|9E$Me@jmsX z$-hO5AOr1gOnbF9A2OJ`0%mv1Ynb_c)p|n%Cbn&nOMQs{Gh;NK2-m9OZXYUVe7y%_ zrBzjEZ}a(GVsd?r%_EtJH~ug_D2S7C}oZnW0ZDKX|F^oik0|EWHl;5 zW4I9ex3OOm4VUjak%L&6e?Jm zA0m}$3XqVDHz}PKma1xXYcsm1=t5S`Q^ zXniZPdz|V#NqT{Hepf>mbd;{W0|TD*sBd?U04O$eYnMNd)CH3GiJBCP!7%APL3fi8 z%9e^hIK$+Zqx5E3utt~4iseYD%`ei|NyWX8X#c-ua_^0Lf)xH14l432l(OU(AtePH zopF-3+i|>)GxYCAAOh)@^JDavhUmb9)%f9pK7^)|r=x{w&q5uK#Ey2QkKM<5anogILe7#l{^{K1~jSS5& z4_nQ_^PSGyX*|0un9sw55@Cxh&*TV~5*~*J@)?*^4(jv3bMN46sM`!2s7P#upwH)x z`QTv)f|i0QdUS*a!%~+9+^4RktZ!s2buDEXdb8_<6WydN>u)}l4TYf-j9U1)9=O1E zFtVGhrW5}`(x^VzzyAfn-!wRHRsJXX9CF~d^uWEla zbQkFgrYt%nFi$U#4{LOScjr7^6O^1|p?EoY#TkyGtX`CeHE;jD-CGzl)IWGvPVn5R^3YFRI;q7V$!=+;3n=9TKZ2VTWXbt!=VlyYRP z{y?!gw+g{%&qAGc8xyB~!@PfH3W*!*SgNc9FrnO%Bm;{i;b$oyL;?m;!EIE?vJaoF1aS_5oDFCj z>BNP#9ztEA%9D#VdYSy=QhimvG9N>L$9Cu(Z}~F43A+HRbey!jhnpU|O0SRWXm10= zl%{5#QPzVjpihLU_n;y57-Wf8$iGfj@RrOJ9dIr^C4&Us?%#;MH7rJgXg-Z+gxp$i zBi~!C#|9c@?P`5PK3Y+zTr{{AR)|Le_5pG zdv`soj|S!76*nl?uhXw#*RvCkM9^s|V*2{ZI(^+da*Z0ygE1=!&PyN>8A4K^=_ZX} zlXG-C1DuO$F|86*v8qz;`I#=xKTMa*-bf%@7z7KjcEDxBEhBoUMC%T(wH5is#<~O2 z+Xp`UwND4V;-~eIp!{&29xi!Lgc62xWonze(hZ@#ccD&{S>>>9^Q-ag`Q^Yek!qw> zXP1Lbo4WOw7|Ws%e#^hb@7OAf9pUFhiaDUZY|vrbF%LViXeq$=+{i$&BB^OyNCkrn z4MTnBE8p0lb7aZSbb1PbJP!KRO2nRPH|V@^^-#XrS`YVJgPn4CItR|LS5yLBH1xOQ zXu^F%{#MD=4LV`l-7n~X{HRu!N$PSaUd{m>=goOZ|0Xg1G}1Y({T*mT$DOap2Mum3 z*CQ-QBzcpwYQt7$VB7V1dNRwhszPZpKR6%fFq;^Nz`LRm$51} zc7Qsdj6WAfLuaVOGg1aEXbPsMB2!5j$^yeV$_M+(sO83o`uN^hc?9RkL|OURn`(ZU zT514bwLH8{|3h{)G_$$}?TeUm;Kt4q$63?vK+jYw0>C=2Yn%RV@(A7=Q@b7VLujJR zj2bF)`x!*MITkO3djNKSQLW>KlNN0h_FQIr;^acL&Wzw@sk6Lc|Hkc^V!@jF=LirL z7v4Ozkk?L>OY>y_L{u!UwfZcB4Z&oC1n8gZyEqQ;@@R#;aj=0MsI>>`@w~kH{s#8E z01_QW=i*W1+&P)o*2ex8Xeo}CmS*f-5g{b3S;Kgk4HoB)z)UlK@0V z**SqbXPSxWB_^D+55p<3|E3Gg^`@f<(1j&RI~Z|Na$j<;_u6}ORg5&gsE2uvy`_`T zYMkmM4&l4^p3cu4w0Ts0KPhLlT|Vo^>~ns=8Fv@eJjy}t3*bTXPbnuzC0FTVX$X04 z;r+oUGu$GB*fPzBtg#`BTgjtCqGZgMypxx7cd~r78P*v*iDymp)Kn(}y+bt2XUp|y zkUk;KYM^BF>Fb6=-Vjd}T+*YzYHag0f=25@YQRdFuTx3!r*R835;Pb*I@t?mU(3cm zohLi{beeapPj88m>_>mp_a@2e9Mo$!A8=EoXf%qpMK6WoIP z&Ydzf;AGxmE+tAmUWWhP=#2RlYf$Zbwylv;bT@uS2rk*Quh~n-zLS76MJfVL(CZ2~ zQ&Yy+MGM`AFT60rBVL^0m87OQnKzm1_ zL|5lVIsY1qo-D5<-6>CsMX^+-W;;j(mO5XM>}(J#r_@Q6<=IYLpw;_HwsU`sRKz;p zmi)0!mgEd`h5;=G6|!_rT5zIW$T zCp9Q@%OS)6((K$Io5V@zumLGJTzMgZHg+ z=X(KpeUY==8@=86H8PfIa?XB41ho+L=heA_jeQajXn^+c_6NtsHc@Ifwd2%d@Z?Znsoh6fxhE92( zZVgSGBRBSiwD;w{(BjP4+L}5k*%F$bgcpb!>VWU+GIS_4iR7Xq*J9 z>}>+!KbqvO_pfujR7`ef%gG~X*8K3JP=eP#*?lq)3+l+2$*wD}j38G<-1;z zoG*5V%a&pnvq5{qsb1bRcU&yLEq7$Q>E1t2cMp$<#Wi^oXS>}2NuKOxNmmtUlXsgt z5kGja#=CotyEI99_z@S1-2@N+-5V3z)7j?D`i@(4L(H)bdF}`9G&#A&O^^{yZoU`0 z*8L<)9$N{1=0ESwkej!--;G5ts<&y2TbF_x*)Iz#-FspY7kFN!yC)Fe-hRX|F}E*V zEIB_8r%A=CaBA5hzIe~A^a@tHI#Bj2Sf#W=_a4c4-(4m}D^WzhS{Tlk3vY(MAs4>m zBtYN7KbH${xx3}UBVlY&`w3+A>RC4=IWIf-;A0TQl!!aZ`(C~KRDyhV(M^{AF>aw; zy#L=7qoF&HTtsi;wYmPYtOqArLPzQ_)3}kWw~XGn<{f2a=#`; z54pp<7yjyQ5AaXPgJtebGUItST>a~C&y(`pYvGU=c`6(?M(+7OWa6Qx!lAW0UJK*M j^me?Km3AfL?G^Kje>45g%)i6G+rB>UYp>s0^2GlEIfBye From 11b5a49e0a226029f8c463a93cbc4ef994eaf258 Mon Sep 17 00:00:00 2001 From: Dmitrii Zolotov Date: Sat, 3 Oct 2026 12:37:43 +0300 Subject: [PATCH 06/34] fix: Leave out photons stretched past sixteen times their spacing Once the bench took part in the shadow map, every photon found somewhere to land, and the ones leaving a liquid's rim edge-on were drawn as quads over most of the caustic tile. Their light is too thin to see, so both the GLSL pass and its CPU port skip them; camera orbits are smooth again. --- .../lib/src/cpu_shaders_shadow_passes.dart | 7 + .../shaders/lighting/caustic_photon.vert | 10 + .../flutter3d_webgl/lib/engine_shaders.dart | 10 + .../flutter3d_webgpu/lib/engine_shaders.dart | 692 +++++++++--------- 4 files changed, 380 insertions(+), 339 deletions(-) diff --git a/packages/flutter3d_cpu/lib/src/cpu_shaders_shadow_passes.dart b/packages/flutter3d_cpu/lib/src/cpu_shaders_shadow_passes.dart index 5c66a2c54..724e8d88d 100644 --- a/packages/flutter3d_cpu/lib/src/cpu_shaders_shadow_passes.dart +++ b/packages/flutter3d_cpu/lib/src/cpu_shaders_shadow_passes.dart @@ -378,6 +378,13 @@ final class CausticPhotonVertexShader implements CpuVertexShaderByIndex { final prevY = _follow(b, u, v - texel); if (prevY != null) down = at - prevY.$1; } + // Stretched past sixteen times its own spacing either way, a photon's + // light is spread a two-hundred-and-fiftieth as thin as where it set + // out, and drawing it is a quad over most of the tile for nothing to + // see: as caustic_photon.vert, it is left out. + if (across.length > 16.0 * grid.z || down.length > 16.0 * grid.w) { + return away; + } final least = grid.y; final ax = _atLeast(across * 1.5, spacingX, least); final by = _atLeast(down * 1.5, spacingY, least); diff --git a/packages/flutter3d_shaders/shaders/lighting/caustic_photon.vert b/packages/flutter3d_shaders/shaders/lighting/caustic_photon.vert index 1faf27c50..2fec53e5b 100644 --- a/packages/flutter3d_shaders/shaders/lighting/caustic_photon.vert +++ b/packages/flutter3d_shaders/shaders/lighting/caustic_photon.vert @@ -199,6 +199,16 @@ void main() { vec4 prev_y = Follow(uv - vec2(0.0, texel), unused); if (prev_y.w > 0.5) b = here.xy - prev_y.xy; } + // **Stretched past sixteen times its own spacing either way, left out.** + // Its light is spread a two-hundred-and-fiftieth as thin as where it set + // out, so it shows nothing; drawn, a photon whose neighbour landed across + // the tile was a quad over most of it, and the hundreds of them at a + // liquid's rim, where the light leaves edge-on, cost more than the rest + // of the frame together once the bench was in the map for them to land. + if (length(a) > 16.0 * caustic_info.grid.z || + length(b) > 16.0 * caustic_info.grid.w) { + return; + } // Half again, so neighbouring quads overlap, and never under the least. float least = caustic_info.grid.y; a = AtLeast(1.5 * a, spacing_x, least); diff --git a/packages/flutter3d_webgl/lib/engine_shaders.dart b/packages/flutter3d_webgl/lib/engine_shaders.dart index 552bf6411..2f3099535 100644 --- a/packages/flutter3d_webgl/lib/engine_shaders.dart +++ b/packages/flutter3d_webgl/lib/engine_shaders.dart @@ -2364,6 +2364,16 @@ void main() { vec4 prev_y = Follow(uv - vec2(0.0, texel), unused); if (prev_y.w > 0.5) b = here.xy - prev_y.xy; } + // **Stretched past sixteen times its own spacing either way, left out.** + // Its light is spread a two-hundred-and-fiftieth as thin as where it set + // out, so it shows nothing; drawn, a photon whose neighbour landed across + // the tile was a quad over most of it, and the hundreds of them at a + // liquid's rim, where the light leaves edge-on, cost more than the rest + // of the frame together once the bench was in the map for them to land. + if (length(a) > 16.0 * caustic_info.grid.z || + length(b) > 16.0 * caustic_info.grid.w) { + return; + } // Half again, so neighbouring quads overlap, and never under the least. float least = caustic_info.grid.y; a = AtLeast(1.5 * a, spacing_x, least); diff --git a/packages/flutter3d_webgpu/lib/engine_shaders.dart b/packages/flutter3d_webgpu/lib/engine_shaders.dart index 138fca5e1..166f9687b 100644 --- a/packages/flutter3d_webgpu/lib/engine_shaders.dart +++ b/packages/flutter3d_webgpu/lib/engine_shaders.dart @@ -3535,48 +3535,48 @@ fn AtLeast_u0028_vf2_u003b_vf2_u003b_f1_u003b(a: ptr>, fallb var size: f32; var local: vec2; - let _e50 = (*a); - size = length(_e50); - let _e52 = size; - if (_e52 < 0.000000001f) { - let _e54 = (*fallback); - let _e56 = (*least); - return (normalize(_e54) * _e56); - } - let _e58 = size; - let _e59 = (*least); - if (_e58 < _e59) { - let _e61 = (*a); - let _e62 = (*least); - let _e63 = size; - local = (_e61 * (_e62 / _e63)); - } else { - let _e66 = (*a); - local = _e66; - } - let _e67 = local; - return _e67; + let _e51 = (*a); + size = length(_e51); + let _e53 = size; + if (_e53 < 0.000000001f) { + let _e55 = (*fallback); + let _e57 = (*least); + return (normalize(_e55) * _e57); + } + let _e59 = size; + let _e60 = (*least); + if (_e59 < _e60) { + let _e62 = (*a); + let _e63 = (*least); + let _e64 = size; + local = (_e62 * (_e63 / _e64)); + } else { + let _e67 = (*a); + local = _e67; + } + let _e68 = local; + return _e68; } fn Schlick_u0028_f1_u003b_f1_u003b(f0_: ptr, cosine: ptr) -> f32 { var c: f32; - let _e48 = (*cosine); - c = clamp((1f - _e48), 0f, 1f); - let _e51 = (*f0_); + let _e49 = (*cosine); + c = clamp((1f - _e49), 0f, 1f); let _e52 = (*f0_); - let _e54 = c; - let _e56 = c; - let _e58 = c; - let _e60 = c; - let _e62 = c; - return (_e51 + ((((((1f - _e52) * _e54) * _e56) * _e58) * _e60) * _e62)); + let _e53 = (*f0_); + let _e55 = c; + let _e57 = c; + let _e59 = c; + let _e61 = c; + let _e63 = c; + return (_e52 + ((((((1f - _e53) * _e55) * _e57) * _e59) * _e61) * _e63)); } fn MapUv_u0028_vf4_u003b(p: ptr>) -> vec2 { - let _e47 = (*p)[0u]; - let _e51 = (*p)[1u]; - return vec2(((_e47 * 0.5f) + 0.5f), (0.5f - (_e51 * 0.5f))); + let _e48 = (*p)[0u]; + let _e52 = (*p)[1u]; + return vec2(((_e48 * 0.5f) + 0.5f), (0.5f - (_e52 * 0.5f))); } fn Follow_u0028_vf2_u003b_vf3_u003b(uv: ptr>, energy: ptr>) -> vec4 { @@ -3616,191 +3616,191 @@ fn Follow_u0028_vf2_u003b_vf3_u003b(uv: ptr>, energy: ptr(0f, 0f, 0f); - let _e80 = (*uv); - let _e81 = textureSampleLevel(caustic_front_tex, caustic_front_smp, _e80, 0f); - front = _e81; - let _e83 = front[3u]; - let _e84 = (_e83 >= 1f); - phi_100_ = _e84; - if !(_e84) { - let _e86 = front; - let _e88 = front; - phi_100_ = (dot(_e86.xyz, _e88.xyz) < 0.25f); - } - let _e93 = phi_100_; - if _e93 { + let _e81 = (*uv); + let _e82 = textureSampleLevel(caustic_front_tex, caustic_front_smp, _e81, 0f); + front = _e82; + let _e84 = front[3u]; + let _e85 = (_e84 >= 1f); + phi_100_ = _e85; + if !(_e85) { + let _e87 = front; + let _e89 = front; + phi_100_ = (dot(_e87.xyz, _e89.xyz) < 0.25f); + } + let _e94 = phi_100_; + if _e94 { return vec4(0f, 0f, 0f, 0f); } - let _e95 = (*uv)[0u]; - let _e99 = (*uv)[1u]; - ndc = vec2(((_e95 * 2f) - 1f), ((0.5f - _e99) * 2f)); - let _e104 = caustic_info.map_to_world; - let _e105 = ndc; - let _e107 = front[3u]; - entry = (_e104 * vec4(_e105.x, _e105.y, _e107, 1f)).xyz; - let _e114 = caustic_info.map_to_world; - range = length((_e114 * vec4(0f, 0f, 1f, 0f)).xyz); - let _e119 = caustic_info.light; - l = normalize(_e119.xyz); - let _e122 = front; - n1_ = normalize(_e122.xyz); - let _e125 = n1_; - let _e126 = l; - if (dot(_e125, _e126) > 0f) { - let _e129 = n1_; - n1_ = -(_e129); - } - let _e133 = caustic_info.optics[0u]; - index = max(_e133, 1f); - let _e135 = l; - let _e136 = n1_; - let _e137 = index; - inside = refract(_e135, _e136, (1f / _e137)); - let _e140 = (*uv); - let _e141 = textureSampleLevel(caustic_back_tex, caustic_back_smp, _e140, 0f); - back = _e141; - let _e143 = back[3u]; - let _e145 = front[3u]; - if (_e143 <= _e145) { + let _e96 = (*uv)[0u]; + let _e100 = (*uv)[1u]; + ndc = vec2(((_e96 * 2f) - 1f), ((0.5f - _e100) * 2f)); + let _e105 = caustic_info.map_to_world; + let _e106 = ndc; + let _e108 = front[3u]; + entry = (_e105 * vec4(_e106.x, _e106.y, _e108, 1f)).xyz; + let _e115 = caustic_info.map_to_world; + range = length((_e115 * vec4(0f, 0f, 1f, 0f)).xyz); + let _e120 = caustic_info.light; + l = normalize(_e120.xyz); + let _e123 = front; + n1_ = normalize(_e123.xyz); + let _e126 = n1_; + let _e127 = l; + if (dot(_e126, _e127) > 0f) { + let _e130 = n1_; + n1_ = -(_e130); + } + let _e134 = caustic_info.optics[0u]; + index = max(_e134, 1f); + let _e136 = l; + let _e137 = n1_; + let _e138 = index; + inside = refract(_e136, _e137, (1f / _e138)); + let _e141 = (*uv); + let _e142 = textureSampleLevel(caustic_back_tex, caustic_back_smp, _e141, 0f); + back = _e142; + let _e144 = back[3u]; + let _e146 = front[3u]; + if (_e144 <= _e146) { return vec4(0f, 0f, 0f, 0f); } - let _e148 = back[3u]; - let _e150 = front[3u]; - let _e152 = range; - across = ((_e148 - _e150) * _e152); - let _e154 = entry; - let _e155 = inside; - let _e156 = across; - let _e157 = inside; - let _e158 = l; - exit = (_e154 + (_e155 * (_e156 / max(dot(_e157, _e158), 0.2f)))); - let _e165 = caustic_info.world_to_map; - let _e166 = exit; - param = (_e165 * vec4(_e166.x, _e166.y, _e166.z, 1f)); - let _e172 = MapUv_u0028_vf4_u003b((¶m)); - let _e176 = textureSampleLevel(caustic_back_tex, caustic_back_smp, clamp(_e172, vec2(0f), vec2(1f)), 0f); - there = _e176; - let _e177 = there; - let _e179 = there; - if (dot(_e177.xyz, _e179.xyz) > 0.25f) { - let _e183 = there; - local_1 = normalize(_e183.xyz); - } else { - let _e186 = back; - local_1 = normalize(_e186.xyz); - } - let _e189 = local_1; - n2_ = _e189; - let _e190 = n2_; - let _e191 = inside; - if (dot(_e190, _e191) < 0f) { - let _e194 = n2_; - n2_ = -(_e194); - } - let _e196 = inside; - let _e197 = n2_; - let _e199 = index; - out_ray = refract(_e196, -(_e197), _e199); - let _e201 = out_ray; + let _e149 = back[3u]; + let _e151 = front[3u]; + let _e153 = range; + across = ((_e149 - _e151) * _e153); + let _e155 = entry; + let _e156 = inside; + let _e157 = across; + let _e158 = inside; + let _e159 = l; + exit = (_e155 + (_e156 * (_e157 / max(dot(_e158, _e159), 0.2f)))); + let _e166 = caustic_info.world_to_map; + let _e167 = exit; + param = (_e166 * vec4(_e167.x, _e167.y, _e167.z, 1f)); + let _e173 = MapUv_u0028_vf4_u003b((¶m)); + let _e177 = textureSampleLevel(caustic_back_tex, caustic_back_smp, clamp(_e173, vec2(0f), vec2(1f)), 0f); + there = _e177; + let _e178 = there; + let _e180 = there; + if (dot(_e178.xyz, _e180.xyz) > 0.25f) { + let _e184 = there; + local_1 = normalize(_e184.xyz); + } else { + let _e187 = back; + local_1 = normalize(_e187.xyz); + } + let _e190 = local_1; + n2_ = _e190; + let _e191 = n2_; + let _e192 = inside; + if (dot(_e191, _e192) < 0f) { + let _e195 = n2_; + n2_ = -(_e195); + } + let _e197 = inside; + let _e198 = n2_; + let _e200 = index; + out_ray = refract(_e197, -(_e198), _e200); let _e202 = out_ray; - if (dot(_e201, _e202) < 0.000001f) { + let _e203 = out_ray; + if (dot(_e202, _e203) < 0.000001f) { return vec4(0f, 0f, 0f, 0f); } - let _e205 = out_ray; - out_ray = normalize(_e205); - let _e207 = out_ray; - let _e208 = l; - if (dot(_e207, _e208) < 0.3f) { + let _e206 = out_ray; + out_ray = normalize(_e206); + let _e208 = out_ray; + let _e209 = l; + if (dot(_e208, _e209) < 0.3f) { return vec4(0f, 0f, 0f, 0f); } - let _e213 = caustic_info.optics[1u]; - f0_1 = _e213; - let _e215 = caustic_info.tint; - let _e217 = l; - let _e218 = n1_; - let _e221 = f0_1; - param_1 = _e221; - param_2 = abs(dot(_e217, _e218)); - let _e222 = Schlick_u0028_f1_u003b_f1_u003b((¶m_1), (¶m_2)); - let _e225 = out_ray; - let _e226 = n2_; - let _e229 = f0_1; - param_3 = _e229; - param_4 = abs(dot(_e225, _e226)); - let _e230 = Schlick_u0028_f1_u003b_f1_u003b((¶m_3), (¶m_4)); - (*energy) = ((_e215.xyz * (1f - _e222)) * (1f - _e230)); - let _e235 = caustic_info.optics[2u]; - fading = _e235; - let _e236 = fading; - if (_e236 > 0f) { - let _e239 = caustic_info.attenuation; - let _e242 = exit; - let _e243 = entry; - let _e246 = fading; - let _e250 = (*energy); - (*energy) = (_e250 * pow(max(_e239.xyz, vec3(0.0001f, 0.0001f, 0.0001f)), vec3((length((_e242 - _e243)) / _e246)))); - } - let _e252 = exit; - p_1 = _e252; - let _e253 = out_ray; - let _e254 = l; - down = max(dot(_e253, _e254), 0.05f); + let _e214 = caustic_info.optics[1u]; + f0_1 = _e214; + let _e216 = caustic_info.tint; + let _e218 = l; + let _e219 = n1_; + let _e222 = f0_1; + param_1 = _e222; + param_2 = abs(dot(_e218, _e219)); + let _e223 = Schlick_u0028_f1_u003b_f1_u003b((¶m_1), (¶m_2)); + let _e226 = out_ray; + let _e227 = n2_; + let _e230 = f0_1; + param_3 = _e230; + param_4 = abs(dot(_e226, _e227)); + let _e231 = Schlick_u0028_f1_u003b_f1_u003b((¶m_3), (¶m_4)); + (*energy) = ((_e216.xyz * (1f - _e223)) * (1f - _e231)); + let _e236 = caustic_info.optics[2u]; + fading = _e236; + let _e237 = fading; + if (_e237 > 0f) { + let _e240 = caustic_info.attenuation; + let _e243 = exit; + let _e244 = entry; + let _e247 = fading; + let _e251 = (*energy); + (*energy) = (_e251 * pow(max(_e240.xyz, vec3(0.0001f, 0.0001f, 0.0001f)), vec3((length((_e243 - _e244)) / _e247)))); + } + let _e253 = exit; + p_1 = _e253; + let _e254 = out_ray; + let _e255 = l; + down = max(dot(_e254, _e255), 0.05f); k = 0i; loop { - let _e257 = k; - if (_e257 < 4i) { - let _e260 = caustic_info.world_to_tile; - let _e261 = p_1; - q = (_e260 * vec4(_e261.x, _e261.y, _e261.z, 1f)); - let _e267 = q; - param_5 = _e267; - let _e268 = MapUv_u0028_vf4_u003b((¶m_5)); - let _e272 = textureSampleLevel(caustic_depth_tex, caustic_depth_smp, clamp(_e268, vec2(0f), vec2(1f)), 0f); - receiver = _e272.x; - let _e274 = receiver; - let _e276 = q[2u]; - let _e278 = range; - let _e280 = down; - advance = (((_e274 - _e276) * _e278) / _e280); - let _e282 = k; - if (_e282 == 0i) { - let _e284 = advance; - advance = max(_e284, 0f); - } - let _e286 = out_ray; - let _e287 = advance; - let _e289 = p_1; - p_1 = (_e289 + (_e286 * _e287)); + let _e258 = k; + if (_e258 < 4i) { + let _e261 = caustic_info.world_to_tile; + let _e262 = p_1; + q = (_e261 * vec4(_e262.x, _e262.y, _e262.z, 1f)); + let _e268 = q; + param_5 = _e268; + let _e269 = MapUv_u0028_vf4_u003b((¶m_5)); + let _e273 = textureSampleLevel(caustic_depth_tex, caustic_depth_smp, clamp(_e269, vec2(0f), vec2(1f)), 0f); + receiver = _e273.x; + let _e275 = receiver; + let _e277 = q[2u]; + let _e279 = range; + let _e281 = down; + advance = (((_e275 - _e277) * _e279) / _e281); + let _e283 = k; + if (_e283 == 0i) { + let _e285 = advance; + advance = max(_e285, 0f); + } + let _e287 = out_ray; + let _e288 = advance; + let _e290 = p_1; + p_1 = (_e290 + (_e287 * _e288)); continue; } else { break; } continuing { - let _e291 = k; - k = (_e291 + 1i); - } - } - let _e294 = caustic_info.world_to_tile; - let _e295 = p_1; - landed = (_e294 * vec4(_e295.x, _e295.y, _e295.z, 1f)); - let _e301 = landed; - param_6 = _e301; - let _e302 = MapUv_u0028_vf4_u003b((¶m_6)); - let _e306 = textureSampleLevel(caustic_depth_tex, caustic_depth_smp, clamp(_e302, vec2(0f), vec2(1f)), 0f); - under = _e306.x; - let _e308 = under; - let _e310 = landed[2u]; - let _e313 = range; - if ((abs((_e308 - _e310)) * _e313) > 0.02f) { + let _e292 = k; + k = (_e292 + 1i); + } + } + let _e295 = caustic_info.world_to_tile; + let _e296 = p_1; + landed = (_e295 * vec4(_e296.x, _e296.y, _e296.z, 1f)); + let _e302 = landed; + param_6 = _e302; + let _e303 = MapUv_u0028_vf4_u003b((¶m_6)); + let _e307 = textureSampleLevel(caustic_depth_tex, caustic_depth_smp, clamp(_e303, vec2(0f), vec2(1f)), 0f); + under = _e307.x; + let _e309 = under; + let _e311 = landed[2u]; + let _e314 = range; + if ((abs((_e309 - _e311)) * _e314) > 0.02f) { return vec4(0f, 0f, 0f, 0f); } - let _e317 = caustic_info.world_to_clip; - let _e318 = p_1; - clip = (_e317 * vec4(_e318.x, _e318.y, _e318.z, 1f)); - let _e324 = clip; - let _e327 = clip[3u]; - let _e329 = (_e324.xy / vec2(_e327)); - return vec4(_e329.x, _e329.y, 0f, 1f); + let _e318 = caustic_info.world_to_clip; + let _e319 = p_1; + clip = (_e318 * vec4(_e319.x, _e319.y, _e319.z, 1f)); + let _e325 = clip; + let _e328 = clip[3u]; + let _e330 = (_e325.xy / vec2(_e328)); + return vec4(_e330.x, _e330.y, 0f, 1f); } fn main_1() { @@ -3842,150 +3842,164 @@ fn main_1() { var param_22: f32; var area: f32; var share: f32; + var phi_654_: bool; - let _e83 = corner_1; - v_uv = _e83; + let _e84 = corner_1; + v_uv = _e84; v_color = vec4(0f, 0f, 0f, 0f); unnamed.gl_Position = vec4(4f, 4f, 0.5f, 1f); - let _e87 = caustic_info.grid[0u]; - n = _e87; - let _e88 = gl_InstanceIndex_1; - id = f32(_e88); - let _e90 = id; - let _e91 = n; - column = (_e90 - (floor((_e90 / _e91)) * _e91)); - let _e96 = id; - let _e97 = n; - row = floor((_e96 / _e97)); - let _e100 = column; - let _e102 = n; - let _e104 = row; - let _e106 = n; - uv_1 = vec2(((_e100 + 0.5f) / _e102), ((_e104 + 0.5f) / _e106)); - let _e109 = n; - texel = (1f / _e109); - let _e111 = uv_1; - param_7 = _e111; - let _e112 = Follow_u0028_vf2_u003b_vf3_u003b((¶m_7), (¶m_8)); - let _e113 = param_8; - energy_1 = _e113; - here = _e112; - let _e115 = here[3u]; - if (_e115 < 0.5f) { + let _e88 = caustic_info.grid[0u]; + n = _e88; + let _e89 = gl_InstanceIndex_1; + id = f32(_e89); + let _e91 = id; + let _e92 = n; + column = (_e91 - (floor((_e91 / _e92)) * _e92)); + let _e97 = id; + let _e98 = n; + row = floor((_e97 / _e98)); + let _e101 = column; + let _e103 = n; + let _e105 = row; + let _e107 = n; + uv_1 = vec2(((_e101 + 0.5f) / _e103), ((_e105 + 0.5f) / _e107)); + let _e110 = n; + texel = (1f / _e110); + let _e112 = uv_1; + param_7 = _e112; + let _e113 = Follow_u0028_vf2_u003b_vf3_u003b((¶m_7), (¶m_8)); + let _e114 = param_8; + energy_1 = _e114; + here = _e113; + let _e116 = here[3u]; + if (_e116 < 0.5f) { + return; + } + let _e120 = caustic_info.grid[2u]; + spacing_x = vec2(_e120, 0f); + let _e124 = caustic_info.grid[3u]; + spacing_y = vec2(0f, _e124); + let _e126 = uv_1; + let _e127 = texel; + param_9 = (_e126 + vec2(_e127, 0f)); + let _e130 = Follow_u0028_vf2_u003b_vf3_u003b((¶m_9), (¶m_10)); + let _e131 = param_10; + unused = _e131; + next_x = _e130; + let _e133 = next_x[3u]; + if (_e133 > 0.5f) { + let _e135 = next_x; + let _e137 = here; + local_2 = (_e135.xy - _e137.xy); + } else { + let _e140 = spacing_x; + local_2 = _e140; + } + let _e141 = local_2; + a_1 = _e141; + let _e143 = next_x[3u]; + if (_e143 < 0.5f) { + let _e145 = uv_1; + let _e146 = texel; + param_11 = (_e145 - vec2(_e146, 0f)); + let _e149 = Follow_u0028_vf2_u003b_vf3_u003b((¶m_11), (¶m_12)); + let _e150 = param_12; + unused = _e150; + prev_x = _e149; + let _e152 = prev_x[3u]; + if (_e152 > 0.5f) { + let _e154 = here; + let _e156 = prev_x; + a_1 = (_e154.xy - _e156.xy); + } + } + let _e159 = uv_1; + let _e160 = texel; + param_13 = (_e159 + vec2(0f, _e160)); + let _e163 = Follow_u0028_vf2_u003b_vf3_u003b((¶m_13), (¶m_14)); + let _e164 = param_14; + unused = _e164; + next_y = _e163; + let _e166 = next_y[3u]; + if (_e166 > 0.5f) { + let _e168 = next_y; + let _e170 = here; + local_3 = (_e168.xy - _e170.xy); + } else { + let _e173 = spacing_y; + local_3 = _e173; + } + let _e174 = local_3; + b = _e174; + let _e176 = next_y[3u]; + if (_e176 < 0.5f) { + let _e178 = uv_1; + let _e179 = texel; + param_15 = (_e178 - vec2(0f, _e179)); + let _e182 = Follow_u0028_vf2_u003b_vf3_u003b((¶m_15), (¶m_16)); + let _e183 = param_16; + unused = _e183; + prev_y = _e182; + let _e185 = prev_y[3u]; + if (_e185 > 0.5f) { + let _e187 = here; + let _e189 = prev_y; + b = (_e187.xy - _e189.xy); + } + } + let _e192 = a_1; + let _e196 = caustic_info.grid[2u]; + let _e198 = (length(_e192) > (16f * _e196)); + phi_654_ = _e198; + if !(_e198) { + let _e200 = b; + let _e204 = caustic_info.grid[3u]; + phi_654_ = (length(_e200) > (16f * _e204)); + } + let _e208 = phi_654_; + if _e208 { return; } - let _e119 = caustic_info.grid[2u]; - spacing_x = vec2(_e119, 0f); - let _e123 = caustic_info.grid[3u]; - spacing_y = vec2(0f, _e123); - let _e125 = uv_1; - let _e126 = texel; - param_9 = (_e125 + vec2(_e126, 0f)); - let _e129 = Follow_u0028_vf2_u003b_vf3_u003b((¶m_9), (¶m_10)); - let _e130 = param_10; - unused = _e130; - next_x = _e129; - let _e132 = next_x[3u]; - if (_e132 > 0.5f) { - let _e134 = next_x; - let _e136 = here; - local_2 = (_e134.xy - _e136.xy); - } else { - let _e139 = spacing_x; - local_2 = _e139; - } - let _e140 = local_2; - a_1 = _e140; - let _e142 = next_x[3u]; - if (_e142 < 0.5f) { - let _e144 = uv_1; - let _e145 = texel; - param_11 = (_e144 - vec2(_e145, 0f)); - let _e148 = Follow_u0028_vf2_u003b_vf3_u003b((¶m_11), (¶m_12)); - let _e149 = param_12; - unused = _e149; - prev_x = _e148; - let _e151 = prev_x[3u]; - if (_e151 > 0.5f) { - let _e153 = here; - let _e155 = prev_x; - a_1 = (_e153.xy - _e155.xy); - } - } - let _e158 = uv_1; - let _e159 = texel; - param_13 = (_e158 + vec2(0f, _e159)); - let _e162 = Follow_u0028_vf2_u003b_vf3_u003b((¶m_13), (¶m_14)); - let _e163 = param_14; - unused = _e163; - next_y = _e162; - let _e165 = next_y[3u]; - if (_e165 > 0.5f) { - let _e167 = next_y; - let _e169 = here; - local_3 = (_e167.xy - _e169.xy); - } else { - let _e172 = spacing_y; - local_3 = _e172; - } - let _e173 = local_3; - b = _e173; - let _e175 = next_y[3u]; - if (_e175 < 0.5f) { - let _e177 = uv_1; - let _e178 = texel; - param_15 = (_e177 - vec2(0f, _e178)); - let _e181 = Follow_u0028_vf2_u003b_vf3_u003b((¶m_15), (¶m_16)); - let _e182 = param_16; - unused = _e182; - prev_y = _e181; - let _e184 = prev_y[3u]; - if (_e184 > 0.5f) { - let _e186 = here; - let _e188 = prev_y; - b = (_e186.xy - _e188.xy); - } - } - let _e193 = caustic_info.grid[1u]; - least_1 = _e193; - let _e194 = a_1; - param_17 = (_e194 * 1.5f); - let _e196 = spacing_x; - param_18 = _e196; - let _e197 = least_1; - param_19 = _e197; - let _e198 = AtLeast_u0028_vf2_u003b_vf2_u003b_f1_u003b((¶m_17), (¶m_18), (¶m_19)); - a_1 = _e198; - let _e199 = b; - param_20 = (_e199 * 1.5f); - let _e201 = spacing_y; - param_21 = _e201; - let _e202 = least_1; - param_22 = _e202; - let _e203 = AtLeast_u0028_vf2_u003b_vf2_u003b_f1_u003b((¶m_20), (¶m_21), (¶m_22)); - b = _e203; - let _e205 = a_1[0u]; - let _e207 = b[1u]; - let _e210 = a_1[1u]; - let _e212 = b[0u]; - let _e216 = least_1; - let _e217 = least_1; - area = max(abs(((_e205 * _e207) - (_e210 * _e212))), (_e216 * _e217)); - let _e220 = here; - let _e223 = corner_1[0u]; - let _e224 = a_1; - let _e228 = corner_1[1u]; - let _e229 = b; - let _e231 = ((_e220.xy + (_e224 * _e223)) + (_e229 * _e228)); - unnamed.gl_Position = vec4(_e231.x, _e231.y, 0.5f, 1f); - let _e238 = caustic_info.grid[2u]; - let _e241 = caustic_info.grid[3u]; - share = (_e238 * _e241); - let _e243 = energy_1; - let _e244 = share; - let _e246 = area; - let _e249 = ((_e243 * _e244) / vec3((1.0471976f * _e246))); - v_color = vec4(_e249.x, _e249.y, _e249.z, 0f); + let _e211 = caustic_info.grid[1u]; + least_1 = _e211; + let _e212 = a_1; + param_17 = (_e212 * 1.5f); + let _e214 = spacing_x; + param_18 = _e214; + let _e215 = least_1; + param_19 = _e215; + let _e216 = AtLeast_u0028_vf2_u003b_vf2_u003b_f1_u003b((¶m_17), (¶m_18), (¶m_19)); + a_1 = _e216; + let _e217 = b; + param_20 = (_e217 * 1.5f); + let _e219 = spacing_y; + param_21 = _e219; + let _e220 = least_1; + param_22 = _e220; + let _e221 = AtLeast_u0028_vf2_u003b_vf2_u003b_f1_u003b((¶m_20), (¶m_21), (¶m_22)); + b = _e221; + let _e223 = a_1[0u]; + let _e225 = b[1u]; + let _e228 = a_1[1u]; + let _e230 = b[0u]; + let _e234 = least_1; + let _e235 = least_1; + area = max(abs(((_e223 * _e225) - (_e228 * _e230))), (_e234 * _e235)); + let _e238 = here; + let _e241 = corner_1[0u]; + let _e242 = a_1; + let _e246 = corner_1[1u]; + let _e247 = b; + let _e249 = ((_e238.xy + (_e242 * _e241)) + (_e247 * _e246)); + unnamed.gl_Position = vec4(_e249.x, _e249.y, 0.5f, 1f); + let _e256 = caustic_info.grid[2u]; + let _e259 = caustic_info.grid[3u]; + share = (_e256 * _e259); + let _e261 = energy_1; + let _e262 = share; + let _e264 = area; + let _e267 = ((_e261 * _e262) / vec3((1.0471976f * _e264))); + v_color = vec4(_e267.x, _e267.y, _e267.z, 0f); return; } From 9a59c73466975ecefa482ae30a8c203e3b985df2 Mon Sep 17 00:00:00 2001 From: Dmitrii Zolotov Date: Sat, 3 Oct 2026 13:13:45 +0300 Subject: [PATCH 07/34] fix: Stop drops where they land on the bench or a glass A drop that came down on the bench kept its speed along it and slid off for good, ending up under another glass where it looked as if it were inside. A viscous liquid has no velocity along a wall at rest, and a drop smaller than the capillary length is held whole by its pinned edge, so particles touching a wall keep only what leaves it, and such drops stand still. A drop that touches a vessel's glass from inside runs down into its liquid, as a stream's parcels already do. --- .../flutter3d_physics/lib/src/fluid/jet.dart | 5 + .../lib/src/fluid/liquid_body.dart | 12 ++ .../lib/src/fluid/particle_fluid.dart | 113 +++++++++++++++++- .../test/fluid/particle_fluid_test.dart | 22 ++++ 4 files changed, 148 insertions(+), 4 deletions(-) diff --git a/packages/flutter3d_physics/lib/src/fluid/jet.dart b/packages/flutter3d_physics/lib/src/fluid/jet.dart index 7b3df9a54..1b824af8d 100644 --- a/packages/flutter3d_physics/lib/src/fluid/jet.dart +++ b/packages/flutter3d_physics/lib/src/fluid/jet.dart @@ -24,6 +24,11 @@ abstract interface class JetReceiver { /// receiver's surface: whether its underside has. bool catches(Vector3 point, double radius); + /// Whether a drop of [radius] at [point] (world) touches this receiver's + /// glass from inside it: water wets glass, and a drop held there by the + /// wall runs down into the liquid as a film. + bool wets(Vector3 point, double radius); + /// Takes [volume] cubic metres of [medium] carrying [concentrations], /// arriving at [point] moving at [velocity]. void receive( diff --git a/packages/flutter3d_physics/lib/src/fluid/liquid_body.dart b/packages/flutter3d_physics/lib/src/fluid/liquid_body.dart index 3efd0f048..5319716e8 100644 --- a/packages/flutter3d_physics/lib/src/fluid/liquid_body.dart +++ b/packages/flutter3d_physics/lib/src/fluid/liquid_body.dart @@ -178,6 +178,18 @@ final class LiquidBody implements JetReceiver { return _up.dot(q) - radius <= surface + 0.25 * radius; } + @override + bool wets(Vector3 point, double radius) { + final shape = this.shape; + if (shape is! RevolvedVessel) return false; + final q = _near(point, radius); + if (q == null || !shape.contains(q)) return false; + final at = shape.wallDistance(q); + // Held a radius off the glass, and so touching it within a radius and + // a quarter. + return at != null && at.distance > -1.25 * radius; + } + /// Liquid arriving from a stream: added, first heaped where it lands — /// its own volume over the patch it strikes — and striking the surface /// with the momentum it comes down with, from where both spread as waves. diff --git a/packages/flutter3d_physics/lib/src/fluid/particle_fluid.dart b/packages/flutter3d_physics/lib/src/fluid/particle_fluid.dart index 79bd15d9b..36e50621d 100644 --- a/packages/flutter3d_physics/lib/src/fluid/particle_fluid.dart +++ b/packages/flutter3d_physics/lib/src/fluid/particle_fluid.dart @@ -242,12 +242,13 @@ final class ParticleFluid { for (var s = 0; s < count; s++) { _substep(sub, g, walls); } - // Into a vessel's liquid: handed over, whole. + // Into a vessel's liquid, or onto its glass inside, which runs down + // into it: handed over, whole. final radius = 0.5 * spacing; for (var i = _x.length - 1; i >= 0; i--) { final at = _x[i].toVector3(); for (final r in receivers) { - if (!r.catches(at, radius)) continue; + if (!r.catches(at, radius) && !r.wets(at, radius)) continue; r.receive(particleVolume, at, _v[i].toVector3(), medium, _c[i]); _received += particleVolume; _x.removeAt(i); @@ -270,6 +271,14 @@ final class ParticleFluid { for (var i = 0; i < n; i++) { _collide(_x[i], obstacles); } + // **What touches a wall is pinned to it.** A drop's edge on glass or + // the bench holds where it is until something pushes harder than the + // contact angle's hysteresis lets it, which nothing a millimetre drop + // weighs does: a particle touching a wall at the start of the substep + // moves only off it, or not at all. Left free along it, three + // particles that came down on the bench rolled away over each other as + // a wheel does, faster with every turn. + final pinned = [for (var i = 0; i < n; i++) _contact(_x[i], obstacles)]; final rho0 = medium.density; final m = _mass; final norm = 1.0 / _latticeSum; @@ -305,7 +314,11 @@ final class ParticleFluid { } // Predict, then hold the density to the rest density. final p = [ - for (var i = 0; i < n; i++) _advance(_x[i], _v[i], dt, obstacles), + for (var i = 0; i < n; i++) + if (pinned[i] case final wall?) + _pin(_advance(_x[i], _v[i], dt, obstacles), _x[i], wall) + else + _advance(_x[i], _v[i], dt, obstacles), ]; final lambda = List.filled(n, 0.0); final grid2 = _Grid(h, p); @@ -353,6 +366,7 @@ final class ParticleFluid { for (var i = 0; i < n; i++) { p[i].add(delta[i]); _collide(p[i], obstacles); + if (pinned[i] case final wall?) _pin(p[i], _x[i], wall); } } // Velocities from the move, then XSPH's viscosity. @@ -370,12 +384,103 @@ final class ParticleFluid { smoothed[i].addScaled(_v[j] - _v[i], share * w); } } + // A viscous liquid's velocity at a wall at rest is nil along it, and + // nothing goes on into it: what touches one keeps only the part of its + // velocity that leaves. Left its speed along the wall, a drop that fell + // on the bench slid off at five centimetres a second and never + // stopped, and ended up under another glass's foot, looking as if it + // were inside. + final onWall = List.filled(n, false); for (var i = 0; i < n; i++) { - _v[i] = smoothed[i]; + final wall = _contact(p[i], obstacles); + onWall[i] = wall != null; + _v[i] = wall == null + ? smoothed[i] + : wall * math.max(_dot(smoothed[i], wall), 0.0); _x[i] = p[i]; } + _holdSmallDrops(near, onWall, gravity); } + /// **A drop smaller than the capillary length, pinned, stands still.** + /// Under ℓc = √(σ/ρg), 2.7 mm for water, surface tension holds a drop's + /// shape against its weight, and what of it touches a wall is pinned: + /// it stays as a whole where it is. Pinning only the particles that touch + /// let the others turn over them, and a three-particle drop on the bench + /// rolled away; a puddle wider than ℓc still spreads. + void _holdSmallDrops(List> near, List onWall, _V gravity) { + final n = _x.length; + final g = gravity.length; + if (n == 0 || g <= 0.0 || medium.surfaceTension <= 0.0) return; + final capillary = math.sqrt(medium.surfaceTension / (medium.density * g)); + final parent = List.generate(n, (i) => i); + int root(int i) { + var r = i; + while (parent[r] != r) { + r = parent[r]; + } + return parent[i] = r; + } + + // One drop: particles nearer each other than a spacing and a half. + final touching = 2.25 * spacing * spacing; + for (var i = 0; i < n; i++) { + for (final j in near[i]) { + if (_x[i].distance2(_x[j]) < touching) parent[root(i)] = root(j); + } + } + final low = {}; + final high = {}; + final held = {}; + for (var i = 0; i < n; i++) { + final r = root(i); + final p = _x[i]; + final lo = low[r] ??= p.copy(); + final hi = high[r] ??= p.copy(); + lo + ..x = math.min(lo.x, p.x) + ..y = math.min(lo.y, p.y) + ..z = math.min(lo.z, p.z); + hi + ..x = math.max(hi.x, p.x) + ..y = math.max(hi.y, p.y) + ..z = math.max(hi.z, p.z); + if (onWall[i]) held.add(r); + } + for (var i = 0; i < n; i++) { + final r = root(i); + if (!held.contains(r)) continue; + // Across it, a particle's width beyond the centres. + if ((high[r]! - low[r]!).length + spacing < capillary) { + _v[i] = _V(0, 0, 0); + } + } + } + + /// The normal of the wall [p] touches, if it touches one. Put out a + /// radius from a wall, a particle touches it at a radius and a little. + _V? _contact(_V p, List obstacles) { + final reach = 0.55 * spacing; + for (final o in obstacles) { + final hit = o.touch(p.toVector3(), reach); + if (hit != null) return _V(hit.normal.x, hit.normal.y, hit.normal.z); + } + return null; + } + + /// [p] moved back to where [from] was along the wall of normal [n]: off + /// it is the only way it goes. + _V _pin(_V p, _V from, _V n) { + final off = math.max(_dot(p - from, n), 0.0); + p + ..x = from.x + n.x * off + ..y = from.y + n.y * off + ..z = from.z + n.z * off; + return p; + } + + static double _dot(_V a, _V b) => a.x * b.x + a.y * b.y + a.z * b.z; + /// Where [x] moving at [v] is after [dt]: moved in pieces of two fifths /// of a spacing, put out of the walls after each. A wall holds what comes /// within a radius of it or half its thickness into it, a band wider than diff --git a/packages/flutter3d_physics/test/fluid/particle_fluid_test.dart b/packages/flutter3d_physics/test/fluid/particle_fluid_test.dart index 36354817b..2a5c2c538 100644 --- a/packages/flutter3d_physics/test/fluid/particle_fluid_test.dart +++ b/packages/flutter3d_physics/test/fluid/particle_fluid_test.dart @@ -24,6 +24,28 @@ void main() { expect(1 - y, closeTo(0.5 * 1.62 * 0.25, 0.5 * 1.62 * 0.25 * 0.01)); }); + test('a drop thrown along the bench stops where it lands', () { + // Mutation: drop the no-slip at walls, and a drop that came down + // moving five centimetres a second sideways is half a metre off after + // ten seconds, sliding still. + final fluid = ParticleFluid(medium: FluidMedium.water, spacing: 0.001); + final bench = [PlaneObstacle(normal: Vector3(0, 1, 0), offset: 0)]; + fluid.inject( + 3 * fluid.particleVolume, + Vector3(0, 0.01, 0), + Vector3(0.05, 0, 0), + ); + for (var i = 0; i < 2400; i++) { + fluid.step(1 / 240, gravity: Vector3(0, -9.81, 0), obstacles: bench); + } + for (final p in fluid.positions) { + // A fall of a centimetre takes 45 ms, and five centimetres a second + // carries it two and a quarter millimetres in that. + expect(p.x, lessThan(0.005)); + expect(p.y, lessThan(0.002)); + } + }); + test('what is less than a particle waits in the bank, and is counted', () { final fluid = ParticleFluid(medium: FluidMedium.water, spacing: 0.002); fluid.inject(2.5 * fluid.particleVolume, Vector3.zero(), Vector3.zero()); From bb74138a408df00a0903838201969af461166986 Mon Sep 17 00:00:00 2001 From: Dmitrii Zolotov Date: Sat, 3 Oct 2026 13:45:34 +0300 Subject: [PATCH 08/34] feat: Let spilt liquid lie on a floor as a puddle A floor given to the fluid world now takes what reaches it as puddles: one body each, with its volume and what is dissolved in it, instead of thousands of particles. A spread puddle is 2lc*sin(theta/2) deep and a small one is a cap at the contact angle; it spreads as a viscous gravity current and runs together with the ones it meets. capMesh draws them. A tube emptied on the bench used to leave 7500 particles that took a quarter of an hour to step. --- ARCHITECTURE.md | 2 +- README.md | 2 +- .../lib/src/geometry/liquid_shapes.dart | 54 +++++ .../test/geometry/liquid_shapes_test.dart | 14 ++ .../lib/flutter3d_physics.dart | 1 + .../lib/src/fluid/fluid_world.dart | 20 +- .../lib/src/fluid/puddle.dart | 226 ++++++++++++++++++ .../test/fluid/puddle_test.dart | 89 +++++++ site/content/core/liquids.md | 8 +- site/content/quickstart.md | 2 +- site/content/reference/testing.md | 10 +- 11 files changed, 415 insertions(+), 13 deletions(-) create mode 100644 packages/flutter3d_physics/lib/src/fluid/puddle.dart create mode 100644 packages/flutter3d_physics/test/fluid/puddle_test.dart diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index fde253cc2..0571c38d9 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -2691,7 +2691,7 @@ storage. |---|---| | Style | `dart format` | | Analysis | `flutter analyze` clean across the workspace, no warnings | -| Unit tests | **11341 tests** across 43 packages and 10 applications | +| Unit tests | **11347 tests** across 43 packages and 10 applications | | Structure rules | 35, `dart run tool/structure.dart`, the first CI step | | CI | GitHub Actions over `tool/ci.sh`, on `ubuntu-latest`, with no graphics card | diff --git a/README.md b/README.md index 8cdb4b03d..1221cb3f4 100644 --- a/README.md +++ b/README.md @@ -158,7 +158,7 @@ Or one package at a time: (cd packages/flutter3d_physics && dart test) # plain Dart, no Flutter needed ``` -There are 11341 tests across forty-three packages and nine applications. The +There are 11347 tests across forty-three packages and nine applications. The only ones that need a GPU are the Impeller half of the golden set. The other half is rendered by the software backend, which is what makes 90 scenes checkable in a headless run. diff --git a/packages/flutter3d_core/lib/src/geometry/liquid_shapes.dart b/packages/flutter3d_core/lib/src/geometry/liquid_shapes.dart index 7b32097a0..6c5aaeb49 100644 --- a/packages/flutter3d_core/lib/src/geometry/liquid_shapes.dart +++ b/packages/flutter3d_core/lib/src/geometry/liquid_shapes.dart @@ -521,6 +521,60 @@ MeshData particleMesh( return builder.build(); } +/// Liquid lying on a level surface: for each, a spherical cap of base +/// [radii] and height [heights] standing on the surface at [centres], up +/// being +y. What a drop or a puddle on the bench is drawn as: its top as +/// a cap, its underside, on the surface, left out. +MeshData capMesh( + List centres, + List radii, + List heights, { + int segments = 32, + int rings = 6, +}) { + final builder = MeshBuilder(VertexLayout.standard); + for (var i = 0; i < centres.length; i++) { + final c = centres[i]; + final r = radii[i]; + final h = heights[i]; + if (r <= 0.0 || h <= 0.0) continue; + // The sphere the cap is cut from: its radius and how far its middle is + // under the surface. + final sphere = (r * r + h * h) / (2.0 * h); + final below = sphere - h; + final rim = math.asin((r / sphere).clamp(0.0, 1.0)); + final base = builder.vertexCount; + for (var k = 0; k <= rings; k++) { + // From the top (k = 0) to the rim. + final a = rim * k / rings; + for (var j = 0; j < segments; j++) { + final b = 2.0 * math.pi * j / segments; + final n = Vector3( + math.sin(a) * math.cos(b), + math.cos(a), + math.sin(a) * math.sin(b), + ); + builder.addVertex( + position: c + Vector3(0, -below, 0) + n * sphere, + normal: n, + ); + } + } + for (var k = 0; k < rings; k++) { + for (var j = 0; j < segments; j++) { + final a0 = base + k * segments + j; + final a1 = base + k * segments + (j + 1) % segments; + final b0 = a0 + segments; + final b1 = a1 + segments; + builder + ..addTriangle(a0, a1, b1) + ..addTriangle(a0, b1, b0); + } + } + } + return builder.build(); +} + /// A unit icosahedron split once: each face into four, the new points /// pushed out onto the sphere. final (List, List<(int, int, int)>) _sphere = () { diff --git a/packages/flutter3d_core/test/geometry/liquid_shapes_test.dart b/packages/flutter3d_core/test/geometry/liquid_shapes_test.dart index 3882fdcf7..8acbe462c 100644 --- a/packages/flutter3d_core/test/geometry/liquid_shapes_test.dart +++ b/packages/flutter3d_core/test/geometry/liquid_shapes_test.dart @@ -124,6 +124,20 @@ void main() { expect(_enclosed(dots), greaterThan(0)); }); + test('a puddle is drawn as a cap of its radius and height', () { + final cap = capMesh([Vector3(0.1, 0, 0)], [0.02], [0.001]); + final ys = [for (var i = 0; i < cap.vertexCount; i++) cap.positionAt(i).y]; + // Its top as high as asked, its rim on the bench. + expect(ys.reduce(math.max), closeTo(0.001, 1e-7)); + expect(ys.reduce(math.min), closeTo(0.0, 1e-7)); + var widest = 0.0; + for (var i = 0; i < cap.vertexCount; i++) { + final p = cap.positionAt(i); + widest = math.max(widest, math.sqrt(math.pow(p.x - 0.1, 2) + p.z * p.z)); + } + expect(widest, closeTo(0.02, 1e-7)); + }); + test('a tipped tube keeps its liquid inside its glass, meniscus and all', () { // Mutation: lift the surface along up with the meniscus of the radius, // as for a tube standing, and the long sides of a tipped tube's liquid diff --git a/packages/flutter3d_physics/lib/flutter3d_physics.dart b/packages/flutter3d_physics/lib/flutter3d_physics.dart index 4235be381..f4a06e3fc 100644 --- a/packages/flutter3d_physics/lib/flutter3d_physics.dart +++ b/packages/flutter3d_physics/lib/flutter3d_physics.dart @@ -50,6 +50,7 @@ export 'src/fluid/liquid_layer.dart'; export 'src/fluid/outflow.dart'; export 'src/fluid/particle_fluid.dart'; export 'src/fluid/pipe.dart'; +export 'src/fluid/puddle.dart'; export 'src/fluid/vessel_shape.dart'; export 'src/inertia.dart'; export 'src/portable_math.dart'; diff --git a/packages/flutter3d_physics/lib/src/fluid/fluid_world.dart b/packages/flutter3d_physics/lib/src/fluid/fluid_world.dart index d97a561e2..8011b25db 100644 --- a/packages/flutter3d_physics/lib/src/fluid/fluid_world.dart +++ b/packages/flutter3d_physics/lib/src/fluid/fluid_world.dart @@ -6,6 +6,7 @@ import 'jet.dart'; import 'liquid_body.dart'; import 'particle_fluid.dart'; import 'pipe.dart'; +import 'puddle.dart'; /// Liquids in a world: the vessels, the pipes between them, and the streams /// running from one to another, stepped together at a fixed step. @@ -56,12 +57,20 @@ final class FluidWorld { /// medium: what streams broke into, what splashed, what lies spilt. final Map particles = {}; + /// The puddles on each flat [floor]: what lands there lies there, as a + /// drop or a puddle, not as particles. + late final List spills = [ + for (final o in floor ?? const []) + if (o is PlaneObstacle) PuddleSurface(o), + ]; + /// Every cubic metre the world holds: in vessels, in the air, as - /// particles. + /// particles, in puddles. double get volume => bodies.fold(0.0, (s, b) => s + b.volume) + jets.values.fold(0.0, (s, j) => s + j.inFlight) + - particles.values.fold(0.0, (s, p) => s + p.volume); + particles.values.fold(0.0, (s, p) => s + p.volume) + + spills.fold(0.0, (s, p) => s + p.volume); double _carried = 0.0; int _ran = 0; @@ -131,7 +140,7 @@ final class FluidWorld { dt, gravity: gravity, obstacles: walls, - receivers: bodies, + receivers: [...bodies, ...spills], )) { particles .putIfAbsent( @@ -161,8 +170,11 @@ final class FluidWorld { dt, gravity: gravity, obstacles: everywhere, - receivers: bodies, + receivers: [...bodies, ...spills], ); } + for (final spill in spills) { + spill.step(dt, gravity: gravity); + } } } diff --git a/packages/flutter3d_physics/lib/src/fluid/puddle.dart b/packages/flutter3d_physics/lib/src/fluid/puddle.dart new file mode 100644 index 000000000..7a6f576af --- /dev/null +++ b/packages/flutter3d_physics/lib/src/fluid/puddle.dart @@ -0,0 +1,226 @@ +import 'dart:math' as math; + +import 'package:vector_math/vector_math.dart'; + +import '../portable_math.dart'; +import 'fluid_medium.dart'; +import 'jet.dart'; +import 'particle_fluid.dart'; + +/// Liquid lying on a flat surface: a drop or a puddle, as one body. +/// +/// **Its shape is surface tension's and gravity's.** Spread out, a puddle +/// is as deep as the capillary length and the contact angle make it, +/// h = 2ℓc·sin(θ/2) with ℓc = √(σ/ρg) (de Gennes, Brochard-Wyart and Quéré, +/// *Capillarity and Wetting Phenomena*, §2.1.2): wider and it would thin +/// past what surface tension holds at its edge, narrower and gravity +/// flattens it further. Smaller than that, it is a drop, a spherical cap +/// meeting the surface at θ. Whichever is wider is what it is: the cap +/// while it is small, the puddle once its weight counts. +/// +/// **It gets there as a viscous gravity current.** A volume V let go on a +/// plane spreads as R(t) = 0.894·(ρgV³/3μ)^⅛·t^⅛ (Huppert, 1982); it stops +/// where it reaches its shape. Water reaches it in milliseconds; honey +/// takes its time. +final class Puddle { + Puddle({required this.medium, required this.centre, required this.normal}); + + final FluidMedium medium; + + /// Its middle, on the surface. + final Vector3 centre; + + /// The surface's normal, away from it. + final Vector3 normal; + + double _volume = 0.0; + final Map _amounts = {}; + + /// Seconds since it was first wetted, as a gravity current counts them. + double age = 0.0; + + /// Cubic metres in it. + double get volume => _volume; + + /// What is dissolved in it, as concentrations. + Map get concentrations => _volume <= 0.0 + ? const {} + : {for (final e in _amounts.entries) e.key: e.value / _volume}; + + /// Adds [volume] carrying [concentrations], landing at [point]: the + /// middle moves to the centre of what it holds. + void add(double volume, Vector3 point, Map concentrations) { + if (volume <= 0.0) return; + final onPlane = point - normal * normal.dot(point - centre); + final total = _volume + volume; + centre.setFrom(centre * (_volume / total) + onPlane * (volume / total)); + _volume = total; + concentrations.forEach((k, c) { + _amounts[k] = (_amounts[k] ?? 0.0) + c * volume; + }); + } + + /// [other] taken in, whole. + void merge(Puddle other) { + final total = _volume + other._volume; + if (total <= 0.0) return; + centre.setFrom( + centre * (_volume / total) + other.centre * (other._volume / total), + ); + _volume = total; + other._amounts.forEach((k, a) => _amounts[k] = (_amounts[k] ?? 0.0) + a); + age = math.max(age, other.age); + } + + /// How far it reaches across the surface, metres. + double radius(double g) { + if (_volume <= 0.0) return 0.0; + final rest = restRadius(g); + if (medium.viscosity <= 0.0 || age <= 0.0) return rest; + final current = + 0.894 * + Portable.pow( + medium.density * + g * + _volume * + _volume * + _volume / + (3.0 * medium.viscosity), + 0.125, + ) * + Portable.pow(age, 0.125); + return math.min(rest, current.toDouble()); + } + + /// Its radius once it has stopped spreading: the cap's or the puddle's, + /// whichever is wider. + double restRadius(double g) { + if (_volume <= 0.0) return 0.0; + final theta = medium.contactAngle.clamp(0.05, math.pi - 0.05); + final s = Portable.sin(theta); + final c = Portable.cos(theta); + // A spherical cap of base R meeting the plane at θ holds + // πR³(2 − 3cosθ + cos³θ)/(3sin³θ). + final cap = math + .pow( + 3.0 * _volume * s * s * s / (math.pi * (2.0 - 3.0 * c + c * c * c)), + 1.0 / 3.0, + ) + .toDouble(); + final capillary = math.sqrt( + medium.surfaceTension / (medium.density * math.max(g, 1e-9)), + ); + final deep = 2.0 * capillary * Portable.sin(theta / 2.0); + final flat = math.sqrt(_volume / (math.pi * deep)); + return math.max(cap, flat); + } + + /// The height of a spherical cap of base [radius] holding what it holds: + /// what it is drawn as. A flat puddle drawn so is a lens twice as deep + /// in the middle as it is on average, and holds the same. + double capHeight(double radius) { + if (_volume <= 0.0 || radius <= 0.0) return 0.0; + // V = πH(3R² + H²)/6, solved for H by Newton from the flat guess. + var h = 2.0 * _volume / (math.pi * radius * radius); + for (var i = 0; i < 8; i++) { + final f = math.pi * h * (3.0 * radius * radius + h * h) / 6.0 - _volume; + final df = math.pi * (radius * radius + h * h) / 2.0; + h -= f / df; + } + return math.max(h, 0.0); + } +} + +/// A flat surface's puddles: everything that reaches the surface becomes +/// one, or joins the one it lands in. +/// +/// A receiver like a vessel: a stream that runs onto the bench lands in +/// it, and so does a drop. Liquid on the bench is then a few bodies, each +/// its volume and what is dissolved in it, and not thousands of particles +/// to step and draw. +final class PuddleSurface implements JetReceiver { + PuddleSurface(this.surface); + + final PlaneObstacle surface; + + final List puddles = []; + + /// The gravity the puddles last spread under. + double _g = 9.81; + + /// Cubic metres lying here. + double get volume => puddles.fold(0.0, (s, p) => s + p.volume); + + @override + bool catches(Vector3 point, double radius) => + // What rests on the surface rests a radius off it; a quarter of one + // more, as a vessel's floor allows. + surface.normal.dot(point) - surface.offset <= 1.25 * radius; + + @override + bool wets(Vector3 point, double radius) => false; + + @override + void receive( + double volume, + Vector3 point, + Vector3 velocity, + FluidMedium medium, + Map concentrations, + ) { + final onPlane = + point - surface.normal * (surface.normal.dot(point) - surface.offset); + // Into a puddle it lands on, or the start of a new one. + Puddle? into; + for (final p in puddles) { + if (p.medium.name != medium.name) continue; + if ((p.centre - onPlane).length <= p.radius(_g)) { + into = p; + break; + } + } + into ??= () { + final made = Puddle( + medium: medium, + centre: onPlane.clone(), + normal: surface.normal.clone(), + ); + puddles.add(made); + return made; + }(); + into.add(volume, onPlane, concentrations); + _join(); + } + + /// Spreads every puddle on by [dt] under [gravity], and runs together + /// those that meet. + void step(double dt, {required Vector3 gravity}) { + _g = math.max(-gravity.dot(surface.normal), 0.0); + if (puddles.isEmpty) return; + for (final p in puddles) { + p.age += dt; + } + _join(); + } + + void _join() { + var joined = true; + while (joined) { + joined = false; + outer: + for (var i = 0; i < puddles.length; i++) { + for (var j = i + 1; j < puddles.length; j++) { + final a = puddles[i]; + final b = puddles[j]; + if (a.medium.name != b.medium.name) continue; + if ((a.centre - b.centre).length < a.radius(_g) + b.radius(_g)) { + a.merge(b); + puddles.removeAt(j); + joined = true; + break outer; + } + } + } + } + } +} diff --git a/packages/flutter3d_physics/test/fluid/puddle_test.dart b/packages/flutter3d_physics/test/fluid/puddle_test.dart new file mode 100644 index 000000000..d08fa4f8b --- /dev/null +++ b/packages/flutter3d_physics/test/fluid/puddle_test.dart @@ -0,0 +1,89 @@ +import 'dart:math' as math; + +import 'package:flutter3d_physics/flutter3d_physics.dart'; +import 'package:test/test.dart'; +import 'package:vector_math/vector_math.dart'; + +PuddleSurface _bench() => + PuddleSurface(PlaneObstacle(normal: Vector3(0, 1, 0), offset: 0)); + +void main() { + const g = 9.81; + const water = FluidMedium.water; + + test('a spread puddle is as deep as the capillary length and θ make it', () { + // 2ℓc·sin(θ/2): a little under a millimetre for water on glass at 20°. + // Mutation: leave out the sine, and ten millilitres lie as a disc + // five centimetres across, five millimetres deep. + final bench = _bench() + ..receive(1e-5, Vector3(0, 0.001, 0), Vector3.zero(), water, const {}); + final puddle = bench.puddles.single; + final r = puddle.restRadius(g); + final deep = puddle.volume / (math.pi * r * r); + final capillary = math.sqrt(water.surfaceTension / (water.density * g)); + expect( + deep, + closeTo(2 * capillary * math.sin(water.contactAngle / 2), 1e-9), + ); + }); + + test('a small drop is a cap meeting the bench at its contact angle', () { + final bench = _bench() + ..receive(1e-9, Vector3(0, 0.0005, 0), Vector3.zero(), water, const {}); + final drop = bench.puddles.single; + final r = drop.restRadius(g); + final h = drop.capHeight(r); + // The cap's angle at its edge, from its base and height. + expect(2 * math.atan(h / r), closeTo(water.contactAngle, 1e-6)); + expect(math.pi * h * (3 * r * r + h * h) / 6, closeTo(drop.volume, 1e-18)); + }); + + test('drops landing apart stay apart, and run together when they meet', () { + final bench = _bench() + ..receive(1e-8, Vector3(0, 0, 0), Vector3.zero(), water, const {'a': 1}) + ..receive(1e-8, Vector3(0.1, 0, 0), Vector3.zero(), water, const {}); + expect(bench.puddles, hasLength(2)); + // Poured between them until they reach each other. + for (var i = 0; i < 40; i++) { + bench.receive(5e-7, Vector3(0.05, 0, 0), Vector3.zero(), water, const {}); + } + expect(bench.puddles, hasLength(1)); + expect(bench.volume, closeTo(2e-8 + 40 * 5e-7, 1e-15)); + // What was dissolved in one is in the whole, by its share. + expect( + bench.puddles.single.concentrations['a'], + closeTo(1e-8 / bench.volume, 1e-12), + ); + }); + + test('a glass emptied on the bench lies there, every drop of it', () { + // Mutation: leave the bench out of the receivers, and what ran out is + // thousands of particles, which took a quarter of an hour to step. + final world = FluidWorld( + gravity: Vector3(0, -g, 0), + floor: [PlaneObstacle(normal: Vector3(0, 1, 0), offset: 0)], + ); + final glass = LiquidBody( + shape: RevolvedVessel([ + Vector2(0, 0.0005), + Vector2(0.008, 0.0005), + Vector2(0.008, 0.1), + ]), + medium: water, + volume: math.pi * 0.008 * 0.008 * 0.05, + modes: 4, + ); + world.bodies.add(glass); + final total = world.volume; + final turn = Matrix3.rotationZ(2.5); + for (var i = 0; i < 240 * 4; i++) { + glass.place(turn, Vector3(0, 0.12, 0)); + world.advance(world.step); + } + expect(glass.volume, lessThan(total * 0.02)); + expect(world.volume, closeTo(total, total * 1e-9)); + final lying = world.spills.single.volume; + expect(lying, greaterThan(total * 0.9)); + expect(world.particles.values.fold(0, (s, p) => s + p.count), lessThan(50)); + }); +} diff --git a/site/content/core/liquids.md b/site/content/core/liquids.md index ef8a8ab48..15b66764f 100644 --- a/site/content/core/liquids.md +++ b/site/content/core/liquids.md @@ -6,7 +6,7 @@ description: Incompressible liquid in vessels of any shape, in SI units under th The liquid part of `flutter3d_physics` lives in `lib/src/fluid/` and knows nothing about any particular game. It is in metres, kilograms and seconds, and gravity is whatever the world says, so the same tube on the Moon pours six times slower and its meniscus stands six times taller. -It is a hybrid, because no single method is right everywhere. Liquid standing in a vessel is a volume with a free surface on it, and the surface moves by its modes. Liquid leaving a vessel is a stream of parcels. A stream that breaks becomes drops, and drops are particles. Each part hands volume to the next one exactly, and the world can tell you where every cubic millimetre is. +It is a hybrid, because no single method is right everywhere. Liquid standing in a vessel is a volume with a free surface on it, and the surface moves by its modes. Liquid leaving a vessel is a stream of parcels. A stream that breaks becomes drops, and drops are particles. What reaches the bench lies there as a puddle. Each part hands volume to the next one exactly, and the world can tell you where every cubic millimetre is. ```dart final world = FluidWorld( @@ -64,6 +64,12 @@ The world keeps the accounts: every jet's `emitted` is `inFlight + landed + drop Drops are `ParticleFluid`, position-based fluids on the CPU, in double precision. Particles are held to the rest density only where they are compressed, so a surface does not pull itself inward. Cohesion follows Akinci, with the coefficient worked out so that pulling a slab of particles apart costs 2σ per square metre, which is what surface tension is. A particle is stepped in substeps short against the capillary time √(ρs³/σ), a third of a millisecond for millimetre water, and short enough that nothing passes through glass between one look and the next. Drops that land in a vessel become its liquid, with what was dissolved in them. +A drop is stopped by the wall it touches: a viscous liquid has no velocity along a wall at rest, and a drop smaller than the capillary length √(σ/ρg), 2.7 mm for water, is held whole by its pinned edge. A drop that touches a vessel's glass from inside runs down into its liquid. + +## Puddles + +What reaches a floor given to the world becomes a `Puddle` on its `PuddleSurface`, one body with a volume and what is dissolved in it, not particles. A spread puddle is 2ℓc·sin(θ/2) deep, under a millimetre for water on glass; a smaller one is a spherical cap meeting the surface at the contact angle. It spreads there as a viscous gravity current, R ∝ (ρgV³/μ)^⅛·t^⅛ (Huppert), which water finishes in milliseconds. Puddles that meet run together. Draw them with `capMesh(...)`. + ## Capillarity `TubeMeniscus` solves the Young–Laplace equation for a tube's radius and the liquid's contact angle by shooting, so a narrow tube's meniscus is the right curve, not a fillet. `jurinHeight` is the rise in a thin tube, and the tests check one against the other. A `LiquidBody` lifts its drawn surface by the meniscus and adds the capillary pressure where it matters, in pipes. diff --git a/site/content/quickstart.md b/site/content/quickstart.md index ba0875a52..3cfe20ed7 100644 --- a/site/content/quickstart.md +++ b/site/content/quickstart.md @@ -91,7 +91,7 @@ tool/ci.sh # shaders, analyze, every test (cd packages/flutter3d_physics && dart test) # plain Dart, no Flutter needed ``` -There are 11341 tests across 43 packages and twelve applications, and only about thirty need a GPU: the Impeller half of the golden set. The other half renders through the software backend, so ninety scenes stay checkable in a headless run. +There are 11347 tests across 43 packages and twelve applications, and only about thirty need a GPU: the Impeller half of the golden set. The other half renders through the software backend, so ninety scenes stay checkable in a headless run. ## Your own application diff --git a/site/content/reference/testing.md b/site/content/reference/testing.md index 32f1f61d4..5fac10f54 100644 --- a/site/content/reference/testing.md +++ b/site/content/reference/testing.md @@ -1,10 +1,10 @@ --- -description: Four independent golden sets, mutation-checking every new test, determinism and snapshots, and why only about thirty of 11341 tests need a GPU. +description: Four independent golden sets, mutation-checking every new test, determinism and snapshots, and why only about thirty of 11347 tests need a GPU. --- # Testing -11341 tests across 43 packages and nine applications, counted the same way the `the document says how many tests there are` rule does: a scan of every `test(`/`testWidgets(` call. The rule holds `ARCHITECTURE.md` §13, the README and this page to the answer. The README went on saying 1242 across thirteen packages for as long as nothing compared it with anything. About thirty need a GPU; the [architecture](/core/architecture/) is what keeps the number that low. +11347 tests across 43 packages and nine applications, counted the same way the `the document says how many tests there are` rule does: a scan of every `test(`/`testWidgets(` call. The rule holds `ARCHITECTURE.md` §13, the README and this page to the answer. The README went on saying 1242 across thirteen packages for as long as nothing compared it with anything. About thirty need a GPU; the [architecture](/core/architecture/) is what keeps the number that low. | Package | Tests | | Package | Tests | |---|---|---|---|---| @@ -12,7 +12,7 @@ description: Four independent golden sets, mutation-checking every new test, det | | | | `flutter3d_mesh` | 599 | | | | | `apps/flutter3d_modeler` | 1750 | | `flutter3d_sim` | 691 | | `pad_input` | 67 | -| `flutter3d_lab` | 15 | | `flutter3d_core` | 772 | +| `flutter3d_lab` | 15 | | `flutter3d_core` | 773 | | `flutter3d_lti` | 26 | | `apps/flutter3d_lab_pendulum` | 7 | | | | | `apps/flutter3d_lab_incident` | 13 | | `flutter3d_game_shooter` | 340 | | `flutter3d_audio_core` | 55 | @@ -23,7 +23,7 @@ description: Four independent golden sets, mutation-checking every new test, det | `flutter3d_cpu` | 380 | | `apps/flutter3d_demo_strategy` | 50 | | `apps/flutter3d_editor` | 234 | | `apps/flutter3d_demo_arcade` | 20 | | `apps/flutter3d_demo_racing` | 162 | | `pointer_lock` | 28 | -| `flutter3d_physics` | 269 | | `flutter3d_webgpu` | 193 | +| `flutter3d_physics` | 274 | | `flutter3d_webgpu` | 193 | | `flutter3d_game_strategy` | 133 | | `flutter3d_editor_mcp` | 36 | | `apps/flutter3d_demo_river` | 54 | | `flutter3d_testing` | 45 | | `flutter3d_editor_core` | 141 | | `flutter3d_editor_widgets` | 91 | @@ -40,7 +40,7 @@ description: Four independent golden sets, mutation-checking every new test, det | `flame_flutter3d` | 140 | | `apps/flutter3d_showcase` | 88 | | `flame_multiplayer` | 9 | | `flame_multiplayer_dashwire` | 3 | -The rows sum to 11314 rather than 11341: the remaining 26 live in `packages/*/example/test`, which the count includes and this table does not, among them the two seeds a new project starts from, `packages/flutter3d_app/example` and `packages/flutter3d_game/example`. +The rows sum to 11320 rather than 11347: the remaining 26 live in `packages/*/example/test`, which the count includes and this table does not, among them the two seeds a new project starts from, `packages/flutter3d_app/example` and `packages/flutter3d_game/example`. `flutter3d_samples` is not in the table and has no `test/` at all: it is test data with two path constants over it, and other packages' decoder tests are what exercise it. `flutter3d_conformance` is missing for a different reason: it is invoked as a script harness rather than through `flutter test`, so it does not surface in a grep of `test(` calls either. See below for what that cost once. From d59b36ea6e77243a0649fca9339237ba837e2525 Mon Sep 17 00:00:00 2001 From: Dmitrii Zolotov Date: Sat, 3 Oct 2026 13:45:35 +0300 Subject: [PATCH 09/34] feat: Lean a tube up to a half turn, lifted alike either way A tube can now be tipped past the lean it holds its liquid at, mouth down at the most, and what runs out lies on the bench as a puddle drawn in its own colour. The hand lifts it out of the row by the height either side needs, so the tube at the end of the row no longer lies down on the bench when it leans off it. --- packages/education/chemlab/lib/src/bench.dart | 65 ++++++++++++++++--- .../education/chemlab/test/bench_test.dart | 37 +++++++++++ 2 files changed, 92 insertions(+), 10 deletions(-) diff --git a/packages/education/chemlab/lib/src/bench.dart b/packages/education/chemlab/lib/src/bench.dart index c7ac96e79..f72b3fe23 100644 --- a/packages/education/chemlab/lib/src/bench.dart +++ b/packages/education/chemlab/lib/src/bench.dart @@ -550,12 +550,11 @@ final class Bench { if (!photons && vessel.tilt == 0.0) _repaint(vessel); } - /// The furthest [vessel] may lean either way: a little short of where what - /// it holds reaches the lip and would run out on the bench. - double maxLean(Vessel vessel) => math.max( - 0.05, - math.min(1.45, _tiltHolding(vessel, vessel.liquid.volume) - 0.08), - ); + /// The furthest [vessel] may lean either way: a half turn, mouth down. + /// Past the lean it holds its liquid at, what it holds runs out over the + /// lip, onto the bench or into whatever is under it, as it would from a + /// glass in a hand; stopped short of that, nothing could be spilled. + double maxLean(Vessel vessel) => math.pi; /// How far [vessel] must be lifted to lean as it does without passing /// through the glass standing round it. @@ -1017,6 +1016,10 @@ final class Bench { final Map _drops = {}; final Map _dropColours = {}; + /// The puddles on the bench drawn, one node each, reused in order. + final List _puddles = []; + final List _puddleColours = []; + /// Moves everything on by [seconds], and says whether anything still /// moves, so the caller knows to ask for another frame. bool step(double seconds) { @@ -1029,10 +1032,18 @@ final class Bench { // the rise is eased as the turn is. Taken for the lean it had, the // height jumped by centimetres the frame the tipping glass first came // over a neighbour, and the jolt threw nearly all it held out. - final need = math.max( - _clearance(vessel), - _clearance(vessel, vessel.leanTo), - ); + // + // **Either way, the same height.** A hand takes a glass up out of the + // row whichever way it then tips it: lifted only as far as the side it + // leaned to needed, a tube at the end of the row leaning off it was + // not lifted at all and lay down on the bench, and leaning one way + // and the other looked like two different hands. + final need = [ + vessel.tilt, + -vessel.tilt, + vessel.leanTo, + -vessel.leanTo, + ].map((at) => _clearance(vessel, at)).reduce(math.max); final rose = _ease2(vessel, need, seconds); vessel.lift = need > 0.0 ? 1.0 : 0.0; if (_turn(vessel, seconds) | rose) { @@ -1207,6 +1218,40 @@ final class Bench { ); node.visible = fluid.count > 0; }); + // What lies on the bench: a cap of each drop or puddle's own radius and + // height, the colour of what is in it. + final g = world.gravity.length; + final lying = [for (final s in world.spills) ...s.puddles]; + for (var i = 0; i < math.max(lying.length, _puddles.length); i++) { + if (i >= lying.length) { + _puddles[i].visible = false; + continue; + } + final puddle = lying[i]; + final colour = _colourOf(puddle.concentrations); + if (i >= _puddles.length) { + final made = MeshNode( + _upload(capMesh(const [], const [], const [])), + liquid(_rgb(colour), depth: 0.001), + name: 'puddle', + )..castsShadow = false; + scene.add(made); + _puddles.add(made); + _puddleColours.add(colour); + } + final node = _puddles[i]; + if (_puddleColours[i] != colour) { + _puddleColours[i] = colour; + node.material = liquid(_rgb(colour), depth: 0.001); + } + final r = puddle.radius(g); + if (r < puddle.restRadius(g)) any = true; + _swap( + node, + capMesh([puddle.centre], [r], [puddle.capHeight(r)]), + ); + node.visible = true; + } return any; } diff --git a/packages/education/chemlab/test/bench_test.dart b/packages/education/chemlab/test/bench_test.dart index 4d99b1028..883a7f70f 100644 --- a/packages/education/chemlab/test/bench_test.dart +++ b/packages/education/chemlab/test/bench_test.dart @@ -336,4 +336,41 @@ void main() { expect(tube.liquid.volume, closeTo(start, start * 1e-9)); expect(bench.world.jets, isEmpty); }); + + test('a tube leaned either way is lifted out of the row alike', () { + // Mutation: lift it only as far as the side it leans to needs, and the + // tube at the end of the row, leaning off it, lies down on the bench. + final kit = cpuTestDevice(width: 8, height: 8); + double height(double lean) { + final bench = Bench(kit.device); + final tube = bench.vessels.first; + bench.lean(tube, lean, across: Vector3(0, 0, -1)); + for (var i = 0; i < 120; i++) { + bench.step(1 / 60); + } + return tube.body.localMatrix.getTranslation().y; + } + + expect(height(-1.0), closeTo(height(1.0), 1e-6)); + expect(height(-1.0), greaterThan(0.05)); + }); + + test('a tube turned mouth down empties into a puddle on the bench', () { + final kit = cpuTestDevice(width: 8, height: 8); + final bench = Bench(kit.device); + final tube = bench.vessels[2]; + final everything = bench.world.volume; + final held = tube.liquid.volume; + bench.lean(tube, bench.maxLean(tube), across: Vector3(0, 0, -1)); + for (var i = 0; i < 600; i++) { + bench.step(1 / 60); + } + expect(tube.liquid.volume, lessThan(held * 0.02)); + // Every drop of it is somewhere: in the glasses, in the air, or lying + // on the bench, nearly all of it as one puddle. + expect(bench.world.volume, closeTo(everything, everything * 1e-9)); + final lying = bench.world.spills.single; + expect(lying.volume, greaterThan(held * 0.9)); + expect(lying.puddles.first.volume, greaterThan(held * 0.8)); + }); } From 16eba77e48d85f7100086493e480612de2e224ea Mon Sep 17 00:00:00 2001 From: Dmitrii Zolotov Date: Sat, 3 Oct 2026 14:05:37 +0300 Subject: [PATCH 10/34] feat: Draw the tail of a stopped pour back into a bulb Once the lip stops feeding a stream, its upper end eats the thread ahead of it at Keller's sqrt(sigma/(rho*r)) and gathers it into a bulb. The tail of a pour used to fall whole, as wide at its end as along it, like a bent rod of glass. --- .../flutter3d_physics/lib/src/fluid/jet.dart | 88 ++++++++++++++++++- .../test/fluid/jet_test.dart | 30 +++++++ 2 files changed, 114 insertions(+), 4 deletions(-) diff --git a/packages/flutter3d_physics/lib/src/fluid/jet.dart b/packages/flutter3d_physics/lib/src/fluid/jet.dart index 1b824af8d..333049012 100644 --- a/packages/flutter3d_physics/lib/src/fluid/jet.dart +++ b/packages/flutter3d_physics/lib/src/fluid/jet.dart @@ -197,6 +197,7 @@ final class Jet { return; } _emitted += volume; + _fresh = true; final speed = math.max(velocity.length, 1e-6); final w = math.max(width, 1e-6); _parcels.add( @@ -223,6 +224,7 @@ final class Jet { List receivers = const [], }) { final drops = []; + _retract(dt); var walls = obstacles; if (_parcels.isNotEmpty) { // Every parcel, and as far as any moves this step, in one ball. @@ -386,6 +388,83 @@ final class Jet { return drops; } + /// Whether anything left the lip since the last step: the newest parcel + /// is held to the lip while it does, and its end is free once it stops. + bool _fresh = false; + + /// **A free end draws back into the stream** (Keller, 1983): surface + /// tension pulls a thread's end in at √(σ/ρr), gathering what it passes + /// into a bulb. The upper end of a stretch held neither by the lip nor by + /// a wall gives as much of its liquid to its neighbour as that speed + /// covers of its length in the step, and goes once it has given it all. + /// Without it the tail of a pour, cut off as the glass came back up, fell + /// whole, as wide at its end as anywhere, like a bent rod of glass. + void _retract(double dt) { + final fresh = _fresh; + _fresh = false; + bool newerFree(int i) => + (i == _parcels.length - 1 && !fresh) || _parcels[i].endsRun; + bool olderFree(int i) => i == 0 || _parcels[i - 1].endsRun; + var i = _parcels.length - 1; + while (i >= 1) { + final bulb = _parcels[i]; + if (bulb.onWall || !newerFree(i)) { + i--; + continue; + } + // The bulb eats the thread ahead of it at the speed the thread's own + // radius gives, a parcel at a time, for as long as the step lasts. + var left = dt; + while (left > 0.0 && !olderFree(i)) { + final thread = _parcels[i - 1]; + // The thread's far end is an end too: what is left is a drop. + if (thread.onWall || olderFree(i - 1)) break; + final radius = math.sqrt(thread.section / math.pi); + if (radius <= 0.0) break; + final speed = math.sqrt( + thread.medium.surfaceTension / (thread.medium.density * radius), + ); + final length = math.max(thread.velocity.length, 1e-6) * thread.dt; + final whole = length / speed; + final eaten = whole <= left ? 1.0 : left / whole; + _gather(bulb, thread, thread.volume * eaten); + left -= whole * eaten; + if (eaten < 1.0) { + thread.dt *= 1.0 - eaten; + break; + } + // All of it: the bulb is where it was. + bulb.position.setFrom(thread.position); + bulb.previous.setFrom(thread.previous); + _parcels.removeAt(i - 1); + i--; + } + i--; + } + } + + /// [amount] of [from]'s liquid into [into], with its momentum and what is + /// dissolved in it. + static void _gather(_Parcel into, _Parcel from, double amount) { + if (amount <= 0.0) return; + final total = into.volume + amount; + into.velocity + ..scale(into.volume / total) + ..addScaled(from.velocity, amount / total); + into.concentrations = { + for (final k in { + ...into.concentrations.keys, + ...from.concentrations.keys, + }) + k: + ((into.concentrations[k] ?? 0.0) * into.volume + + (from.concentrations[k] ?? 0.0) * amount) / + total, + }; + into.volume = total; + from.volume -= amount; + } + /// The stream as runs of samples, lip first: each run is a stretch with /// nothing missing from it, ready to be swept into a tube. List> get runs { @@ -436,15 +515,16 @@ final class _Parcel { /// What it is: which liquid, and what is dissolved in it. final FluidMedium medium; - final Map concentrations; + Map concentrations; final Vector3 position; final Vector3 velocity; - final double volume; + double volume; /// The step it left in: its length along the stream is its speed times - /// this, so its section is its volume over that. - final double dt; + /// this, so its section is its volume over that. Shortened as a bulb + /// eats into it, which leaves its section as it was. + double dt; /// How wide and thick a sheet it left as, and which way across. final double width; diff --git a/packages/flutter3d_physics/test/fluid/jet_test.dart b/packages/flutter3d_physics/test/fluid/jet_test.dart index 54f676083..a698ad72f 100644 --- a/packages/flutter3d_physics/test/fluid/jet_test.dart +++ b/packages/flutter3d_physics/test/fluid/jet_test.dart @@ -84,6 +84,36 @@ void main() { expect((oldest - expected).length, lessThan(1e-3)); }); + test('the tail of a stream cut off draws back into a bulb', () { + // Mutation: leave its end where it was, and the tail falls as wide at + // its end as along it, like a rod, for as long as it falls. + final jet = Jet(medium: FluidMedium.water, breakupGrowth: 1e9); + const dt = 1 / 1000; + final g = Vector3(0, -9.81, 0); + for (var k = 0; k < 100; k++) { + jet.emit( + flow: 4e-6, + dt: dt, + point: Vector3(0, 1, 0), + velocity: Vector3(0.3, 0, 0), + width: 0.004, + across: Vector3(0, 0, 1), + ); + jet.step(dt, gravity: g); + } + final before = jet.runs.single.length; + for (var k = 0; k < 30; k++) { + jet.step(dt, gravity: g); + } + final run = jet.runs.single; + // Its end, the lip's side, has gathered what it drew back past. + double section(JetSample s) => math.pi * s.wide * s.thick; + final middle = run[run.length ~/ 2]; + expect(section(run.first), greaterThan(1.5 * section(middle))); + expect(run.length, lessThan(before)); + expect(jet.inFlight, closeTo(jet.emitted, jet.emitted * 1e-12)); + }); + test('every drop of it is somewhere', () { final body = LiquidBody( shape: RevolvedVessel([ From cbef4f02f70fe9934aa26b26b20041c917d4d1c6 Mon Sep 17 00:00:00 2001 From: Dmitrii Zolotov Date: Sat, 3 Oct 2026 14:05:37 +0300 Subject: [PATCH 11/34] fix: Let go what is short of a particle once no more liquid comes The bank kept the end of every run of drops, up to a particle's worth, counted and nowhere. It now leaves as a last, smaller particle where the liquid last came in, and lands as the amount it is. --- .../lib/src/fluid/particle_fluid.dart | 43 +++- .../test/fluid/particle_fluid_test.dart | 37 ++++ .../flutter3d_physics/tool/filter_cost.dart | 96 --------- .../flutter3d_physics/tool/ground_cost.dart | 185 ------------------ 4 files changed, 77 insertions(+), 284 deletions(-) delete mode 100644 packages/flutter3d_physics/tool/filter_cost.dart delete mode 100644 packages/flutter3d_physics/tool/ground_cost.dart diff --git a/packages/flutter3d_physics/lib/src/fluid/particle_fluid.dart b/packages/flutter3d_physics/lib/src/fluid/particle_fluid.dart index 36e50621d..7836ea8fc 100644 --- a/packages/flutter3d_physics/lib/src/fluid/particle_fluid.dart +++ b/packages/flutter3d_physics/lib/src/fluid/particle_fluid.dart @@ -119,6 +119,16 @@ final class ParticleFluid { final List<_V> _x = []; final List<_V> _v = []; + /// Each particle's liquid, cubic metres: [particleVolume], but for the + /// last of a run of drops, which is what was left in the bank. + final List _vol = []; + + /// Where and how fast the last liquid came in, and whether any came in + /// since the last step: the bank is let go there once none does. + final _V _lastAt = _V(0, 0, 0); + final _V _lastVelocity = _V(0, 0, 0); + bool _injected = false; + /// What is dissolved in each particle, as concentrations; and in the /// bank, as amounts. final List> _c = []; @@ -135,7 +145,10 @@ final class ParticleFluid { int get count => _x.length; /// Cubic metres here: every particle and the bank. - double get volume => _x.length * particleVolume + _bank; + double get volume => _vol.fold(0.0, (s, v) => s + v) + _bank; + + /// The particles' liquid, cubic metres each. + List get volumes => List.unmodifiable(_vol); /// What is dissolved in the particles, as concentrations over all of /// them: for drawing them the colour of what they are. @@ -162,6 +175,15 @@ final class ParticleFluid { Map concentrations = const {}, }) { _bank += amount; + _injected = true; + _lastAt + ..x = position.x + ..y = position.y + ..z = position.z; + _lastVelocity + ..x = velocity.x + ..y = velocity.y + ..z = velocity.z; concentrations.forEach((key, c) { _bankAmounts[key] = (_bankAmounts[key] ?? 0.0) + c * amount; }); @@ -192,6 +214,7 @@ final class ParticleFluid { ), ); _v.add(_V(velocity.x, velocity.y, velocity.z)); + _vol.add(particleVolume); _c.add(carried); placed++; } @@ -207,6 +230,19 @@ final class ParticleFluid { List obstacles = const [], List receivers = const [], }) { + // **What is less than a particle is let go too**, once no more liquid + // comes to make it one: as a particle of its own amount, where the last + // came in. Kept in the bank, the end of every run of drops, up to a + // particle's worth of it, was counted and was nowhere. + if (!_injected && _bank > 0.0) { + _x.add(_lastAt.copy()); + _v.add(_lastVelocity.copy()); + _vol.add(_bank); + _c.add({for (final e in _bankAmounts.entries) e.key: e.value / _bank}); + _bank = 0.0; + _bankAmounts.clear(); + } + _injected = false; if (_x.isEmpty) return; // A quarter of the capillary time a substep at most, and never fewer // than asked. How far a particle goes in one is not held here: it is @@ -249,10 +285,11 @@ final class ParticleFluid { final at = _x[i].toVector3(); for (final r in receivers) { if (!r.catches(at, radius) && !r.wets(at, radius)) continue; - r.receive(particleVolume, at, _v[i].toVector3(), medium, _c[i]); - _received += particleVolume; + r.receive(_vol[i], at, _v[i].toVector3(), medium, _c[i]); + _received += _vol[i]; _x.removeAt(i); _v.removeAt(i); + _vol.removeAt(i); _c.removeAt(i); break; } diff --git a/packages/flutter3d_physics/test/fluid/particle_fluid_test.dart b/packages/flutter3d_physics/test/fluid/particle_fluid_test.dart index 2a5c2c538..50e91a835 100644 --- a/packages/flutter3d_physics/test/fluid/particle_fluid_test.dart +++ b/packages/flutter3d_physics/test/fluid/particle_fluid_test.dart @@ -55,6 +55,43 @@ void main() { expect(fluid.count, 3); }); + test('what is left in the bank is let go once no more comes', () { + // Mutation: keep it banked, and a third of a particle stays counted + // and nowhere, however long the world runs. + final fluid = ParticleFluid(medium: FluidMedium.water, spacing: 0.002); + final at = Vector3(0, 0.1, 0); + fluid + ..inject(1.3 * fluid.particleVolume, at, Vector3.zero()) + // The step it came in on, more may still come. + ..step(1 / 240, gravity: Vector3(0, -9.81, 0)); + expect(fluid.count, 1); + fluid.step(1 / 240, gravity: Vector3(0, -9.81, 0)); + expect(fluid.count, 2); + expect(fluid.volumes.last, closeTo(0.3 * fluid.particleVolume, 1e-18)); + expect(fluid.volume, closeTo(1.3 * fluid.particleVolume, 1e-18)); + // And it lands as what it is. + final glass = LiquidBody( + shape: RevolvedVessel([ + Vector2(0, 0), + Vector2(0.02, 0), + Vector2(0.02, 0.2), + ]), + medium: FluidMedium.water, + volume: 1e-6, + modes: 2, + )..place(Matrix3.identity(), Vector3(0, -0.15, 0)); + for (var i = 0; i < 240; i++) { + fluid.step( + 1 / 240, + gravity: Vector3(0, -9.81, 0), + obstacles: [InsideWalls(glass)], + receivers: [glass], + ); + } + expect(fluid.count, 0); + expect(glass.volume, closeTo(1e-6 + 1.3 * fluid.particleVolume, 1e-18)); + }); + test( 'a block of liquid settles at its rest density and stays in its box', () { diff --git a/packages/flutter3d_physics/tool/filter_cost.dart b/packages/flutter3d_physics/tool/filter_cost.dart deleted file mode 100644 index a70014c6b..000000000 --- a/packages/flutter3d_physics/tool/filter_cost.dart +++ /dev/null @@ -1,96 +0,0 @@ -/// How much the contact filter costs in the loop it was put into. -/// -/// dart run tool/filter_cost.dart -/// -/// The predicate goes into `sweep`, which the character controller calls four -/// times a step and a game steps sixty times a second. An indirect call there -/// is the kind of thing that is cheap until it is not, and the plan that asked -/// for it asked for this number too. -/// -/// ## What the context object cost -/// -/// The filter took `(Collider, Vector3)` until it was widened to one -/// [SweptContact], so that a field could be added to it later without breaking -/// every filter anybody had written. That is not free, and this is what it came -/// to on one machine, three runs each, microseconds per step with a trivial -/// filter installed: -/// -/// two positional arguments 1.932 -/// a `late`-field context 1.997 (+3.4%) -/// the context as it is now 1.953 (+1.1%) -/// -/// Half the cost was `late`. A `late` field carries an is-it-initialised check -/// on every read, and a filter reads both fields on every contact; the object -/// now holds a nullable behind a non-null getter and a vector it copies into, -/// and neither is checked. The remaining one percent is the object itself, and -/// it buys the ability to tell a filter something new without a major version. -library; - -import 'package:flutter3d_physics/flutter3d_physics.dart'; -import 'package:vector_math/vector_math.dart'; - -const int _steps = 200000; - -CollisionWorld _level() { - final world = CollisionWorld() - ..add( - Collider( - shape: CollisionBox(Vector3(60.0, 0.5, 60.0)), - position: Vector3(0.0, -0.5, 0.0), - ), - ); - // Something to sweep against: a field of pillars, which is what a level of - // brushes looks like to the broadphase. - for (var x = -40; x <= 40; x += 4) { - for (var z = -40; z <= 40; z += 4) { - world.add( - Collider( - shape: CollisionBox(Vector3(0.6, 2.0, 0.6)), - position: Vector3(x.toDouble(), 2.0, z.toDouble()), - ), - ); - } - } - return world; -} - -double _run({ContactFilter? filter}) { - final world = _level(); - final body = CharacterController( - world: world, - position: Vector3(1.0, 0.9, 1.0), - )..solidFilter = filter; - final wish = Vector3(1.0, 0.0, 0.35); - final clock = Stopwatch()..start(); - for (var i = 0; i < _steps; i++) { - if (i % 900 == 0) body.requestJump(); - body.step(1.0 / 60.0, wishDirection: wish); - if (body.position.x > 40.0 || body.position.z > 40.0) { - body.teleport(Vector3(-40.0, 0.9, -40.0)); - } - } - clock.stop(); - return clock.elapsedMicroseconds / _steps; -} - -void main() { - // Warm, then measure: the first thousand steps are the JIT's. - _run(); - final without = _run(); - _run(filter: (SweptContact c) => true); - final trivial = _run(filter: (SweptContact c) => true); - final oneWay = _run( - filter: (SweptContact c) => - c.other.layer & (1 << 6) == 0 || c.normal.y > 0.5, - ); - - // ignore: avoid_print - print( - 'microseconds per step over $_steps steps\n' - ' no filter ${without.toStringAsFixed(3)}\n' - ' trivial filter ${trivial.toStringAsFixed(3)} ' - '(+${((trivial / without - 1) * 100).toStringAsFixed(1)}%)\n' - ' one-way filter ${oneWay.toStringAsFixed(3)} ' - '(+${((oneWay / without - 1) * 100).toStringAsFixed(1)}%)', - ); -} diff --git a/packages/flutter3d_physics/tool/ground_cost.dart b/packages/flutter3d_physics/tool/ground_cost.dart deleted file mode 100644 index 9ae5bcf2b..000000000 --- a/packages/flutter3d_physics/tool/ground_cost.dart +++ /dev/null @@ -1,185 +0,0 @@ -/// What sweeping against sampled ground costs, beside sweeping against a box. -/// -/// dart run tool/ground_cost.dart -/// -/// **The number that decides whether ground can be a collision shape at all.** -/// A field of triangles is not one convex solid, so every sweep against it -/// walks several prisms instead of one set of planes, and "several" is decided -/// by how much ground the swept box covers. A body a third of a metre across -/// moving a tenth of a metre a step touches one or two cells, which is two or -/// four triangles — but that is an argument, and this is the measurement. -/// -/// ## What was measured, on macOS-arm64, Dart 3.12, 2026-09-08 -/// -/// One sweep of a player-sized box onto the surface, averaged over two hundred -/// thousand of them, microseconds each — two runs, and they agreed to within -/// three per cent: -/// -/// against one box 0.13 -/// against ground, 1 m cells 0.53 (4.1x) -/// against ground, 4 m cells 0.31 (2.4x) -/// against ground, 1 m cells, a capsule 0.48 -/// -/// And the step those add up to, sixty thousand of them: -/// -/// a walking body over one box 0.52 -/// a walking body over ground 3.5 (6.7x) -/// -/// **Four times a brush for one sweep, and nearly seven times for a step.** The -/// step is the worse ratio because a controller makes four or five sweeps and a -/// depenetration in one, and each of them now walks four to eight prisms where -/// it used to walk one box. Three and a half microseconds is still a -/// three-hundredth of a sixtieth of a second, so a hundred bodies walking on -/// ground is a fifth of a frame — comfortable for a strategy and worth knowing -/// before somebody puts a thousand there. -/// -/// **The cell size is the dial, and it is the level's.** Wider cells mean fewer -/// triangles under a body and a coarser surface; the difference between one -/// metre and four is nearly a factor of two, and it is what a level author is -/// choosing between without being told. -/// -/// The capsule being *cheaper* than the box it fits in reads backwards. It -/// walks exactly the same prisms — the broadphase asks the bounding box, and -/// the two have the same one — so the tenth is in the growth: a capsule's reach -/// along a normal is one multiply and an add, and a box's is three of each. -/// -/// ## What is not measured here -/// -/// A triangle mesh. There is not one: `CollisionHeightfield` is the whole of -/// what this package can be handed as ground, and a general mesh — which needs -/// a spatial index inside the shape rather than a grid it already is — has not -/// been written. The row it would occupy in the table above is missing rather -/// than estimated. -library; - -import 'dart:typed_data'; - -import 'package:flutter3d_physics/flutter3d_physics.dart'; -import 'package:vector_math/vector_math.dart'; - -const int _sweeps = 200000; - -CollisionWorld _ground(double cellSize) { - const n = 65; - final heights = Float32List(n * n); - for (var row = 0; row < n; row++) { - for (var column = 0; column < n; column++) { - heights[row * n + column] = - 0.06 * ((column * 5 + row * 3) % 7) + - 0.04 * ((column * 3 + row * 11) % 5); - } - } - final world = CollisionWorld() - ..add( - Collider( - shape: CollisionHeightfield( - columns: n, - rows: n, - cellSize: cellSize, - heights: heights, - ), - position: Vector3.zero(), - ), - ); - world.update(); - return world; -} - -/// One brush the same size as the whole field, so the broadphase has the same -/// amount of work to do and the difference is the narrow phase alone. -CollisionWorld _brush(double cellSize) { - final span = 64.0 * cellSize; - final world = CollisionWorld() - ..addBox(Vector3(0.0, -1.0, 0.0), Vector3(span, 2.0, span)); - world.update(); - return world; -} - -/// Sweeps [shape] downward from a walk across the field, and returns the -/// microseconds one sweep took. -double _cost(CollisionWorld world, CollisionShape shape, double span) { - final hit = SweepHit(); - final from = Vector3.zero(); - // Down onto the surface and a little along it: the shape of the probe the - // ground check makes, and long enough to actually land. A sweep that misses - // is a sweep that stops at the first rejection, which would measure the - // broadphase rather than the geometry. - final delta = Vector3(0.05, -1.6, 0.03); - var landed = 0; - final clock = Stopwatch()..start(); - for (var i = 0; i < _sweeps; i++) { - // A walk that covers the field rather than one spot, so the measurement is - // not of one cell staying in the cache. - final t = i / _sweeps; - from.setValues( - (t * span * 7.0) % span - span * 0.5, - 2.0, - (t * span * 3.0) % span - span * 0.5, - ); - if (world.sweep(shape, from, delta, hit)) landed++; - } - clock.stop(); - if (landed < _sweeps) { - // ignore: avoid_print - print(' (only $landed of $_sweeps sweeps landed on anything)'); - } - return clock.elapsedMicroseconds / _sweeps; -} - -/// A whole step of a walking body, which is what the sweep cost adds up to. -double _stepCost(CollisionWorld world) { - final walker = CharacterController( - world: world, - position: Vector3(0.0, 2.0, 0.0), - ); - final wish = Vector3(1.0, 0.0, 0.35); - const steps = 60000; - final clock = Stopwatch()..start(); - for (var i = 0; i < steps; i++) { - walker.step(1.0 / 60.0, wishDirection: wish); - if (walker.position.x > 24.0 || walker.position.z > 24.0) { - walker.teleport(Vector3(-24.0, 2.0, -24.0)); - } - } - clock.stop(); - return clock.elapsedMicroseconds / steps; -} - -void main() { - final body = CollisionBox(Vector3(0.35, 0.9, 0.35)); - final capsule = CollisionCapsule(radius: 0.35, halfHeight: 0.55); - - final fine = _ground(1.0); - final coarse = _ground(4.0); - final flat = _brush(1.0); - - // Warm, then measure: the first pass is the JIT's. - _cost(flat, body, 64.0); - _cost(fine, body, 64.0); - _cost(coarse, body, 256.0); - - final box = _cost(flat, body, 64.0); - final ground = _cost(fine, body, 64.0); - final wide = _cost(coarse, body, 256.0); - final rounded = _cost(fine, capsule, 64.0); - - _stepCost(_brush(1.0)); - _stepCost(_ground(1.0)); - final walkFlat = _stepCost(_brush(1.0)); - final walkGround = _stepCost(_ground(1.0)); - - // ignore: avoid_print - print( - 'microseconds a sweep, over $_sweeps of them\n' - ' against one box ${box.toStringAsFixed(3)}\n' - ' against ground, 1 m cells ${ground.toStringAsFixed(3)}' - ' (${(ground / box).toStringAsFixed(1)}x)\n' - ' against ground, 4 m cells ${wide.toStringAsFixed(3)}' - ' (${(wide / box).toStringAsFixed(1)}x)\n' - ' against ground, 1 m cells, a capsule ${rounded.toStringAsFixed(3)}\n' - '\nmicroseconds a step of a walking body\n' - ' over one box ${walkFlat.toStringAsFixed(3)}\n' - ' over ground, 1 m cells ${walkGround.toStringAsFixed(3)}' - ' (${(walkGround / walkFlat).toStringAsFixed(1)}x)', - ); -} From 451b4c1f1b62f1a596a6ac00d4152892db26c618 Mon Sep 17 00:00:00 2001 From: Dmitrii Zolotov Date: Sat, 3 Oct 2026 14:06:27 +0300 Subject: [PATCH 12/34] feat: Mirror streams, drops and puddles in the tabletop Only the liquids in the glasses stood in the mirror; a stream poured over the bench had no reflection. Each stream, drop and puddle node now has one sharing its mesh. Drops are sized and centred by the liquid each particle carries. --- ARCHITECTURE.md | 2 +- README.md | 2 +- packages/education/chemlab/lib/src/bench.dart | 66 +++++++++++++++++-- site/content/core/liquids.md | 3 +- site/content/quickstart.md | 2 +- site/content/reference/testing.md | 8 +-- 6 files changed, 68 insertions(+), 15 deletions(-) diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 0571c38d9..0411b568a 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -2691,7 +2691,7 @@ storage. |---|---| | Style | `dart format` | | Analysis | `flutter analyze` clean across the workspace, no warnings | -| Unit tests | **11347 tests** across 43 packages and 10 applications | +| Unit tests | **11349 tests** across 43 packages and 10 applications | | Structure rules | 35, `dart run tool/structure.dart`, the first CI step | | CI | GitHub Actions over `tool/ci.sh`, on `ubuntu-latest`, with no graphics card | diff --git a/README.md b/README.md index 1221cb3f4..f45309053 100644 --- a/README.md +++ b/README.md @@ -158,7 +158,7 @@ Or one package at a time: (cd packages/flutter3d_physics && dart test) # plain Dart, no Flutter needed ``` -There are 11347 tests across forty-three packages and nine applications. The +There are 11349 tests across forty-three packages and nine applications. The only ones that need a GPU are the Impeller half of the golden set. The other half is rendered by the software backend, which is what makes 90 scenes checkable in a headless run. diff --git a/packages/education/chemlab/lib/src/bench.dart b/packages/education/chemlab/lib/src/bench.dart index f72b3fe23..49ff15b71 100644 --- a/packages/education/chemlab/lib/src/bench.dart +++ b/packages/education/chemlab/lib/src/bench.dart @@ -1016,6 +1016,16 @@ final class Bench { final Map _drops = {}; final Map _dropColours = {}; + /// What is out of the glasses (streams, drops, puddles) hung upside down + /// under the tabletop, as each vessel's liquid is in its own mirror: one + /// reflection per node, sharing its mesh. + late final SceneNode _spiltMirror = () { + final made = SceneNode(name: 'spilt reflection')..setScale(1, -1, 1); + scene.add(made); + return made; + }(); + final Map _spiltReflections = {}; + /// The puddles on the bench drawn, one node each, reused in order. final List _puddles = []; final List _puddleColours = []; @@ -1199,7 +1209,7 @@ final class Bench { node.material = liquid(_rgb(colour), depth: 2.0 * fluid.spacing); } if (fluid.count > 0) any = true; - final drops = _clusters(fluid.positions, fluid.spacing); + final drops = _clusters(fluid.positions, fluid.volumes, fluid.spacing); _swap( node, particleMesh( @@ -1209,7 +1219,7 @@ final class Bench { for (final d in drops) math .pow( - 3.0 * d.count * fluid.particleVolume / (4.0 * math.pi), + 3.0 * d.volume / (4.0 * math.pi), 1.0 / 3.0, ) .toDouble(), @@ -1252,15 +1262,55 @@ final class Bench { ); node.visible = true; } + _reflectSpilt(); return any; } + /// Every stream, drop and puddle node given its reflection, or brought + /// up to date with it: the same mesh, shown when it is, the colour of + /// its liquid. Left out, a stream poured over the bench stood in the + /// mirror nowhere, under glasses whose liquids all did. + void _reflectSpilt() { + final nodes = [..._streams.values, ..._drops.values, ..._puddles]; + for (final gone in _spiltReflections.keys + .where((n) => !nodes.contains(n)) + .toList()) { + _spiltReflections.remove(gone)!.removeFromParent(); + } + for (final node in nodes) { + final c = node.material.baseColor; + final colour = Vector3(c.x, c.y, c.z); + final reflection = _spiltReflections.putIfAbsent(node, () { + final made = + MeshNode( + node.mesh, + _reflection(albedo: null, colour: colour), + name: '${node.name} reflection', + ) + ..castsShadow = false + ..lightChannels = LightChannels.none; + _spiltMirror.add(made); + return made; + }); + reflection + ..mesh = node.mesh + ..visible = node.visible; + final was = reflection.material.baseColor; + if ((was.x - colour.x * 0.7).abs() > 1e-6 || + (was.y - colour.y * 0.7).abs() > 1e-6 || + (was.z - colour.z * 0.7).abs() > 1e-6) { + reflection.material = _reflection(albedo: null, colour: colour); + } + } + } + /// [positions] gathered into drops: particles nearer each other than /// one and a half spacings are one drop, drawn as one sphere of all their /// liquid. A stream that breaks into drops two and a third of its width /// across was drawn as a scatter of millimetre dots, each a particle. - static List<({Vector3 centre, int count})> _clusters( + static List<({Vector3 centre, double volume})> _clusters( List positions, + List volumes, double spacing, ) { final n = positions.length; @@ -1281,17 +1331,19 @@ final class Bench { } } } - final sums = {}; + // Each drop's middle is the middle of its liquid, weighed by volume. + final sums = {}; for (var i = 0; i < n; i++) { final r = root(i); final s = sums[r]; + final v = volumes[i]; sums[r] = s == null - ? (sum: positions[i].clone(), count: 1) - : (sum: s.sum..add(positions[i]), count: s.count + 1); + ? (sum: positions[i] * v, volume: v) + : (sum: s.sum..addScaled(positions[i], v), volume: s.volume + v); } return [ for (final s in sums.values) - (centre: s.sum / s.count.toDouble(), count: s.count), + (centre: s.sum / s.volume, volume: s.volume), ]; } diff --git a/site/content/core/liquids.md b/site/content/core/liquids.md index 15b66764f..1928074a1 100644 --- a/site/content/core/liquids.md +++ b/site/content/core/liquids.md @@ -57,12 +57,13 @@ What leaves goes into a `Jet`, as parcels each holding one step's flow. A parcel - A thread grows Rayleigh–Plateau ripples at Weber's rate, the Grant–Middleman form of it, and breaks into drops when they have grown e¹² times. On a wall it does not break. - Where it meets glass the liquid wets, it runs down the wall as a rivulet. Too slow, and it runs down the outside of the glass it came from: the teapot effect, with cling speed √(σ(1 + cos θ)/(ρe)). - A fast drop that lands on a surface splashes when Mundo's K = Oh·Re^1.25 is over 57.7. +- The upper end of a stretch the lip no longer holds, the tail of a pour that has stopped, draws back into a bulb at Keller's √(σ/ρr), eating the thread ahead of it. The world keeps the accounts: every jet's `emitted` is `inFlight + landed + dropped`. ## Drops -Drops are `ParticleFluid`, position-based fluids on the CPU, in double precision. Particles are held to the rest density only where they are compressed, so a surface does not pull itself inward. Cohesion follows Akinci, with the coefficient worked out so that pulling a slab of particles apart costs 2σ per square metre, which is what surface tension is. A particle is stepped in substeps short against the capillary time √(ρs³/σ), a third of a millisecond for millimetre water, and short enough that nothing passes through glass between one look and the next. Drops that land in a vessel become its liquid, with what was dissolved in them. +Drops are `ParticleFluid`, position-based fluids on the CPU, in double precision. Particles are held to the rest density only where they are compressed, so a surface does not pull itself inward. Cohesion follows Akinci, with the coefficient worked out so that pulling a slab of particles apart costs 2σ per square metre, which is what surface tension is. A particle is stepped in substeps short against the capillary time √(ρs³/σ), a third of a millisecond for millimetre water, and short enough that nothing passes through glass between one look and the next. Drops that land in a vessel become its liquid, with what was dissolved in them. Liquid arrives in any amount and leaves as whole particles; what is short of one waits only while more is coming, and then goes as a last, smaller particle where the rest came in. A drop is stopped by the wall it touches: a viscous liquid has no velocity along a wall at rest, and a drop smaller than the capillary length √(σ/ρg), 2.7 mm for water, is held whole by its pinned edge. A drop that touches a vessel's glass from inside runs down into its liquid. diff --git a/site/content/quickstart.md b/site/content/quickstart.md index 3cfe20ed7..5217d9aa5 100644 --- a/site/content/quickstart.md +++ b/site/content/quickstart.md @@ -91,7 +91,7 @@ tool/ci.sh # shaders, analyze, every test (cd packages/flutter3d_physics && dart test) # plain Dart, no Flutter needed ``` -There are 11347 tests across 43 packages and twelve applications, and only about thirty need a GPU: the Impeller half of the golden set. The other half renders through the software backend, so ninety scenes stay checkable in a headless run. +There are 11349 tests across 43 packages and twelve applications, and only about thirty need a GPU: the Impeller half of the golden set. The other half renders through the software backend, so ninety scenes stay checkable in a headless run. ## Your own application diff --git a/site/content/reference/testing.md b/site/content/reference/testing.md index 5fac10f54..e11561873 100644 --- a/site/content/reference/testing.md +++ b/site/content/reference/testing.md @@ -1,10 +1,10 @@ --- -description: Four independent golden sets, mutation-checking every new test, determinism and snapshots, and why only about thirty of 11347 tests need a GPU. +description: Four independent golden sets, mutation-checking every new test, determinism and snapshots, and why only about thirty of 11349 tests need a GPU. --- # Testing -11347 tests across 43 packages and nine applications, counted the same way the `the document says how many tests there are` rule does: a scan of every `test(`/`testWidgets(` call. The rule holds `ARCHITECTURE.md` §13, the README and this page to the answer. The README went on saying 1242 across thirteen packages for as long as nothing compared it with anything. About thirty need a GPU; the [architecture](/core/architecture/) is what keeps the number that low. +11349 tests across 43 packages and nine applications, counted the same way the `the document says how many tests there are` rule does: a scan of every `test(`/`testWidgets(` call. The rule holds `ARCHITECTURE.md` §13, the README and this page to the answer. The README went on saying 1242 across thirteen packages for as long as nothing compared it with anything. About thirty need a GPU; the [architecture](/core/architecture/) is what keeps the number that low. | Package | Tests | | Package | Tests | |---|---|---|---|---| @@ -23,7 +23,7 @@ description: Four independent golden sets, mutation-checking every new test, det | `flutter3d_cpu` | 380 | | `apps/flutter3d_demo_strategy` | 50 | | `apps/flutter3d_editor` | 234 | | `apps/flutter3d_demo_arcade` | 20 | | `apps/flutter3d_demo_racing` | 162 | | `pointer_lock` | 28 | -| `flutter3d_physics` | 274 | | `flutter3d_webgpu` | 193 | +| `flutter3d_physics` | 276 | | `flutter3d_webgpu` | 193 | | `flutter3d_game_strategy` | 133 | | `flutter3d_editor_mcp` | 36 | | `apps/flutter3d_demo_river` | 54 | | `flutter3d_testing` | 45 | | `flutter3d_editor_core` | 141 | | `flutter3d_editor_widgets` | 91 | @@ -40,7 +40,7 @@ description: Four independent golden sets, mutation-checking every new test, det | `flame_flutter3d` | 140 | | `apps/flutter3d_showcase` | 88 | | `flame_multiplayer` | 9 | | `flame_multiplayer_dashwire` | 3 | -The rows sum to 11320 rather than 11347: the remaining 26 live in `packages/*/example/test`, which the count includes and this table does not, among them the two seeds a new project starts from, `packages/flutter3d_app/example` and `packages/flutter3d_game/example`. +The rows sum to 11322 rather than 11349: the remaining 26 live in `packages/*/example/test`, which the count includes and this table does not, among them the two seeds a new project starts from, `packages/flutter3d_app/example` and `packages/flutter3d_game/example`. `flutter3d_samples` is not in the table and has no `test/` at all: it is test data with two path constants over it, and other packages' decoder tests are what exercise it. `flutter3d_conformance` is missing for a different reason: it is invoked as a script harness rather than through `flutter test`, so it does not surface in a grep of `test(` calls either. See below for what that cost once. From 42dcdbdfdcc16cf8195ba19a979b389028eac570 Mon Sep 17 00:00:00 2001 From: Dmitrii Zolotov Date: Sat, 3 Oct 2026 14:34:12 +0300 Subject: [PATCH 13/34] fix: Filter what see-through casters let through as the opaque edge is The light a glass or a liquid lets through to its shadow was read from the shadow atlas in one tap, relying on a bilinear step the atlas does not get, so a translucent shadow's edge stepped a texel at a time. It is now averaged over the same 3x3 texels as the opaque edge, in the GLSL and in the CPU port. --- .../src/cpu_shaders_shadow_directional.dart | 15 +- .../flutter3d_shaders/shaders/lib/shadow.glsl | 22 +- .../flutter3d_webgl/lib/engine_shaders.dart | 132 +- .../flutter3d_webgpu/lib/engine_shaders.dart | 28072 ++++++++-------- 4 files changed, 14266 insertions(+), 13975 deletions(-) diff --git a/packages/flutter3d_cpu/lib/src/cpu_shaders_shadow_directional.dart b/packages/flutter3d_cpu/lib/src/cpu_shaders_shadow_directional.dart index 2a3563373..f16d2933b 100644 --- a/packages/flutter3d_cpu/lib/src/cpu_shaders_shadow_directional.dart +++ b/packages/flutter3d_cpu/lib/src/cpu_shaders_shadow_directional.dart @@ -182,9 +182,20 @@ double shadowFactor( // What the see-through casters let through, before the filter, whose soft // path leaves early — `ShadowSettings.translucentCasters`; `shadow.glsl` - // has the layout. + // has the layout. Averaged over the 3×3 texels the opaque edge is, as there. if (biases.w > 0.5) { - final stored = map.sample(u.clamp(loU, hiU), vv.clamp(loV, hiV)); + final stored = Vector4.zero(); + for (var y = -1; y <= 1; y++) { + for (var x = -1; x <= 1; x++) { + stored.add( + map.sample( + (u + x * texelU).clamp(loU, hiU), + (vv + y * texelV).clamp(loV, hiV), + ), + ); + } + } + stored.scale(1.0 / 9.0); final k = strength.clamp(0.0, 1.0); double through(double value) => 1.0 + (value.clamp(0.0, 4.0) - 1.0) * k; shadowTransmittance.setValues( diff --git a/packages/flutter3d_shaders/shaders/lib/shadow.glsl b/packages/flutter3d_shaders/shaders/lib/shadow.glsl index dedd5d86e..933fc48f9 100644 --- a/packages/flutter3d_shaders/shaders/lib/shadow.glsl +++ b/packages/flutter3d_shaders/shaders/lib/shadow.glsl @@ -220,13 +220,23 @@ float ShadowFactor(Surface s, LightSample light, int lightIndex) { // cut. A sign rather than another uniform, for the reason the softness // itself rides here. // **What the see-through casters let through** — before the filter, whose - // soft path leaves early where it finds no blocker. One bilinear tap: a - // translucent caster's shadow is light shaded rather than light stopped, - // and its edge is softened by the filtering the tap already gets. Green - // and blue hold what was taken from red and green, alpha what was left of - // blue — the layout `shadow_transmittance.frag` explains. + // soft path leaves early where it finds no blocker. Averaged over the same + // 3×3 texels the opaque edge is: the atlas is read without filtering, and + // one tap, which once relied on the sampler's bilinear step, drew a glass + // or a liquid's shadow edge as stairs a texel high. Green and blue hold + // what was taken from red and green, alpha what was left of blue — the + // layout `shadow_transmittance.frag` explains. if (frag_info.shadow_bias.w > 0.5) { - vec4 stored = textureLod(shadow_texture, clamp(uv, tileLo, tileHi), 0.0); + vec4 stored = vec4(0.0); + for (int y = -1; y <= 1; y++) { + for (int x = -1; x <= 1; x++) { + stored += textureLod( + shadow_texture, + clamp(uv + vec2(float(x), float(y)) * texel, tileLo, tileHi), + 0.0); + } + } + stored *= 1.0 / 9.0; // Up to four: light a caster gathered, not only light it stopped. vec3 through = clamp(vec3(1.0 - stored.g, 1.0 - stored.b, stored.a), 0.0, 4.0); light_transmittance = mix(vec3(1.0), through, clamp(strength, 0.0, 1.0)); diff --git a/packages/flutter3d_webgl/lib/engine_shaders.dart b/packages/flutter3d_webgl/lib/engine_shaders.dart index 2f3099535..3059a9354 100644 --- a/packages/flutter3d_webgl/lib/engine_shaders.dart +++ b/packages/flutter3d_webgl/lib/engine_shaders.dart @@ -9684,13 +9684,23 @@ float ShadowFactor(Surface s, LightSample light, int lightIndex) { // cut. A sign rather than another uniform, for the reason the softness // itself rides here. // **What the see-through casters let through** — before the filter, whose - // soft path leaves early where it finds no blocker. One bilinear tap: a - // translucent caster's shadow is light shaded rather than light stopped, - // and its edge is softened by the filtering the tap already gets. Green - // and blue hold what was taken from red and green, alpha what was left of - // blue — the layout `shadow_transmittance.frag` explains. + // soft path leaves early where it finds no blocker. Averaged over the same + // 3×3 texels the opaque edge is: the atlas is read without filtering, and + // one tap, which once relied on the sampler's bilinear step, drew a glass + // or a liquid's shadow edge as stairs a texel high. Green and blue hold + // what was taken from red and green, alpha what was left of blue — the + // layout `shadow_transmittance.frag` explains. if (frag_info.shadow_bias.w > 0.5) { - vec4 stored = textureLod(shadow_texture, clamp(uv, tileLo, tileHi), 0.0); + vec4 stored = vec4(0.0); + for (int y = -1; y <= 1; y++) { + for (int x = -1; x <= 1; x++) { + stored += textureLod( + shadow_texture, + clamp(uv + vec2(float(x), float(y)) * texel, tileLo, tileHi), + 0.0); + } + } + stored *= 1.0 / 9.0; // Up to four: light a caster gathered, not only light it stopped. vec3 through = clamp(vec3(1.0 - stored.g, 1.0 - stored.b, stored.a), 0.0, 4.0); light_transmittance = mix(vec3(1.0), through, clamp(strength, 0.0, 1.0)); @@ -12338,13 +12348,23 @@ float ShadowFactor(Surface s, LightSample light, int lightIndex) { // cut. A sign rather than another uniform, for the reason the softness // itself rides here. // **What the see-through casters let through** — before the filter, whose - // soft path leaves early where it finds no blocker. One bilinear tap: a - // translucent caster's shadow is light shaded rather than light stopped, - // and its edge is softened by the filtering the tap already gets. Green - // and blue hold what was taken from red and green, alpha what was left of - // blue — the layout `shadow_transmittance.frag` explains. + // soft path leaves early where it finds no blocker. Averaged over the same + // 3×3 texels the opaque edge is: the atlas is read without filtering, and + // one tap, which once relied on the sampler's bilinear step, drew a glass + // or a liquid's shadow edge as stairs a texel high. Green and blue hold + // what was taken from red and green, alpha what was left of blue — the + // layout `shadow_transmittance.frag` explains. if (frag_info.shadow_bias.w > 0.5) { - vec4 stored = textureLod(shadow_texture, clamp(uv, tileLo, tileHi), 0.0); + vec4 stored = vec4(0.0); + for (int y = -1; y <= 1; y++) { + for (int x = -1; x <= 1; x++) { + stored += textureLod( + shadow_texture, + clamp(uv + vec2(float(x), float(y)) * texel, tileLo, tileHi), + 0.0); + } + } + stored *= 1.0 / 9.0; // Up to four: light a caster gathered, not only light it stopped. vec3 through = clamp(vec3(1.0 - stored.g, 1.0 - stored.b, stored.a), 0.0, 4.0); light_transmittance = mix(vec3(1.0), through, clamp(strength, 0.0, 1.0)); @@ -15027,13 +15047,23 @@ float ShadowFactor(Surface s, LightSample light, int lightIndex) { // cut. A sign rather than another uniform, for the reason the softness // itself rides here. // **What the see-through casters let through** — before the filter, whose - // soft path leaves early where it finds no blocker. One bilinear tap: a - // translucent caster's shadow is light shaded rather than light stopped, - // and its edge is softened by the filtering the tap already gets. Green - // and blue hold what was taken from red and green, alpha what was left of - // blue — the layout `shadow_transmittance.frag` explains. + // soft path leaves early where it finds no blocker. Averaged over the same + // 3×3 texels the opaque edge is: the atlas is read without filtering, and + // one tap, which once relied on the sampler's bilinear step, drew a glass + // or a liquid's shadow edge as stairs a texel high. Green and blue hold + // what was taken from red and green, alpha what was left of blue — the + // layout `shadow_transmittance.frag` explains. if (frag_info.shadow_bias.w > 0.5) { - vec4 stored = textureLod(shadow_texture, clamp(uv, tileLo, tileHi), 0.0); + vec4 stored = vec4(0.0); + for (int y = -1; y <= 1; y++) { + for (int x = -1; x <= 1; x++) { + stored += textureLod( + shadow_texture, + clamp(uv + vec2(float(x), float(y)) * texel, tileLo, tileHi), + 0.0); + } + } + stored *= 1.0 / 9.0; // Up to four: light a caster gathered, not only light it stopped. vec3 through = clamp(vec3(1.0 - stored.g, 1.0 - stored.b, stored.a), 0.0, 4.0); light_transmittance = mix(vec3(1.0), through, clamp(strength, 0.0, 1.0)); @@ -18572,13 +18602,23 @@ float ShadowFactor(Surface s, LightSample light, int lightIndex) { // cut. A sign rather than another uniform, for the reason the softness // itself rides here. // **What the see-through casters let through** — before the filter, whose - // soft path leaves early where it finds no blocker. One bilinear tap: a - // translucent caster's shadow is light shaded rather than light stopped, - // and its edge is softened by the filtering the tap already gets. Green - // and blue hold what was taken from red and green, alpha what was left of - // blue — the layout `shadow_transmittance.frag` explains. + // soft path leaves early where it finds no blocker. Averaged over the same + // 3×3 texels the opaque edge is: the atlas is read without filtering, and + // one tap, which once relied on the sampler's bilinear step, drew a glass + // or a liquid's shadow edge as stairs a texel high. Green and blue hold + // what was taken from red and green, alpha what was left of blue — the + // layout `shadow_transmittance.frag` explains. if (frag_info.shadow_bias.w > 0.5) { - vec4 stored = textureLod(shadow_texture, clamp(uv, tileLo, tileHi), 0.0); + vec4 stored = vec4(0.0); + for (int y = -1; y <= 1; y++) { + for (int x = -1; x <= 1; x++) { + stored += textureLod( + shadow_texture, + clamp(uv + vec2(float(x), float(y)) * texel, tileLo, tileHi), + 0.0); + } + } + stored *= 1.0 / 9.0; // Up to four: light a caster gathered, not only light it stopped. vec3 through = clamp(vec3(1.0 - stored.g, 1.0 - stored.b, stored.a), 0.0, 4.0); light_transmittance = mix(vec3(1.0), through, clamp(strength, 0.0, 1.0)); @@ -22085,13 +22125,23 @@ float ShadowFactor(Surface s, LightSample light, int lightIndex) { // cut. A sign rather than another uniform, for the reason the softness // itself rides here. // **What the see-through casters let through** — before the filter, whose - // soft path leaves early where it finds no blocker. One bilinear tap: a - // translucent caster's shadow is light shaded rather than light stopped, - // and its edge is softened by the filtering the tap already gets. Green - // and blue hold what was taken from red and green, alpha what was left of - // blue — the layout `shadow_transmittance.frag` explains. + // soft path leaves early where it finds no blocker. Averaged over the same + // 3×3 texels the opaque edge is: the atlas is read without filtering, and + // one tap, which once relied on the sampler's bilinear step, drew a glass + // or a liquid's shadow edge as stairs a texel high. Green and blue hold + // what was taken from red and green, alpha what was left of blue — the + // layout `shadow_transmittance.frag` explains. if (frag_info.shadow_bias.w > 0.5) { - vec4 stored = textureLod(shadow_texture, clamp(uv, tileLo, tileHi), 0.0); + vec4 stored = vec4(0.0); + for (int y = -1; y <= 1; y++) { + for (int x = -1; x <= 1; x++) { + stored += textureLod( + shadow_texture, + clamp(uv + vec2(float(x), float(y)) * texel, tileLo, tileHi), + 0.0); + } + } + stored *= 1.0 / 9.0; // Up to four: light a caster gathered, not only light it stopped. vec3 through = clamp(vec3(1.0 - stored.g, 1.0 - stored.b, stored.a), 0.0, 4.0); light_transmittance = mix(vec3(1.0), through, clamp(strength, 0.0, 1.0)); @@ -37905,13 +37955,23 @@ float ShadowFactor(Surface s, LightSample light, int lightIndex) { // cut. A sign rather than another uniform, for the reason the softness // itself rides here. // **What the see-through casters let through** — before the filter, whose - // soft path leaves early where it finds no blocker. One bilinear tap: a - // translucent caster's shadow is light shaded rather than light stopped, - // and its edge is softened by the filtering the tap already gets. Green - // and blue hold what was taken from red and green, alpha what was left of - // blue — the layout `shadow_transmittance.frag` explains. + // soft path leaves early where it finds no blocker. Averaged over the same + // 3×3 texels the opaque edge is: the atlas is read without filtering, and + // one tap, which once relied on the sampler's bilinear step, drew a glass + // or a liquid's shadow edge as stairs a texel high. Green and blue hold + // what was taken from red and green, alpha what was left of blue — the + // layout `shadow_transmittance.frag` explains. if (frag_info.shadow_bias.w > 0.5) { - vec4 stored = textureLod(shadow_texture, clamp(uv, tileLo, tileHi), 0.0); + vec4 stored = vec4(0.0); + for (int y = -1; y <= 1; y++) { + for (int x = -1; x <= 1; x++) { + stored += textureLod( + shadow_texture, + clamp(uv + vec2(float(x), float(y)) * texel, tileLo, tileHi), + 0.0); + } + } + stored *= 1.0 / 9.0; // Up to four: light a caster gathered, not only light it stopped. vec3 through = clamp(vec3(1.0 - stored.g, 1.0 - stored.b, stored.a), 0.0, 4.0); light_transmittance = mix(vec3(1.0), through, clamp(strength, 0.0, 1.0)); diff --git a/packages/flutter3d_webgpu/lib/engine_shaders.dart b/packages/flutter3d_webgpu/lib/engine_shaders.dart index 166f9687b..3e30f3ac1 100644 --- a/packages/flutter3d_webgpu/lib/engine_shaders.dart +++ b/packages/flutter3d_webgpu/lib/engine_shaders.dart @@ -6546,10 +6546,10 @@ var metallic_roughness_texture_tex: texture_2d; var metallic_roughness_texture_smp: sampler; fn ViewDepth_u0028_() -> f32 { - let _e186 = v_world_position_1; - let _e188 = fog_info.eye; - let _e192 = fog_info.forward; - return dot((_e186 - _e188.xyz), _e192.xyz); + let _e187 = v_world_position_1; + let _e189 = fog_info.eye; + let _e193 = fog_info.forward; + return dot((_e187 - _e189.xyz), _e193.xyz); } fn WeightedBlendedWeight_u0028_f1_u003b(alpha: ptr) -> f32 { @@ -6558,22 +6558,22 @@ fn WeightedBlendedWeight_u0028_f1_u003b(alpha: ptr) -> f32 { var far: f32; var far3_: f32; - let _e191 = ViewDepth_u0028_(); - z = abs(_e191); - let _e193 = z; - near = (_e193 / 5f); - let _e195 = z; - far = (_e195 / 200f); - let _e197 = far; + let _e192 = ViewDepth_u0028_(); + z = abs(_e192); + let _e194 = z; + near = (_e194 / 5f); + let _e196 = z; + far = (_e196 / 200f); let _e198 = far; - let _e200 = far; - far3_ = ((_e197 * _e198) * _e200); - let _e202 = (*alpha); - let _e203 = near; + let _e199 = far; + let _e201 = far; + far3_ = ((_e198 * _e199) * _e201); + let _e203 = (*alpha); let _e204 = near; - let _e207 = far3_; + let _e205 = near; let _e208 = far3_; - return (_e202 * clamp((10f / ((0.00001f + (_e203 * _e204)) + (_e207 * _e208))), 0.01f, 3000f)); + let _e209 = far3_; + return (_e203 * clamp((10f / ((0.00001f + (_e204 * _e205)) + (_e208 * _e209))), 0.01f, 3000f)); } fn WriteWeightedBlended_u0028_() { @@ -6585,39 +6585,39 @@ fn WriteWeightedBlended_u0028_() { var revealage: bool; var local: vec4; - let _e195 = fog_info.forward[3u]; - mode = _e195; - let _e196 = mode; - if (_e196 > 0.5f) { - let _e199 = frag_color[3u]; - alpha_1 = _e199; - let _e200 = alpha_1; - param = _e200; - let _e201 = WeightedBlendedWeight_u0028_f1_u003b((¶m)); - weight = _e201; - let _e202 = frag_color; - let _e204 = weight; - let _e205 = (_e202.xyz * _e204); - let _e206 = alpha_1; - let _e207 = weight; - accumulate = vec4(_e205.x, _e205.y, _e205.z, (_e206 * _e207)); - let _e213 = mode; - let _e215 = mode; - revealage = ((_e213 > 1.5f) && (_e215 < 2.5f)); - let _e218 = revealage; - if _e218 { - let _e219 = alpha_1; - local = vec4(_e219); + let _e196 = fog_info.forward[3u]; + mode = _e196; + let _e197 = mode; + if (_e197 > 0.5f) { + let _e200 = frag_color[3u]; + alpha_1 = _e200; + let _e201 = alpha_1; + param = _e201; + let _e202 = WeightedBlendedWeight_u0028_f1_u003b((¶m)); + weight = _e202; + let _e203 = frag_color; + let _e205 = weight; + let _e206 = (_e203.xyz * _e205); + let _e207 = alpha_1; + let _e208 = weight; + accumulate = vec4(_e206.x, _e206.y, _e206.z, (_e207 * _e208)); + let _e214 = mode; + let _e216 = mode; + revealage = ((_e214 > 1.5f) && (_e216 < 2.5f)); + let _e219 = revealage; + if _e219 { + let _e220 = alpha_1; + local = vec4(_e220); } else { - let _e221 = accumulate; - local = _e221; + let _e222 = accumulate; + local = _e222; } - let _e222 = local; - frag_color = _e222; - let _e223 = mode; - if (_e223 > 2.5f) { - let _e225 = alpha_1; - frag_surface = vec4(_e225); + let _e223 = local; + frag_color = _e223; + let _e224 = mode; + if (_e224 > 2.5f) { + let _e226 = alpha_1; + frag_surface = vec4(_e226); } } return; @@ -6626,29 +6626,29 @@ fn WriteWeightedBlended_u0028_() { fn EncodeOctahedral_u0028_vf3_u003b(n: ptr>) -> vec2 { var e: vec2; - let _e189 = (*n)[0u]; - let _e192 = (*n)[1u]; - let _e196 = (*n)[2u]; - let _e199 = (*n); - (*n) = (_e199 / vec3(((abs(_e189) + abs(_e192)) + abs(_e196)))); - let _e202 = (*n); - e = _e202.xy; - let _e205 = (*n)[2u]; - if (_e205 < 0f) { - let _e207 = (*n); - let _e213 = (*n)[0u]; - let _e217 = (*n)[1u]; - e = ((vec2(1f) - abs(_e207.yx)) * vec2(select(-1f, 1f, (_e213 >= 0f)), select(-1f, 1f, (_e217 >= 0f)))); + let _e190 = (*n)[0u]; + let _e193 = (*n)[1u]; + let _e197 = (*n)[2u]; + let _e200 = (*n); + (*n) = (_e200 / vec3(((abs(_e190) + abs(_e193)) + abs(_e197)))); + let _e203 = (*n); + e = _e203.xy; + let _e206 = (*n)[2u]; + if (_e206 < 0f) { + let _e208 = (*n); + let _e214 = (*n)[0u]; + let _e218 = (*n)[1u]; + e = ((vec2(1f) - abs(_e208.yx)) * vec2(select(-1f, 1f, (_e214 >= 0f)), select(-1f, 1f, (_e218 >= 0f)))); } - let _e222 = e; - return ((_e222 * 0.5f) + vec2(0.5f)); + let _e223 = e; + return ((_e223 * 0.5f) + vec2(0.5f)); } fn LinearToSrgb_u0028_vf3_u003b(linear: ptr>) -> vec3 { - let _e187 = (*linear); - let _e189 = (*linear); - let _e193 = (*linear); - return mix((_e187 * 12.92f), ((pow(_e189, vec3(0.41666666f, 0.41666666f, 0.41666666f)) * 1.055f) - vec3(0.055f, 0.055f, 0.055f)), step(vec3(0.0031308f, 0.0031308f, 0.0031308f), _e193)); + let _e188 = (*linear); + let _e190 = (*linear); + let _e194 = (*linear); + return mix((_e188 * 12.92f), ((pow(_e190, vec3(0.41666666f, 0.41666666f, 0.41666666f)) * 1.055f) - vec3(0.055f, 0.055f, 0.055f)), step(vec3(0.0031308f, 0.0031308f, 0.0031308f), _e194)); } fn WriteSurfaceGeometry_u0028_f1_u003b(roughness: ptr) { @@ -6656,52 +6656,52 @@ fn WriteSurfaceGeometry_u0028_f1_u003b(roughness: ptr) { var geometric: vec3; var param_2: vec3; - let _e190 = g_albedo; - param_1 = clamp(_e190, vec3(0f, 0f, 0f), vec3(1f, 1f, 1f)); - let _e192 = LinearToSrgb_u0028_vf3_u003b((¶m_1)); - frag_albedo = vec4(_e192.x, _e192.y, _e192.z, 1f); - let _e197 = g_debug_surface_on; - if _e197 { - let _e198 = g_debug_surface; - let _e199 = ViewDepth_u0028_(); - frag_surface = vec4(_e198.x, _e198.y, _e198.z, _e199); + let _e191 = g_albedo; + param_1 = clamp(_e191, vec3(0f, 0f, 0f), vec3(1f, 1f, 1f)); + let _e193 = LinearToSrgb_u0028_vf3_u003b((¶m_1)); + frag_albedo = vec4(_e193.x, _e193.y, _e193.z, 1f); + let _e198 = g_debug_surface_on; + if _e198 { + let _e199 = g_debug_surface; + let _e200 = ViewDepth_u0028_(); + frag_surface = vec4(_e199.x, _e199.y, _e199.z, _e200); return; } - let _e204 = v_normal_1; - geometric = normalize(_e204); - let _e206 = gl_FrontFacing_1; - if !(_e206) { - let _e208 = geometric; - geometric = -(_e208); - } - let _e210 = geometric; - param_2 = _e210; - let _e211 = EncodeOctahedral_u0028_vf3_u003b((¶m_2)); - let _e212 = (*roughness); - let _e214 = ViewDepth_u0028_(); - frag_surface = vec4(_e211.x, _e211.y, clamp(_e212, 0f, 1f), _e214); + let _e205 = v_normal_1; + geometric = normalize(_e205); + let _e207 = gl_FrontFacing_1; + if !(_e207) { + let _e209 = geometric; + geometric = -(_e209); + } + let _e211 = geometric; + param_2 = _e211; + let _e212 = EncodeOctahedral_u0028_vf3_u003b((¶m_2)); + let _e213 = (*roughness); + let _e215 = ViewDepth_u0028_(); + frag_surface = vec4(_e212.x, _e212.y, clamp(_e213, 0f, 1f), _e215); return; } fn Orthographic_u0028_() -> bool { - let _e188 = fog_info.projection[0u]; - return (_e188 > 0.5f); + let _e189 = fog_info.projection[0u]; + return (_e189 > 0.5f); } fn EyeDistance_u0028_() -> f32 { var local_1: f32; - let _e187 = Orthographic_u0028_(); - if _e187 { - let _e188 = ViewDepth_u0028_(); - local_1 = max(_e188, 0f); + let _e188 = Orthographic_u0028_(); + if _e188 { + let _e189 = ViewDepth_u0028_(); + local_1 = max(_e189, 0f); } else { - let _e190 = v_world_position_1; - let _e192 = fog_info.eye; - local_1 = distance(_e190, _e192.xyz); + let _e191 = v_world_position_1; + let _e193 = fog_info.eye; + local_1 = distance(_e191, _e193.xyz); } - let _e195 = local_1; - return _e195; + let _e196 = local_1; + return _e196; } fn ApplyFog_u0028_vf3_u003b(color: ptr>) -> vec3 { @@ -6711,41 +6711,41 @@ fn ApplyFog_u0028_vf3_u003b(color: ptr>) -> vec3 { var k: f32; var local_2: f32; - let _e194 = fog_info.fog[3u]; - density = _e194; - let _e195 = density; - if (_e195 <= 0f) { - let _e197 = (*color); - return _e197; - } - let _e198 = EyeDistance_u0028_(); - d = _e198; - let _e201 = fog_info.eye[3u]; - falloff = _e201; - let _e202 = falloff; - if (_e202 > 0f) { - let _e204 = falloff; - let _e206 = v_world_position_1[1u]; - let _e209 = fog_info.eye[1u]; - k = (_e204 * (_e206 - _e209)); - let _e212 = k; - if (abs(_e212) > 0.001f) { - let _e215 = k; - let _e219 = k; - local_2 = ((1f - exp(-(_e215))) / _e219); + let _e195 = fog_info.fog[3u]; + density = _e195; + let _e196 = density; + if (_e196 <= 0f) { + let _e198 = (*color); + return _e198; + } + let _e199 = EyeDistance_u0028_(); + d = _e199; + let _e202 = fog_info.eye[3u]; + falloff = _e202; + let _e203 = falloff; + if (_e203 > 0f) { + let _e205 = falloff; + let _e207 = v_world_position_1[1u]; + let _e210 = fog_info.eye[1u]; + k = (_e205 * (_e207 - _e210)); + let _e213 = k; + if (abs(_e213) > 0.001f) { + let _e216 = k; + let _e220 = k; + local_2 = ((1f - exp(-(_e216))) / _e220); } else { - let _e221 = k; - local_2 = (1f - (0.5f * _e221)); + let _e222 = k; + local_2 = (1f - (0.5f * _e222)); } - let _e224 = local_2; - let _e225 = density; - density = (_e225 * _e224); + let _e225 = local_2; + let _e226 = density; + density = (_e226 * _e225); } - let _e228 = fog_info.fog; - let _e230 = (*color); - let _e231 = density; - let _e233 = d; - return mix(_e228.xyz, _e230, vec3(clamp(exp((-(_e231) * _e233)), 0f, 1f))); + let _e229 = fog_info.fog; + let _e231 = (*color); + let _e232 = density; + let _e234 = d; + return mix(_e229.xyz, _e231, vec3(clamp(exp((-(_e232) * _e234)), 0f, 1f))); } fn WriteSurface_u0028_vf3_u003b_f1_u003b_f1_u003b(linearColor: ptr>, alpha_2: ptr, roughness_1: ptr) { @@ -6753,44 +6753,44 @@ fn WriteSurface_u0028_vf3_u003b_f1_u003b_f1_u003b(linearColor: ptr; var param_4: f32; - let _e192 = g_premultiply; - let _e193 = (*alpha_2); - weight_1 = select(1f, _e193, _e192); - let _e195 = (*linearColor); - param_3 = _e195; - let _e196 = ApplyFog_u0028_vf3_u003b((¶m_3)); - let _e197 = weight_1; - let _e198 = (_e196 * _e197); - let _e199 = (*alpha_2); - let _e200 = g_pass_through; - frag_color = vec4(_e198.x, _e198.y, _e198.z, (_e199 * (1f - _e200))); - let _e207 = (*roughness_1); - param_4 = _e207; + let _e193 = g_premultiply; + let _e194 = (*alpha_2); + weight_1 = select(1f, _e194, _e193); + let _e196 = (*linearColor); + param_3 = _e196; + let _e197 = ApplyFog_u0028_vf3_u003b((¶m_3)); + let _e198 = weight_1; + let _e199 = (_e197 * _e198); + let _e200 = (*alpha_2); + let _e201 = g_pass_through; + frag_color = vec4(_e199.x, _e199.y, _e199.z, (_e200 * (1f - _e201))); + let _e208 = (*roughness_1); + param_4 = _e208; WriteSurfaceGeometry_u0028_f1_u003b((¶m_4)); WriteWeightedBlended_u0028_(); return; } fn SrgbToLinear_u0028_vf3_u003b(srgb: ptr>) -> vec3 { - let _e187 = (*srgb); - let _e190 = (*srgb); - let _e195 = (*srgb); - return mix((_e187 / vec3(12.92f)), pow(((_e190 + vec3(0.055f, 0.055f, 0.055f)) / vec3(1.055f)), vec3(2.4f, 2.4f, 2.4f)), step(vec3(0.04045f, 0.04045f, 0.04045f), _e195)); + let _e188 = (*srgb); + let _e191 = (*srgb); + let _e196 = (*srgb); + return mix((_e188 / vec3(12.92f)), pow(((_e191 + vec3(0.055f, 0.055f, 0.055f)) / vec3(1.055f)), vec3(2.4f, 2.4f, 2.4f)), step(vec3(0.04045f, 0.04045f, 0.04045f), _e196)); } fn NonFinite_u0028_vf3_u003b(c: ptr>) -> bool { var phi_2559_: bool; - let _e187 = (*c); let _e188 = (*c); - let _e190 = any((_e187 != _e188)); - phi_2559_ = _e190; - if !(_e190) { - let _e192 = (*c); - phi_2559_ = any((abs(_e192) > vec3(300000000000000000000000000000000000000f, 300000000000000000000000000000000000000f, 300000000000000000000000000000000000000f))); + let _e189 = (*c); + let _e191 = any((_e188 != _e189)); + phi_2559_ = _e191; + if !(_e191) { + let _e193 = (*c); + phi_2559_ = any((abs(_e193) > vec3(300000000000000000000000000000000000000f, 300000000000000000000000000000000000000f, 300000000000000000000000000000000000000f))); } - let _e197 = phi_2559_; - return _e197; + let _e198 = phi_2559_; + return _e198; } fn WriteDebugView_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_vf3_u003b(s: ptr, lit: ptr>) -> bool { @@ -6808,78 +6808,78 @@ fn WriteDebugView_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_ var param_9: vec3; var param_10: f32; - let _e203 = frag_info.debug_view[0u]; - view = _e203; - let _e204 = view; - if (_e204 < 0.5f) { + let _e204 = frag_info.debug_view[0u]; + view = _e204; + let _e205 = view; + if (_e205 < 0.5f) { return false; } - let _e207 = gl_FragCoord_1[0u]; - let _e210 = frag_info.debug_view[1u]; - let _e213 = frag_info.debug_view[2u]; - if (_e207 < (_e210 * _e213)) { + let _e208 = gl_FragCoord_1[0u]; + let _e211 = frag_info.debug_view[1u]; + let _e214 = frag_info.debug_view[2u]; + if (_e208 < (_e211 * _e214)) { return false; } - let _e216 = view; - code = i32((_e216 + 0.5f)); + let _e217 = view; + code = i32((_e217 + 0.5f)); shown = vec3(0f, 0f, 0f); - let _e219 = code; - if (_e219 == 1i) { - let _e222 = (*s).albedo; - param_5 = clamp(_e222, vec3(0f, 0f, 0f), vec3(1f, 1f, 1f)); - let _e224 = LinearToSrgb_u0028_vf3_u003b((¶m_5)); - shown = _e224; - } else { - let _e225 = code; - if (_e225 == 2i) { - let _e228 = (*s).n; - shown = ((_e228 * 0.5f) + vec3(0.5f, 0.5f, 0.5f)); + let _e220 = code; + if (_e220 == 1i) { + let _e223 = (*s).albedo; + param_5 = clamp(_e223, vec3(0f, 0f, 0f), vec3(1f, 1f, 1f)); + let _e225 = LinearToSrgb_u0028_vf3_u003b((¶m_5)); + shown = _e225; + } else { + let _e226 = code; + if (_e226 == 2i) { + let _e229 = (*s).n; + shown = ((_e229 * 0.5f) + vec3(0.5f, 0.5f, 0.5f)); } else { - let _e231 = code; - if (_e231 == 3i) { - let _e234 = (*s).roughness; - shown = vec3(clamp(_e234, 0f, 1f)); + let _e232 = code; + if (_e232 == 3i) { + let _e235 = (*s).roughness; + shown = vec3(clamp(_e235, 0f, 1f)); } else { - let _e237 = code; - if (_e237 == 4i) { - let _e240 = (*s).metallic; - shown = vec3(clamp(_e240, 0f, 1f)); + let _e238 = code; + if (_e238 == 4i) { + let _e241 = (*s).metallic; + shown = vec3(clamp(_e241, 0f, 1f)); } else { - let _e243 = code; - if (_e243 == 5i) { - let _e246 = (*s).occlusion; - shown = vec3(clamp(_e246, 0f, 1f)); + let _e244 = code; + if (_e244 == 5i) { + let _e247 = (*s).occlusion; + shown = vec3(clamp(_e247, 0f, 1f)); } else { - let _e249 = code; - if (_e249 == 6i) { - let _e252 = (*s).emissive; - param_6 = clamp(_e252, vec3(0f, 0f, 0f), vec3(1f, 1f, 1f)); - let _e254 = LinearToSrgb_u0028_vf3_u003b((¶m_6)); - shown = _e254; + let _e250 = code; + if (_e250 == 6i) { + let _e253 = (*s).emissive; + param_6 = clamp(_e253, vec3(0f, 0f, 0f), vec3(1f, 1f, 1f)); + let _e255 = LinearToSrgb_u0028_vf3_u003b((¶m_6)); + shown = _e255; } else { - let _e255 = code; - if (_e255 == 7i) { - let _e257 = v_texcoord_1; - let _e258 = fract(_e257); - shown = vec3(_e258.x, _e258.y, 0f); + let _e256 = code; + if (_e256 == 7i) { + let _e258 = v_texcoord_1; + let _e259 = fract(_e258); + shown = vec3(_e259.x, _e259.y, 0f); } else { - let _e262 = code; - if (_e262 == 8i) { - let _e264 = (*lit); - param_7 = clamp(_e264, vec3(0f, 0f, 0f), vec3(1f, 1f, 1f)); - let _e266 = LinearToSrgb_u0028_vf3_u003b((¶m_7)); - grey = dot(_e266, vec3(0.2126f, 0.7152f, 0.0722f)); - let _e268 = (*lit); - param_8 = _e268; - let _e269 = NonFinite_u0028_vf3_u003b((¶m_8)); - if _e269 { + let _e263 = code; + if (_e263 == 8i) { + let _e265 = (*lit); + param_7 = clamp(_e265, vec3(0f, 0f, 0f), vec3(1f, 1f, 1f)); + let _e267 = LinearToSrgb_u0028_vf3_u003b((¶m_7)); + grey = dot(_e267, vec3(0.2126f, 0.7152f, 0.0722f)); + let _e269 = (*lit); + param_8 = _e269; + let _e270 = NonFinite_u0028_vf3_u003b((¶m_8)); + if _e270 { local_3 = vec3(1f, 0f, 1f); } else { - let _e270 = grey; - local_3 = vec3((_e270 * 0.5f)); + let _e271 = grey; + local_3 = vec3((_e271 * 0.5f)); } - let _e273 = local_3; - shown = _e273; + let _e274 = local_3; + shown = _e274; } } } @@ -6888,61 +6888,61 @@ fn WriteDebugView_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_ } } } - let _e274 = g_premultiply; - if _e274 { - let _e276 = (*s).alpha; - local_4 = _e276; + let _e275 = g_premultiply; + if _e275 { + let _e277 = (*s).alpha; + local_4 = _e277; } else { local_4 = 1f; } - let _e277 = local_4; - weight_2 = _e277; - let _e278 = shown; - param_9 = _e278; - let _e279 = SrgbToLinear_u0028_vf3_u003b((¶m_9)); - let _e280 = weight_2; - let _e281 = (_e279 * _e280); - let _e283 = (*s).alpha; - frag_color = vec4(_e281.x, _e281.y, _e281.z, _e283); - let _e289 = (*s).roughness; - param_10 = _e289; + let _e278 = local_4; + weight_2 = _e278; + let _e279 = shown; + param_9 = _e279; + let _e280 = SrgbToLinear_u0028_vf3_u003b((¶m_9)); + let _e281 = weight_2; + let _e282 = (_e280 * _e281); + let _e284 = (*s).alpha; + frag_color = vec4(_e282.x, _e282.y, _e282.z, _e284); + let _e290 = (*s).roughness; + param_10 = _e290; WriteSurfaceGeometry_u0028_f1_u003b((¶m_10)); WriteWeightedBlended_u0028_(); return true; } fn ShadeLight_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_struct_u002d_LightSample_u002d_vf3_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf31_u003b(s_1: ptr, light: ptr) -> vec3 { - let _e189 = (*s_1).albedo; - return _e189; + let _e190 = (*s_1).albedo; + return _e190; } fn PointShadowDiskTap_u0028_i1_u003b(i: ptr) -> vec2 { - let _e187 = (*i); - if (_e187 == 0i) { + let _e188 = (*i); + if (_e188 == 0i) { return vec2(-0.94201624f, -0.39906216f); } - let _e189 = (*i); - if (_e189 == 1i) { + let _e190 = (*i); + if (_e190 == 1i) { return vec2(0.9455861f, -0.76890725f); } - let _e191 = (*i); - if (_e191 == 2i) { + let _e192 = (*i); + if (_e192 == 2i) { return vec2(-0.0941841f, -0.9293887f); } - let _e193 = (*i); - if (_e193 == 3i) { + let _e194 = (*i); + if (_e194 == 3i) { return vec2(0.34495938f, 0.2938776f); } - let _e195 = (*i); - if (_e195 == 4i) { + let _e196 = (*i); + if (_e196 == 4i) { return vec2(-0.9158858f, 0.45771432f); } - let _e197 = (*i); - if (_e197 == 5i) { - return vec2(-0.8154423f, -0.87912464f); + let _e198 = (*i); + if (_e198 == 5i) { + return vec2(-0.8154423f, -0.87912464f); } - let _e199 = (*i); - if (_e199 == 6i) { + let _e200 = (*i); + if (_e200 == 6i) { return vec2(-0.38277543f, 0.27676845f); } return vec2(0.974844f, 0.7564838f); @@ -6952,20 +6952,20 @@ fn PointShadowOffset_u0028_i1_u003b_f1_u003b_f1_u003b_f1_u003b(i_1: ptr; var param_11: i32; - let _e192 = (*i_1); - param_11 = _e192; - let _e193 = PointShadowDiskTap_u0028_i1_u003b((¶m_11)); - p = _e193; - let _e195 = p[0u]; - let _e196 = (*ca); - let _e199 = p[1u]; - let _e200 = (*sa); - let _e204 = p[0u]; - let _e205 = (*sa); - let _e208 = p[1u]; - let _e209 = (*ca); - let _e213 = (*radius); - return (vec2(((_e195 * _e196) - (_e199 * _e200)), ((_e204 * _e205) + (_e208 * _e209))) * _e213); + let _e193 = (*i_1); + param_11 = _e193; + let _e194 = PointShadowDiskTap_u0028_i1_u003b((¶m_11)); + p = _e194; + let _e196 = p[0u]; + let _e197 = (*ca); + let _e200 = p[1u]; + let _e201 = (*sa); + let _e205 = p[0u]; + let _e206 = (*sa); + let _e209 = p[1u]; + let _e210 = (*ca); + let _e214 = (*radius); + return (vec2(((_e196 * _e197) - (_e200 * _e201)), ((_e205 * _e206) + (_e209 * _e210))) * _e214); } fn PointShadowDistance_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b(uv: ptr>, offset: ptr>, tile: ptr>, range: ptr) -> f32 { @@ -6973,27 +6973,27 @@ fn PointShadowDistance_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b(uv: ptr; var atlas: vec2; - let _e195 = point_shadow.params[0u]; - inset = _e195; - let _e196 = (*uv); - let _e197 = (*offset); - let _e199 = inset; + let _e196 = point_shadow.params[0u]; + inset = _e196; + let _e197 = (*uv); + let _e198 = (*offset); let _e200 = inset; - local_5 = clamp((_e196 + _e197), vec2(_e199), vec2((1f - _e200))); - let _e205 = local_5; - let _e206 = (*tile); - atlas = ((_e205 + _e206) * vec2(0.16666667f, 0.16666667f)); - let _e211 = point_shadow.params3_[0u]; - if (_e211 > 0.5f) { - let _e214 = atlas[1u]; - atlas[1u] = (1f - _e214); - } - let _e217 = atlas; - let _e218 = textureSampleLevel(point_shadow_texture_tex, point_shadow_texture_smp, _e217, 0f); - let _e220 = atlas; - let _e221 = textureSampleLevel(point_shadow_static_texture_tex, point_shadow_static_texture_smp, _e220, 0f); - let _e224 = (*range); - return (min(_e218.x, _e221.x) * _e224); + let _e201 = inset; + local_5 = clamp((_e197 + _e198), vec2(_e200), vec2((1f - _e201))); + let _e206 = local_5; + let _e207 = (*tile); + atlas = ((_e206 + _e207) * vec2(0.16666667f, 0.16666667f)); + let _e212 = point_shadow.params3_[0u]; + if (_e212 > 0.5f) { + let _e215 = atlas[1u]; + atlas[1u] = (1f - _e215); + } + let _e218 = atlas; + let _e219 = textureSampleLevel(point_shadow_texture_tex, point_shadow_texture_smp, _e218, 0f); + let _e221 = atlas; + let _e222 = textureSampleLevel(point_shadow_static_texture_tex, point_shadow_static_texture_smp, _e221, 0f); + let _e225 = (*range); + return (min(_e219.x, _e222.x) * _e225); } fn PointShadowTap_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b_f1_u003b(uv_1: ptr>, offset_1: ptr>, tile_1: ptr>, range_1: ptr, receiver: ptr) -> f32 { @@ -7003,24 +7003,24 @@ fn PointShadowTap_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b_f1_u003b(uv_1: pt var param_14: vec2; var param_15: f32; - let _e196 = (*uv_1); - param_12 = _e196; - let _e197 = (*offset_1); - param_13 = _e197; - let _e198 = (*tile_1); - param_14 = _e198; - let _e199 = (*range_1); - param_15 = _e199; - let _e200 = PointShadowDistance_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b((¶m_12), (¶m_13), (¶m_14), (¶m_15)); - stored = _e200; - let _e201 = stored; - let _e202 = (*range_1); - if (_e201 >= (_e202 * 0.999f)) { + let _e197 = (*uv_1); + param_12 = _e197; + let _e198 = (*offset_1); + param_13 = _e198; + let _e199 = (*tile_1); + param_14 = _e199; + let _e200 = (*range_1); + param_15 = _e200; + let _e201 = PointShadowDistance_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b((¶m_12), (¶m_13), (¶m_14), (¶m_15)); + stored = _e201; + let _e202 = stored; + let _e203 = (*range_1); + if (_e202 >= (_e203 * 0.999f)) { return 1f; } - let _e205 = (*receiver); - let _e206 = stored; - return select(1f, 0f, (_e205 > _e206)); + let _e206 = (*receiver); + let _e207 = stored; + return select(1f, 0f, (_e206 > _e207)); } fn PointShadowPenumbra_u0028_vf2_u003b_vf2_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b(uv_2: ptr>, tile_2: ptr>, range_2: ptr, receiver_1: ptr, ca_1: ptr, sa_1: ptr, tanHalf: ptr, blockerOut: ptr) -> f32 { @@ -7047,111 +7047,111 @@ fn PointShadowPenumbra_u0028_vf2_u003b_vf2_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u var world: f32; (*blockerOut) = -1f; - let _e217 = point_shadow.params2_[1u]; - lightRadius = _e217; - let _e220 = point_shadow.params2_[0u]; - minRadius = _e220; - let _e223 = point_shadow.params2_[2u]; - maxRadius = _e223; - let _e224 = lightRadius; - if (_e224 <= 0f) { - let _e226 = (*uv_2); - param_16 = _e226; + let _e218 = point_shadow.params2_[1u]; + lightRadius = _e218; + let _e221 = point_shadow.params2_[0u]; + minRadius = _e221; + let _e224 = point_shadow.params2_[2u]; + maxRadius = _e224; + let _e225 = lightRadius; + if (_e225 <= 0f) { + let _e227 = (*uv_2); + param_16 = _e227; param_17 = vec2(0f, 0f); - let _e227 = (*tile_2); - param_18 = _e227; - let _e228 = (*range_2); - param_19 = _e228; - let _e229 = PointShadowDistance_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b((¶m_16), (¶m_17), (¶m_18), (¶m_19)); - (*blockerOut) = _e229; - let _e230 = minRadius; - return _e230; + let _e228 = (*tile_2); + param_18 = _e228; + let _e229 = (*range_2); + param_19 = _e229; + let _e230 = PointShadowDistance_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b((¶m_16), (¶m_17), (¶m_18), (¶m_19)); + (*blockerOut) = _e230; + let _e231 = minRadius; + return _e231; } sum = 0f; count = 0f; i_2 = 0i; loop { - let _e231 = i_2; - if (_e231 < 8i) { - let _e233 = i_2; - param_20 = _e233; - let _e234 = (*ca_1); - param_21 = _e234; - let _e235 = (*sa_1); - param_22 = _e235; - let _e236 = maxRadius; - param_23 = _e236; - let _e237 = PointShadowOffset_u0028_i1_u003b_f1_u003b_f1_u003b_f1_u003b((¶m_20), (¶m_21), (¶m_22), (¶m_23)); - let _e238 = (*uv_2); - param_24 = _e238; - param_25 = _e237; - let _e239 = (*tile_2); - param_26 = _e239; - let _e240 = (*range_2); - param_27 = _e240; - let _e241 = PointShadowDistance_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b((¶m_24), (¶m_25), (¶m_26), (¶m_27)); - stored_1 = _e241; - let _e242 = stored_1; - let _e243 = (*range_2); - if (_e242 >= (_e243 * 0.999f)) { + let _e232 = i_2; + if (_e232 < 8i) { + let _e234 = i_2; + param_20 = _e234; + let _e235 = (*ca_1); + param_21 = _e235; + let _e236 = (*sa_1); + param_22 = _e236; + let _e237 = maxRadius; + param_23 = _e237; + let _e238 = PointShadowOffset_u0028_i1_u003b_f1_u003b_f1_u003b_f1_u003b((¶m_20), (¶m_21), (¶m_22), (¶m_23)); + let _e239 = (*uv_2); + param_24 = _e239; + param_25 = _e238; + let _e240 = (*tile_2); + param_26 = _e240; + let _e241 = (*range_2); + param_27 = _e241; + let _e242 = PointShadowDistance_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b((¶m_24), (¶m_25), (¶m_26), (¶m_27)); + stored_1 = _e242; + let _e243 = stored_1; + let _e244 = (*range_2); + if (_e243 >= (_e244 * 0.999f)) { continue; } - let _e246 = stored_1; - let _e247 = (*receiver_1); - if (_e246 >= _e247) { + let _e247 = stored_1; + let _e248 = (*receiver_1); + if (_e247 >= _e248) { continue; } - let _e249 = stored_1; - let _e250 = sum; - sum = (_e250 + _e249); - let _e252 = count; - count = (_e252 + 1f); + let _e250 = stored_1; + let _e251 = sum; + sum = (_e251 + _e250); + let _e253 = count; + count = (_e253 + 1f); continue; } else { break; } continuing { - let _e254 = i_2; - i_2 = (_e254 + 1i); + let _e255 = i_2; + i_2 = (_e255 + 1i); } } - let _e256 = count; - if (_e256 < 0.5f) { + let _e257 = count; + if (_e257 < 0.5f) { return -1f; } - let _e258 = sum; - let _e259 = count; - blocker = max((_e258 / _e259), 0.0001f); - let _e262 = blocker; - (*blockerOut) = _e262; - let _e263 = lightRadius; - let _e264 = (*receiver_1); - let _e265 = blocker; - let _e269 = blocker; - world = ((_e263 * max((_e264 - _e265), 0f)) / _e269); - let _e271 = world; - let _e272 = (*receiver_1); - let _e274 = (*tanHalf); - let _e277 = minRadius; - let _e278 = maxRadius; - return clamp((_e271 / ((2f * _e272) * _e274)), _e277, _e278); + let _e259 = sum; + let _e260 = count; + blocker = max((_e259 / _e260), 0.0001f); + let _e263 = blocker; + (*blockerOut) = _e263; + let _e264 = lightRadius; + let _e265 = (*receiver_1); + let _e266 = blocker; + let _e270 = blocker; + world = ((_e264 * max((_e265 - _e266), 0f)) / _e270); + let _e272 = world; + let _e273 = (*receiver_1); + let _e275 = (*tanHalf); + let _e278 = minRadius; + let _e279 = maxRadius; + return clamp((_e272 / ((2f * _e273) * _e275)), _e278, _e279); } fn FragCoordFromTop_u0028_f1_u003b(rows: ptr) -> vec2 { var local_6: vec2; - let _e188 = (*rows); - if (_e188 > 0f) { - let _e191 = gl_FragCoord_1[0u]; - let _e192 = (*rows); - let _e194 = gl_FragCoord_1[1u]; - local_6 = vec2(_e191, (_e192 - _e194)); + let _e189 = (*rows); + if (_e189 > 0f) { + let _e192 = gl_FragCoord_1[0u]; + let _e193 = (*rows); + let _e195 = gl_FragCoord_1[1u]; + local_6 = vec2(_e192, (_e193 - _e195)); } else { - let _e197 = gl_FragCoord_1; - local_6 = _e197.xy; + let _e198 = gl_FragCoord_1; + local_6 = _e198.xy; } - let _e199 = local_6; - return _e199; + let _e200 = local_6; + return _e200; } fn PointShadowFactor_u0028_vf3_u003b_vf3_u003b_i1_u003b(world_1: ptr>, normal: ptr>, lightIndex: ptr) -> f32 { @@ -7209,257 +7209,257 @@ fn PointShadowFactor_u0028_vf3_u003b_vf3_u003b_i1_u003b(world_1: ptr= _e327) { + let _e283 = nDotL; + slope = min((sqrt(max((1f - (_e276 * _e277)), 0f)) / (_e282 * _e283)), 8f); + let _e287 = toLightLength; + let _e289 = (*lightIndex); + let _e293 = point_shadow.slots[_e289][2u]; + let _e298 = point_shadow.params3_[1u]; + texel = (((2f * _e287) * max(_e293, 0.0001f)) * _e298); + let _e300 = (*world_1); + let _e301 = (*normal); + let _e302 = texel; + let _e306 = point_shadow.params[3u]; + let _e308 = slope; + origin = (_e300 + (((_e301 * _e302) * _e306) * (1f + _e308))); + let _e312 = origin; + let _e313 = slot; + let _e316 = point_shadow.lights[_e313]; + toFragment = (_e312 - _e316.xyz); + let _e319 = toFragment; + distance_ = length(_e319); + let _e321 = slot; + let _e325 = point_shadow.lights[_e321][3u]; + range_3 = max(_e325, 0.0001f); + let _e327 = distance_; + let _e328 = range_3; + if (_e327 >= _e328) { return 1f; } face = 0i; - let _e329 = (*lightIndex); - let _e333 = point_shadow.slots[_e329][1u]; - if (_e333 < 0.5f) { - let _e335 = toFragment; - a = abs(_e335); - let _e338 = a[0u]; - let _e340 = a[1u]; - let _e341 = (_e338 >= _e340); - phi_2246_ = _e341; - if _e341 { - let _e343 = a[0u]; - let _e345 = a[2u]; - phi_2246_ = (_e343 >= _e345); - } - let _e348 = phi_2246_; - if _e348 { - let _e350 = toFragment[0u]; - face = select(1i, 0i, (_e350 > 0f)); + let _e330 = (*lightIndex); + let _e334 = point_shadow.slots[_e330][1u]; + if (_e334 < 0.5f) { + let _e336 = toFragment; + a = abs(_e336); + let _e339 = a[0u]; + let _e341 = a[1u]; + let _e342 = (_e339 >= _e341); + phi_2246_ = _e342; + if _e342 { + let _e344 = a[0u]; + let _e346 = a[2u]; + phi_2246_ = (_e344 >= _e346); + } + let _e349 = phi_2246_; + if _e349 { + let _e351 = toFragment[0u]; + face = select(1i, 0i, (_e351 > 0f)); } else { - let _e354 = a[1u]; - let _e356 = a[2u]; - if (_e354 >= _e356) { - let _e359 = toFragment[1u]; - face = select(3i, 2i, (_e359 > 0f)); + let _e355 = a[1u]; + let _e357 = a[2u]; + if (_e355 >= _e357) { + let _e360 = toFragment[1u]; + face = select(3i, 2i, (_e360 > 0f)); } else { - let _e363 = toFragment[2u]; - face = select(5i, 4i, (_e363 > 0f)); + let _e364 = toFragment[2u]; + face = select(5i, 4i, (_e364 > 0f)); } } } - let _e366 = slot; - let _e368 = face; - let _e372 = point_shadow.faces[((_e366 * 6i) + _e368)]; - let _e373 = origin; - clip = (_e372 * vec4(_e373.x, _e373.y, _e373.z, 1f)); - let _e380 = clip[3u]; - if (_e380 <= 0f) { - return 1f; - } - let _e382 = clip; - let _e385 = clip[3u]; - ndc = (_e382.xy / vec2(_e385)); - let _e389 = ndc[0u]; - let _e391 = (abs(_e389) > 1f); - phi_2307_ = _e391; - if !(_e391) { - let _e394 = ndc[1u]; - phi_2307_ = (abs(_e394) > 1f); - } - let _e398 = phi_2307_; - if _e398 { + let _e367 = slot; + let _e369 = face; + let _e373 = point_shadow.faces[((_e367 * 6i) + _e369)]; + let _e374 = origin; + clip = (_e373 * vec4(_e374.x, _e374.y, _e374.z, 1f)); + let _e381 = clip[3u]; + if (_e381 <= 0f) { return 1f; } - let _e400 = ndc[0u]; - let _e404 = ndc[1u]; - uv_3 = vec2(((_e400 * 0.5f) + 0.5f), (0.5f - (_e404 * 0.5f))); - let _e408 = face; - let _e410 = slot; - tile_3 = vec2(f32(_e408), f32(_e410)); - let _e413 = distance_; - let _e416 = point_shadow.params[1u]; - receiver_2 = (_e413 - _e416); - let _e420 = frag_info.target_origin[0u]; - param_28 = _e420; - let _e421 = FragCoordFromTop_u0028_f1_u003b((¶m_28)); - noise = fract((52.982918f * fract(dot(_e421, vec2(0.06711056f, 0.00583715f))))); - let _e426 = noise; - angle = (_e426 * 6.2831855f); - let _e428 = angle; - ca_2 = cos(_e428); - let _e430 = angle; - sa_2 = sin(_e430); - let _e432 = (*lightIndex); - let _e436 = point_shadow.slots[_e432][2u]; - tanHalf_1 = max(_e436, 0.0001f); - blocker_1 = -1f; - let _e438 = uv_3; - param_29 = _e438; - let _e439 = tile_3; - param_30 = _e439; - let _e440 = range_3; - param_31 = _e440; - let _e441 = receiver_2; - param_32 = _e441; - let _e442 = ca_2; - param_33 = _e442; - let _e443 = sa_2; - param_34 = _e443; - let _e444 = tanHalf_1; - param_35 = _e444; - let _e445 = PointShadowPenumbra_u0028_vf2_u003b_vf2_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b((¶m_29), (¶m_30), (¶m_31), (¶m_32), (¶m_33), (¶m_34), (¶m_35), (¶m_36)); - let _e446 = param_36; - blocker_1 = _e446; - radius_1 = _e445; - let _e449 = point_shadow.params2_[3u]; - if (_e449 > 0.5f) { - g_debug_surface_on = true; - let _e451 = radius_1; - if (_e451 < 0f) { - local_7 = vec3(0f, 0f, 1f); - } else { - let _e453 = radius_1; - let _e456 = point_shadow.params2_[2u]; - let _e460 = blocker_1; - let _e461 = range_3; - local_7 = vec3(clamp((_e453 / max(_e456, 0.000001f)), 0f, 1f), clamp((_e460 / _e461), 0f, 1f), 0f); - } - let _e465 = local_7; - g_debug_surface = _e465; + let _e383 = clip; + let _e386 = clip[3u]; + ndc = (_e383.xy / vec2(_e386)); + let _e390 = ndc[0u]; + let _e392 = (abs(_e390) > 1f); + phi_2307_ = _e392; + if !(_e392) { + let _e395 = ndc[1u]; + phi_2307_ = (abs(_e395) > 1f); } - let _e466 = radius_1; - if (_e466 < 0f) { + let _e399 = phi_2307_; + if _e399 { return 1f; } - let _e468 = uv_3; - param_37 = _e468; - param_38 = vec2(0f, 0f); - let _e469 = tile_3; - param_39 = _e469; - let _e470 = range_3; - param_40 = _e470; - let _e471 = receiver_2; - param_41 = _e471; - let _e472 = PointShadowTap_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b_f1_u003b((¶m_37), (¶m_38), (¶m_39), (¶m_40), (¶m_41)); - lit_1 = _e472; - let _e473 = radius_1; - if (_e473 > 0f) { - i_3 = 0i; - loop { - let _e475 = i_3; - if (_e475 < 8i) { - let _e477 = i_3; - param_42 = _e477; - let _e478 = ca_2; - param_43 = _e478; - let _e479 = sa_2; - param_44 = _e479; - let _e480 = radius_1; - param_45 = _e480; - let _e481 = PointShadowOffset_u0028_i1_u003b_f1_u003b_f1_u003b_f1_u003b((¶m_42), (¶m_43), (¶m_44), (¶m_45)); - let _e482 = uv_3; - param_46 = _e482; - param_47 = _e481; - let _e483 = tile_3; - param_48 = _e483; - let _e484 = range_3; - param_49 = _e484; - let _e485 = receiver_2; - param_50 = _e485; - let _e486 = PointShadowTap_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b_f1_u003b((¶m_46), (¶m_47), (¶m_48), (¶m_49), (¶m_50)); - let _e487 = lit_1; - lit_1 = (_e487 + _e486); - continue; - } else { - break; - } - continuing { - let _e489 = i_3; - i_3 = (_e489 + 1i); - } - } - let _e491 = lit_1; - lit_1 = (_e491 * 0.11111111f); - } - let _e493 = lit_1; - let _e494 = strength; - return mix(1f, _e493, clamp(_e494, 0f, 1f)); -} - -fn VogelDisc_u0028_i1_u003b_i1_u003b_f1_u003b(i_4: ptr, n_1: ptr, turn: ptr) -> vec2 { - var r: f32; + let _e401 = ndc[0u]; + let _e405 = ndc[1u]; + uv_3 = vec2(((_e401 * 0.5f) + 0.5f), (0.5f - (_e405 * 0.5f))); + let _e409 = face; + let _e411 = slot; + tile_3 = vec2(f32(_e409), f32(_e411)); + let _e414 = distance_; + let _e417 = point_shadow.params[1u]; + receiver_2 = (_e414 - _e417); + let _e421 = frag_info.target_origin[0u]; + param_28 = _e421; + let _e422 = FragCoordFromTop_u0028_f1_u003b((¶m_28)); + noise = fract((52.982918f * fract(dot(_e422, vec2(0.06711056f, 0.00583715f))))); + let _e427 = noise; + angle = (_e427 * 6.2831855f); + let _e429 = angle; + ca_2 = cos(_e429); + let _e431 = angle; + sa_2 = sin(_e431); + let _e433 = (*lightIndex); + let _e437 = point_shadow.slots[_e433][2u]; + tanHalf_1 = max(_e437, 0.0001f); + blocker_1 = -1f; + let _e439 = uv_3; + param_29 = _e439; + let _e440 = tile_3; + param_30 = _e440; + let _e441 = range_3; + param_31 = _e441; + let _e442 = receiver_2; + param_32 = _e442; + let _e443 = ca_2; + param_33 = _e443; + let _e444 = sa_2; + param_34 = _e444; + let _e445 = tanHalf_1; + param_35 = _e445; + let _e446 = PointShadowPenumbra_u0028_vf2_u003b_vf2_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b((¶m_29), (¶m_30), (¶m_31), (¶m_32), (¶m_33), (¶m_34), (¶m_35), (¶m_36)); + let _e447 = param_36; + blocker_1 = _e447; + radius_1 = _e446; + let _e450 = point_shadow.params2_[3u]; + if (_e450 > 0.5f) { + g_debug_surface_on = true; + let _e452 = radius_1; + if (_e452 < 0f) { + local_7 = vec3(0f, 0f, 1f); + } else { + let _e454 = radius_1; + let _e457 = point_shadow.params2_[2u]; + let _e461 = blocker_1; + let _e462 = range_3; + local_7 = vec3(clamp((_e454 / max(_e457, 0.000001f)), 0f, 1f), clamp((_e461 / _e462), 0f, 1f), 0f); + } + let _e466 = local_7; + g_debug_surface = _e466; + } + let _e467 = radius_1; + if (_e467 < 0f) { + return 1f; + } + let _e469 = uv_3; + param_37 = _e469; + param_38 = vec2(0f, 0f); + let _e470 = tile_3; + param_39 = _e470; + let _e471 = range_3; + param_40 = _e471; + let _e472 = receiver_2; + param_41 = _e472; + let _e473 = PointShadowTap_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b_f1_u003b((¶m_37), (¶m_38), (¶m_39), (¶m_40), (¶m_41)); + lit_1 = _e473; + let _e474 = radius_1; + if (_e474 > 0f) { + i_3 = 0i; + loop { + let _e476 = i_3; + if (_e476 < 8i) { + let _e478 = i_3; + param_42 = _e478; + let _e479 = ca_2; + param_43 = _e479; + let _e480 = sa_2; + param_44 = _e480; + let _e481 = radius_1; + param_45 = _e481; + let _e482 = PointShadowOffset_u0028_i1_u003b_f1_u003b_f1_u003b_f1_u003b((¶m_42), (¶m_43), (¶m_44), (¶m_45)); + let _e483 = uv_3; + param_46 = _e483; + param_47 = _e482; + let _e484 = tile_3; + param_48 = _e484; + let _e485 = range_3; + param_49 = _e485; + let _e486 = receiver_2; + param_50 = _e486; + let _e487 = PointShadowTap_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b_f1_u003b((¶m_46), (¶m_47), (¶m_48), (¶m_49), (¶m_50)); + let _e488 = lit_1; + lit_1 = (_e488 + _e487); + continue; + } else { + break; + } + continuing { + let _e490 = i_3; + i_3 = (_e490 + 1i); + } + } + let _e492 = lit_1; + lit_1 = (_e492 * 0.11111111f); + } + let _e494 = lit_1; + let _e495 = strength; + return mix(1f, _e494, clamp(_e495, 0f, 1f)); +} + +fn VogelDisc_u0028_i1_u003b_i1_u003b_f1_u003b(i_4: ptr, n_1: ptr, turn: ptr) -> vec2 { + var r: f32; var theta: f32; - let _e191 = (*i_4); - let _e194 = (*n_1); - r = sqrt(((f32(_e191) + 0.5f) / f32(_e194))); - let _e198 = (*i_4); - let _e201 = (*turn); - theta = ((f32(_e198) * 2.3999631f) + _e201); - let _e203 = r; - let _e204 = theta; - let _e206 = theta; - return (vec2(cos(_e204), sin(_e206)) * _e203); + let _e192 = (*i_4); + let _e195 = (*n_1); + r = sqrt(((f32(_e192) + 0.5f) / f32(_e195))); + let _e199 = (*i_4); + let _e202 = (*turn); + theta = ((f32(_e199) * 2.3999631f) + _e202); + let _e204 = r; + let _e205 = theta; + let _e207 = theta; + return (vec2(cos(_e205), sin(_e207)) * _e204); } fn ShadowNoise_u0028_() -> f32 { var at: vec2; var param_51: f32; - let _e190 = frag_info.target_origin[0u]; - param_51 = _e190; - let _e191 = FragCoordFromTop_u0028_f1_u003b((¶m_51)); - let _e194 = frag_info.target_origin[3u]; - at = (_e191 + vec2((5.588238f * max(_e194, 0f)))); - let _e199 = at; - return fract((52.982918f * fract(dot(_e199, vec2(0.06711056f, 0.00583715f))))); + let _e191 = frag_info.target_origin[0u]; + param_51 = _e191; + let _e192 = FragCoordFromTop_u0028_f1_u003b((¶m_51)); + let _e195 = frag_info.target_origin[3u]; + at = (_e192 + vec2((5.588238f * max(_e195, 0f)))); + let _e200 = at; + return fract((52.982918f * fract(dot(_e200, vec2(0.06711056f, 0.00583715f))))); } fn EvsmChebyshev_u0028_vf2_u003b_f1_u003b_f1_u003b_f1_u003b(moments: ptr>, t: ptr, minVariance: ptr, bleed: ptr) -> f32 { @@ -7468,37 +7468,37 @@ fn EvsmChebyshev_u0028_vf2_u003b_f1_u003b_f1_u003b_f1_u003b(moments: ptr) -> vec2 { var d_2: f32; - let _e188 = (*depth); - d_2 = ((2f * clamp(_e188, 0f, 1f)) - 1f); - let _e192 = d_2; - let _e195 = d_2; - return vec2(exp((40f * _e192)), -(exp((-5f * _e195)))); + let _e189 = (*depth); + d_2 = ((2f * clamp(_e189, 0f, 1f)) - 1f); + let _e193 = d_2; + let _e196 = d_2; + return vec2(exp((40f * _e193)), -(exp((-5f * _e196)))); } fn EvsmVisibility_u0028_vf4_u003b_f1_u003b_f1_u003b(moments_1: ptr>, depth_1: ptr, bleed_1: ptr) -> f32 { @@ -7516,37 +7516,37 @@ fn EvsmVisibility_u0028_vf4_u003b_f1_u003b_f1_u003b(moments_1: ptr(0.004f, 0.0005f) * _e204); - let _e207 = scale[0u]; - let _e209 = scale[0u]; - let _e211 = (*moments_1); - param_53 = _e211.xy; - let _e214 = warped[0u]; - param_54 = _e214; - param_55 = (_e207 * _e209); - let _e215 = (*bleed_1); - param_56 = _e215; - let _e216 = EvsmChebyshev_u0028_vf2_u003b_f1_u003b_f1_u003b_f1_u003b((¶m_53), (¶m_54), (¶m_55), (¶m_56)); - positive = _e216; - let _e218 = scale[1u]; - let _e220 = scale[1u]; - let _e222 = (*moments_1); - param_57 = _e222.zw; - let _e225 = warped[1u]; - param_58 = _e225; - param_59 = (_e218 * _e220); - let _e226 = (*bleed_1); - param_60 = _e226; - let _e227 = EvsmChebyshev_u0028_vf2_u003b_f1_u003b_f1_u003b_f1_u003b((¶m_57), (¶m_58), (¶m_59), (¶m_60)); - negative = _e227; - let _e228 = positive; - let _e229 = negative; - return min(_e228, _e229); + let _e203 = (*depth_1); + param_52 = _e203; + let _e204 = EvsmWarp_u0028_f1_u003b((¶m_52)); + warped = _e204; + let _e205 = warped; + scale = (vec2(0.004f, 0.0005f) * _e205); + let _e208 = scale[0u]; + let _e210 = scale[0u]; + let _e212 = (*moments_1); + param_53 = _e212.xy; + let _e215 = warped[0u]; + param_54 = _e215; + param_55 = (_e208 * _e210); + let _e216 = (*bleed_1); + param_56 = _e216; + let _e217 = EvsmChebyshev_u0028_vf2_u003b_f1_u003b_f1_u003b_f1_u003b((¶m_53), (¶m_54), (¶m_55), (¶m_56)); + positive = _e217; + let _e219 = scale[1u]; + let _e221 = scale[1u]; + let _e223 = (*moments_1); + param_57 = _e223.zw; + let _e226 = warped[1u]; + param_58 = _e226; + param_59 = (_e219 * _e221); + let _e227 = (*bleed_1); + param_60 = _e227; + let _e228 = EvsmChebyshev_u0028_vf2_u003b_f1_u003b_f1_u003b_f1_u003b((¶m_57), (¶m_58), (¶m_59), (¶m_60)); + negative = _e228; + let _e229 = positive; + let _e230 = negative; + return min(_e229, _e230); } fn ShadowFactor_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_struct_u002d_LightSample_u002d_vf3_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf31_u003b_i1_u003b(s_2: ptr, light_1: ptr, lightIndex_1: ptr) -> f32 { @@ -7584,6 +7584,8 @@ fn ShadowFactor_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf var tileLo: vec2; var tileHi: vec2; var stored_2: vec4; + var y: i32; + var x: i32; var through: vec3; var softness: f32; var lit_2: f32; @@ -7591,8 +7593,8 @@ fn ShadowFactor_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf var param_61: vec4; var param_62: f32; var param_63: f32; - var y: i32; - var x: i32; + var y_1: i32; + var x_1: i32; var occluder: f32; var spread: f32; var turn_1: f32; @@ -7621,45 +7623,45 @@ fn ShadowFactor_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf var phi_3683_: bool; var phi_3690_: bool; - let _e256 = frag_info.shadow_params[3u]; - strength_1 = _e256; - let _e257 = strength_1; - if (_e257 <= 0f) { + let _e259 = frag_info.shadow_params[3u]; + strength_1 = _e259; + let _e260 = strength_1; + if (_e260 <= 0f) { return 1f; } - let _e259 = (*lightIndex_1); - let _e262 = frag_info.frame_params[2u]; - if (_e259 != i32((_e262 + 0.5f))) { + let _e262 = (*lightIndex_1); + let _e265 = frag_info.frame_params[2u]; + if (_e262 != i32((_e265 + 0.5f))) { return 1f; } - let _e268 = frag_info.shadow_cascades[2u]; - cascadeCount = i32((_e268 + 0.5f)); - let _e271 = v_world_position_1; - let _e273 = frag_info.camera_position; - viewDistance = length((_e271 - _e273.xyz)); + let _e271 = frag_info.shadow_cascades[2u]; + cascadeCount = i32((_e271 + 0.5f)); + let _e274 = v_world_position_1; + let _e276 = frag_info.camera_position; + viewDistance = length((_e274 - _e276.xyz)); cascade = 0i; - let _e277 = cascadeCount; - let _e278 = (_e277 > 1i); - phi_3504_ = _e278; - if _e278 { - let _e279 = viewDistance; - let _e282 = frag_info.shadow_cascades[0u]; - phi_3504_ = (_e279 > _e282); - } - let _e285 = phi_3504_; - if _e285 { + let _e280 = cascadeCount; + let _e281 = (_e280 > 1i); + phi_3504_ = _e281; + if _e281 { + let _e282 = viewDistance; + let _e285 = frag_info.shadow_cascades[0u]; + phi_3504_ = (_e282 > _e285); + } + let _e288 = phi_3504_; + if _e288 { cascade = 1i; } - let _e286 = cascadeCount; - let _e287 = (_e286 > 2i); - phi_3515_ = _e287; - if _e287 { - let _e288 = viewDistance; - let _e291 = frag_info.shadow_cascades[1u]; - phi_3515_ = (_e288 > _e291); + let _e289 = cascadeCount; + let _e290 = (_e289 > 2i); + phi_3515_ = _e290; + if _e290 { + let _e291 = viewDistance; + let _e294 = frag_info.shadow_cascades[1u]; + phi_3515_ = (_e291 > _e294); } - let _e294 = phi_3515_; - if _e294 { + let _e297 = phi_3515_; + if _e297 { cascade = 2i; } uv_4 = vec2(0f, 0f); @@ -7670,247 +7672,280 @@ fn ShadowFactor_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf receiverSlope = 0f; attempt = 0i; loop { - let _e295 = attempt; - if (_e295 < 3i) { - let _e297 = cascade; - let _e298 = attempt; - which = (_e297 + _e298); - let _e300 = which; - let _e301 = cascadeCount; - if (_e300 >= _e301) { + let _e298 = attempt; + if (_e298 < 3i) { + let _e300 = cascade; + let _e301 = attempt; + which = (_e300 + _e301); + let _e303 = which; + let _e304 = cascadeCount; + if (_e303 >= _e304) { break; } - let _e303 = which; - if (_e303 == 0i) { - let _e306 = frag_info.shadow_matrix; - local_8 = _e306; + let _e306 = which; + if (_e306 == 0i) { + let _e309 = frag_info.shadow_matrix; + local_8 = _e309; } else { - let _e307 = which; - if (_e307 == 1i) { - let _e310 = frag_info.shadow_matrix_far; - local_9 = _e310; + let _e310 = which; + if (_e310 == 1i) { + let _e313 = frag_info.shadow_matrix_far; + local_9 = _e313; } else { - let _e312 = frag_info.shadow_matrix_farthest; - local_9 = _e312; + let _e315 = frag_info.shadow_matrix_farthest; + local_9 = _e315; } - let _e313 = local_9; - local_8 = _e313; - } - let _e314 = local_8; - matrix = _e314; - let _e317 = matrix[0][0u]; - let _e320 = matrix[1][0u]; - let _e323 = matrix[2][0u]; - axisX = vec3(_e317, _e320, _e323); - let _e327 = matrix[0][1u]; - let _e330 = matrix[1][1u]; - let _e333 = matrix[2][1u]; - axisY = vec3(_e327, _e330, _e333); - let _e335 = axisX; - rowX = max(length(_e335), 0.000001f); - let _e338 = axisY; - rowY = max(length(_e338), 0.000001f); - let _e343 = frag_info.shadow_cascades[3u]; - let _e345 = rowX; - texelMetres = ((2f * _e343) / _e345); - let _e349 = frag_info.shadow_cascades[3u]; - let _e352 = (*s_2).n; - let _e353 = axisX; - let _e356 = rowX; - let _e357 = rowX; - let _e361 = (*s_2).n; - let _e362 = axisY; - let _e365 = rowY; - let _e366 = rowY; - reach = ((3f * _e349) * ((abs(dot(_e352, _e353)) / (_e356 * _e357)) + (abs(dot(_e361, _e362)) / (_e365 * _e366)))); - let _e373 = frag_info.shadow_params[2u]; - let _e374 = texelMetres; - flatOffset = min(_e373, _e374); - let _e376 = v_world_position_1; - let _e378 = (*s_2).n; - let _e379 = flatOffset; - let _e380 = reach; - origin_1 = (_e376 + (_e378 * (_e379 + _e380))); - let _e384 = matrix; - let _e385 = origin_1; - lightSpace = (_e384 * vec4(_e385.x, _e385.y, _e385.z, 1f)); - let _e392 = lightSpace[3u]; - if (_e392 <= 0f) { + let _e316 = local_9; + local_8 = _e316; + } + let _e317 = local_8; + matrix = _e317; + let _e320 = matrix[0][0u]; + let _e323 = matrix[1][0u]; + let _e326 = matrix[2][0u]; + axisX = vec3(_e320, _e323, _e326); + let _e330 = matrix[0][1u]; + let _e333 = matrix[1][1u]; + let _e336 = matrix[2][1u]; + axisY = vec3(_e330, _e333, _e336); + let _e338 = axisX; + rowX = max(length(_e338), 0.000001f); + let _e341 = axisY; + rowY = max(length(_e341), 0.000001f); + let _e346 = frag_info.shadow_cascades[3u]; + let _e348 = rowX; + texelMetres = ((2f * _e346) / _e348); + let _e352 = frag_info.shadow_cascades[3u]; + let _e355 = (*s_2).n; + let _e356 = axisX; + let _e359 = rowX; + let _e360 = rowX; + let _e364 = (*s_2).n; + let _e365 = axisY; + let _e368 = rowY; + let _e369 = rowY; + reach = ((3f * _e352) * ((abs(dot(_e355, _e356)) / (_e359 * _e360)) + (abs(dot(_e364, _e365)) / (_e368 * _e369)))); + let _e376 = frag_info.shadow_params[2u]; + let _e377 = texelMetres; + flatOffset = min(_e376, _e377); + let _e379 = v_world_position_1; + let _e381 = (*s_2).n; + let _e382 = flatOffset; + let _e383 = reach; + origin_1 = (_e379 + (_e381 * (_e382 + _e383))); + let _e387 = matrix; + let _e388 = origin_1; + lightSpace = (_e387 * vec4(_e388.x, _e388.y, _e388.z, 1f)); + let _e395 = lightSpace[3u]; + if (_e395 <= 0f) { continue; } - let _e394 = lightSpace; - let _e397 = lightSpace[3u]; - candidate = (_e394.xyz / vec3(_e397)); - let _e401 = candidate[0u]; - let _e405 = candidate[1u]; - inTile = vec2(((_e401 * 0.5f) + 0.5f), (0.5f - (_e405 * 0.5f))); - let _e410 = inTile[0u]; - let _e411 = (_e410 < 0f); - phi_3676_ = _e411; - if !(_e411) { - let _e414 = inTile[0u]; - phi_3676_ = (_e414 > 1f); - } - let _e417 = phi_3676_; - phi_3683_ = _e417; - if !(_e417) { - let _e420 = inTile[1u]; - phi_3683_ = (_e420 < 0f); - } - let _e423 = phi_3683_; - phi_3690_ = _e423; - if !(_e423) { - let _e426 = inTile[1u]; - phi_3690_ = (_e426 > 1f); - } - let _e429 = phi_3690_; - if _e429 { + let _e397 = lightSpace; + let _e400 = lightSpace[3u]; + candidate = (_e397.xyz / vec3(_e400)); + let _e404 = candidate[0u]; + let _e408 = candidate[1u]; + inTile = vec2(((_e404 * 0.5f) + 0.5f), (0.5f - (_e408 * 0.5f))); + let _e413 = inTile[0u]; + let _e414 = (_e413 < 0f); + phi_3676_ = _e414; + if !(_e414) { + let _e417 = inTile[0u]; + phi_3676_ = (_e417 > 1f); + } + let _e420 = phi_3676_; + phi_3683_ = _e420; + if !(_e420) { + let _e423 = inTile[1u]; + phi_3683_ = (_e423 < 0f); + } + let _e426 = phi_3683_; + phi_3690_ = _e426; + if !(_e426) { + let _e429 = inTile[1u]; + phi_3690_ = (_e429 > 1f); + } + let _e432 = phi_3690_; + if _e432 { continue; } - let _e431 = candidate[2u]; - if (_e431 > 1f) { - let _e433 = which; - let _e434 = cascadeCount; - if (_e433 < (_e434 - 1i)) { + let _e434 = candidate[2u]; + if (_e434 > 1f) { + let _e436 = which; + let _e437 = cascadeCount; + if (_e436 < (_e437 - 1i)) { continue; } candidate[2u] = 1f; } - let _e439 = inTile[0u]; - let _e440 = which; - let _e443 = cascadeCount; - let _e447 = inTile[1u]; - uv_4 = vec2(((_e439 + f32(_e440)) / f32(_e443)), _e447); - let _e449 = candidate; - projected = _e449; - let _e450 = which; - cascade = _e450; - let _e451 = texelMetres; - cascadeTexel = _e451; - let _e454 = matrix[0][2u]; - let _e457 = matrix[1][2u]; - let _e460 = matrix[2][2u]; - cascadeDepth = (1f / max(length(vec3(_e454, _e457, _e460)), 0.000001f)); - let _e466 = (*s_2).n; - let _e469 = matrix[0][2u]; - let _e472 = matrix[1][2u]; - let _e475 = matrix[2][2u]; - let _e479 = cascadeDepth; - cosSlope = clamp((abs(dot(_e466, vec3(_e469, _e472, _e475))) * _e479), 0.1f, 1f); - let _e482 = texelMetres; - let _e483 = cosSlope; - let _e484 = cosSlope; - let _e490 = cosSlope; - let _e492 = cascadeDepth; - receiverSlope = (((_e482 * sqrt(max((1f - (_e483 * _e484)), 0f))) / _e490) / _e492); + let _e442 = inTile[0u]; + let _e443 = which; + let _e446 = cascadeCount; + let _e450 = inTile[1u]; + uv_4 = vec2(((_e442 + f32(_e443)) / f32(_e446)), _e450); + let _e452 = candidate; + projected = _e452; + let _e453 = which; + cascade = _e453; + let _e454 = texelMetres; + cascadeTexel = _e454; + let _e457 = matrix[0][2u]; + let _e460 = matrix[1][2u]; + let _e463 = matrix[2][2u]; + cascadeDepth = (1f / max(length(vec3(_e457, _e460, _e463)), 0.000001f)); + let _e469 = (*s_2).n; + let _e472 = matrix[0][2u]; + let _e475 = matrix[1][2u]; + let _e478 = matrix[2][2u]; + let _e482 = cascadeDepth; + cosSlope = clamp((abs(dot(_e469, vec3(_e472, _e475, _e478))) * _e482), 0.1f, 1f); + let _e485 = texelMetres; + let _e486 = cosSlope; + let _e487 = cosSlope; + let _e493 = cosSlope; + let _e495 = cascadeDepth; + receiverSlope = (((_e485 * sqrt(max((1f - (_e486 * _e487)), 0f))) / _e493) / _e495); found = true; break; } else { break; } continuing { - let _e494 = attempt; - attempt = (_e494 + 1i); + let _e497 = attempt; + attempt = (_e497 + 1i); } } - let _e496 = found; - if !(_e496) { + let _e499 = found; + if !(_e499) { return 1f; } - let _e498 = cascade; - if (_e498 == 0i) { - let _e502 = frag_info.shadow_bias[0u]; - local_10 = _e502; + let _e501 = cascade; + if (_e501 == 0i) { + let _e505 = frag_info.shadow_bias[0u]; + local_10 = _e505; } else { - let _e503 = cascade; - if (_e503 == 1i) { - let _e507 = frag_info.shadow_bias[1u]; - local_11 = _e507; - } else { - let _e510 = frag_info.shadow_bias[2u]; + let _e506 = cascade; + if (_e506 == 1i) { + let _e510 = frag_info.shadow_bias[1u]; local_11 = _e510; - } - let _e511 = local_11; - local_10 = _e511; - } - let _e512 = local_10; - bias = _e512; - let _e515 = frag_info.shadow_params[0u]; - let _e518 = frag_info.shadow_cascades[3u]; - texel_1 = vec2(_e515, _e518); - let _e520 = cascade; - let _e522 = cascadeCount; - let _e526 = texel_1; - tileLo = (vec2((f32(_e520) / f32(_e522)), 0f) + (_e526 * 0.5f)); - let _e529 = cascade; - let _e532 = cascadeCount; - let _e536 = texel_1; - tileHi = (vec2((f32((_e529 + 1i)) / f32(_e532)), 1f) - (_e536 * 0.5f)); - let _e541 = frag_info.shadow_bias[3u]; - if (_e541 > 0.5f) { - let _e543 = uv_4; - let _e544 = tileLo; - let _e545 = tileHi; - let _e547 = textureSampleLevel(shadow_texture_tex, shadow_texture_smp, clamp(_e543, _e544, _e545), 0f); - stored_2 = _e547; - let _e549 = stored_2[1u]; - let _e552 = stored_2[2u]; - let _e555 = stored_2[3u]; - through = clamp(vec3((1f - _e549), (1f - _e552), _e555), vec3(0f), vec3(4f)); - let _e560 = through; - let _e561 = strength_1; - light_transmittance = mix(vec3(1f, 1f, 1f), _e560, vec3(clamp(_e561, 0f, 1f))); - } - let _e567 = frag_info.ambient_ground[3u]; - softness = _e567; + } else { + let _e513 = frag_info.shadow_bias[2u]; + local_11 = _e513; + } + let _e514 = local_11; + local_10 = _e514; + } + let _e515 = local_10; + bias = _e515; + let _e518 = frag_info.shadow_params[0u]; + let _e521 = frag_info.shadow_cascades[3u]; + texel_1 = vec2(_e518, _e521); + let _e523 = cascade; + let _e525 = cascadeCount; + let _e529 = texel_1; + tileLo = (vec2((f32(_e523) / f32(_e525)), 0f) + (_e529 * 0.5f)); + let _e532 = cascade; + let _e535 = cascadeCount; + let _e539 = texel_1; + tileHi = (vec2((f32((_e532 + 1i)) / f32(_e535)), 1f) - (_e539 * 0.5f)); + let _e544 = frag_info.shadow_bias[3u]; + if (_e544 > 0.5f) { + stored_2 = vec4(0f, 0f, 0f, 0f); + y = -1i; + loop { + let _e546 = y; + if (_e546 <= 1i) { + x = -1i; + loop { + let _e548 = x; + if (_e548 <= 1i) { + let _e550 = uv_4; + let _e551 = x; + let _e553 = y; + let _e556 = texel_1; + let _e559 = tileLo; + let _e560 = tileHi; + let _e562 = textureSampleLevel(shadow_texture_tex, shadow_texture_smp, clamp((_e550 + (vec2(f32(_e551), f32(_e553)) * _e556)), _e559, _e560), 0f); + let _e563 = stored_2; + stored_2 = (_e563 + _e562); + continue; + } else { + break; + } + continuing { + let _e565 = x; + x = (_e565 + 1i); + } + } + continue; + } else { + break; + } + continuing { + let _e567 = y; + y = (_e567 + 1i); + } + } + let _e569 = stored_2; + stored_2 = (_e569 * 0.11111111f); + let _e572 = stored_2[1u]; + let _e575 = stored_2[2u]; + let _e578 = stored_2[3u]; + through = clamp(vec3((1f - _e572), (1f - _e575), _e578), vec3(0f), vec3(4f)); + let _e583 = through; + let _e584 = strength_1; + light_transmittance = mix(vec3(1f, 1f, 1f), _e583, vec3(clamp(_e584, 0f, 1f))); + } + let _e590 = frag_info.ambient_ground[3u]; + softness = _e590; lit_2 = 0f; - let _e568 = softness; - if (_e568 < 0f) { - let _e570 = uv_4; - let _e571 = tileLo; - let _e572 = tileHi; - let _e574 = textureSampleLevel(shadow_texture_tex, shadow_texture_smp, clamp(_e570, _e571, _e572), 0f); - moments_2 = _e574; - let _e576 = projected[2u]; - let _e577 = bias; - let _e579 = softness; - let _e583 = moments_2; - param_61 = _e583; - param_62 = (_e576 - _e577); - param_63 = clamp((-(_e579) - 1f), 0f, 0.95f); - let _e584 = EvsmVisibility_u0028_vf4_u003b_f1_u003b_f1_u003b((¶m_61), (¶m_62), (¶m_63)); - lit_2 = _e584; - } else { - let _e585 = softness; - if (_e585 <= 0f) { - y = -1i; + let _e591 = softness; + if (_e591 < 0f) { + let _e593 = uv_4; + let _e594 = tileLo; + let _e595 = tileHi; + let _e597 = textureSampleLevel(shadow_texture_tex, shadow_texture_smp, clamp(_e593, _e594, _e595), 0f); + moments_2 = _e597; + let _e599 = projected[2u]; + let _e600 = bias; + let _e602 = softness; + let _e606 = moments_2; + param_61 = _e606; + param_62 = (_e599 - _e600); + param_63 = clamp((-(_e602) - 1f), 0f, 0.95f); + let _e607 = EvsmVisibility_u0028_vf4_u003b_f1_u003b_f1_u003b((¶m_61), (¶m_62), (¶m_63)); + lit_2 = _e607; + } else { + let _e608 = softness; + if (_e608 <= 0f) { + y_1 = -1i; loop { - let _e587 = y; - if (_e587 <= 1i) { - x = -1i; + let _e610 = y_1; + if (_e610 <= 1i) { + x_1 = -1i; loop { - let _e589 = x; - if (_e589 <= 1i) { - let _e591 = uv_4; - let _e592 = x; - let _e594 = y; - let _e597 = texel_1; - let _e600 = tileLo; - let _e601 = tileHi; - let _e603 = textureSampleLevel(shadow_texture_tex, shadow_texture_smp, clamp((_e591 + (vec2(f32(_e592), f32(_e594)) * _e597)), _e600, _e601), 0f); - occluder = _e603.x; - let _e606 = projected[2u]; - let _e607 = bias; - let _e609 = occluder; - let _e612 = lit_2; - lit_2 = (_e612 + select(1f, 0f, ((_e606 - _e607) > _e609))); + let _e612 = x_1; + if (_e612 <= 1i) { + let _e614 = uv_4; + let _e615 = x_1; + let _e617 = y_1; + let _e620 = texel_1; + let _e623 = tileLo; + let _e624 = tileHi; + let _e626 = textureSampleLevel(shadow_texture_tex, shadow_texture_smp, clamp((_e614 + (vec2(f32(_e615), f32(_e617)) * _e620)), _e623, _e624), 0f); + occluder = _e626.x; + let _e629 = projected[2u]; + let _e630 = bias; + let _e632 = occluder; + let _e635 = lit_2; + lit_2 = (_e635 + select(1f, 0f, ((_e629 - _e630) > _e632))); continue; } else { break; } continuing { - let _e614 = x; - x = (_e614 + 1i); + let _e637 = x_1; + x_1 = (_e637 + 1i); } } continue; @@ -7918,125 +7953,125 @@ fn ShadowFactor_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf break; } continuing { - let _e616 = y; - y = (_e616 + 1i); + let _e639 = y_1; + y_1 = (_e639 + 1i); } } - let _e618 = lit_2; - lit_2 = (_e618 * 0.11111111f); + let _e641 = lit_2; + lit_2 = (_e641 * 0.11111111f); } else { - let _e620 = softness; - spread = tan(min(_e620, 0.5f)); - let _e623 = ShadowNoise_u0028_(); - turn_1 = (_e623 * 6.2831855f); - let _e625 = spread; - let _e627 = projected[2u]; - let _e629 = cascadeDepth; - let _e631 = cascadeTexel; - searchRadius = clamp((((_e625 * _e627) * _e629) / _e631), 1f, 16f); + let _e643 = softness; + spread = tan(min(_e643, 0.5f)); + let _e646 = ShadowNoise_u0028_(); + turn_1 = (_e646 * 6.2831855f); + let _e648 = spread; + let _e650 = projected[2u]; + let _e652 = cascadeDepth; + let _e654 = cascadeTexel; + searchRadius = clamp((((_e648 * _e650) * _e652) / _e654), 1f, 16f); blockerSum = 0f; blockerCount = 0f; i_5 = 0i; loop { - let _e634 = i_5; - if (_e634 < 16i) { - let _e636 = i_5; - param_64 = _e636; + let _e657 = i_5; + if (_e657 < 16i) { + let _e659 = i_5; + param_64 = _e659; param_65 = 16i; - let _e637 = turn_1; - param_66 = _e637; - let _e638 = VogelDisc_u0028_i1_u003b_i1_u003b_f1_u003b((¶m_64), (¶m_65), (¶m_66)); - disc = _e638; - let _e639 = bias; - let _e640 = disc; - let _e642 = searchRadius; - let _e646 = receiverSlope; - tapBias = (_e639 + (max(((length(_e640) * _e642) - 1.5f), 0f) * _e646)); - let _e649 = uv_4; - let _e650 = disc; - let _e651 = texel_1; - let _e653 = searchRadius; - let _e656 = tileLo; - let _e657 = tileHi; - let _e659 = textureSampleLevel(shadow_texture_tex, shadow_texture_smp, clamp((_e649 + ((_e650 * _e651) * _e653)), _e656, _e657), 0f); - occluder_1 = _e659.x; - let _e662 = projected[2u]; - let _e663 = tapBias; - let _e665 = occluder_1; - if ((_e662 - _e663) > _e665) { - let _e667 = occluder_1; - let _e668 = blockerSum; - blockerSum = (_e668 + _e667); - let _e670 = blockerCount; - blockerCount = (_e670 + 1f); + let _e660 = turn_1; + param_66 = _e660; + let _e661 = VogelDisc_u0028_i1_u003b_i1_u003b_f1_u003b((¶m_64), (¶m_65), (¶m_66)); + disc = _e661; + let _e662 = bias; + let _e663 = disc; + let _e665 = searchRadius; + let _e669 = receiverSlope; + tapBias = (_e662 + (max(((length(_e663) * _e665) - 1.5f), 0f) * _e669)); + let _e672 = uv_4; + let _e673 = disc; + let _e674 = texel_1; + let _e676 = searchRadius; + let _e679 = tileLo; + let _e680 = tileHi; + let _e682 = textureSampleLevel(shadow_texture_tex, shadow_texture_smp, clamp((_e672 + ((_e673 * _e674) * _e676)), _e679, _e680), 0f); + occluder_1 = _e682.x; + let _e685 = projected[2u]; + let _e686 = tapBias; + let _e688 = occluder_1; + if ((_e685 - _e686) > _e688) { + let _e690 = occluder_1; + let _e691 = blockerSum; + blockerSum = (_e691 + _e690); + let _e693 = blockerCount; + blockerCount = (_e693 + 1f); } continue; } else { break; } continuing { - let _e672 = i_5; - i_5 = (_e672 + 1i); + let _e695 = i_5; + i_5 = (_e695 + 1i); } } - let _e674 = blockerCount; - if (_e674 <= 0f) { + let _e697 = blockerCount; + if (_e697 <= 0f) { return 1f; } - let _e677 = projected[2u]; - let _e678 = blockerSum; - let _e679 = blockerCount; - let _e683 = cascadeDepth; - gap = (max((_e677 - (_e678 / _e679)), 0f) * _e683); - let _e685 = spread; - let _e686 = gap; - let _e688 = cascadeTexel; - radius_2 = clamp(((_e685 * _e686) / _e688), 1f, 16f); + let _e700 = projected[2u]; + let _e701 = blockerSum; + let _e702 = blockerCount; + let _e706 = cascadeDepth; + gap = (max((_e700 - (_e701 / _e702)), 0f) * _e706); + let _e708 = spread; + let _e709 = gap; + let _e711 = cascadeTexel; + radius_2 = clamp(((_e708 * _e709) / _e711), 1f, 16f); i_6 = 0i; loop { - let _e691 = i_6; - if (_e691 < 16i) { - let _e693 = turn_1; - let _e695 = i_6; - param_67 = _e695; + let _e714 = i_6; + if (_e714 < 16i) { + let _e716 = turn_1; + let _e718 = i_6; + param_67 = _e718; param_68 = 16i; - param_69 = (_e693 + 1f); - let _e696 = VogelDisc_u0028_i1_u003b_i1_u003b_f1_u003b((¶m_67), (¶m_68), (¶m_69)); - disc_1 = _e696; - let _e697 = bias; - let _e698 = disc_1; - let _e700 = radius_2; - let _e704 = receiverSlope; - tapBias_1 = (_e697 + (max(((length(_e698) * _e700) - 1.5f), 0f) * _e704)); - let _e707 = uv_4; - let _e708 = disc_1; - let _e709 = texel_1; - let _e711 = radius_2; - let _e714 = tileLo; - let _e715 = tileHi; - let _e717 = textureSampleLevel(shadow_texture_tex, shadow_texture_smp, clamp((_e707 + ((_e708 * _e709) * _e711)), _e714, _e715), 0f); - occluder_2 = _e717.x; - let _e720 = projected[2u]; - let _e721 = tapBias_1; - let _e723 = occluder_2; - let _e726 = lit_2; - lit_2 = (_e726 + select(1f, 0f, ((_e720 - _e721) > _e723))); + param_69 = (_e716 + 1f); + let _e719 = VogelDisc_u0028_i1_u003b_i1_u003b_f1_u003b((¶m_67), (¶m_68), (¶m_69)); + disc_1 = _e719; + let _e720 = bias; + let _e721 = disc_1; + let _e723 = radius_2; + let _e727 = receiverSlope; + tapBias_1 = (_e720 + (max(((length(_e721) * _e723) - 1.5f), 0f) * _e727)); + let _e730 = uv_4; + let _e731 = disc_1; + let _e732 = texel_1; + let _e734 = radius_2; + let _e737 = tileLo; + let _e738 = tileHi; + let _e740 = textureSampleLevel(shadow_texture_tex, shadow_texture_smp, clamp((_e730 + ((_e731 * _e732) * _e734)), _e737, _e738), 0f); + occluder_2 = _e740.x; + let _e743 = projected[2u]; + let _e744 = tapBias_1; + let _e746 = occluder_2; + let _e749 = lit_2; + lit_2 = (_e749 + select(1f, 0f, ((_e743 - _e744) > _e746))); continue; } else { break; } continuing { - let _e728 = i_6; - i_6 = (_e728 + 1i); + let _e751 = i_6; + i_6 = (_e751 + 1i); } } - let _e730 = lit_2; - lit_2 = (_e730 * 0.0625f); + let _e753 = lit_2; + lit_2 = (_e753 * 0.0625f); } } - let _e732 = lit_2; - let _e733 = strength_1; - return mix(1f, _e732, clamp(_e733, 0f, 1f)); + let _e755 = lit_2; + let _e756 = strength_1; + return mix(1f, _e755, clamp(_e756, 0f, 1f)); } fn LightVisibility_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_struct_u002d_LightSample_u002d_vf3_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf31_u003b_i1_u003b(s_3: ptr, light_2: ptr, index: ptr) -> f32 { @@ -8044,19 +8079,19 @@ fn LightVisibility_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d var param_71: LightSample; var param_72: i32; - let _e192 = (*s_3); - param_70 = _e192; - let _e193 = (*light_2); - param_71 = _e193; - let _e194 = (*index); - param_72 = _e194; - let _e195 = ShadowFactor_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_struct_u002d_LightSample_u002d_vf3_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf31_u003b_i1_u003b((¶m_70), (¶m_71), (¶m_72)); - return _e195; + let _e193 = (*s_3); + param_70 = _e193; + let _e194 = (*light_2); + param_71 = _e194; + let _e195 = (*index); + param_72 = _e195; + let _e196 = ShadowFactor_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_struct_u002d_LightSample_u002d_vf3_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf31_u003b_i1_u003b((¶m_70), (¶m_71), (¶m_72)); + return _e196; } fn LightHasShadow_u0028_i1_u003b(index_1: ptr) -> bool { - let _e187 = (*index_1); - return (_e187 < 8i); + let _e188 = (*index_1); + return (_e188 < 8i); } fn PunctualAttenuation_u0028_f1_u003b_f1_u003b(distance_1: ptr, range_4: ptr) -> f32 { @@ -8064,26 +8099,26 @@ fn PunctualAttenuation_u0028_f1_u003b_f1_u003b(distance_1: ptr, r var ratio: f32; var window: f32; - let _e191 = (*distance_1); let _e192 = (*distance_1); - attenuation = (1f / max((_e191 * _e192), 0.0001f)); - let _e196 = (*range_4); - if (_e196 > 0f) { - let _e198 = (*distance_1); - let _e199 = (*range_4); - ratio = (_e198 / _e199); - let _e201 = ratio; + let _e193 = (*distance_1); + attenuation = (1f / max((_e192 * _e193), 0.0001f)); + let _e197 = (*range_4); + if (_e197 > 0f) { + let _e199 = (*distance_1); + let _e200 = (*range_4); + ratio = (_e199 / _e200); let _e202 = ratio; - let _e204 = ratio; - let _e206 = ratio; - window = clamp((1f - (((_e201 * _e202) * _e204) * _e206)), 0f, 1f); - let _e210 = window; + let _e203 = ratio; + let _e205 = ratio; + let _e207 = ratio; + window = clamp((1f - (((_e202 * _e203) * _e205) * _e207)), 0f, 1f); let _e211 = window; - let _e213 = attenuation; - attenuation = (_e213 * (_e210 * _e211)); + let _e212 = window; + let _e214 = attenuation; + attenuation = (_e214 * (_e211 * _e212)); } - let _e215 = attenuation; - return _e215; + let _e216 = attenuation; + return _e216; } fn RectangleClosestPoint_u0028_vf3_u003b_vf3_u003b_vf3_u003b_vf3_u003b_vf3_u003b(centre: ptr>, halfWidth: ptr>, halfHeight: ptr>, world_2: ptr>, mirror: ptr>) -> vec3 { @@ -8100,75 +8135,75 @@ fn RectangleClosestPoint_u0028_vf3_u003b_vf3_u003b_vf3_u003b_vf3_u003b_vf3_u003b var u: f32; var v: f32; - let _e203 = (*halfWidth); - let _e204 = (*halfHeight); - n_2 = cross(_e203, _e204); - let _e206 = n_2; - nLen = length(_e206); - let _e208 = nLen; - if (_e208 < 0.000000000001f) { - let _e210 = (*centre); - return _e210; + let _e204 = (*halfWidth); + let _e205 = (*halfHeight); + n_2 = cross(_e204, _e205); + let _e207 = n_2; + nLen = length(_e207); + let _e209 = nLen; + if (_e209 < 0.000000000001f) { + let _e211 = (*centre); + return _e211; } - let _e211 = nLen; - let _e212 = n_2; - n_2 = (_e212 / vec3(_e211)); - let _e215 = (*centre); - let _e216 = (*world_2); - toPlane = (_e215 - _e216); - let _e218 = (*mirror); - let _e219 = n_2; - denom = dot(_e218, _e219); - let _e221 = denom; - if (abs(_e221) < 0.00001f) { - let _e224 = toPlane; - let _e225 = n_2; - let _e226 = toPlane; - let _e227 = n_2; - onPlane = (_e224 - (_e225 * dot(_e226, _e227))); - } else { - let _e231 = toPlane; - let _e232 = n_2; - let _e234 = denom; - t_1 = (dot(_e231, _e232) / _e234); - let _e236 = t_1; - if (_e236 > 0f) { - let _e238 = (*mirror); - let _e239 = t_1; - local_12 = (_e238 * _e239); + let _e212 = nLen; + let _e213 = n_2; + n_2 = (_e213 / vec3(_e212)); + let _e216 = (*centre); + let _e217 = (*world_2); + toPlane = (_e216 - _e217); + let _e219 = (*mirror); + let _e220 = n_2; + denom = dot(_e219, _e220); + let _e222 = denom; + if (abs(_e222) < 0.00001f) { + let _e225 = toPlane; + let _e226 = n_2; + let _e227 = toPlane; + let _e228 = n_2; + onPlane = (_e225 - (_e226 * dot(_e227, _e228))); + } else { + let _e232 = toPlane; + let _e233 = n_2; + let _e235 = denom; + t_1 = (dot(_e232, _e233) / _e235); + let _e237 = t_1; + if (_e237 > 0f) { + let _e239 = (*mirror); + let _e240 = t_1; + local_12 = (_e239 * _e240); } else { - let _e241 = toPlane; - let _e242 = n_2; - let _e243 = toPlane; - let _e244 = n_2; - local_12 = (_e241 - (_e242 * dot(_e243, _e244))); + let _e242 = toPlane; + let _e243 = n_2; + let _e244 = toPlane; + let _e245 = n_2; + local_12 = (_e242 - (_e243 * dot(_e244, _e245))); } - let _e248 = local_12; - onPlane = _e248; + let _e249 = local_12; + onPlane = _e249; } - let _e249 = onPlane; - let _e250 = toPlane; - offset_2 = (_e249 - _e250); - let _e252 = (*halfWidth); + let _e250 = onPlane; + let _e251 = toPlane; + offset_2 = (_e250 - _e251); let _e253 = (*halfWidth); - wLen2_ = max(dot(_e252, _e253), 0.000000000001f); - let _e256 = (*halfHeight); + let _e254 = (*halfWidth); + wLen2_ = max(dot(_e253, _e254), 0.000000000001f); let _e257 = (*halfHeight); - hLen2_ = max(dot(_e256, _e257), 0.000000000001f); - let _e260 = offset_2; - let _e261 = (*halfWidth); - let _e263 = wLen2_; - u = clamp((dot(_e260, _e261) / _e263), -1f, 1f); - let _e266 = offset_2; - let _e267 = (*halfHeight); - let _e269 = hLen2_; - v = clamp((dot(_e266, _e267) / _e269), -1f, 1f); - let _e272 = (*centre); - let _e273 = (*halfWidth); - let _e274 = u; - let _e277 = (*halfHeight); - let _e278 = v; - return ((_e272 + (_e273 * _e274)) + (_e277 * _e278)); + let _e258 = (*halfHeight); + hLen2_ = max(dot(_e257, _e258), 0.000000000001f); + let _e261 = offset_2; + let _e262 = (*halfWidth); + let _e264 = wLen2_; + u = clamp((dot(_e261, _e262) / _e264), -1f, 1f); + let _e267 = offset_2; + let _e268 = (*halfHeight); + let _e270 = hLen2_; + v = clamp((dot(_e267, _e268) / _e270), -1f, 1f); + let _e273 = (*centre); + let _e274 = (*halfWidth); + let _e275 = u; + let _e278 = (*halfHeight); + let _e279 = v; + return ((_e273 + (_e274 * _e275)) + (_e278 * _e279)); } fn LambertEdge_u0028_vf3_u003b_vf3_u003b_vf3_u003b(a_1: ptr>, b: ptr>, n_3: ptr>) -> f32 { @@ -8179,32 +8214,32 @@ fn LambertEdge_u0028_vf3_u003b_vf3_u003b_vf3_u003b(a_1: ptr> var len: f32; var local_13: f32; - let _e195 = (*a_1); let _e196 = (*a_1); - ua = (_e195 / vec3(max(length(_e196), 0.000000000001f))); - let _e201 = (*b); + let _e197 = (*a_1); + ua = (_e196 / vec3(max(length(_e197), 0.000000000001f))); let _e202 = (*b); - ub = (_e201 / vec3(max(length(_e202), 0.000000000001f))); - let _e207 = ua; - let _e208 = ub; - angle_1 = acos(clamp(dot(_e207, _e208), -1f, 1f)); - let _e212 = ua; - let _e213 = ub; - axis = cross(_e212, _e213); - let _e215 = axis; - len = length(_e215); - let _e217 = len; - if (_e217 > 0.000001f) { - let _e219 = angle_1; - let _e220 = axis; - let _e221 = (*n_3); - let _e224 = len; - local_13 = ((_e219 * dot(_e220, _e221)) / _e224); + let _e203 = (*b); + ub = (_e202 / vec3(max(length(_e203), 0.000000000001f))); + let _e208 = ua; + let _e209 = ub; + angle_1 = acos(clamp(dot(_e208, _e209), -1f, 1f)); + let _e213 = ua; + let _e214 = ub; + axis = cross(_e213, _e214); + let _e216 = axis; + len = length(_e216); + let _e218 = len; + if (_e218 > 0.000001f) { + let _e220 = angle_1; + let _e221 = axis; + let _e222 = (*n_3); + let _e225 = len; + local_13 = ((_e220 * dot(_e221, _e222)) / _e225); } else { local_13 = 0f; } - let _e226 = local_13; - return _e226; + let _e227 = local_13; + return _e227; } fn RectangleFormFactor_u0028_vf3_u005b_4_u005d_u003b_vf3_u003b(corners: ptr, 4>>, n_4: ptr>) -> f32 { @@ -8235,98 +8270,98 @@ fn RectangleFormFactor_u0028_vf3_u005b_4_u005d_u003b_vf3_u003b(corners: ptr(0f, 0f, 0f); i_7 = 0i; loop { - let _e209 = i_7; - if (_e209 < 4i) { - let _e211 = i_7; - let _e213 = (*corners)[_e211]; - a_2 = _e213; - let _e214 = i_7; - if (_e214 == 3i) { + let _e210 = i_7; + if (_e210 < 4i) { + let _e212 = i_7; + let _e214 = (*corners)[_e212]; + a_2 = _e214; + let _e215 = i_7; + if (_e215 == 3i) { local_14 = 0i; } else { - let _e216 = i_7; - local_14 = (_e216 + 1i); - } - let _e218 = local_14; - let _e220 = (*corners)[_e218]; - b_1 = _e220; - let _e221 = a_2; - let _e222 = (*n_4); - ha = dot(_e221, _e222); - let _e224 = b_1; - let _e225 = (*n_4); - hb = dot(_e224, _e225); - let _e227 = ha; - let _e228 = hb; - d_3 = (_e227 - _e228); - let _e230 = a_2; - let _e231 = b_1; - let _e232 = a_2; - let _e234 = d_3; - if (abs(_e234) > 0.000000000001f) { - let _e237 = ha; - let _e238 = d_3; - local_15 = (_e237 / _e238); + let _e217 = i_7; + local_14 = (_e217 + 1i); + } + let _e219 = local_14; + let _e221 = (*corners)[_e219]; + b_1 = _e221; + let _e222 = a_2; + let _e223 = (*n_4); + ha = dot(_e222, _e223); + let _e225 = b_1; + let _e226 = (*n_4); + hb = dot(_e225, _e226); + let _e228 = ha; + let _e229 = hb; + d_3 = (_e228 - _e229); + let _e231 = a_2; + let _e232 = b_1; + let _e233 = a_2; + let _e235 = d_3; + if (abs(_e235) > 0.000000000001f) { + let _e238 = ha; + let _e239 = d_3; + local_15 = (_e238 / _e239); } else { local_15 = 0f; } - let _e240 = local_15; - q = (_e230 + ((_e231 - _e232) * _e240)); - let _e243 = ha; - aAbove = (_e243 > 0f); - let _e245 = hb; - bAbove = (_e245 > 0f); - let _e247 = aAbove; - let _e248 = bAbove; - if (_e247 || _e248) { - let _e250 = aAbove; - let _e251 = a_2; - let _e252 = q; - let _e255 = bAbove; - let _e256 = b_1; - let _e257 = q; - param_73 = select(_e252, _e251, vec3(_e250)); - param_74 = select(_e257, _e256, vec3(_e255)); - let _e260 = (*n_4); - param_75 = _e260; - let _e261 = LambertEdge_u0028_vf3_u003b_vf3_u003b_vf3_u003b((¶m_73), (¶m_74), (¶m_75)); - local_16 = _e261; + let _e241 = local_15; + q = (_e231 + ((_e232 - _e233) * _e241)); + let _e244 = ha; + aAbove = (_e244 > 0f); + let _e246 = hb; + bAbove = (_e246 > 0f); + let _e248 = aAbove; + let _e249 = bAbove; + if (_e248 || _e249) { + let _e251 = aAbove; + let _e252 = a_2; + let _e253 = q; + let _e256 = bAbove; + let _e257 = b_1; + let _e258 = q; + param_73 = select(_e253, _e252, vec3(_e251)); + param_74 = select(_e258, _e257, vec3(_e256)); + let _e261 = (*n_4); + param_75 = _e261; + let _e262 = LambertEdge_u0028_vf3_u003b_vf3_u003b_vf3_u003b((¶m_73), (¶m_74), (¶m_75)); + local_16 = _e262; } else { local_16 = 0f; } - let _e262 = local_16; - let _e263 = total; - total = (_e263 + _e262); - let _e265 = aAbove; - let _e266 = bAbove; - let _e269 = q; - let _e270 = exit; - exit = select(_e270, _e269, vec3((_e265 && !(_e266)))); - let _e273 = aAbove; - let _e275 = bAbove; - let _e277 = q; - let _e278 = entry; - entry = select(_e278, _e277, vec3((!(_e273) && _e275))); + let _e263 = local_16; + let _e264 = total; + total = (_e264 + _e263); + let _e266 = aAbove; + let _e267 = bAbove; + let _e270 = q; + let _e271 = exit; + exit = select(_e271, _e270, vec3((_e266 && !(_e267)))); + let _e274 = aAbove; + let _e276 = bAbove; + let _e278 = q; + let _e279 = entry; + entry = select(_e279, _e278, vec3((!(_e274) && _e276))); continue; } else { break; } continuing { - let _e281 = i_7; - i_7 = (_e281 + 1i); - } - } - let _e283 = exit; - param_76 = _e283; - let _e284 = entry; - param_77 = _e284; - let _e285 = (*n_4); - param_78 = _e285; - let _e286 = LambertEdge_u0028_vf3_u003b_vf3_u003b_vf3_u003b((¶m_76), (¶m_77), (¶m_78)); - let _e287 = total; - total = (_e287 + _e286); - let _e289 = total; - return max((-(_e289) * 0.5f), 0f); + let _e282 = i_7; + i_7 = (_e282 + 1i); + } + } + let _e284 = exit; + param_76 = _e284; + let _e285 = entry; + param_77 = _e285; + let _e286 = (*n_4); + param_78 = _e286; + let _e287 = LambertEdge_u0028_vf3_u003b_vf3_u003b_vf3_u003b((¶m_76), (¶m_77), (¶m_78)); + let _e288 = total; + total = (_e288 + _e287); + let _e290 = total; + return max((-(_e290) * 0.5f), 0f); } fn LightListLane_u0028_vf4_u003b_i1_u003b(four: ptr>, slot_1: ptr) -> f32 { @@ -8335,91 +8370,91 @@ fn LightListLane_u0028_vf4_u003b_i1_u003b(four: ptr>, slot_1 var local_18: f32; var local_19: f32; - let _e192 = (*slot_1); let _e193 = (*slot_1); - lane = (_e192 - ((_e193 / 4i) * 4i)); - let _e197 = lane; - if (_e197 == 0i) { - let _e200 = (*four)[0u]; - local_17 = _e200; - } else { - let _e201 = lane; - if (_e201 == 1i) { - let _e204 = (*four)[1u]; - local_18 = _e204; + let _e194 = (*slot_1); + lane = (_e193 - ((_e194 / 4i) * 4i)); + let _e198 = lane; + if (_e198 == 0i) { + let _e201 = (*four)[0u]; + local_17 = _e201; + } else { + let _e202 = lane; + if (_e202 == 1i) { + let _e205 = (*four)[1u]; + local_18 = _e205; } else { - let _e205 = lane; - if (_e205 == 2i) { - let _e208 = (*four)[2u]; - local_19 = _e208; + let _e206 = lane; + if (_e206 == 2i) { + let _e209 = (*four)[2u]; + local_19 = _e209; } else { - let _e210 = (*four)[3u]; - local_19 = _e210; + let _e211 = (*four)[3u]; + local_19 = _e211; } - let _e211 = local_19; - local_18 = _e211; + let _e212 = local_19; + local_18 = _e212; } - let _e212 = local_18; - local_17 = _e212; + let _e213 = local_18; + local_17 = _e213; } - let _e213 = local_17; - return _e213; + let _e214 = local_17; + return _e214; } fn LightListScale_u0028_i1_u003b(slot_2: ptr) -> f32 { var param_79: vec4; var param_80: i32; - let _e189 = (*slot_2); - let _e193 = light_list_info.scales[(_e189 / 4i)]; - param_79 = _e193; - let _e194 = (*slot_2); - param_80 = _e194; - let _e195 = LightListLane_u0028_vf4_u003b_i1_u003b((¶m_79), (¶m_80)); - return _e195; + let _e190 = (*slot_2); + let _e194 = light_list_info.scales[(_e190 / 4i)]; + param_79 = _e194; + let _e195 = (*slot_2); + param_80 = _e195; + let _e196 = LightListLane_u0028_vf4_u003b_i1_u003b((¶m_79), (¶m_80)); + return _e196; } fn InSlots_u0028_f1_u003b(row: ptr) -> bool { var a_3: vec4; var b_2: vec4; - let _e191 = light_list_info.slot_rows[0i]; - let _e192 = (*row); - a_3 = abs((_e191 - vec4(_e192))); - let _e198 = light_list_info.slot_rows[1i]; - let _e199 = (*row); - b_2 = abs((_e198 - vec4(_e199))); - let _e204 = a_3[0u]; - let _e206 = a_3[1u]; - let _e209 = a_3[2u]; - let _e211 = a_3[3u]; - let _e215 = b_2[0u]; - let _e217 = b_2[1u]; - let _e220 = b_2[2u]; - let _e222 = b_2[3u]; - return (min(min(min(_e204, _e206), min(_e209, _e211)), min(min(_e215, _e217), min(_e220, _e222))) < 0.5f); + let _e192 = light_list_info.slot_rows[0i]; + let _e193 = (*row); + a_3 = abs((_e192 - vec4(_e193))); + let _e199 = light_list_info.slot_rows[1i]; + let _e200 = (*row); + b_2 = abs((_e199 - vec4(_e200))); + let _e205 = a_3[0u]; + let _e207 = a_3[1u]; + let _e210 = a_3[2u]; + let _e212 = a_3[3u]; + let _e216 = b_2[0u]; + let _e218 = b_2[1u]; + let _e221 = b_2[2u]; + let _e223 = b_2[3u]; + return (min(min(min(_e205, _e207), min(_e210, _e212)), min(min(_e216, _e218), min(_e221, _e223))) < 0.5f); } fn LightListRow_u0028_i1_u003b(slot_3: ptr) -> f32 { var param_81: vec4; var param_82: i32; - let _e189 = (*slot_3); - let _e193 = light_list_info.indices[(_e189 / 4i)]; - param_81 = _e193; - let _e194 = (*slot_3); - param_82 = _e194; - let _e195 = LightListLane_u0028_vf4_u003b_i1_u003b((¶m_81), (¶m_82)); - return _e195; + let _e190 = (*slot_3); + let _e194 = light_list_info.indices[(_e190 / 4i)]; + param_81 = _e194; + let _e195 = (*slot_3); + param_82 = _e195; + let _e196 = LightListLane_u0028_vf4_u003b_i1_u003b((¶m_81), (¶m_82)); + return _e196; } fn LightListTexel_u0028_f1_u003b_f1_u003b(texel_2: ptr, row_1: ptr) -> vec4 { - let _e188 = (*texel_2); - let _e192 = light_list_info.list[1u]; - let _e194 = (*row_1); - let _e198 = light_list_info.list[2u]; - let _e201 = textureSampleLevel(light_list_texture_tex, light_list_texture_smp, vec2(((_e188 + 0.5f) * _e192), ((_e194 + 0.5f) * _e198)), 0f); - return _e201; + let _e189 = (*texel_2); + let _e193 = light_list_info.list[1u]; + let _e195 = (*row_1); + let _e199 = light_list_info.list[2u]; + let _e202 = textureSampleLevel(light_list_texture_tex, light_list_texture_smp, vec2(((_e189 + 0.5f) * _e193), ((_e195 + 0.5f) * _e199)), 0f); + return _e202; } fn ClusterRow_u0028_i1_u003b(slot_4: ptr) -> f32 { @@ -8433,35 +8468,35 @@ fn ClusterRow_u0028_i1_u003b(slot_4: ptr) -> f32 { var param_85: vec4; var param_86: i32; - let _e196 = g_cluster_offset; - let _e197 = (*slot_4); - entry_1 = (_e196 + f32(_e197)); - let _e200 = entry_1; - row_2 = floor((_e200 / 16f)); - let _e203 = entry_1; - let _e204 = row_2; - within = (_e203 - (_e204 * 16f)); - let _e207 = within; - texel_3 = floor((_e207 / 4f)); - let _e212 = light_list_info.cluster_depth[3u]; - let _e213 = row_2; - let _e215 = texel_3; - param_83 = _e215; - param_84 = (_e212 + _e213); - let _e216 = LightListTexel_u0028_f1_u003b_f1_u003b((¶m_83), (¶m_84)); - four_1 = _e216; - let _e217 = within; - let _e218 = texel_3; - let _e223 = four_1; - param_85 = _e223; - param_86 = i32(((_e217 - (_e218 * 4f)) + 0.5f)); - let _e224 = LightListLane_u0028_vf4_u003b_i1_u003b((¶m_85), (¶m_86)); - return _e224; + let _e197 = g_cluster_offset; + let _e198 = (*slot_4); + entry_1 = (_e197 + f32(_e198)); + let _e201 = entry_1; + row_2 = floor((_e201 / 16f)); + let _e204 = entry_1; + let _e205 = row_2; + within = (_e204 - (_e205 * 16f)); + let _e208 = within; + texel_3 = floor((_e208 / 4f)); + let _e213 = light_list_info.cluster_depth[3u]; + let _e214 = row_2; + let _e216 = texel_3; + param_83 = _e216; + param_84 = (_e213 + _e214); + let _e217 = LightListTexel_u0028_f1_u003b_f1_u003b((¶m_83), (¶m_84)); + four_1 = _e217; + let _e218 = within; + let _e219 = texel_3; + let _e224 = four_1; + param_85 = _e224; + param_86 = i32(((_e218 - (_e219 * 4f)) + 0.5f)); + let _e225 = LightListLane_u0028_vf4_u003b_i1_u003b((¶m_85), (¶m_86)); + return _e225; } fn Clustered_u0028_() -> bool { - let _e188 = light_list_info.cluster_grid[3u]; - return (_e188 > 0.5f); + let _e189 = light_list_info.cluster_grid[3u]; + return (_e189 > 0.5f); } fn SampleLight_u0028_i1_u003b_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b(index_2: ptr, s_4: ptr) -> LightSample { @@ -8517,353 +8552,353 @@ fn SampleLight_u0028_i1_u003b_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_ light_3.integrated = 0f; light_3.ltc = vec3(0f, 0f, 0f); - let _e239 = (*index_2); - if (_e239 < 8i) { - let _e241 = (*index_2); - let _e244 = frag_info.light_position[_e241]; - position = _e244; - let _e245 = (*index_2); - let _e248 = frag_info.light_color[_e245]; - color_1 = _e248; - let _e249 = (*index_2); - let _e252 = frag_info.light_direction[_e249]; - direction = _e252; - let _e253 = (*index_2); - let _e256 = frag_info.light_cone[_e253]; - cone = _e256; - } else { - let _e257 = (*index_2); - slot_5 = (_e257 - 8i); - let _e259 = Clustered_u0028_(); - clustered = _e259; - let _e260 = clustered; - if _e260 { - let _e261 = slot_5; - param_87 = _e261; - let _e262 = ClusterRow_u0028_i1_u003b((¶m_87)); - local_20 = _e262; + let _e240 = (*index_2); + if (_e240 < 8i) { + let _e242 = (*index_2); + let _e245 = frag_info.light_position[_e242]; + position = _e245; + let _e246 = (*index_2); + let _e249 = frag_info.light_color[_e246]; + color_1 = _e249; + let _e250 = (*index_2); + let _e253 = frag_info.light_direction[_e250]; + direction = _e253; + let _e254 = (*index_2); + let _e257 = frag_info.light_cone[_e254]; + cone = _e257; + } else { + let _e258 = (*index_2); + slot_5 = (_e258 - 8i); + let _e260 = Clustered_u0028_(); + clustered = _e260; + let _e261 = clustered; + if _e261 { + let _e262 = slot_5; + param_87 = _e262; + let _e263 = ClusterRow_u0028_i1_u003b((¶m_87)); + local_20 = _e263; } else { - let _e263 = slot_5; - param_88 = _e263; - let _e264 = LightListRow_u0028_i1_u003b((¶m_88)); - local_20 = _e264; + let _e264 = slot_5; + param_88 = _e264; + let _e265 = LightListRow_u0028_i1_u003b((¶m_88)); + local_20 = _e265; } - let _e265 = local_20; - listRow = _e265; - let _e266 = listRow; - let _e270 = light_list_info.list[2u]; - v_1 = ((_e266 + 0.5f) * _e270); - let _e274 = light_list_info.list[1u]; - u_1 = _e274; - let _e275 = u_1; - let _e277 = v_1; - let _e279 = textureSampleLevel(light_list_texture_tex, light_list_texture_smp, vec2((0.5f * _e275), _e277), 0f); - position = _e279; - let _e280 = u_1; - let _e282 = v_1; - let _e284 = textureSampleLevel(light_list_texture_tex, light_list_texture_smp, vec2((1.5f * _e280), _e282), 0f); - color_1 = _e284; - let _e285 = u_1; - let _e287 = v_1; - let _e289 = textureSampleLevel(light_list_texture_tex, light_list_texture_smp, vec2((2.5f * _e285), _e287), 0f); - direction = _e289; - let _e290 = u_1; - let _e292 = v_1; - let _e294 = textureSampleLevel(light_list_texture_tex, light_list_texture_smp, vec2((3.5f * _e290), _e292), 0f); - cone = _e294; - let _e295 = clustered; - if _e295 { - let _e296 = listRow; - param_89 = _e296; - let _e297 = InSlots_u0028_f1_u003b((¶m_89)); - local_21 = select(1f, 0f, _e297); + let _e266 = local_20; + listRow = _e266; + let _e267 = listRow; + let _e271 = light_list_info.list[2u]; + v_1 = ((_e267 + 0.5f) * _e271); + let _e275 = light_list_info.list[1u]; + u_1 = _e275; + let _e276 = u_1; + let _e278 = v_1; + let _e280 = textureSampleLevel(light_list_texture_tex, light_list_texture_smp, vec2((0.5f * _e276), _e278), 0f); + position = _e280; + let _e281 = u_1; + let _e283 = v_1; + let _e285 = textureSampleLevel(light_list_texture_tex, light_list_texture_smp, vec2((1.5f * _e281), _e283), 0f); + color_1 = _e285; + let _e286 = u_1; + let _e288 = v_1; + let _e290 = textureSampleLevel(light_list_texture_tex, light_list_texture_smp, vec2((2.5f * _e286), _e288), 0f); + direction = _e290; + let _e291 = u_1; + let _e293 = v_1; + let _e295 = textureSampleLevel(light_list_texture_tex, light_list_texture_smp, vec2((3.5f * _e291), _e293), 0f); + cone = _e295; + let _e296 = clustered; + if _e296 { + let _e297 = listRow; + param_89 = _e297; + let _e298 = InSlots_u0028_f1_u003b((¶m_89)); + local_21 = select(1f, 0f, _e298); } else { - let _e299 = slot_5; - param_90 = _e299; - let _e300 = LightListScale_u0028_i1_u003b((¶m_90)); - local_21 = _e300; - } - let _e301 = local_21; - let _e303 = color_1[3u]; - color_1[3u] = (_e303 * _e301); - } - let _e307 = position[3u]; - type_39 = _e307; - let _e308 = type_39; - if (_e308 > 2.5f) { - let _e310 = direction; - halfWidth_1 = _e310.xyz; - let _e312 = cone; - halfHeight_1 = _e312.xyz; - let _e314 = position; - let _e316 = v_world_position_1; - toCentre = (_e314.xyz - _e316); - let _e318 = toCentre; - let _e319 = halfWidth_1; - let _e321 = halfHeight_1; - corners_1[0i] = ((_e318 - _e319) - _e321); - let _e324 = toCentre; - let _e325 = halfWidth_1; - let _e327 = halfHeight_1; - corners_1[1i] = ((_e324 + _e325) - _e327); - let _e330 = toCentre; - let _e331 = halfWidth_1; - let _e333 = halfHeight_1; - corners_1[2i] = ((_e330 + _e331) + _e333); - let _e336 = toCentre; - let _e337 = halfWidth_1; - let _e339 = halfHeight_1; - corners_1[3i] = ((_e336 - _e337) + _e339); - let _e342 = toCentre; - let _e343 = halfWidth_1; - let _e344 = halfHeight_1; - behind = (dot(_e342, cross(_e343, _e344)) >= 0f); - let _e348 = behind; - if _e348 { + let _e300 = slot_5; + param_90 = _e300; + let _e301 = LightListScale_u0028_i1_u003b((¶m_90)); + local_21 = _e301; + } + let _e302 = local_21; + let _e304 = color_1[3u]; + color_1[3u] = (_e304 * _e302); + } + let _e308 = position[3u]; + type_39 = _e308; + let _e309 = type_39; + if (_e309 > 2.5f) { + let _e311 = direction; + halfWidth_1 = _e311.xyz; + let _e313 = cone; + halfHeight_1 = _e313.xyz; + let _e315 = position; + let _e317 = v_world_position_1; + toCentre = (_e315.xyz - _e317); + let _e319 = toCentre; + let _e320 = halfWidth_1; + let _e322 = halfHeight_1; + corners_1[0i] = ((_e319 - _e320) - _e322); + let _e325 = toCentre; + let _e326 = halfWidth_1; + let _e328 = halfHeight_1; + corners_1[1i] = ((_e325 + _e326) - _e328); + let _e331 = toCentre; + let _e332 = halfWidth_1; + let _e334 = halfHeight_1; + corners_1[2i] = ((_e331 + _e332) + _e334); + let _e337 = toCentre; + let _e338 = halfWidth_1; + let _e340 = halfHeight_1; + corners_1[3i] = ((_e337 - _e338) + _e340); + let _e343 = toCentre; + let _e344 = halfWidth_1; + let _e345 = halfHeight_1; + behind = (dot(_e343, cross(_e344, _e345)) >= 0f); + let _e349 = behind; + if _e349 { local_22 = 0f; } else { - let _e349 = corners_1; - param_91 = _e349; - let _e351 = (*s_4).n; - param_92 = _e351; - let _e352 = RectangleFormFactor_u0028_vf3_u005b_4_u005d_u003b_vf3_u003b((¶m_91), (¶m_92)); - local_22 = _e352; - } - let _e353 = local_22; - formFactor = _e353; - let _e354 = halfWidth_1; - let _e355 = halfHeight_1; - area = (length(cross(_e354, _e355)) * 4f); - let _e359 = area; - if (_e359 > 0.000000001f) { - let _e361 = area; - local_23 = (1f / _e361); + let _e350 = corners_1; + param_91 = _e350; + let _e352 = (*s_4).n; + param_92 = _e352; + let _e353 = RectangleFormFactor_u0028_vf3_u005b_4_u005d_u003b_vf3_u003b((¶m_91), (¶m_92)); + local_22 = _e353; + } + let _e354 = local_22; + formFactor = _e354; + let _e355 = halfWidth_1; + let _e356 = halfHeight_1; + area = (length(cross(_e355, _e356)) * 4f); + let _e360 = area; + if (_e360 > 0.000000001f) { + let _e362 = area; + local_23 = (1f / _e362); } else { local_23 = 0f; } - let _e363 = local_23; - radiance = _e363; - let _e364 = toCentre; - distance_2 = length(_e364); - let _e367 = direction[3u]; - if (_e367 > 0f) { - let _e369 = distance_2; - let _e371 = direction[3u]; - ratio_1 = (_e369 / _e371); - let _e373 = ratio_1; + let _e364 = local_23; + radiance = _e364; + let _e365 = toCentre; + distance_2 = length(_e365); + let _e368 = direction[3u]; + if (_e368 > 0f) { + let _e370 = distance_2; + let _e372 = direction[3u]; + ratio_1 = (_e370 / _e372); let _e374 = ratio_1; - let _e376 = ratio_1; - let _e378 = ratio_1; - window_1 = clamp((1f - (((_e373 * _e374) * _e376) * _e378)), 0f, 1f); - let _e382 = window_1; + let _e375 = ratio_1; + let _e377 = ratio_1; + let _e379 = ratio_1; + window_1 = clamp((1f - (((_e374 * _e375) * _e377) * _e379)), 0f, 1f); let _e383 = window_1; - let _e385 = radiance; - radiance = (_e385 * (_e382 * _e383)); - } - let _e388 = (*s_4).v; - let _e391 = (*s_4).n; - mirror_1 = reflect(-(_e388), _e391); - let _e393 = position; - param_93 = _e393.xyz; - let _e395 = halfWidth_1; - param_94 = _e395; - let _e396 = halfHeight_1; - param_95 = _e396; - let _e397 = v_world_position_1; - param_96 = _e397; - let _e398 = mirror_1; - param_97 = _e398; - let _e399 = RectangleClosestPoint_u0028_vf3_u003b_vf3_u003b_vf3_u003b_vf3_u003b_vf3_u003b((¶m_93), (¶m_94), (¶m_95), (¶m_96), (¶m_97)); - representative = _e399; - let _e400 = representative; - let _e401 = v_world_position_1; - toPoint = (_e400 - _e401); - let _e403 = toPoint; - pointDistance = length(_e403); - let _e405 = pointDistance; - if (_e405 > 0.000001f) { - let _e407 = toPoint; - let _e408 = pointDistance; - local_24 = (_e407 / vec3(_e408)); + let _e384 = window_1; + let _e386 = radiance; + radiance = (_e386 * (_e383 * _e384)); + } + let _e389 = (*s_4).v; + let _e392 = (*s_4).n; + mirror_1 = reflect(-(_e389), _e392); + let _e394 = position; + param_93 = _e394.xyz; + let _e396 = halfWidth_1; + param_94 = _e396; + let _e397 = halfHeight_1; + param_95 = _e397; + let _e398 = v_world_position_1; + param_96 = _e398; + let _e399 = mirror_1; + param_97 = _e399; + let _e400 = RectangleClosestPoint_u0028_vf3_u003b_vf3_u003b_vf3_u003b_vf3_u003b_vf3_u003b((¶m_93), (¶m_94), (¶m_95), (¶m_96), (¶m_97)); + representative = _e400; + let _e401 = representative; + let _e402 = v_world_position_1; + toPoint = (_e401 - _e402); + let _e404 = toPoint; + pointDistance = length(_e404); + let _e406 = pointDistance; + if (_e406 > 0.000001f) { + let _e408 = toPoint; + let _e409 = pointDistance; + local_24 = (_e408 / vec3(_e409)); } else { - let _e412 = (*s_4).n; - local_24 = _e412; - } - let _e413 = local_24; - light_3.l = _e413; - let _e416 = light_3.l; - let _e418 = (*s_4).v; - light_3.h = normalize((_e416 + _e418)); - let _e422 = formFactor; - light_3.n_dot_l = _e422; - let _e425 = (*s_4).n; - let _e427 = light_3.h; - light_3.n_dot_h = max(dot(_e425, _e427), 0f); - let _e432 = (*s_4).v; - let _e434 = light_3.h; - light_3.v_dot_h = max(dot(_e432, _e434), 0f); - let _e438 = color_1; - let _e441 = color_1[3u]; - let _e443 = radiance; - light_3.radiance = ((_e438.xyz * _e441) * _e443); - let _e446 = light_3; - return _e446; - } - let _e447 = direction; - aim = normalize(_e447.xyz); + let _e413 = (*s_4).n; + local_24 = _e413; + } + let _e414 = local_24; + light_3.l = _e414; + let _e417 = light_3.l; + let _e419 = (*s_4).v; + light_3.h = normalize((_e417 + _e419)); + let _e423 = formFactor; + light_3.n_dot_l = _e423; + let _e426 = (*s_4).n; + let _e428 = light_3.h; + light_3.n_dot_h = max(dot(_e426, _e428), 0f); + let _e433 = (*s_4).v; + let _e435 = light_3.h; + light_3.v_dot_h = max(dot(_e433, _e435), 0f); + let _e439 = color_1; + let _e442 = color_1[3u]; + let _e444 = radiance; + light_3.radiance = ((_e439.xyz * _e442) * _e444); + let _e447 = light_3; + return _e447; + } + let _e448 = direction; + aim = normalize(_e448.xyz); attenuation_1 = 1f; - let _e450 = type_39; - if (_e450 < 0.5f) { - let _e452 = aim; - light_3.l = -(_e452); - } else { - let _e455 = position; - let _e457 = v_world_position_1; - toLight_1 = (_e455.xyz - _e457); - let _e459 = toLight_1; - distance_3 = length(_e459); - let _e461 = distance_3; - if (_e461 < 0.000001f) { - let _e464 = (*s_4).n; - light_3.l = _e464; - let _e467 = (*s_4).n; - light_3.h = _e467; + let _e451 = type_39; + if (_e451 < 0.5f) { + let _e453 = aim; + light_3.l = -(_e453); + } else { + let _e456 = position; + let _e458 = v_world_position_1; + toLight_1 = (_e456.xyz - _e458); + let _e460 = toLight_1; + distance_3 = length(_e460); + let _e462 = distance_3; + if (_e462 < 0.000001f) { + let _e465 = (*s_4).n; + light_3.l = _e465; + let _e468 = (*s_4).n; + light_3.h = _e468; light_3.radiance = vec3(0f, 0f, 0f); light_3.n_dot_l = 0f; light_3.n_dot_h = 0f; light_3.v_dot_h = 0f; - let _e473 = light_3; - return _e473; - } - let _e474 = toLight_1; - let _e475 = distance_3; - light_3.l = (_e474 / vec3(_e475)); - let _e479 = distance_3; - param_98 = _e479; - let _e481 = direction[3u]; - param_99 = _e481; - let _e482 = PunctualAttenuation_u0028_f1_u003b_f1_u003b((¶m_98), (¶m_99)); - attenuation_1 = _e482; - let _e483 = type_39; - if (_e483 > 1.5f) { - let _e485 = aim; - let _e487 = light_3.l; - cosAngle = dot(_e485, -(_e487)); - let _e490 = cosAngle; - let _e492 = cone[1u]; - let _e495 = cone[0u]; - let _e497 = cone[1u]; - let _e501 = attenuation_1; - attenuation_1 = (_e501 * clamp(((_e490 - _e492) / (_e495 - _e497)), 0f, 1f)); - } - } - let _e504 = light_3.l; - let _e506 = (*s_4).v; - light_3.h = normalize((_e504 + _e506)); - let _e511 = (*s_4).n; - let _e513 = light_3.l; - light_3.n_dot_l = max(dot(_e511, _e513), 0f); - let _e518 = (*s_4).n; - let _e520 = light_3.h; - light_3.n_dot_h = max(dot(_e518, _e520), 0f); - let _e525 = (*s_4).v; - let _e527 = light_3.h; - light_3.v_dot_h = max(dot(_e525, _e527), 0f); - let _e531 = color_1; - let _e534 = color_1[3u]; - let _e536 = attenuation_1; - light_3.radiance = ((_e531.xyz * _e534) * _e536); - let _e539 = light_3; - return _e539; -} - -fn FindCluster_u0028_vf3_u003b(world_3: ptr>) { - var clip_1: vec4; - var ndc_1: vec2; - var grid: vec3; - var near_1: f32; - var tx: f32; - var ty: f32; - var tz: f32; - var local_25: f32; - var cell: f32; - var row_3: f32; - var header: vec4; - var param_100: f32; - var param_101: f32; - - let _e201 = light_list_info.cluster_view_projection; - let _e202 = (*world_3); - clip_1 = (_e201 * vec4(_e202.x, _e202.y, _e202.z, 1f)); - let _e208 = clip_1; - let _e211 = clip_1[3u]; - ndc_1 = (_e208.xy / vec2(max(_e211, 0.000001f))); - let _e216 = light_list_info.cluster_grid; - grid = _e216.xyz; - let _e220 = light_list_info.cluster_depth[0u]; - near_1 = _e220; - let _e222 = ndc_1[0u]; - let _e226 = grid[0u]; - let _e230 = grid[0u]; - tx = clamp(floor((((_e222 * 0.5f) + 0.5f) * _e226)), 0f, (_e230 - 1f)); - let _e234 = ndc_1[1u]; - let _e238 = grid[1u]; - let _e242 = grid[1u]; - ty = clamp(floor((((_e234 * 0.5f) + 0.5f) * _e238)), 0f, (_e242 - 1f)); - let _e246 = clip_1[3u]; - let _e247 = near_1; - if (_e246 <= _e247) { - local_25 = 0f; - } else { - let _e250 = clip_1[3u]; - let _e251 = near_1; - let _e256 = light_list_info.cluster_depth[1u]; - let _e260 = grid[2u]; - local_25 = clamp(floor((log((_e250 / _e251)) * _e256)), 0f, (_e260 - 1f)); - } - let _e263 = local_25; - tz = _e263; - let _e264 = tx; - let _e265 = ty; - let _e267 = grid[0u]; - let _e270 = tz; - let _e272 = grid[0u]; - let _e275 = grid[1u]; - cell = ((_e264 + (_e265 * _e267)) + ((_e270 * _e272) * _e275)); - let _e278 = cell; - row_3 = floor((_e278 / 4f)); - let _e281 = cell; - let _e282 = row_3; - let _e287 = light_list_info.cluster_depth[2u]; - let _e288 = row_3; - param_100 = (_e281 - (_e282 * 4f)); - param_101 = (_e287 + _e288); - let _e290 = LightListTexel_u0028_f1_u003b_f1_u003b((¶m_100), (¶m_101)); - header = _e290; - let _e292 = header[0u]; - g_cluster_offset = _e292; - let _e294 = header[1u]; - g_cluster_count = _e294; - return; -} - + let _e474 = light_3; + return _e474; + } + let _e475 = toLight_1; + let _e476 = distance_3; + light_3.l = (_e475 / vec3(_e476)); + let _e480 = distance_3; + param_98 = _e480; + let _e482 = direction[3u]; + param_99 = _e482; + let _e483 = PunctualAttenuation_u0028_f1_u003b_f1_u003b((¶m_98), (¶m_99)); + attenuation_1 = _e483; + let _e484 = type_39; + if (_e484 > 1.5f) { + let _e486 = aim; + let _e488 = light_3.l; + cosAngle = dot(_e486, -(_e488)); + let _e491 = cosAngle; + let _e493 = cone[1u]; + let _e496 = cone[0u]; + let _e498 = cone[1u]; + let _e502 = attenuation_1; + attenuation_1 = (_e502 * clamp(((_e491 - _e493) / (_e496 - _e498)), 0f, 1f)); + } + } + let _e505 = light_3.l; + let _e507 = (*s_4).v; + light_3.h = normalize((_e505 + _e507)); + let _e512 = (*s_4).n; + let _e514 = light_3.l; + light_3.n_dot_l = max(dot(_e512, _e514), 0f); + let _e519 = (*s_4).n; + let _e521 = light_3.h; + light_3.n_dot_h = max(dot(_e519, _e521), 0f); + let _e526 = (*s_4).v; + let _e528 = light_3.h; + light_3.v_dot_h = max(dot(_e526, _e528), 0f); + let _e532 = color_1; + let _e535 = color_1[3u]; + let _e537 = attenuation_1; + light_3.radiance = ((_e532.xyz * _e535) * _e537); + let _e540 = light_3; + return _e540; +} + +fn FindCluster_u0028_vf3_u003b(world_3: ptr>) { + var clip_1: vec4; + var ndc_1: vec2; + var grid: vec3; + var near_1: f32; + var tx: f32; + var ty: f32; + var tz: f32; + var local_25: f32; + var cell: f32; + var row_3: f32; + var header: vec4; + var param_100: f32; + var param_101: f32; + + let _e202 = light_list_info.cluster_view_projection; + let _e203 = (*world_3); + clip_1 = (_e202 * vec4(_e203.x, _e203.y, _e203.z, 1f)); + let _e209 = clip_1; + let _e212 = clip_1[3u]; + ndc_1 = (_e209.xy / vec2(max(_e212, 0.000001f))); + let _e217 = light_list_info.cluster_grid; + grid = _e217.xyz; + let _e221 = light_list_info.cluster_depth[0u]; + near_1 = _e221; + let _e223 = ndc_1[0u]; + let _e227 = grid[0u]; + let _e231 = grid[0u]; + tx = clamp(floor((((_e223 * 0.5f) + 0.5f) * _e227)), 0f, (_e231 - 1f)); + let _e235 = ndc_1[1u]; + let _e239 = grid[1u]; + let _e243 = grid[1u]; + ty = clamp(floor((((_e235 * 0.5f) + 0.5f) * _e239)), 0f, (_e243 - 1f)); + let _e247 = clip_1[3u]; + let _e248 = near_1; + if (_e247 <= _e248) { + local_25 = 0f; + } else { + let _e251 = clip_1[3u]; + let _e252 = near_1; + let _e257 = light_list_info.cluster_depth[1u]; + let _e261 = grid[2u]; + local_25 = clamp(floor((log((_e251 / _e252)) * _e257)), 0f, (_e261 - 1f)); + } + let _e264 = local_25; + tz = _e264; + let _e265 = tx; + let _e266 = ty; + let _e268 = grid[0u]; + let _e271 = tz; + let _e273 = grid[0u]; + let _e276 = grid[1u]; + cell = ((_e265 + (_e266 * _e268)) + ((_e271 * _e273) * _e276)); + let _e279 = cell; + row_3 = floor((_e279 / 4f)); + let _e282 = cell; + let _e283 = row_3; + let _e288 = light_list_info.cluster_depth[2u]; + let _e289 = row_3; + param_100 = (_e282 - (_e283 * 4f)); + param_101 = (_e288 + _e289); + let _e291 = LightListTexel_u0028_f1_u003b_f1_u003b((¶m_100), (¶m_101)); + header = _e291; + let _e293 = header[0u]; + g_cluster_offset = _e293; + let _e295 = header[1u]; + g_cluster_count = _e295; + return; +} + fn LightCount_u0028_() -> i32 { var tail: f32; var param_102: vec3; - let _e190 = light_list_info.list[0u]; - tail = _e190; - let _e191 = Clustered_u0028_(); - if _e191 { - let _e192 = v_world_position_1; - param_102 = _e192; + let _e191 = light_list_info.list[0u]; + tail = _e191; + let _e192 = Clustered_u0028_(); + if _e192 { + let _e193 = v_world_position_1; + param_102 = _e193; FindCluster_u0028_vf3_u003b((¶m_102)); - let _e193 = g_cluster_count; - tail = _e193; + let _e194 = g_cluster_count; + tail = _e194; } - let _e196 = frag_info.frame_params[1u]; - let _e200 = tail; - return (clamp(i32((_e196 + 0.5f)), 0i, 8i) + clamp(i32((_e200 + 0.5f)), 0i, 24i)); + let _e197 = frag_info.frame_params[1u]; + let _e201 = tail; + return (clamp(i32((_e197 + 0.5f)), 0i, 8i) + clamp(i32((_e201 + 0.5f)), 0i, 24i)); } fn AccumulateLights_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b(s_5: ptr) -> vec3 { @@ -8886,123 +8921,123 @@ fn AccumulateLights_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002 var param_113: LightSample; total_1 = vec3(0f, 0f, 0f); - let _e204 = LightCount_u0028_(); - count_1 = _e204; + let _e205 = LightCount_u0028_(); + count_1 = _e205; i_8 = 0i; loop { - let _e205 = i_8; - if (_e205 < 32i) { - let _e207 = i_8; - let _e208 = count_1; - if (_e207 >= _e208) { + let _e206 = i_8; + if (_e206 < 32i) { + let _e208 = i_8; + let _e209 = count_1; + if (_e208 >= _e209) { break; } - let _e210 = i_8; - param_103 = _e210; - let _e211 = (*s_5); - param_104 = _e211; - let _e212 = SampleLight_u0028_i1_u003b_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b((¶m_103), (¶m_104)); - light_4 = _e212; - let _e214 = light_4.n_dot_l; - if (_e214 <= 0f) { + let _e211 = i_8; + param_103 = _e211; + let _e212 = (*s_5); + param_104 = _e212; + let _e213 = SampleLight_u0028_i1_u003b_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b((¶m_103), (¶m_104)); + light_4 = _e213; + let _e215 = light_4.n_dot_l; + if (_e215 <= 0f) { continue; } light_transmittance = vec3(1f, 1f, 1f); - let _e216 = i_8; - param_105 = _e216; - let _e217 = LightHasShadow_u0028_i1_u003b((¶m_105)); - if _e217 { - let _e218 = (*s_5); - param_106 = _e218; - let _e219 = light_4; - param_107 = _e219; - let _e220 = i_8; - param_108 = _e220; - let _e221 = LightVisibility_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_struct_u002d_LightSample_u002d_vf3_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf31_u003b_i1_u003b((¶m_106), (¶m_107), (¶m_108)); - let _e222 = v_world_position_1; - param_109 = _e222; - let _e224 = (*s_5).n; - param_110 = _e224; - let _e225 = i_8; - param_111 = _e225; - let _e226 = PointShadowFactor_u0028_vf3_u003b_vf3_u003b_i1_u003b((¶m_109), (¶m_110), (¶m_111)); - local_26 = (_e221 * _e226); + let _e217 = i_8; + param_105 = _e217; + let _e218 = LightHasShadow_u0028_i1_u003b((¶m_105)); + if _e218 { + let _e219 = (*s_5); + param_106 = _e219; + let _e220 = light_4; + param_107 = _e220; + let _e221 = i_8; + param_108 = _e221; + let _e222 = LightVisibility_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_struct_u002d_LightSample_u002d_vf3_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf31_u003b_i1_u003b((¶m_106), (¶m_107), (¶m_108)); + let _e223 = v_world_position_1; + param_109 = _e223; + let _e225 = (*s_5).n; + param_110 = _e225; + let _e226 = i_8; + param_111 = _e226; + let _e227 = PointShadowFactor_u0028_vf3_u003b_vf3_u003b_i1_u003b((¶m_109), (¶m_110), (¶m_111)); + local_26 = (_e222 * _e227); } else { local_26 = 1f; } - let _e228 = local_26; - visibility = _e228; - let _e229 = visibility; - if (_e229 <= 0f) { + let _e229 = local_26; + visibility = _e229; + let _e230 = visibility; + if (_e230 <= 0f) { continue; } - let _e231 = (*s_5); - param_112 = _e231; - let _e232 = light_4; - param_113 = _e232; - let _e233 = ShadeLight_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_struct_u002d_LightSample_u002d_vf3_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf31_u003b((¶m_112), (¶m_113)); - let _e235 = light_4.radiance; - let _e238 = light_4.n_dot_l; - let _e240 = visibility; - let _e242 = light_transmittance; - let _e244 = total_1; - total_1 = (_e244 + ((((_e233 * _e235) * _e238) * _e240) * _e242)); + let _e232 = (*s_5); + param_112 = _e232; + let _e233 = light_4; + param_113 = _e233; + let _e234 = ShadeLight_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_struct_u002d_LightSample_u002d_vf3_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf31_u003b((¶m_112), (¶m_113)); + let _e236 = light_4.radiance; + let _e239 = light_4.n_dot_l; + let _e241 = visibility; + let _e243 = light_transmittance; + let _e245 = total_1; + total_1 = (_e245 + ((((_e234 * _e236) * _e239) * _e241) * _e243)); continue; } else { break; } continuing { - let _e246 = i_8; - i_8 = (_e246 + 1i); + let _e247 = i_8; + i_8 = (_e247 + 1i); } } - let _e248 = total_1; - return _e248; + let _e249 = total_1; + return _e249; } fn SampleLightmap_u0028_() -> vec3 { var texel_4: vec4; - let _e187 = v_lightmap_uv_1; - let _e188 = textureSample(lightmap_texture_tex, lightmap_texture_smp, _e187); - texel_4 = _e188; - let _e189 = texel_4; - let _e192 = texel_4[3u]; - return ((_e189.xyz * _e192) * 8f); + let _e188 = v_lightmap_uv_1; + let _e189 = textureSample(lightmap_texture_tex, lightmap_texture_smp, _e188); + texel_4 = _e189; + let _e190 = texel_4; + let _e193 = texel_4[3u]; + return ((_e190.xyz * _e193) * 8f); } fn MaterialLodBias_u0028_() -> f32 { - let _e188 = frag_info.target_origin[1u]; - return _e188; + let _e189 = frag_info.target_origin[1u]; + return _e189; } fn ApplyEmissiveMap_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b(s_6: ptr) { var emissive: vec3; var param_114: vec3; - let _e189 = v_texcoord_1; - let _e190 = MaterialLodBias_u0028_(); - let _e191 = textureSampleBias(emissive_texture_tex, emissive_texture_smp, _e189, _e190); - param_114 = _e191.xyz; - let _e193 = SrgbToLinear_u0028_vf3_u003b((¶m_114)); - emissive = _e193; - let _e194 = emissive; - let _e196 = frag_info.emissive; - let _e201 = frag_info.material2_[3u]; - (*s_6).emissive = ((_e194 * _e196.xyz) * _e201); + let _e190 = v_texcoord_1; + let _e191 = MaterialLodBias_u0028_(); + let _e192 = textureSampleBias(emissive_texture_tex, emissive_texture_smp, _e190, _e191); + param_114 = _e192.xyz; + let _e194 = SrgbToLinear_u0028_vf3_u003b((¶m_114)); + emissive = _e194; + let _e195 = emissive; + let _e197 = frag_info.emissive; + let _e202 = frag_info.material2_[3u]; + (*s_6).emissive = ((_e195 * _e197.xyz) * _e202); return; } fn ApplyOcclusionMap_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b(s_7: ptr) { var occlusion: f32; - let _e188 = v_texcoord_1; - let _e189 = MaterialLodBias_u0028_(); - let _e190 = textureSampleBias(occlusion_texture_tex, occlusion_texture_smp, _e188, _e189); - occlusion = _e190.x; - let _e192 = occlusion; - let _e195 = frag_info.material2_[2u]; - (*s_7).occlusion = mix(1f, _e192, clamp(_e195, 0f, 1f)); + let _e189 = v_texcoord_1; + let _e190 = MaterialLodBias_u0028_(); + let _e191 = textureSampleBias(occlusion_texture_tex, occlusion_texture_smp, _e189, _e190); + occlusion = _e191.x; + let _e193 = occlusion; + let _e196 = frag_info.material2_[2u]; + (*s_7).occlusion = mix(1f, _e193, clamp(_e196, 0f, 1f)); return; } @@ -9012,64 +9047,64 @@ fn ApplyNormalMap_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_ var b_3: vec3; var sampled: vec3; - let _e191 = v_texcoord_1; - let _e192 = MaterialLodBias_u0028_(); - let _e193 = textureSampleBias(normal_texture_tex, normal_texture_smp, _e191, _e192); - sampledTexel = _e193; - let _e194 = v_tangent_1; - t_2 = _e194.xyz; - let _e196 = t_2; - let _e198 = (*s_8).n; - let _e200 = (*s_8).n; - let _e201 = t_2; - t_2 = (_e196 - (_e198 * dot(_e200, _e201))); - let _e205 = t_2; + let _e192 = v_texcoord_1; + let _e193 = MaterialLodBias_u0028_(); + let _e194 = textureSampleBias(normal_texture_tex, normal_texture_smp, _e192, _e193); + sampledTexel = _e194; + let _e195 = v_tangent_1; + t_2 = _e195.xyz; + let _e197 = t_2; + let _e199 = (*s_8).n; + let _e201 = (*s_8).n; + let _e202 = t_2; + t_2 = (_e197 - (_e199 * dot(_e201, _e202))); let _e206 = t_2; - if (dot(_e205, _e206) < 0.000000000001f) { + let _e207 = t_2; + if (dot(_e206, _e207) < 0.000000000001f) { return; } - let _e209 = t_2; - t_2 = normalize(_e209); - let _e212 = (*s_8).n; - let _e213 = t_2; - let _e216 = v_tangent_1[3u]; - b_3 = (cross(_e212, _e213) * _e216); - let _e218 = gl_FrontFacing_1; - if !(_e218) { - let _e220 = t_2; - t_2 = -(_e220); - } - let _e222 = sampledTexel; - sampled = ((_e222.xyz * 2f) - vec3(1f)); - let _e229 = frag_info.emissive[3u]; - if (_e229 > 0.5f) { - let _e231 = sampled; - let _e233 = sampled; - sampled[2u] = sqrt(max((1f - dot(_e231.xy, _e233.xy)), 0f)); - } - let _e242 = frag_info.material2_[1u]; - let _e243 = sampled; - let _e245 = (_e243.xy * _e242); - sampled[0u] = _e245.x; - sampled[1u] = _e245.y; - let _e250 = t_2; - let _e252 = sampled[0u]; - let _e254 = b_3; - let _e256 = sampled[1u]; - let _e260 = (*s_8).n; - let _e262 = sampled[2u]; - (*s_8).n = normalize((((_e250 * _e252) + (_e254 * _e256)) + (_e260 * _e262))); - let _e268 = (*s_8).n; - let _e270 = (*s_8).v; - (*s_8).n_dot_v = max(dot(_e268, _e270), 0.0001f); + let _e210 = t_2; + t_2 = normalize(_e210); + let _e213 = (*s_8).n; + let _e214 = t_2; + let _e217 = v_tangent_1[3u]; + b_3 = (cross(_e213, _e214) * _e217); + let _e219 = gl_FrontFacing_1; + if !(_e219) { + let _e221 = t_2; + t_2 = -(_e221); + } + let _e223 = sampledTexel; + sampled = ((_e223.xyz * 2f) - vec3(1f)); + let _e230 = frag_info.emissive[3u]; + if (_e230 > 0.5f) { + let _e232 = sampled; + let _e234 = sampled; + sampled[2u] = sqrt(max((1f - dot(_e232.xy, _e234.xy)), 0f)); + } + let _e243 = frag_info.material2_[1u]; + let _e244 = sampled; + let _e246 = (_e244.xy * _e243); + sampled[0u] = _e246.x; + sampled[1u] = _e246.y; + let _e251 = t_2; + let _e253 = sampled[0u]; + let _e255 = b_3; + let _e257 = sampled[1u]; + let _e261 = (*s_8).n; + let _e263 = sampled[2u]; + (*s_8).n = normalize((((_e251 * _e253) + (_e255 * _e257)) + (_e261 * _e263))); + let _e269 = (*s_8).n; + let _e271 = (*s_8).v; + (*s_8).n_dot_v = max(dot(_e269, _e271), 0.0001f); return; } fn AtlasTexel_u0028_vf2_u003b(texel_5: ptr>) -> vec4 { - let _e187 = (*texel_5); - let _e191 = irradiance_info.atlas; - let _e194 = textureSampleLevel(irradiance_texture_tex, irradiance_texture_smp, ((_e187 + vec2(0.5f)) * _e191.xy), 0f); - return _e194; + let _e188 = (*texel_5); + let _e192 = irradiance_info.atlas; + let _e195 = textureSampleLevel(irradiance_texture_tex, irradiance_texture_smp, ((_e188 + vec2(0.5f)) * _e192.xy), 0f); + return _e195; } fn TileBilinear_u0028_vf2_u003b_f1_u003b_vf2_u003b(corner: ptr>, interior: ptr, uv_5: ptr>) -> vec4 { @@ -9085,42 +9120,42 @@ fn TileBilinear_u0028_vf2_u003b_f1_u003b_vf2_u003b(corner: ptr; var param_118: vec2; - let _e200 = (*uv_5); - let _e201 = (*interior); - at_1 = ((vec2(1f) + (_e200 * _e201)) - vec2(0.5f)); - let _e207 = at_1; - low = floor(_e207); - let _e209 = at_1; - let _e210 = low; - f = (_e209 - _e210); - let _e212 = (*corner); - let _e213 = low; - param_115 = (_e212 + _e213); - let _e215 = AtlasTexel_u0028_vf2_u003b((¶m_115)); - a_4 = _e215; - let _e216 = (*corner); - let _e217 = low; - param_116 = ((_e216 + _e217) + vec2(1f, 0f)); - let _e220 = AtlasTexel_u0028_vf2_u003b((¶m_116)); - b_4 = _e220; - let _e221 = (*corner); - let _e222 = low; - param_117 = ((_e221 + _e222) + vec2(0f, 1f)); - let _e225 = AtlasTexel_u0028_vf2_u003b((¶m_117)); - c_1 = _e225; - let _e226 = (*corner); - let _e227 = low; - param_118 = ((_e226 + _e227) + vec2(1f, 1f)); - let _e230 = AtlasTexel_u0028_vf2_u003b((¶m_118)); - d_4 = _e230; - let _e231 = a_4; - let _e232 = b_4; - let _e234 = f[0u]; - let _e237 = c_1; - let _e238 = d_4; - let _e240 = f[0u]; - let _e244 = f[1u]; - return mix(mix(_e231, _e232, vec4(_e234)), mix(_e237, _e238, vec4(_e240)), vec4(_e244)); + let _e201 = (*uv_5); + let _e202 = (*interior); + at_1 = ((vec2(1f) + (_e201 * _e202)) - vec2(0.5f)); + let _e208 = at_1; + low = floor(_e208); + let _e210 = at_1; + let _e211 = low; + f = (_e210 - _e211); + let _e213 = (*corner); + let _e214 = low; + param_115 = (_e213 + _e214); + let _e216 = AtlasTexel_u0028_vf2_u003b((¶m_115)); + a_4 = _e216; + let _e217 = (*corner); + let _e218 = low; + param_116 = ((_e217 + _e218) + vec2(1f, 0f)); + let _e221 = AtlasTexel_u0028_vf2_u003b((¶m_116)); + b_4 = _e221; + let _e222 = (*corner); + let _e223 = low; + param_117 = ((_e222 + _e223) + vec2(0f, 1f)); + let _e226 = AtlasTexel_u0028_vf2_u003b((¶m_117)); + c_1 = _e226; + let _e227 = (*corner); + let _e228 = low; + param_118 = ((_e227 + _e228) + vec2(1f, 1f)); + let _e231 = AtlasTexel_u0028_vf2_u003b((¶m_118)); + d_4 = _e231; + let _e232 = a_4; + let _e233 = b_4; + let _e235 = f[0u]; + let _e238 = c_1; + let _e239 = d_4; + let _e241 = f[0u]; + let _e245 = f[1u]; + return mix(mix(_e232, _e233, vec4(_e235)), mix(_e238, _e239, vec4(_e241)), vec4(_e245)); } fn ProbeOctahedral_u0028_vf3_u003b(direction_1: ptr>) -> vec2 { @@ -9128,29 +9163,29 @@ fn ProbeOctahedral_u0028_vf3_u003b(direction_1: ptr>) -> vec var n_5: vec3; var xy: vec2; - let _e191 = (*direction_1)[0u]; - let _e194 = (*direction_1)[1u]; - let _e198 = (*direction_1)[2u]; - sum_1 = ((abs(_e191) + abs(_e194)) + abs(_e198)); - let _e201 = sum_1; - if (_e201 <= 0f) { + let _e192 = (*direction_1)[0u]; + let _e195 = (*direction_1)[1u]; + let _e199 = (*direction_1)[2u]; + sum_1 = ((abs(_e192) + abs(_e195)) + abs(_e199)); + let _e202 = sum_1; + if (_e202 <= 0f) { return vec2(0.5f, 0.5f); } - let _e203 = (*direction_1); - let _e204 = sum_1; - n_5 = (_e203 / vec3(_e204)); - let _e207 = n_5; - xy = _e207.xy; - let _e210 = n_5[2u]; - if (_e210 < 0f) { - let _e213 = n_5[1u]; - let _e217 = n_5[0u]; - let _e222 = n_5[0u]; - let _e226 = n_5[1u]; - xy = vec2(((1f - abs(_e213)) * select(-1f, 1f, (_e217 >= 0f))), ((1f - abs(_e222)) * select(-1f, 1f, (_e226 >= 0f)))); + let _e204 = (*direction_1); + let _e205 = sum_1; + n_5 = (_e204 / vec3(_e205)); + let _e208 = n_5; + xy = _e208.xy; + let _e211 = n_5[2u]; + if (_e211 < 0f) { + let _e214 = n_5[1u]; + let _e218 = n_5[0u]; + let _e223 = n_5[0u]; + let _e227 = n_5[1u]; + xy = vec2(((1f - abs(_e214)) * select(-1f, 1f, (_e218 >= 0f))), ((1f - abs(_e223)) * select(-1f, 1f, (_e227 >= 0f)))); } - let _e231 = xy; - return ((_e231 * 0.5f) + vec2(0.5f)); + let _e232 = xy; + return ((_e232 * 0.5f) + vec2(0.5f)); } fn SampleIrradiance_u0028_vf3_u003b_vf3_u003b_vf3_u003b(world_4: ptr>, normal_1: ptr>, view_1: ptr>) -> vec3 { @@ -9198,190 +9233,190 @@ fn SampleIrradiance_u0028_vf3_u003b_vf3_u003b_vf3_u003b(world_4: ptr; var local_27: vec3; - let _e233 = irradiance_info.origin; - origin_2 = _e233.xyz; - let _e236 = irradiance_info.spacing; - spacing = _e236.xyz; - let _e239 = irradiance_info.counts; - counts = _e239.xyz; - let _e243 = irradiance_info.tiles[0u]; - irradianceTile = _e243; - let _e246 = irradiance_info.tiles[1u]; - depthTile = _e246; - let _e249 = irradiance_info.tiles[2u]; - columns = _e249; - let _e252 = irradiance_info.tiles[3u]; - momentsTop = _e252; - let _e253 = (*normal_1); - unit = normalize(_e253); - let _e255 = (*world_4); - let _e256 = unit; - let _e259 = irradiance_info.spacing[3u]; - let _e262 = (*view_1); - let _e265 = irradiance_info.counts[3u]; - biased = ((_e255 + (_e256 * _e259)) + (_e262 * _e265)); - let _e268 = biased; - let _e269 = origin_2; - let _e271 = spacing; - grid_1 = ((_e268 - _e269) / _e271); - let _e273 = grid_1; - let _e275 = counts; - base = clamp(floor(_e273), vec3(0f, 0f, 0f), (_e275 - vec3(2f))); - let _e279 = grid_1; - let _e280 = base; - f_1 = clamp((_e279 - _e280), vec3(0f, 0f, 0f), vec3(1f, 1f, 1f)); + let _e234 = irradiance_info.origin; + origin_2 = _e234.xyz; + let _e237 = irradiance_info.spacing; + spacing = _e237.xyz; + let _e240 = irradiance_info.counts; + counts = _e240.xyz; + let _e244 = irradiance_info.tiles[0u]; + irradianceTile = _e244; + let _e247 = irradiance_info.tiles[1u]; + depthTile = _e247; + let _e250 = irradiance_info.tiles[2u]; + columns = _e250; + let _e253 = irradiance_info.tiles[3u]; + momentsTop = _e253; + let _e254 = (*normal_1); + unit = normalize(_e254); + let _e256 = (*world_4); + let _e257 = unit; + let _e260 = irradiance_info.spacing[3u]; + let _e263 = (*view_1); + let _e266 = irradiance_info.counts[3u]; + biased = ((_e256 + (_e257 * _e260)) + (_e263 * _e266)); + let _e269 = biased; + let _e270 = origin_2; + let _e272 = spacing; + grid_1 = ((_e269 - _e270) / _e272); + let _e274 = grid_1; + let _e276 = counts; + base = clamp(floor(_e274), vec3(0f, 0f, 0f), (_e276 - vec3(2f))); + let _e280 = grid_1; + let _e281 = base; + f_1 = clamp((_e280 - _e281), vec3(0f, 0f, 0f), vec3(1f, 1f, 1f)); total_2 = vec3(0f, 0f, 0f); weights = 0f; corner_1 = 0i; loop { - let _e283 = corner_1; - if (_e283 < 8i) { - let _e285 = corner_1; - let _e288 = corner_1; - let _e293 = corner_1; - offset_3 = vec3(f32((_e285 & 1i)), f32(((_e288 >> bitcast(1i)) & 1i)), f32(((_e293 >> bitcast(2i)) & 1i))); - let _e299 = base; - let _e300 = offset_3; - cell_1 = (_e299 + _e300); - let _e303 = cell_1[2u]; - let _e305 = counts[1u]; - let _e308 = cell_1[1u]; - let _e311 = counts[0u]; - let _e314 = cell_1[0u]; - probe = ((((_e303 * _e305) + _e308) * _e311) + _e314); - let _e316 = probe; - let _e317 = columns; - let _e322 = probe; - let _e323 = columns; - tile_4 = vec2((_e316 - (floor((_e316 / _e317)) * _e317)), floor((_e322 / _e323))); - let _e327 = tile_4; - let _e328 = irradianceTile; - irradianceCorner = (_e327 * (_e328 + 2f)); - let _e332 = tile_4[0u]; - let _e333 = depthTile; - let _e336 = momentsTop; - let _e338 = tile_4[1u]; - let _e339 = depthTile; - momentCorner = vec2((_e332 * (_e333 + 2f)), (_e336 + (_e338 * (_e339 + 2f)))); - let _e344 = irradianceCorner; - param_119 = (_e344 + vec2(1f)); - let _e347 = AtlasTexel_u0028_vf2_u003b((¶m_119)); - if (_e347.w < 0.5f) { + let _e284 = corner_1; + if (_e284 < 8i) { + let _e286 = corner_1; + let _e289 = corner_1; + let _e294 = corner_1; + offset_3 = vec3(f32((_e286 & 1i)), f32(((_e289 >> bitcast(1i)) & 1i)), f32(((_e294 >> bitcast(2i)) & 1i))); + let _e300 = base; + let _e301 = offset_3; + cell_1 = (_e300 + _e301); + let _e304 = cell_1[2u]; + let _e306 = counts[1u]; + let _e309 = cell_1[1u]; + let _e312 = counts[0u]; + let _e315 = cell_1[0u]; + probe = ((((_e304 * _e306) + _e309) * _e312) + _e315); + let _e317 = probe; + let _e318 = columns; + let _e323 = probe; + let _e324 = columns; + tile_4 = vec2((_e317 - (floor((_e317 / _e318)) * _e318)), floor((_e323 / _e324))); + let _e328 = tile_4; + let _e329 = irradianceTile; + irradianceCorner = (_e328 * (_e329 + 2f)); + let _e333 = tile_4[0u]; + let _e334 = depthTile; + let _e337 = momentsTop; + let _e339 = tile_4[1u]; + let _e340 = depthTile; + momentCorner = vec2((_e333 * (_e334 + 2f)), (_e337 + (_e339 * (_e340 + 2f)))); + let _e345 = irradianceCorner; + param_119 = (_e345 + vec2(1f)); + let _e348 = AtlasTexel_u0028_vf2_u003b((¶m_119)); + if (_e348.w < 0.5f) { continue; } - let _e350 = f_1; - let _e352 = f_1; - let _e353 = offset_3; - trilinear = mix((vec3(1f, 1f, 1f) - _e350), _e352, _e353); - let _e356 = trilinear[0u]; - let _e358 = trilinear[1u]; - let _e361 = trilinear[2u]; - weight_3 = max(((_e356 * _e358) * _e361), 0.001f); - let _e364 = origin_2; - let _e365 = spacing; - let _e366 = cell_1; - probePosition = (_e364 + (_e365 * _e366)); - let _e369 = probePosition; - let _e370 = biased; - toProbe = (_e369 - _e370); - let _e372 = toProbe; - distance_4 = length(_e372); - let _e374 = distance_4; - if (_e374 > 0.000001f) { - let _e376 = toProbe; - let _e377 = distance_4; - direction_2 = (_e376 / vec3(_e377)); - let _e380 = unit; - let _e381 = probePosition; - let _e382 = (*world_4); - facing = ((dot(_e380, normalize((_e381 - _e382))) * 0.5f) + 0.5f); - let _e388 = facing; + let _e351 = f_1; + let _e353 = f_1; + let _e354 = offset_3; + trilinear = mix((vec3(1f, 1f, 1f) - _e351), _e353, _e354); + let _e357 = trilinear[0u]; + let _e359 = trilinear[1u]; + let _e362 = trilinear[2u]; + weight_3 = max(((_e357 * _e359) * _e362), 0.001f); + let _e365 = origin_2; + let _e366 = spacing; + let _e367 = cell_1; + probePosition = (_e365 + (_e366 * _e367)); + let _e370 = probePosition; + let _e371 = biased; + toProbe = (_e370 - _e371); + let _e373 = toProbe; + distance_4 = length(_e373); + let _e375 = distance_4; + if (_e375 > 0.000001f) { + let _e377 = toProbe; + let _e378 = distance_4; + direction_2 = (_e377 / vec3(_e378)); + let _e381 = unit; + let _e382 = probePosition; + let _e383 = (*world_4); + facing = ((dot(_e381, normalize((_e382 - _e383))) * 0.5f) + 0.5f); let _e389 = facing; - probeWeight = ((_e388 * _e389) + 0.2f); - let _e392 = direction_2; - param_120 = -(_e392); - let _e394 = ProbeOctahedral_u0028_vf3_u003b((¶m_120)); - let _e395 = momentCorner; - param_121 = _e395; - let _e396 = depthTile; - param_122 = _e396; - param_123 = _e394; - let _e397 = TileBilinear_u0028_vf2_u003b_f1_u003b_vf2_u003b((¶m_121), (¶m_122), (¶m_123)); - moments_3 = _e397.xy; + let _e390 = facing; + probeWeight = ((_e389 * _e390) + 0.2f); + let _e393 = direction_2; + param_120 = -(_e393); + let _e395 = ProbeOctahedral_u0028_vf3_u003b((¶m_120)); + let _e396 = momentCorner; + param_121 = _e396; + let _e397 = depthTile; + param_122 = _e397; + param_123 = _e395; + let _e398 = TileBilinear_u0028_vf2_u003b_f1_u003b_vf2_u003b((¶m_121), (¶m_122), (¶m_123)); + moments_3 = _e398.xy; chebyshev = 1f; - let _e399 = distance_4; - let _e401 = moments_3[0u]; - if (_e399 > _e401) { - let _e404 = moments_3[1u]; - let _e406 = moments_3[0u]; - let _e408 = moments_3[0u]; - variance_1 = max((_e404 - (_e406 * _e408)), 0.000001f); - let _e412 = distance_4; - let _e414 = moments_3[0u]; - difference = (_e412 - _e414); - let _e416 = variance_1; + let _e400 = distance_4; + let _e402 = moments_3[0u]; + if (_e400 > _e402) { + let _e405 = moments_3[1u]; + let _e407 = moments_3[0u]; + let _e409 = moments_3[0u]; + variance_1 = max((_e405 - (_e407 * _e409)), 0.000001f); + let _e413 = distance_4; + let _e415 = moments_3[0u]; + difference = (_e413 - _e415); let _e417 = variance_1; - let _e418 = difference; + let _e418 = variance_1; let _e419 = difference; - chebyshev = (_e416 / (_e417 + (_e418 * _e419))); - let _e423 = chebyshev; + let _e420 = difference; + chebyshev = (_e417 / (_e418 + (_e419 * _e420))); let _e424 = chebyshev; - let _e426 = chebyshev; - chebyshev = ((_e423 * _e424) * _e426); + let _e425 = chebyshev; + let _e427 = chebyshev; + chebyshev = ((_e424 * _e425) * _e427); } - let _e428 = probeWeight; - let _e429 = chebyshev; - probeWeight = max((_e428 * max(_e429, 0.05f)), 0.000001f); - let _e433 = probeWeight; - if (_e433 < 0.2f) { - let _e435 = probeWeight; + let _e429 = probeWeight; + let _e430 = chebyshev; + probeWeight = max((_e429 * max(_e430, 0.05f)), 0.000001f); + let _e434 = probeWeight; + if (_e434 < 0.2f) { let _e436 = probeWeight; - let _e439 = probeWeight; - probeWeight = (_e439 * ((_e435 * _e436) * 25f)); + let _e437 = probeWeight; + let _e440 = probeWeight; + probeWeight = (_e440 * ((_e436 * _e437) * 25f)); } - let _e441 = probeWeight; - let _e442 = weight_3; - weight_3 = (_e442 * _e441); - } - let _e444 = unit; - param_124 = _e444; - let _e445 = ProbeOctahedral_u0028_vf3_u003b((¶m_124)); - let _e446 = irradianceCorner; - param_125 = _e446; - let _e447 = irradianceTile; - param_126 = _e447; - param_127 = _e445; - let _e448 = TileBilinear_u0028_vf2_u003b_f1_u003b_vf2_u003b((¶m_125), (¶m_126), (¶m_127)); - let _e450 = weight_3; - let _e452 = total_2; - total_2 = (_e452 + (_e448.xyz * _e450)); - let _e454 = weight_3; - let _e455 = weights; - weights = (_e455 + _e454); + let _e442 = probeWeight; + let _e443 = weight_3; + weight_3 = (_e443 * _e442); + } + let _e445 = unit; + param_124 = _e445; + let _e446 = ProbeOctahedral_u0028_vf3_u003b((¶m_124)); + let _e447 = irradianceCorner; + param_125 = _e447; + let _e448 = irradianceTile; + param_126 = _e448; + param_127 = _e446; + let _e449 = TileBilinear_u0028_vf2_u003b_f1_u003b_vf2_u003b((¶m_125), (¶m_126), (¶m_127)); + let _e451 = weight_3; + let _e453 = total_2; + total_2 = (_e453 + (_e449.xyz * _e451)); + let _e455 = weight_3; + let _e456 = weights; + weights = (_e456 + _e455); continue; } else { break; } continuing { - let _e457 = corner_1; - corner_1 = (_e457 + 1i); + let _e458 = corner_1; + corner_1 = (_e458 + 1i); } } - let _e459 = weights; - if (_e459 > 0f) { - let _e461 = total_2; - let _e462 = weights; - local_27 = (_e461 / vec3(_e462)); + let _e460 = weights; + if (_e460 > 0f) { + let _e462 = total_2; + let _e463 = weights; + local_27 = (_e462 / vec3(_e463)); } else { local_27 = vec3(0f, 0f, 0f); } - let _e465 = local_27; - return _e465; + let _e466 = local_27; + return _e466; } fn IrradianceEnabled_u0028_() -> bool { - let _e188 = irradiance_info.origin[3u]; - return (_e188 > 0.5f); + let _e189 = irradiance_info.origin[3u]; + return (_e189 > 0.5f); } fn ApplyCommonMaps_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b(s_9: ptr) { @@ -9392,50 +9427,50 @@ fn ApplyCommonMaps_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d var param_132: Surface; var param_133: Surface; - let _e193 = IrradianceEnabled_u0028_(); - if _e193 { - let _e194 = v_world_position_1; - param_128 = _e194; - let _e196 = (*s_9).n; - param_129 = _e196; - let _e198 = (*s_9).v; - param_130 = _e198; - let _e199 = SampleIrradiance_u0028_vf3_u003b_vf3_u003b_vf3_u003b((¶m_128), (¶m_129), (¶m_130)); - let _e202 = frag_info.material[2u]; - (*s_9).ambient = (_e199 * _e202); - } - let _e205 = (*s_9); - param_131 = _e205; + let _e194 = IrradianceEnabled_u0028_(); + if _e194 { + let _e195 = v_world_position_1; + param_128 = _e195; + let _e197 = (*s_9).n; + param_129 = _e197; + let _e199 = (*s_9).v; + param_130 = _e199; + let _e200 = SampleIrradiance_u0028_vf3_u003b_vf3_u003b_vf3_u003b((¶m_128), (¶m_129), (¶m_130)); + let _e203 = frag_info.material[2u]; + (*s_9).ambient = (_e200 * _e203); + } + let _e206 = (*s_9); + param_131 = _e206; ApplyNormalMap_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b((¶m_131)); - let _e206 = param_131; - (*s_9) = _e206; - let _e207 = (*s_9); - param_132 = _e207; + let _e207 = param_131; + (*s_9) = _e207; + let _e208 = (*s_9); + param_132 = _e208; ApplyOcclusionMap_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b((¶m_132)); - let _e208 = param_132; - (*s_9) = _e208; - let _e209 = (*s_9); - param_133 = _e209; + let _e209 = param_132; + (*s_9) = _e209; + let _e210 = (*s_9); + param_133 = _e210; ApplyEmissiveMap_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b((¶m_133)); - let _e210 = param_133; - (*s_9) = _e210; + let _e211 = param_133; + (*s_9) = _e211; return; } fn TowardsEye_u0028_() -> vec3 { var local_28: vec3; - let _e187 = Orthographic_u0028_(); - if _e187 { - let _e189 = fog_info.forward; - local_28 = -(_e189.xyz); + let _e188 = Orthographic_u0028_(); + if _e188 { + let _e190 = fog_info.forward; + local_28 = -(_e190.xyz); } else { - let _e193 = fog_info.eye; - let _e195 = v_world_position_1; - local_28 = normalize((_e193.xyz - _e195)); + let _e194 = fog_info.eye; + let _e196 = v_world_position_1; + local_28 = normalize((_e194.xyz - _e196)); } - let _e198 = local_28; - return _e198; + let _e199 = local_28; + return _e199; } fn ReadSurface_u0028_() -> Surface { @@ -9448,89 +9483,89 @@ fn ReadSurface_u0028_() -> Surface { var anchored: vec3; var noise_1: f32; - let _e194 = v_texcoord_1; - let _e195 = MaterialLodBias_u0028_(); - let _e196 = textureSampleBias(base_color_texture_tex, base_color_texture_smp, _e194, _e195); - texel_6 = _e196; - let _e197 = texel_6; - param_134 = _e197.xyz; - let _e199 = SrgbToLinear_u0028_vf3_u003b((¶m_134)); - let _e201 = frag_info.base_color; - param_135 = _e201.xyz; - let _e203 = SrgbToLinear_u0028_vf3_u003b((¶m_135)); - let _e205 = v_color_1; - s_10.albedo = ((_e199 * _e203) * _e205.xyz); - let _e210 = texel_6[3u]; - let _e213 = frag_info.base_color[3u]; - let _e216 = v_color_1[3u]; - s_10.alpha = ((_e210 * _e213) * _e216); - let _e220 = s_10.albedo; - g_albedo = _e220; - let _e223 = frag_info.material2_[0u]; - cutoff = _e223; - let _e224 = cutoff; - if (_e224 > 1f) { - let _e226 = cutoff; - edge = (_e226 - 1f); - let _e229 = s_10.alpha; - let _e230 = edge; - let _e233 = s_10.alpha; - let _e234 = fwidth(_e233); - s_10.alpha = clamp((((_e229 - _e230) / max(_e234, 0.0001f)) + 0.5f), 0f, 1f); - } else { - let _e240 = cutoff; - if (_e240 >= 0f) { - let _e243 = s_10.alpha; - let _e244 = cutoff; - if (_e243 < _e244) { - discard; - } - s_10.alpha = 1f; - } else { - let _e247 = cutoff; - if (_e247 < -1.5f) { - let _e249 = v_world_position_1; - anchored = floor((_e249 * 16f)); - let _e252 = anchored; - noise_1 = fract((sin(dot(_e252, vec3(12.9898f, 78.233f, 37.719f))) * 43758.547f)); - let _e258 = s_10.alpha; - let _e259 = noise_1; - if (_e258 < _e259) { + let _e195 = v_texcoord_1; + let _e196 = MaterialLodBias_u0028_(); + let _e197 = textureSampleBias(base_color_texture_tex, base_color_texture_smp, _e195, _e196); + texel_6 = _e197; + let _e198 = texel_6; + param_134 = _e198.xyz; + let _e200 = SrgbToLinear_u0028_vf3_u003b((¶m_134)); + let _e202 = frag_info.base_color; + param_135 = _e202.xyz; + let _e204 = SrgbToLinear_u0028_vf3_u003b((¶m_135)); + let _e206 = v_color_1; + s_10.albedo = ((_e200 * _e204) * _e206.xyz); + let _e211 = texel_6[3u]; + let _e214 = frag_info.base_color[3u]; + let _e217 = v_color_1[3u]; + s_10.alpha = ((_e211 * _e214) * _e217); + let _e221 = s_10.albedo; + g_albedo = _e221; + let _e224 = frag_info.material2_[0u]; + cutoff = _e224; + let _e225 = cutoff; + if (_e225 > 1f) { + let _e227 = cutoff; + edge = (_e227 - 1f); + let _e230 = s_10.alpha; + let _e231 = edge; + let _e234 = s_10.alpha; + let _e235 = fwidth(_e234); + s_10.alpha = clamp((((_e230 - _e231) / max(_e235, 0.0001f)) + 0.5f), 0f, 1f); + } else { + let _e241 = cutoff; + if (_e241 >= 0f) { + let _e244 = s_10.alpha; + let _e245 = cutoff; + if (_e244 < _e245) { + discard; + } + s_10.alpha = 1f; + } else { + let _e248 = cutoff; + if (_e248 < -1.5f) { + let _e250 = v_world_position_1; + anchored = floor((_e250 * 16f)); + let _e253 = anchored; + noise_1 = fract((sin(dot(_e253, vec3(12.9898f, 78.233f, 37.719f))) * 43758.547f)); + let _e259 = s_10.alpha; + let _e260 = noise_1; + if (_e259 < _e260) { discard; } } } } - let _e261 = cutoff; - let _e263 = cutoff; - g_premultiply = ((_e261 < 0f) && (_e263 > -0.75f)); - let _e266 = v_normal_1; - s_10.n = normalize(_e266); - let _e269 = gl_FrontFacing_1; - if !(_e269) { - let _e272 = s_10.n; - s_10.n = -(_e272); - } - let _e275 = TowardsEye_u0028_(); - s_10.v = _e275; - let _e278 = s_10.n; - let _e280 = s_10.v; - s_10.n_dot_v = max(dot(_e278, _e280), 0.0001f); - let _e286 = frag_info.material[0u]; - s_10.metallic = clamp(_e286, 0f, 1f); - let _e291 = frag_info.material[1u]; - s_10.roughness = clamp(_e291, 0.02f, 1f); - let _e295 = frag_info.ambient_ground; - let _e298 = frag_info.ambient_sky; - let _e302 = s_10.n[1u]; - let _e309 = frag_info.material[2u]; - s_10.ambient = (mix(_e295.xyz, _e298.xyz, vec3(((_e302 * 0.5f) + 0.5f))) * _e309); - let _e314 = frag_info.frame_params[0u]; - s_10.exposure = max(_e314, 0f); + let _e262 = cutoff; + let _e264 = cutoff; + g_premultiply = ((_e262 < 0f) && (_e264 > -0.75f)); + let _e267 = v_normal_1; + s_10.n = normalize(_e267); + let _e270 = gl_FrontFacing_1; + if !(_e270) { + let _e273 = s_10.n; + s_10.n = -(_e273); + } + let _e276 = TowardsEye_u0028_(); + s_10.v = _e276; + let _e279 = s_10.n; + let _e281 = s_10.v; + s_10.n_dot_v = max(dot(_e279, _e281), 0.0001f); + let _e287 = frag_info.material[0u]; + s_10.metallic = clamp(_e287, 0f, 1f); + let _e292 = frag_info.material[1u]; + s_10.roughness = clamp(_e292, 0.02f, 1f); + let _e296 = frag_info.ambient_ground; + let _e299 = frag_info.ambient_sky; + let _e303 = s_10.n[1u]; + let _e310 = frag_info.material[2u]; + s_10.ambient = (mix(_e296.xyz, _e299.xyz, vec3(((_e303 * 0.5f) + 0.5f))) * _e310); + let _e315 = frag_info.frame_params[0u]; + s_10.exposure = max(_e315, 0f); s_10.occlusion = 1f; s_10.emissive = vec3(0f, 0f, 0f); - let _e319 = s_10; - return _e319; + let _e320 = s_10; + return _e320; } fn main_1() { @@ -9553,39 +9588,39 @@ fn main_1() { g_cluster_offset = 0f; g_cluster_count = 0f; light_transmittance = vec3(1f, 1f, 1f); - let _e196 = ReadSurface_u0028_(); - s_11 = _e196; - let _e197 = s_11; - param_136 = _e197; + let _e197 = ReadSurface_u0028_(); + s_11 = _e197; + let _e198 = s_11; + param_136 = _e198; ApplyCommonMaps_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b((¶m_136)); - let _e198 = param_136; - s_11 = _e198; - let _e200 = s_11.albedo; - let _e202 = s_11.ambient; - let _e203 = SampleLightmap_u0028_(); - let _e207 = s_11.occlusion; - ambient = ((_e200 * (_e202 + _e203)) * _e207); - let _e209 = s_11; - param_137 = _e209; - let _e210 = AccumulateLights_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b((¶m_137)); - let _e212 = s_11.occlusion; - let _e214 = ambient; - let _e217 = s_11.emissive; - lit_3 = (((_e210 * _e212) + _e214) + _e217); - let _e219 = s_11; - param_138 = _e219; - let _e220 = lit_3; - param_139 = _e220; - let _e221 = WriteDebugView_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_vf3_u003b((¶m_138), (¶m_139)); - if _e221 { + let _e199 = param_136; + s_11 = _e199; + let _e201 = s_11.albedo; + let _e203 = s_11.ambient; + let _e204 = SampleLightmap_u0028_(); + let _e208 = s_11.occlusion; + ambient = ((_e201 * (_e203 + _e204)) * _e208); + let _e210 = s_11; + param_137 = _e210; + let _e211 = AccumulateLights_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b((¶m_137)); + let _e213 = s_11.occlusion; + let _e215 = ambient; + let _e218 = s_11.emissive; + lit_3 = (((_e211 * _e213) + _e215) + _e218); + let _e220 = s_11; + param_138 = _e220; + let _e221 = lit_3; + param_139 = _e221; + let _e222 = WriteDebugView_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_vf3_u003b((¶m_138), (¶m_139)); + if _e222 { return; } - let _e222 = lit_3; - param_140 = _e222; - let _e224 = s_11.alpha; - param_141 = _e224; - let _e226 = s_11.roughness; - param_142 = _e226; + let _e223 = lit_3; + param_140 = _e223; + let _e225 = s_11.alpha; + param_141 = _e225; + let _e227 = s_11.roughness; + param_142 = _e227; WriteSurface_u0028_vf3_u003b_f1_u003b_f1_u003b((¶m_140), (¶m_141), (¶m_142)); return; } @@ -10093,10 +10128,10 @@ var shadow_texture_tex: texture_2d; var shadow_texture_smp: sampler; fn ViewDepth_u0028_() -> f32 { - let _e187 = v_world_position_1; - let _e189 = fog_info.eye; - let _e193 = fog_info.forward; - return dot((_e187 - _e189.xyz), _e193.xyz); + let _e188 = v_world_position_1; + let _e190 = fog_info.eye; + let _e194 = fog_info.forward; + return dot((_e188 - _e190.xyz), _e194.xyz); } fn WeightedBlendedWeight_u0028_f1_u003b(alpha: ptr) -> f32 { @@ -10105,22 +10140,22 @@ fn WeightedBlendedWeight_u0028_f1_u003b(alpha: ptr) -> f32 { var far: f32; var far3_: f32; - let _e192 = ViewDepth_u0028_(); - z = abs(_e192); - let _e194 = z; - near = (_e194 / 5f); - let _e196 = z; - far = (_e196 / 200f); - let _e198 = far; + let _e193 = ViewDepth_u0028_(); + z = abs(_e193); + let _e195 = z; + near = (_e195 / 5f); + let _e197 = z; + far = (_e197 / 200f); let _e199 = far; - let _e201 = far; - far3_ = ((_e198 * _e199) * _e201); - let _e203 = (*alpha); - let _e204 = near; + let _e200 = far; + let _e202 = far; + far3_ = ((_e199 * _e200) * _e202); + let _e204 = (*alpha); let _e205 = near; - let _e208 = far3_; + let _e206 = near; let _e209 = far3_; - return (_e203 * clamp((10f / ((0.00001f + (_e204 * _e205)) + (_e208 * _e209))), 0.01f, 3000f)); + let _e210 = far3_; + return (_e204 * clamp((10f / ((0.00001f + (_e205 * _e206)) + (_e209 * _e210))), 0.01f, 3000f)); } fn WriteWeightedBlended_u0028_() { @@ -10132,39 +10167,39 @@ fn WriteWeightedBlended_u0028_() { var revealage: bool; var local: vec4; - let _e196 = fog_info.forward[3u]; - mode = _e196; - let _e197 = mode; - if (_e197 > 0.5f) { - let _e200 = frag_color[3u]; - alpha_1 = _e200; - let _e201 = alpha_1; - param = _e201; - let _e202 = WeightedBlendedWeight_u0028_f1_u003b((¶m)); - weight = _e202; - let _e203 = frag_color; - let _e205 = weight; - let _e206 = (_e203.xyz * _e205); - let _e207 = alpha_1; - let _e208 = weight; - accumulate = vec4(_e206.x, _e206.y, _e206.z, (_e207 * _e208)); - let _e214 = mode; - let _e216 = mode; - revealage = ((_e214 > 1.5f) && (_e216 < 2.5f)); - let _e219 = revealage; - if _e219 { - let _e220 = alpha_1; - local = vec4(_e220); + let _e197 = fog_info.forward[3u]; + mode = _e197; + let _e198 = mode; + if (_e198 > 0.5f) { + let _e201 = frag_color[3u]; + alpha_1 = _e201; + let _e202 = alpha_1; + param = _e202; + let _e203 = WeightedBlendedWeight_u0028_f1_u003b((¶m)); + weight = _e203; + let _e204 = frag_color; + let _e206 = weight; + let _e207 = (_e204.xyz * _e206); + let _e208 = alpha_1; + let _e209 = weight; + accumulate = vec4(_e207.x, _e207.y, _e207.z, (_e208 * _e209)); + let _e215 = mode; + let _e217 = mode; + revealage = ((_e215 > 1.5f) && (_e217 < 2.5f)); + let _e220 = revealage; + if _e220 { + let _e221 = alpha_1; + local = vec4(_e221); } else { - let _e222 = accumulate; - local = _e222; + let _e223 = accumulate; + local = _e223; } - let _e223 = local; - frag_color = _e223; - let _e224 = mode; - if (_e224 > 2.5f) { - let _e226 = alpha_1; - frag_surface = vec4(_e226); + let _e224 = local; + frag_color = _e224; + let _e225 = mode; + if (_e225 > 2.5f) { + let _e227 = alpha_1; + frag_surface = vec4(_e227); } } return; @@ -10173,29 +10208,29 @@ fn WriteWeightedBlended_u0028_() { fn EncodeOctahedral_u0028_vf3_u003b(n: ptr>) -> vec2 { var e: vec2; - let _e190 = (*n)[0u]; - let _e193 = (*n)[1u]; - let _e197 = (*n)[2u]; - let _e200 = (*n); - (*n) = (_e200 / vec3(((abs(_e190) + abs(_e193)) + abs(_e197)))); - let _e203 = (*n); - e = _e203.xy; - let _e206 = (*n)[2u]; - if (_e206 < 0f) { - let _e208 = (*n); - let _e214 = (*n)[0u]; - let _e218 = (*n)[1u]; - e = ((vec2(1f) - abs(_e208.yx)) * vec2(select(-1f, 1f, (_e214 >= 0f)), select(-1f, 1f, (_e218 >= 0f)))); + let _e191 = (*n)[0u]; + let _e194 = (*n)[1u]; + let _e198 = (*n)[2u]; + let _e201 = (*n); + (*n) = (_e201 / vec3(((abs(_e191) + abs(_e194)) + abs(_e198)))); + let _e204 = (*n); + e = _e204.xy; + let _e207 = (*n)[2u]; + if (_e207 < 0f) { + let _e209 = (*n); + let _e215 = (*n)[0u]; + let _e219 = (*n)[1u]; + e = ((vec2(1f) - abs(_e209.yx)) * vec2(select(-1f, 1f, (_e215 >= 0f)), select(-1f, 1f, (_e219 >= 0f)))); } - let _e223 = e; - return ((_e223 * 0.5f) + vec2(0.5f)); + let _e224 = e; + return ((_e224 * 0.5f) + vec2(0.5f)); } fn LinearToSrgb_u0028_vf3_u003b(linear: ptr>) -> vec3 { - let _e188 = (*linear); - let _e190 = (*linear); - let _e194 = (*linear); - return mix((_e188 * 12.92f), ((pow(_e190, vec3(0.41666666f, 0.41666666f, 0.41666666f)) * 1.055f) - vec3(0.055f, 0.055f, 0.055f)), step(vec3(0.0031308f, 0.0031308f, 0.0031308f), _e194)); + let _e189 = (*linear); + let _e191 = (*linear); + let _e195 = (*linear); + return mix((_e189 * 12.92f), ((pow(_e191, vec3(0.41666666f, 0.41666666f, 0.41666666f)) * 1.055f) - vec3(0.055f, 0.055f, 0.055f)), step(vec3(0.0031308f, 0.0031308f, 0.0031308f), _e195)); } fn WriteSurfaceGeometry_u0028_f1_u003b(roughness: ptr) { @@ -10203,52 +10238,52 @@ fn WriteSurfaceGeometry_u0028_f1_u003b(roughness: ptr) { var geometric: vec3; var param_2: vec3; - let _e191 = g_albedo; - param_1 = clamp(_e191, vec3(0f, 0f, 0f), vec3(1f, 1f, 1f)); - let _e193 = LinearToSrgb_u0028_vf3_u003b((¶m_1)); - frag_albedo = vec4(_e193.x, _e193.y, _e193.z, 1f); - let _e198 = g_debug_surface_on; - if _e198 { - let _e199 = g_debug_surface; - let _e200 = ViewDepth_u0028_(); - frag_surface = vec4(_e199.x, _e199.y, _e199.z, _e200); + let _e192 = g_albedo; + param_1 = clamp(_e192, vec3(0f, 0f, 0f), vec3(1f, 1f, 1f)); + let _e194 = LinearToSrgb_u0028_vf3_u003b((¶m_1)); + frag_albedo = vec4(_e194.x, _e194.y, _e194.z, 1f); + let _e199 = g_debug_surface_on; + if _e199 { + let _e200 = g_debug_surface; + let _e201 = ViewDepth_u0028_(); + frag_surface = vec4(_e200.x, _e200.y, _e200.z, _e201); return; } - let _e205 = v_normal_1; - geometric = normalize(_e205); - let _e207 = gl_FrontFacing_1; - if !(_e207) { - let _e209 = geometric; - geometric = -(_e209); + let _e206 = v_normal_1; + geometric = normalize(_e206); + let _e208 = gl_FrontFacing_1; + if !(_e208) { + let _e210 = geometric; + geometric = -(_e210); } - let _e211 = geometric; - param_2 = _e211; - let _e212 = EncodeOctahedral_u0028_vf3_u003b((¶m_2)); - let _e213 = (*roughness); - let _e215 = ViewDepth_u0028_(); - frag_surface = vec4(_e212.x, _e212.y, clamp(_e213, 0f, 1f), _e215); + let _e212 = geometric; + param_2 = _e212; + let _e213 = EncodeOctahedral_u0028_vf3_u003b((¶m_2)); + let _e214 = (*roughness); + let _e216 = ViewDepth_u0028_(); + frag_surface = vec4(_e213.x, _e213.y, clamp(_e214, 0f, 1f), _e216); return; } fn Orthographic_u0028_() -> bool { - let _e189 = fog_info.projection[0u]; - return (_e189 > 0.5f); + let _e190 = fog_info.projection[0u]; + return (_e190 > 0.5f); } fn EyeDistance_u0028_() -> f32 { var local_1: f32; - let _e188 = Orthographic_u0028_(); - if _e188 { - let _e189 = ViewDepth_u0028_(); - local_1 = max(_e189, 0f); + let _e189 = Orthographic_u0028_(); + if _e189 { + let _e190 = ViewDepth_u0028_(); + local_1 = max(_e190, 0f); } else { - let _e191 = v_world_position_1; - let _e193 = fog_info.eye; - local_1 = distance(_e191, _e193.xyz); + let _e192 = v_world_position_1; + let _e194 = fog_info.eye; + local_1 = distance(_e192, _e194.xyz); } - let _e196 = local_1; - return _e196; + let _e197 = local_1; + return _e197; } fn ApplyFog_u0028_vf3_u003b(color: ptr>) -> vec3 { @@ -10258,41 +10293,41 @@ fn ApplyFog_u0028_vf3_u003b(color: ptr>) -> vec3 { var k: f32; var local_2: f32; - let _e195 = fog_info.fog[3u]; - density = _e195; - let _e196 = density; - if (_e196 <= 0f) { - let _e198 = (*color); - return _e198; + let _e196 = fog_info.fog[3u]; + density = _e196; + let _e197 = density; + if (_e197 <= 0f) { + let _e199 = (*color); + return _e199; } - let _e199 = EyeDistance_u0028_(); - d = _e199; - let _e202 = fog_info.eye[3u]; - falloff = _e202; - let _e203 = falloff; - if (_e203 > 0f) { - let _e205 = falloff; - let _e207 = v_world_position_1[1u]; - let _e210 = fog_info.eye[1u]; - k = (_e205 * (_e207 - _e210)); - let _e213 = k; - if (abs(_e213) > 0.001f) { - let _e216 = k; - let _e220 = k; - local_2 = ((1f - exp(-(_e216))) / _e220); + let _e200 = EyeDistance_u0028_(); + d = _e200; + let _e203 = fog_info.eye[3u]; + falloff = _e203; + let _e204 = falloff; + if (_e204 > 0f) { + let _e206 = falloff; + let _e208 = v_world_position_1[1u]; + let _e211 = fog_info.eye[1u]; + k = (_e206 * (_e208 - _e211)); + let _e214 = k; + if (abs(_e214) > 0.001f) { + let _e217 = k; + let _e221 = k; + local_2 = ((1f - exp(-(_e217))) / _e221); } else { - let _e222 = k; - local_2 = (1f - (0.5f * _e222)); + let _e223 = k; + local_2 = (1f - (0.5f * _e223)); } - let _e225 = local_2; - let _e226 = density; - density = (_e226 * _e225); + let _e226 = local_2; + let _e227 = density; + density = (_e227 * _e226); } - let _e229 = fog_info.fog; - let _e231 = (*color); - let _e232 = density; - let _e234 = d; - return mix(_e229.xyz, _e231, vec3(clamp(exp((-(_e232) * _e234)), 0f, 1f))); + let _e230 = fog_info.fog; + let _e232 = (*color); + let _e233 = density; + let _e235 = d; + return mix(_e230.xyz, _e232, vec3(clamp(exp((-(_e233) * _e235)), 0f, 1f))); } fn WriteSurface_u0028_vf3_u003b_f1_u003b_f1_u003b(linearColor: ptr>, alpha_2: ptr, roughness_1: ptr) { @@ -10300,44 +10335,44 @@ fn WriteSurface_u0028_vf3_u003b_f1_u003b_f1_u003b(linearColor: ptr; var param_4: f32; - let _e193 = g_premultiply; - let _e194 = (*alpha_2); - weight_1 = select(1f, _e194, _e193); - let _e196 = (*linearColor); - param_3 = _e196; - let _e197 = ApplyFog_u0028_vf3_u003b((¶m_3)); - let _e198 = weight_1; - let _e199 = (_e197 * _e198); - let _e200 = (*alpha_2); - let _e201 = g_pass_through; - frag_color = vec4(_e199.x, _e199.y, _e199.z, (_e200 * (1f - _e201))); - let _e208 = (*roughness_1); - param_4 = _e208; + let _e194 = g_premultiply; + let _e195 = (*alpha_2); + weight_1 = select(1f, _e195, _e194); + let _e197 = (*linearColor); + param_3 = _e197; + let _e198 = ApplyFog_u0028_vf3_u003b((¶m_3)); + let _e199 = weight_1; + let _e200 = (_e198 * _e199); + let _e201 = (*alpha_2); + let _e202 = g_pass_through; + frag_color = vec4(_e200.x, _e200.y, _e200.z, (_e201 * (1f - _e202))); + let _e209 = (*roughness_1); + param_4 = _e209; WriteSurfaceGeometry_u0028_f1_u003b((¶m_4)); WriteWeightedBlended_u0028_(); return; } fn SrgbToLinear_u0028_vf3_u003b(srgb: ptr>) -> vec3 { - let _e188 = (*srgb); - let _e191 = (*srgb); - let _e196 = (*srgb); - return mix((_e188 / vec3(12.92f)), pow(((_e191 + vec3(0.055f, 0.055f, 0.055f)) / vec3(1.055f)), vec3(2.4f, 2.4f, 2.4f)), step(vec3(0.04045f, 0.04045f, 0.04045f), _e196)); + let _e189 = (*srgb); + let _e192 = (*srgb); + let _e197 = (*srgb); + return mix((_e189 / vec3(12.92f)), pow(((_e192 + vec3(0.055f, 0.055f, 0.055f)) / vec3(1.055f)), vec3(2.4f, 2.4f, 2.4f)), step(vec3(0.04045f, 0.04045f, 0.04045f), _e197)); } fn NonFinite_u0028_vf3_u003b(c: ptr>) -> bool { var phi_2562_: bool; - let _e188 = (*c); let _e189 = (*c); - let _e191 = any((_e188 != _e189)); - phi_2562_ = _e191; - if !(_e191) { - let _e193 = (*c); - phi_2562_ = any((abs(_e193) > vec3(300000000000000000000000000000000000000f, 300000000000000000000000000000000000000f, 300000000000000000000000000000000000000f))); + let _e190 = (*c); + let _e192 = any((_e189 != _e190)); + phi_2562_ = _e192; + if !(_e192) { + let _e194 = (*c); + phi_2562_ = any((abs(_e194) > vec3(300000000000000000000000000000000000000f, 300000000000000000000000000000000000000f, 300000000000000000000000000000000000000f))); } - let _e198 = phi_2562_; - return _e198; + let _e199 = phi_2562_; + return _e199; } fn WriteDebugView_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_vf3_u003b(s: ptr, lit: ptr>) -> bool { @@ -10355,78 +10390,78 @@ fn WriteDebugView_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_ var param_9: vec3; var param_10: f32; - let _e204 = frag_info.debug_view[0u]; - view = _e204; - let _e205 = view; - if (_e205 < 0.5f) { + let _e205 = frag_info.debug_view[0u]; + view = _e205; + let _e206 = view; + if (_e206 < 0.5f) { return false; } - let _e208 = gl_FragCoord_1[0u]; - let _e211 = frag_info.debug_view[1u]; - let _e214 = frag_info.debug_view[2u]; - if (_e208 < (_e211 * _e214)) { + let _e209 = gl_FragCoord_1[0u]; + let _e212 = frag_info.debug_view[1u]; + let _e215 = frag_info.debug_view[2u]; + if (_e209 < (_e212 * _e215)) { return false; } - let _e217 = view; - code = i32((_e217 + 0.5f)); + let _e218 = view; + code = i32((_e218 + 0.5f)); shown = vec3(0f, 0f, 0f); - let _e220 = code; - if (_e220 == 1i) { - let _e223 = (*s).albedo; - param_5 = clamp(_e223, vec3(0f, 0f, 0f), vec3(1f, 1f, 1f)); - let _e225 = LinearToSrgb_u0028_vf3_u003b((¶m_5)); - shown = _e225; + let _e221 = code; + if (_e221 == 1i) { + let _e224 = (*s).albedo; + param_5 = clamp(_e224, vec3(0f, 0f, 0f), vec3(1f, 1f, 1f)); + let _e226 = LinearToSrgb_u0028_vf3_u003b((¶m_5)); + shown = _e226; } else { - let _e226 = code; - if (_e226 == 2i) { - let _e229 = (*s).n; - shown = ((_e229 * 0.5f) + vec3(0.5f, 0.5f, 0.5f)); + let _e227 = code; + if (_e227 == 2i) { + let _e230 = (*s).n; + shown = ((_e230 * 0.5f) + vec3(0.5f, 0.5f, 0.5f)); } else { - let _e232 = code; - if (_e232 == 3i) { - let _e235 = (*s).roughness; - shown = vec3(clamp(_e235, 0f, 1f)); + let _e233 = code; + if (_e233 == 3i) { + let _e236 = (*s).roughness; + shown = vec3(clamp(_e236, 0f, 1f)); } else { - let _e238 = code; - if (_e238 == 4i) { - let _e241 = (*s).metallic; - shown = vec3(clamp(_e241, 0f, 1f)); + let _e239 = code; + if (_e239 == 4i) { + let _e242 = (*s).metallic; + shown = vec3(clamp(_e242, 0f, 1f)); } else { - let _e244 = code; - if (_e244 == 5i) { - let _e247 = (*s).occlusion; - shown = vec3(clamp(_e247, 0f, 1f)); + let _e245 = code; + if (_e245 == 5i) { + let _e248 = (*s).occlusion; + shown = vec3(clamp(_e248, 0f, 1f)); } else { - let _e250 = code; - if (_e250 == 6i) { - let _e253 = (*s).emissive; - param_6 = clamp(_e253, vec3(0f, 0f, 0f), vec3(1f, 1f, 1f)); - let _e255 = LinearToSrgb_u0028_vf3_u003b((¶m_6)); - shown = _e255; + let _e251 = code; + if (_e251 == 6i) { + let _e254 = (*s).emissive; + param_6 = clamp(_e254, vec3(0f, 0f, 0f), vec3(1f, 1f, 1f)); + let _e256 = LinearToSrgb_u0028_vf3_u003b((¶m_6)); + shown = _e256; } else { - let _e256 = code; - if (_e256 == 7i) { - let _e258 = v_texcoord_1; - let _e259 = fract(_e258); - shown = vec3(_e259.x, _e259.y, 0f); + let _e257 = code; + if (_e257 == 7i) { + let _e259 = v_texcoord_1; + let _e260 = fract(_e259); + shown = vec3(_e260.x, _e260.y, 0f); } else { - let _e263 = code; - if (_e263 == 8i) { - let _e265 = (*lit); - param_7 = clamp(_e265, vec3(0f, 0f, 0f), vec3(1f, 1f, 1f)); - let _e267 = LinearToSrgb_u0028_vf3_u003b((¶m_7)); - grey = dot(_e267, vec3(0.2126f, 0.7152f, 0.0722f)); - let _e269 = (*lit); - param_8 = _e269; - let _e270 = NonFinite_u0028_vf3_u003b((¶m_8)); - if _e270 { + let _e264 = code; + if (_e264 == 8i) { + let _e266 = (*lit); + param_7 = clamp(_e266, vec3(0f, 0f, 0f), vec3(1f, 1f, 1f)); + let _e268 = LinearToSrgb_u0028_vf3_u003b((¶m_7)); + grey = dot(_e268, vec3(0.2126f, 0.7152f, 0.0722f)); + let _e270 = (*lit); + param_8 = _e270; + let _e271 = NonFinite_u0028_vf3_u003b((¶m_8)); + if _e271 { local_3 = vec3(1f, 0f, 1f); } else { - let _e271 = grey; - local_3 = vec3((_e271 * 0.5f)); + let _e272 = grey; + local_3 = vec3((_e272 * 0.5f)); } - let _e274 = local_3; - shown = _e274; + let _e275 = local_3; + shown = _e275; } } } @@ -10435,24 +10470,24 @@ fn WriteDebugView_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_ } } } - let _e275 = g_premultiply; - if _e275 { - let _e277 = (*s).alpha; - local_4 = _e277; + let _e276 = g_premultiply; + if _e276 { + let _e278 = (*s).alpha; + local_4 = _e278; } else { local_4 = 1f; } - let _e278 = local_4; - weight_2 = _e278; - let _e279 = shown; - param_9 = _e279; - let _e280 = SrgbToLinear_u0028_vf3_u003b((¶m_9)); - let _e281 = weight_2; - let _e282 = (_e280 * _e281); - let _e284 = (*s).alpha; - frag_color = vec4(_e282.x, _e282.y, _e282.z, _e284); - let _e290 = (*s).roughness; - param_10 = _e290; + let _e279 = local_4; + weight_2 = _e279; + let _e280 = shown; + param_9 = _e280; + let _e281 = SrgbToLinear_u0028_vf3_u003b((¶m_9)); + let _e282 = weight_2; + let _e283 = (_e281 * _e282); + let _e285 = (*s).alpha; + frag_color = vec4(_e283.x, _e283.y, _e283.z, _e285); + let _e291 = (*s).roughness; + param_10 = _e291; WriteSurfaceGeometry_u0028_f1_u003b((¶m_10)); WriteWeightedBlended_u0028_(); return true; @@ -10462,44 +10497,44 @@ fn ShadeLight_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_ var shininess: f32; var specular: f32; - let _e192 = (*s_1).roughness; - shininess = mix(256f, 4f, _e192); - let _e195 = (*light).n_dot_h; - let _e196 = shininess; - let _e200 = frag_info.material[3u]; - specular = (pow(_e195, _e196) * _e200); - let _e203 = (*s_1).albedo; - let _e204 = specular; - return (_e203 + vec3(_e204)); + let _e193 = (*s_1).roughness; + shininess = mix(256f, 4f, _e193); + let _e196 = (*light).n_dot_h; + let _e197 = shininess; + let _e201 = frag_info.material[3u]; + specular = (pow(_e196, _e197) * _e201); + let _e204 = (*s_1).albedo; + let _e205 = specular; + return (_e204 + vec3(_e205)); } fn PointShadowDiskTap_u0028_i1_u003b(i: ptr) -> vec2 { - let _e188 = (*i); - if (_e188 == 0i) { + let _e189 = (*i); + if (_e189 == 0i) { return vec2(-0.94201624f, -0.39906216f); } - let _e190 = (*i); - if (_e190 == 1i) { + let _e191 = (*i); + if (_e191 == 1i) { return vec2(0.9455861f, -0.76890725f); } - let _e192 = (*i); - if (_e192 == 2i) { + let _e193 = (*i); + if (_e193 == 2i) { return vec2(-0.0941841f, -0.9293887f); } - let _e194 = (*i); - if (_e194 == 3i) { + let _e195 = (*i); + if (_e195 == 3i) { return vec2(0.34495938f, 0.2938776f); } - let _e196 = (*i); - if (_e196 == 4i) { + let _e197 = (*i); + if (_e197 == 4i) { return vec2(-0.9158858f, 0.45771432f); } - let _e198 = (*i); - if (_e198 == 5i) { + let _e199 = (*i); + if (_e199 == 5i) { return vec2(-0.8154423f, -0.87912464f); } - let _e200 = (*i); - if (_e200 == 6i) { + let _e201 = (*i); + if (_e201 == 6i) { return vec2(-0.38277543f, 0.27676845f); } return vec2(0.974844f, 0.7564838f); @@ -10509,20 +10544,20 @@ fn PointShadowOffset_u0028_i1_u003b_f1_u003b_f1_u003b_f1_u003b(i_1: ptr; var param_11: i32; - let _e193 = (*i_1); - param_11 = _e193; - let _e194 = PointShadowDiskTap_u0028_i1_u003b((¶m_11)); - p = _e194; - let _e196 = p[0u]; - let _e197 = (*ca); - let _e200 = p[1u]; - let _e201 = (*sa); - let _e205 = p[0u]; - let _e206 = (*sa); - let _e209 = p[1u]; - let _e210 = (*ca); - let _e214 = (*radius); - return (vec2(((_e196 * _e197) - (_e200 * _e201)), ((_e205 * _e206) + (_e209 * _e210))) * _e214); + let _e194 = (*i_1); + param_11 = _e194; + let _e195 = PointShadowDiskTap_u0028_i1_u003b((¶m_11)); + p = _e195; + let _e197 = p[0u]; + let _e198 = (*ca); + let _e201 = p[1u]; + let _e202 = (*sa); + let _e206 = p[0u]; + let _e207 = (*sa); + let _e210 = p[1u]; + let _e211 = (*ca); + let _e215 = (*radius); + return (vec2(((_e197 * _e198) - (_e201 * _e202)), ((_e206 * _e207) + (_e210 * _e211))) * _e215); } fn PointShadowDistance_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b(uv: ptr>, offset: ptr>, tile: ptr>, range: ptr) -> f32 { @@ -10530,27 +10565,27 @@ fn PointShadowDistance_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b(uv: ptr; var atlas: vec2; - let _e196 = point_shadow.params[0u]; - inset = _e196; - let _e197 = (*uv); - let _e198 = (*offset); - let _e200 = inset; + let _e197 = point_shadow.params[0u]; + inset = _e197; + let _e198 = (*uv); + let _e199 = (*offset); let _e201 = inset; - local_5 = clamp((_e197 + _e198), vec2(_e200), vec2((1f - _e201))); - let _e206 = local_5; - let _e207 = (*tile); - atlas = ((_e206 + _e207) * vec2(0.16666667f, 0.16666667f)); - let _e212 = point_shadow.params3_[0u]; - if (_e212 > 0.5f) { - let _e215 = atlas[1u]; - atlas[1u] = (1f - _e215); + let _e202 = inset; + local_5 = clamp((_e198 + _e199), vec2(_e201), vec2((1f - _e202))); + let _e207 = local_5; + let _e208 = (*tile); + atlas = ((_e207 + _e208) * vec2(0.16666667f, 0.16666667f)); + let _e213 = point_shadow.params3_[0u]; + if (_e213 > 0.5f) { + let _e216 = atlas[1u]; + atlas[1u] = (1f - _e216); } - let _e218 = atlas; - let _e219 = textureSampleLevel(point_shadow_texture_tex, point_shadow_texture_smp, _e218, 0f); - let _e221 = atlas; - let _e222 = textureSampleLevel(point_shadow_static_texture_tex, point_shadow_static_texture_smp, _e221, 0f); - let _e225 = (*range); - return (min(_e219.x, _e222.x) * _e225); + let _e219 = atlas; + let _e220 = textureSampleLevel(point_shadow_texture_tex, point_shadow_texture_smp, _e219, 0f); + let _e222 = atlas; + let _e223 = textureSampleLevel(point_shadow_static_texture_tex, point_shadow_static_texture_smp, _e222, 0f); + let _e226 = (*range); + return (min(_e220.x, _e223.x) * _e226); } fn PointShadowTap_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b_f1_u003b(uv_1: ptr>, offset_1: ptr>, tile_1: ptr>, range_1: ptr, receiver: ptr) -> f32 { @@ -10560,24 +10595,24 @@ fn PointShadowTap_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b_f1_u003b(uv_1: pt var param_14: vec2; var param_15: f32; - let _e197 = (*uv_1); - param_12 = _e197; - let _e198 = (*offset_1); - param_13 = _e198; - let _e199 = (*tile_1); - param_14 = _e199; - let _e200 = (*range_1); - param_15 = _e200; - let _e201 = PointShadowDistance_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b((¶m_12), (¶m_13), (¶m_14), (¶m_15)); - stored = _e201; - let _e202 = stored; - let _e203 = (*range_1); - if (_e202 >= (_e203 * 0.999f)) { + let _e198 = (*uv_1); + param_12 = _e198; + let _e199 = (*offset_1); + param_13 = _e199; + let _e200 = (*tile_1); + param_14 = _e200; + let _e201 = (*range_1); + param_15 = _e201; + let _e202 = PointShadowDistance_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b((¶m_12), (¶m_13), (¶m_14), (¶m_15)); + stored = _e202; + let _e203 = stored; + let _e204 = (*range_1); + if (_e203 >= (_e204 * 0.999f)) { return 1f; } - let _e206 = (*receiver); - let _e207 = stored; - return select(1f, 0f, (_e206 > _e207)); + let _e207 = (*receiver); + let _e208 = stored; + return select(1f, 0f, (_e207 > _e208)); } fn PointShadowPenumbra_u0028_vf2_u003b_vf2_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b(uv_2: ptr>, tile_2: ptr>, range_2: ptr, receiver_1: ptr, ca_1: ptr, sa_1: ptr, tanHalf: ptr, blockerOut: ptr) -> f32 { @@ -10604,111 +10639,111 @@ fn PointShadowPenumbra_u0028_vf2_u003b_vf2_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u var world: f32; (*blockerOut) = -1f; - let _e218 = point_shadow.params2_[1u]; - lightRadius = _e218; - let _e221 = point_shadow.params2_[0u]; - minRadius = _e221; - let _e224 = point_shadow.params2_[2u]; - maxRadius = _e224; - let _e225 = lightRadius; - if (_e225 <= 0f) { - let _e227 = (*uv_2); - param_16 = _e227; + let _e219 = point_shadow.params2_[1u]; + lightRadius = _e219; + let _e222 = point_shadow.params2_[0u]; + minRadius = _e222; + let _e225 = point_shadow.params2_[2u]; + maxRadius = _e225; + let _e226 = lightRadius; + if (_e226 <= 0f) { + let _e228 = (*uv_2); + param_16 = _e228; param_17 = vec2(0f, 0f); - let _e228 = (*tile_2); - param_18 = _e228; - let _e229 = (*range_2); - param_19 = _e229; - let _e230 = PointShadowDistance_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b((¶m_16), (¶m_17), (¶m_18), (¶m_19)); - (*blockerOut) = _e230; - let _e231 = minRadius; - return _e231; + let _e229 = (*tile_2); + param_18 = _e229; + let _e230 = (*range_2); + param_19 = _e230; + let _e231 = PointShadowDistance_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b((¶m_16), (¶m_17), (¶m_18), (¶m_19)); + (*blockerOut) = _e231; + let _e232 = minRadius; + return _e232; } sum = 0f; count = 0f; i_2 = 0i; loop { - let _e232 = i_2; - if (_e232 < 8i) { - let _e234 = i_2; - param_20 = _e234; - let _e235 = (*ca_1); - param_21 = _e235; - let _e236 = (*sa_1); - param_22 = _e236; - let _e237 = maxRadius; - param_23 = _e237; - let _e238 = PointShadowOffset_u0028_i1_u003b_f1_u003b_f1_u003b_f1_u003b((¶m_20), (¶m_21), (¶m_22), (¶m_23)); - let _e239 = (*uv_2); - param_24 = _e239; - param_25 = _e238; - let _e240 = (*tile_2); - param_26 = _e240; - let _e241 = (*range_2); - param_27 = _e241; - let _e242 = PointShadowDistance_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b((¶m_24), (¶m_25), (¶m_26), (¶m_27)); - stored_1 = _e242; - let _e243 = stored_1; - let _e244 = (*range_2); - if (_e243 >= (_e244 * 0.999f)) { + let _e233 = i_2; + if (_e233 < 8i) { + let _e235 = i_2; + param_20 = _e235; + let _e236 = (*ca_1); + param_21 = _e236; + let _e237 = (*sa_1); + param_22 = _e237; + let _e238 = maxRadius; + param_23 = _e238; + let _e239 = PointShadowOffset_u0028_i1_u003b_f1_u003b_f1_u003b_f1_u003b((¶m_20), (¶m_21), (¶m_22), (¶m_23)); + let _e240 = (*uv_2); + param_24 = _e240; + param_25 = _e239; + let _e241 = (*tile_2); + param_26 = _e241; + let _e242 = (*range_2); + param_27 = _e242; + let _e243 = PointShadowDistance_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b((¶m_24), (¶m_25), (¶m_26), (¶m_27)); + stored_1 = _e243; + let _e244 = stored_1; + let _e245 = (*range_2); + if (_e244 >= (_e245 * 0.999f)) { continue; } - let _e247 = stored_1; - let _e248 = (*receiver_1); - if (_e247 >= _e248) { + let _e248 = stored_1; + let _e249 = (*receiver_1); + if (_e248 >= _e249) { continue; } - let _e250 = stored_1; - let _e251 = sum; - sum = (_e251 + _e250); - let _e253 = count; - count = (_e253 + 1f); + let _e251 = stored_1; + let _e252 = sum; + sum = (_e252 + _e251); + let _e254 = count; + count = (_e254 + 1f); continue; } else { break; } continuing { - let _e255 = i_2; - i_2 = (_e255 + 1i); + let _e256 = i_2; + i_2 = (_e256 + 1i); } } - let _e257 = count; - if (_e257 < 0.5f) { + let _e258 = count; + if (_e258 < 0.5f) { return -1f; } - let _e259 = sum; - let _e260 = count; - blocker = max((_e259 / _e260), 0.0001f); - let _e263 = blocker; - (*blockerOut) = _e263; - let _e264 = lightRadius; - let _e265 = (*receiver_1); - let _e266 = blocker; - let _e270 = blocker; - world = ((_e264 * max((_e265 - _e266), 0f)) / _e270); - let _e272 = world; - let _e273 = (*receiver_1); - let _e275 = (*tanHalf); - let _e278 = minRadius; - let _e279 = maxRadius; - return clamp((_e272 / ((2f * _e273) * _e275)), _e278, _e279); -} - -fn FragCoordFromTop_u0028_f1_u003b(rows: ptr) -> vec2 { - var local_6: vec2; - - let _e189 = (*rows); - if (_e189 > 0f) { - let _e192 = gl_FragCoord_1[0u]; - let _e193 = (*rows); - let _e195 = gl_FragCoord_1[1u]; - local_6 = vec2(_e192, (_e193 - _e195)); - } else { - let _e198 = gl_FragCoord_1; - local_6 = _e198.xy; + let _e260 = sum; + let _e261 = count; + blocker = max((_e260 / _e261), 0.0001f); + let _e264 = blocker; + (*blockerOut) = _e264; + let _e265 = lightRadius; + let _e266 = (*receiver_1); + let _e267 = blocker; + let _e271 = blocker; + world = ((_e265 * max((_e266 - _e267), 0f)) / _e271); + let _e273 = world; + let _e274 = (*receiver_1); + let _e276 = (*tanHalf); + let _e279 = minRadius; + let _e280 = maxRadius; + return clamp((_e273 / ((2f * _e274) * _e276)), _e279, _e280); +} + +fn FragCoordFromTop_u0028_f1_u003b(rows: ptr) -> vec2 { + var local_6: vec2; + + let _e190 = (*rows); + if (_e190 > 0f) { + let _e193 = gl_FragCoord_1[0u]; + let _e194 = (*rows); + let _e196 = gl_FragCoord_1[1u]; + local_6 = vec2(_e193, (_e194 - _e196)); + } else { + let _e199 = gl_FragCoord_1; + local_6 = _e199.xy; } - let _e200 = local_6; - return _e200; + let _e201 = local_6; + return _e201; } fn PointShadowFactor_u0028_vf3_u003b_vf3_u003b_i1_u003b(world_1: ptr>, normal: ptr>, lightIndex: ptr) -> f32 { @@ -10766,257 +10801,257 @@ fn PointShadowFactor_u0028_vf3_u003b_vf3_u003b_i1_u003b(world_1: ptr= _e328) { + let _e284 = nDotL; + slope = min((sqrt(max((1f - (_e277 * _e278)), 0f)) / (_e283 * _e284)), 8f); + let _e288 = toLightLength; + let _e290 = (*lightIndex); + let _e294 = point_shadow.slots[_e290][2u]; + let _e299 = point_shadow.params3_[1u]; + texel = (((2f * _e288) * max(_e294, 0.0001f)) * _e299); + let _e301 = (*world_1); + let _e302 = (*normal); + let _e303 = texel; + let _e307 = point_shadow.params[3u]; + let _e309 = slope; + origin = (_e301 + (((_e302 * _e303) * _e307) * (1f + _e309))); + let _e313 = origin; + let _e314 = slot; + let _e317 = point_shadow.lights[_e314]; + toFragment = (_e313 - _e317.xyz); + let _e320 = toFragment; + distance_ = length(_e320); + let _e322 = slot; + let _e326 = point_shadow.lights[_e322][3u]; + range_3 = max(_e326, 0.0001f); + let _e328 = distance_; + let _e329 = range_3; + if (_e328 >= _e329) { return 1f; } face = 0i; - let _e330 = (*lightIndex); - let _e334 = point_shadow.slots[_e330][1u]; - if (_e334 < 0.5f) { - let _e336 = toFragment; - a = abs(_e336); - let _e339 = a[0u]; - let _e341 = a[1u]; - let _e342 = (_e339 >= _e341); - phi_2249_ = _e342; - if _e342 { - let _e344 = a[0u]; - let _e346 = a[2u]; - phi_2249_ = (_e344 >= _e346); + let _e331 = (*lightIndex); + let _e335 = point_shadow.slots[_e331][1u]; + if (_e335 < 0.5f) { + let _e337 = toFragment; + a = abs(_e337); + let _e340 = a[0u]; + let _e342 = a[1u]; + let _e343 = (_e340 >= _e342); + phi_2249_ = _e343; + if _e343 { + let _e345 = a[0u]; + let _e347 = a[2u]; + phi_2249_ = (_e345 >= _e347); } - let _e349 = phi_2249_; - if _e349 { - let _e351 = toFragment[0u]; - face = select(1i, 0i, (_e351 > 0f)); + let _e350 = phi_2249_; + if _e350 { + let _e352 = toFragment[0u]; + face = select(1i, 0i, (_e352 > 0f)); } else { - let _e355 = a[1u]; - let _e357 = a[2u]; - if (_e355 >= _e357) { - let _e360 = toFragment[1u]; - face = select(3i, 2i, (_e360 > 0f)); + let _e356 = a[1u]; + let _e358 = a[2u]; + if (_e356 >= _e358) { + let _e361 = toFragment[1u]; + face = select(3i, 2i, (_e361 > 0f)); } else { - let _e364 = toFragment[2u]; - face = select(5i, 4i, (_e364 > 0f)); + let _e365 = toFragment[2u]; + face = select(5i, 4i, (_e365 > 0f)); } } } - let _e367 = slot; - let _e369 = face; - let _e373 = point_shadow.faces[((_e367 * 6i) + _e369)]; - let _e374 = origin; - clip = (_e373 * vec4(_e374.x, _e374.y, _e374.z, 1f)); - let _e381 = clip[3u]; - if (_e381 <= 0f) { + let _e368 = slot; + let _e370 = face; + let _e374 = point_shadow.faces[((_e368 * 6i) + _e370)]; + let _e375 = origin; + clip = (_e374 * vec4(_e375.x, _e375.y, _e375.z, 1f)); + let _e382 = clip[3u]; + if (_e382 <= 0f) { return 1f; } - let _e383 = clip; - let _e386 = clip[3u]; - ndc = (_e383.xy / vec2(_e386)); - let _e390 = ndc[0u]; - let _e392 = (abs(_e390) > 1f); - phi_2310_ = _e392; - if !(_e392) { - let _e395 = ndc[1u]; - phi_2310_ = (abs(_e395) > 1f); + let _e384 = clip; + let _e387 = clip[3u]; + ndc = (_e384.xy / vec2(_e387)); + let _e391 = ndc[0u]; + let _e393 = (abs(_e391) > 1f); + phi_2310_ = _e393; + if !(_e393) { + let _e396 = ndc[1u]; + phi_2310_ = (abs(_e396) > 1f); } - let _e399 = phi_2310_; - if _e399 { + let _e400 = phi_2310_; + if _e400 { return 1f; } - let _e401 = ndc[0u]; - let _e405 = ndc[1u]; - uv_3 = vec2(((_e401 * 0.5f) + 0.5f), (0.5f - (_e405 * 0.5f))); - let _e409 = face; - let _e411 = slot; - tile_3 = vec2(f32(_e409), f32(_e411)); - let _e414 = distance_; - let _e417 = point_shadow.params[1u]; - receiver_2 = (_e414 - _e417); - let _e421 = frag_info.target_origin[0u]; - param_28 = _e421; - let _e422 = FragCoordFromTop_u0028_f1_u003b((¶m_28)); - noise = fract((52.982918f * fract(dot(_e422, vec2(0.06711056f, 0.00583715f))))); - let _e427 = noise; - angle = (_e427 * 6.2831855f); - let _e429 = angle; - ca_2 = cos(_e429); - let _e431 = angle; - sa_2 = sin(_e431); - let _e433 = (*lightIndex); - let _e437 = point_shadow.slots[_e433][2u]; - tanHalf_1 = max(_e437, 0.0001f); + let _e402 = ndc[0u]; + let _e406 = ndc[1u]; + uv_3 = vec2(((_e402 * 0.5f) + 0.5f), (0.5f - (_e406 * 0.5f))); + let _e410 = face; + let _e412 = slot; + tile_3 = vec2(f32(_e410), f32(_e412)); + let _e415 = distance_; + let _e418 = point_shadow.params[1u]; + receiver_2 = (_e415 - _e418); + let _e422 = frag_info.target_origin[0u]; + param_28 = _e422; + let _e423 = FragCoordFromTop_u0028_f1_u003b((¶m_28)); + noise = fract((52.982918f * fract(dot(_e423, vec2(0.06711056f, 0.00583715f))))); + let _e428 = noise; + angle = (_e428 * 6.2831855f); + let _e430 = angle; + ca_2 = cos(_e430); + let _e432 = angle; + sa_2 = sin(_e432); + let _e434 = (*lightIndex); + let _e438 = point_shadow.slots[_e434][2u]; + tanHalf_1 = max(_e438, 0.0001f); blocker_1 = -1f; - let _e439 = uv_3; - param_29 = _e439; - let _e440 = tile_3; - param_30 = _e440; - let _e441 = range_3; - param_31 = _e441; - let _e442 = receiver_2; - param_32 = _e442; - let _e443 = ca_2; - param_33 = _e443; - let _e444 = sa_2; - param_34 = _e444; - let _e445 = tanHalf_1; - param_35 = _e445; - let _e446 = PointShadowPenumbra_u0028_vf2_u003b_vf2_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b((¶m_29), (¶m_30), (¶m_31), (¶m_32), (¶m_33), (¶m_34), (¶m_35), (¶m_36)); - let _e447 = param_36; - blocker_1 = _e447; - radius_1 = _e446; - let _e450 = point_shadow.params2_[3u]; - if (_e450 > 0.5f) { + let _e440 = uv_3; + param_29 = _e440; + let _e441 = tile_3; + param_30 = _e441; + let _e442 = range_3; + param_31 = _e442; + let _e443 = receiver_2; + param_32 = _e443; + let _e444 = ca_2; + param_33 = _e444; + let _e445 = sa_2; + param_34 = _e445; + let _e446 = tanHalf_1; + param_35 = _e446; + let _e447 = PointShadowPenumbra_u0028_vf2_u003b_vf2_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b((¶m_29), (¶m_30), (¶m_31), (¶m_32), (¶m_33), (¶m_34), (¶m_35), (¶m_36)); + let _e448 = param_36; + blocker_1 = _e448; + radius_1 = _e447; + let _e451 = point_shadow.params2_[3u]; + if (_e451 > 0.5f) { g_debug_surface_on = true; - let _e452 = radius_1; - if (_e452 < 0f) { + let _e453 = radius_1; + if (_e453 < 0f) { local_7 = vec3(0f, 0f, 1f); } else { - let _e454 = radius_1; - let _e457 = point_shadow.params2_[2u]; - let _e461 = blocker_1; - let _e462 = range_3; - local_7 = vec3(clamp((_e454 / max(_e457, 0.000001f)), 0f, 1f), clamp((_e461 / _e462), 0f, 1f), 0f); + let _e455 = radius_1; + let _e458 = point_shadow.params2_[2u]; + let _e462 = blocker_1; + let _e463 = range_3; + local_7 = vec3(clamp((_e455 / max(_e458, 0.000001f)), 0f, 1f), clamp((_e462 / _e463), 0f, 1f), 0f); } - let _e466 = local_7; - g_debug_surface = _e466; + let _e467 = local_7; + g_debug_surface = _e467; } - let _e467 = radius_1; - if (_e467 < 0f) { + let _e468 = radius_1; + if (_e468 < 0f) { return 1f; } - let _e469 = uv_3; - param_37 = _e469; + let _e470 = uv_3; + param_37 = _e470; param_38 = vec2(0f, 0f); - let _e470 = tile_3; - param_39 = _e470; - let _e471 = range_3; - param_40 = _e471; - let _e472 = receiver_2; - param_41 = _e472; - let _e473 = PointShadowTap_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b_f1_u003b((¶m_37), (¶m_38), (¶m_39), (¶m_40), (¶m_41)); - lit_1 = _e473; - let _e474 = radius_1; - if (_e474 > 0f) { + let _e471 = tile_3; + param_39 = _e471; + let _e472 = range_3; + param_40 = _e472; + let _e473 = receiver_2; + param_41 = _e473; + let _e474 = PointShadowTap_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b_f1_u003b((¶m_37), (¶m_38), (¶m_39), (¶m_40), (¶m_41)); + lit_1 = _e474; + let _e475 = radius_1; + if (_e475 > 0f) { i_3 = 0i; loop { - let _e476 = i_3; - if (_e476 < 8i) { - let _e478 = i_3; - param_42 = _e478; - let _e479 = ca_2; - param_43 = _e479; - let _e480 = sa_2; - param_44 = _e480; - let _e481 = radius_1; - param_45 = _e481; - let _e482 = PointShadowOffset_u0028_i1_u003b_f1_u003b_f1_u003b_f1_u003b((¶m_42), (¶m_43), (¶m_44), (¶m_45)); - let _e483 = uv_3; - param_46 = _e483; - param_47 = _e482; - let _e484 = tile_3; - param_48 = _e484; - let _e485 = range_3; - param_49 = _e485; - let _e486 = receiver_2; - param_50 = _e486; - let _e487 = PointShadowTap_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b_f1_u003b((¶m_46), (¶m_47), (¶m_48), (¶m_49), (¶m_50)); - let _e488 = lit_1; - lit_1 = (_e488 + _e487); + let _e477 = i_3; + if (_e477 < 8i) { + let _e479 = i_3; + param_42 = _e479; + let _e480 = ca_2; + param_43 = _e480; + let _e481 = sa_2; + param_44 = _e481; + let _e482 = radius_1; + param_45 = _e482; + let _e483 = PointShadowOffset_u0028_i1_u003b_f1_u003b_f1_u003b_f1_u003b((¶m_42), (¶m_43), (¶m_44), (¶m_45)); + let _e484 = uv_3; + param_46 = _e484; + param_47 = _e483; + let _e485 = tile_3; + param_48 = _e485; + let _e486 = range_3; + param_49 = _e486; + let _e487 = receiver_2; + param_50 = _e487; + let _e488 = PointShadowTap_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b_f1_u003b((¶m_46), (¶m_47), (¶m_48), (¶m_49), (¶m_50)); + let _e489 = lit_1; + lit_1 = (_e489 + _e488); continue; } else { break; } continuing { - let _e490 = i_3; - i_3 = (_e490 + 1i); + let _e491 = i_3; + i_3 = (_e491 + 1i); } } - let _e492 = lit_1; - lit_1 = (_e492 * 0.11111111f); + let _e493 = lit_1; + lit_1 = (_e493 * 0.11111111f); } - let _e494 = lit_1; - let _e495 = strength; - return mix(1f, _e494, clamp(_e495, 0f, 1f)); + let _e495 = lit_1; + let _e496 = strength; + return mix(1f, _e495, clamp(_e496, 0f, 1f)); } fn VogelDisc_u0028_i1_u003b_i1_u003b_f1_u003b(i_4: ptr, n_1: ptr, turn: ptr) -> vec2 { var r: f32; var theta: f32; - let _e192 = (*i_4); - let _e195 = (*n_1); - r = sqrt(((f32(_e192) + 0.5f) / f32(_e195))); - let _e199 = (*i_4); - let _e202 = (*turn); - theta = ((f32(_e199) * 2.3999631f) + _e202); - let _e204 = r; - let _e205 = theta; - let _e207 = theta; - return (vec2(cos(_e205), sin(_e207)) * _e204); + let _e193 = (*i_4); + let _e196 = (*n_1); + r = sqrt(((f32(_e193) + 0.5f) / f32(_e196))); + let _e200 = (*i_4); + let _e203 = (*turn); + theta = ((f32(_e200) * 2.3999631f) + _e203); + let _e205 = r; + let _e206 = theta; + let _e208 = theta; + return (vec2(cos(_e206), sin(_e208)) * _e205); } fn ShadowNoise_u0028_() -> f32 { var at: vec2; var param_51: f32; - let _e191 = frag_info.target_origin[0u]; - param_51 = _e191; - let _e192 = FragCoordFromTop_u0028_f1_u003b((¶m_51)); - let _e195 = frag_info.target_origin[3u]; - at = (_e192 + vec2((5.588238f * max(_e195, 0f)))); - let _e200 = at; - return fract((52.982918f * fract(dot(_e200, vec2(0.06711056f, 0.00583715f))))); + let _e192 = frag_info.target_origin[0u]; + param_51 = _e192; + let _e193 = FragCoordFromTop_u0028_f1_u003b((¶m_51)); + let _e196 = frag_info.target_origin[3u]; + at = (_e193 + vec2((5.588238f * max(_e196, 0f)))); + let _e201 = at; + return fract((52.982918f * fract(dot(_e201, vec2(0.06711056f, 0.00583715f))))); } fn EvsmChebyshev_u0028_vf2_u003b_f1_u003b_f1_u003b_f1_u003b(moments: ptr>, t: ptr, minVariance: ptr, bleed: ptr) -> f32 { @@ -11025,37 +11060,37 @@ fn EvsmChebyshev_u0028_vf2_u003b_f1_u003b_f1_u003b_f1_u003b(moments: ptr) -> vec2 { var d_2: f32; - let _e189 = (*depth); - d_2 = ((2f * clamp(_e189, 0f, 1f)) - 1f); - let _e193 = d_2; - let _e196 = d_2; - return vec2(exp((40f * _e193)), -(exp((-5f * _e196)))); + let _e190 = (*depth); + d_2 = ((2f * clamp(_e190, 0f, 1f)) - 1f); + let _e194 = d_2; + let _e197 = d_2; + return vec2(exp((40f * _e194)), -(exp((-5f * _e197)))); } fn EvsmVisibility_u0028_vf4_u003b_f1_u003b_f1_u003b(moments_1: ptr>, depth_1: ptr, bleed_1: ptr) -> f32 { @@ -11073,40 +11108,40 @@ fn EvsmVisibility_u0028_vf4_u003b_f1_u003b_f1_u003b(moments_1: ptr(0.004f, 0.0005f) * _e205); - let _e208 = scale[0u]; - let _e210 = scale[0u]; - let _e212 = (*moments_1); - param_53 = _e212.xy; - let _e215 = warped[0u]; - param_54 = _e215; - param_55 = (_e208 * _e210); - let _e216 = (*bleed_1); - param_56 = _e216; - let _e217 = EvsmChebyshev_u0028_vf2_u003b_f1_u003b_f1_u003b_f1_u003b((¶m_53), (¶m_54), (¶m_55), (¶m_56)); - positive = _e217; - let _e219 = scale[1u]; - let _e221 = scale[1u]; - let _e223 = (*moments_1); - param_57 = _e223.zw; - let _e226 = warped[1u]; - param_58 = _e226; - param_59 = (_e219 * _e221); - let _e227 = (*bleed_1); - param_60 = _e227; - let _e228 = EvsmChebyshev_u0028_vf2_u003b_f1_u003b_f1_u003b_f1_u003b((¶m_57), (¶m_58), (¶m_59), (¶m_60)); - negative = _e228; - let _e229 = positive; - let _e230 = negative; - return min(_e229, _e230); -} - -fn ShadowFactor_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_struct_u002d_LightSample_u002d_vf3_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf31_u003b_i1_u003b(s_2: ptr, light_1: ptr, lightIndex_1: ptr) -> f32 { + let _e204 = (*depth_1); + param_52 = _e204; + let _e205 = EvsmWarp_u0028_f1_u003b((¶m_52)); + warped = _e205; + let _e206 = warped; + scale = (vec2(0.004f, 0.0005f) * _e206); + let _e209 = scale[0u]; + let _e211 = scale[0u]; + let _e213 = (*moments_1); + param_53 = _e213.xy; + let _e216 = warped[0u]; + param_54 = _e216; + param_55 = (_e209 * _e211); + let _e217 = (*bleed_1); + param_56 = _e217; + let _e218 = EvsmChebyshev_u0028_vf2_u003b_f1_u003b_f1_u003b_f1_u003b((¶m_53), (¶m_54), (¶m_55), (¶m_56)); + positive = _e218; + let _e220 = scale[1u]; + let _e222 = scale[1u]; + let _e224 = (*moments_1); + param_57 = _e224.zw; + let _e227 = warped[1u]; + param_58 = _e227; + param_59 = (_e220 * _e222); + let _e228 = (*bleed_1); + param_60 = _e228; + let _e229 = EvsmChebyshev_u0028_vf2_u003b_f1_u003b_f1_u003b_f1_u003b((¶m_57), (¶m_58), (¶m_59), (¶m_60)); + negative = _e229; + let _e230 = positive; + let _e231 = negative; + return min(_e230, _e231); +} + +fn ShadowFactor_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_struct_u002d_LightSample_u002d_vf3_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf31_u003b_i1_u003b(s_2: ptr, light_1: ptr, lightIndex_1: ptr) -> f32 { var strength_1: f32; var cascadeCount: i32; var viewDistance: f32; @@ -11141,6 +11176,8 @@ fn ShadowFactor_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf var tileLo: vec2; var tileHi: vec2; var stored_2: vec4; + var y: i32; + var x: i32; var through: vec3; var softness: f32; var lit_2: f32; @@ -11148,8 +11185,8 @@ fn ShadowFactor_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf var param_61: vec4; var param_62: f32; var param_63: f32; - var y: i32; - var x: i32; + var y_1: i32; + var x_1: i32; var occluder: f32; var spread: f32; var turn_1: f32; @@ -11178,45 +11215,45 @@ fn ShadowFactor_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf var phi_3710_: bool; var phi_3717_: bool; - let _e257 = frag_info.shadow_params[3u]; - strength_1 = _e257; - let _e258 = strength_1; - if (_e258 <= 0f) { + let _e260 = frag_info.shadow_params[3u]; + strength_1 = _e260; + let _e261 = strength_1; + if (_e261 <= 0f) { return 1f; } - let _e260 = (*lightIndex_1); - let _e263 = frag_info.frame_params[2u]; - if (_e260 != i32((_e263 + 0.5f))) { + let _e263 = (*lightIndex_1); + let _e266 = frag_info.frame_params[2u]; + if (_e263 != i32((_e266 + 0.5f))) { return 1f; } - let _e269 = frag_info.shadow_cascades[2u]; - cascadeCount = i32((_e269 + 0.5f)); - let _e272 = v_world_position_1; - let _e274 = frag_info.camera_position; - viewDistance = length((_e272 - _e274.xyz)); + let _e272 = frag_info.shadow_cascades[2u]; + cascadeCount = i32((_e272 + 0.5f)); + let _e275 = v_world_position_1; + let _e277 = frag_info.camera_position; + viewDistance = length((_e275 - _e277.xyz)); cascade = 0i; - let _e278 = cascadeCount; - let _e279 = (_e278 > 1i); - phi_3531_ = _e279; - if _e279 { - let _e280 = viewDistance; - let _e283 = frag_info.shadow_cascades[0u]; - phi_3531_ = (_e280 > _e283); - } - let _e286 = phi_3531_; - if _e286 { + let _e281 = cascadeCount; + let _e282 = (_e281 > 1i); + phi_3531_ = _e282; + if _e282 { + let _e283 = viewDistance; + let _e286 = frag_info.shadow_cascades[0u]; + phi_3531_ = (_e283 > _e286); + } + let _e289 = phi_3531_; + if _e289 { cascade = 1i; } - let _e287 = cascadeCount; - let _e288 = (_e287 > 2i); - phi_3542_ = _e288; - if _e288 { - let _e289 = viewDistance; - let _e292 = frag_info.shadow_cascades[1u]; - phi_3542_ = (_e289 > _e292); + let _e290 = cascadeCount; + let _e291 = (_e290 > 2i); + phi_3542_ = _e291; + if _e291 { + let _e292 = viewDistance; + let _e295 = frag_info.shadow_cascades[1u]; + phi_3542_ = (_e292 > _e295); } - let _e295 = phi_3542_; - if _e295 { + let _e298 = phi_3542_; + if _e298 { cascade = 2i; } uv_4 = vec2(0f, 0f); @@ -11227,247 +11264,280 @@ fn ShadowFactor_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf receiverSlope = 0f; attempt = 0i; loop { - let _e296 = attempt; - if (_e296 < 3i) { - let _e298 = cascade; - let _e299 = attempt; - which = (_e298 + _e299); - let _e301 = which; - let _e302 = cascadeCount; - if (_e301 >= _e302) { + let _e299 = attempt; + if (_e299 < 3i) { + let _e301 = cascade; + let _e302 = attempt; + which = (_e301 + _e302); + let _e304 = which; + let _e305 = cascadeCount; + if (_e304 >= _e305) { break; } - let _e304 = which; - if (_e304 == 0i) { - let _e307 = frag_info.shadow_matrix; - local_8 = _e307; + let _e307 = which; + if (_e307 == 0i) { + let _e310 = frag_info.shadow_matrix; + local_8 = _e310; } else { - let _e308 = which; - if (_e308 == 1i) { - let _e311 = frag_info.shadow_matrix_far; - local_9 = _e311; + let _e311 = which; + if (_e311 == 1i) { + let _e314 = frag_info.shadow_matrix_far; + local_9 = _e314; } else { - let _e313 = frag_info.shadow_matrix_farthest; - local_9 = _e313; + let _e316 = frag_info.shadow_matrix_farthest; + local_9 = _e316; } - let _e314 = local_9; - local_8 = _e314; - } - let _e315 = local_8; - matrix = _e315; - let _e318 = matrix[0][0u]; - let _e321 = matrix[1][0u]; - let _e324 = matrix[2][0u]; - axisX = vec3(_e318, _e321, _e324); - let _e328 = matrix[0][1u]; - let _e331 = matrix[1][1u]; - let _e334 = matrix[2][1u]; - axisY = vec3(_e328, _e331, _e334); - let _e336 = axisX; - rowX = max(length(_e336), 0.000001f); - let _e339 = axisY; - rowY = max(length(_e339), 0.000001f); - let _e344 = frag_info.shadow_cascades[3u]; - let _e346 = rowX; - texelMetres = ((2f * _e344) / _e346); - let _e350 = frag_info.shadow_cascades[3u]; - let _e353 = (*s_2).n; - let _e354 = axisX; - let _e357 = rowX; - let _e358 = rowX; - let _e362 = (*s_2).n; - let _e363 = axisY; - let _e366 = rowY; - let _e367 = rowY; - reach = ((3f * _e350) * ((abs(dot(_e353, _e354)) / (_e357 * _e358)) + (abs(dot(_e362, _e363)) / (_e366 * _e367)))); - let _e374 = frag_info.shadow_params[2u]; - let _e375 = texelMetres; - flatOffset = min(_e374, _e375); - let _e377 = v_world_position_1; - let _e379 = (*s_2).n; - let _e380 = flatOffset; - let _e381 = reach; - origin_1 = (_e377 + (_e379 * (_e380 + _e381))); - let _e385 = matrix; - let _e386 = origin_1; - lightSpace = (_e385 * vec4(_e386.x, _e386.y, _e386.z, 1f)); - let _e393 = lightSpace[3u]; - if (_e393 <= 0f) { + let _e317 = local_9; + local_8 = _e317; + } + let _e318 = local_8; + matrix = _e318; + let _e321 = matrix[0][0u]; + let _e324 = matrix[1][0u]; + let _e327 = matrix[2][0u]; + axisX = vec3(_e321, _e324, _e327); + let _e331 = matrix[0][1u]; + let _e334 = matrix[1][1u]; + let _e337 = matrix[2][1u]; + axisY = vec3(_e331, _e334, _e337); + let _e339 = axisX; + rowX = max(length(_e339), 0.000001f); + let _e342 = axisY; + rowY = max(length(_e342), 0.000001f); + let _e347 = frag_info.shadow_cascades[3u]; + let _e349 = rowX; + texelMetres = ((2f * _e347) / _e349); + let _e353 = frag_info.shadow_cascades[3u]; + let _e356 = (*s_2).n; + let _e357 = axisX; + let _e360 = rowX; + let _e361 = rowX; + let _e365 = (*s_2).n; + let _e366 = axisY; + let _e369 = rowY; + let _e370 = rowY; + reach = ((3f * _e353) * ((abs(dot(_e356, _e357)) / (_e360 * _e361)) + (abs(dot(_e365, _e366)) / (_e369 * _e370)))); + let _e377 = frag_info.shadow_params[2u]; + let _e378 = texelMetres; + flatOffset = min(_e377, _e378); + let _e380 = v_world_position_1; + let _e382 = (*s_2).n; + let _e383 = flatOffset; + let _e384 = reach; + origin_1 = (_e380 + (_e382 * (_e383 + _e384))); + let _e388 = matrix; + let _e389 = origin_1; + lightSpace = (_e388 * vec4(_e389.x, _e389.y, _e389.z, 1f)); + let _e396 = lightSpace[3u]; + if (_e396 <= 0f) { continue; } - let _e395 = lightSpace; - let _e398 = lightSpace[3u]; - candidate = (_e395.xyz / vec3(_e398)); - let _e402 = candidate[0u]; - let _e406 = candidate[1u]; - inTile = vec2(((_e402 * 0.5f) + 0.5f), (0.5f - (_e406 * 0.5f))); - let _e411 = inTile[0u]; - let _e412 = (_e411 < 0f); - phi_3703_ = _e412; - if !(_e412) { - let _e415 = inTile[0u]; - phi_3703_ = (_e415 > 1f); - } - let _e418 = phi_3703_; - phi_3710_ = _e418; - if !(_e418) { - let _e421 = inTile[1u]; - phi_3710_ = (_e421 < 0f); - } - let _e424 = phi_3710_; - phi_3717_ = _e424; - if !(_e424) { - let _e427 = inTile[1u]; - phi_3717_ = (_e427 > 1f); - } - let _e430 = phi_3717_; - if _e430 { + let _e398 = lightSpace; + let _e401 = lightSpace[3u]; + candidate = (_e398.xyz / vec3(_e401)); + let _e405 = candidate[0u]; + let _e409 = candidate[1u]; + inTile = vec2(((_e405 * 0.5f) + 0.5f), (0.5f - (_e409 * 0.5f))); + let _e414 = inTile[0u]; + let _e415 = (_e414 < 0f); + phi_3703_ = _e415; + if !(_e415) { + let _e418 = inTile[0u]; + phi_3703_ = (_e418 > 1f); + } + let _e421 = phi_3703_; + phi_3710_ = _e421; + if !(_e421) { + let _e424 = inTile[1u]; + phi_3710_ = (_e424 < 0f); + } + let _e427 = phi_3710_; + phi_3717_ = _e427; + if !(_e427) { + let _e430 = inTile[1u]; + phi_3717_ = (_e430 > 1f); + } + let _e433 = phi_3717_; + if _e433 { continue; } - let _e432 = candidate[2u]; - if (_e432 > 1f) { - let _e434 = which; - let _e435 = cascadeCount; - if (_e434 < (_e435 - 1i)) { + let _e435 = candidate[2u]; + if (_e435 > 1f) { + let _e437 = which; + let _e438 = cascadeCount; + if (_e437 < (_e438 - 1i)) { continue; } candidate[2u] = 1f; } - let _e440 = inTile[0u]; - let _e441 = which; - let _e444 = cascadeCount; - let _e448 = inTile[1u]; - uv_4 = vec2(((_e440 + f32(_e441)) / f32(_e444)), _e448); - let _e450 = candidate; - projected = _e450; - let _e451 = which; - cascade = _e451; - let _e452 = texelMetres; - cascadeTexel = _e452; - let _e455 = matrix[0][2u]; - let _e458 = matrix[1][2u]; - let _e461 = matrix[2][2u]; - cascadeDepth = (1f / max(length(vec3(_e455, _e458, _e461)), 0.000001f)); - let _e467 = (*s_2).n; - let _e470 = matrix[0][2u]; - let _e473 = matrix[1][2u]; - let _e476 = matrix[2][2u]; - let _e480 = cascadeDepth; - cosSlope = clamp((abs(dot(_e467, vec3(_e470, _e473, _e476))) * _e480), 0.1f, 1f); - let _e483 = texelMetres; - let _e484 = cosSlope; - let _e485 = cosSlope; - let _e491 = cosSlope; - let _e493 = cascadeDepth; - receiverSlope = (((_e483 * sqrt(max((1f - (_e484 * _e485)), 0f))) / _e491) / _e493); + let _e443 = inTile[0u]; + let _e444 = which; + let _e447 = cascadeCount; + let _e451 = inTile[1u]; + uv_4 = vec2(((_e443 + f32(_e444)) / f32(_e447)), _e451); + let _e453 = candidate; + projected = _e453; + let _e454 = which; + cascade = _e454; + let _e455 = texelMetres; + cascadeTexel = _e455; + let _e458 = matrix[0][2u]; + let _e461 = matrix[1][2u]; + let _e464 = matrix[2][2u]; + cascadeDepth = (1f / max(length(vec3(_e458, _e461, _e464)), 0.000001f)); + let _e470 = (*s_2).n; + let _e473 = matrix[0][2u]; + let _e476 = matrix[1][2u]; + let _e479 = matrix[2][2u]; + let _e483 = cascadeDepth; + cosSlope = clamp((abs(dot(_e470, vec3(_e473, _e476, _e479))) * _e483), 0.1f, 1f); + let _e486 = texelMetres; + let _e487 = cosSlope; + let _e488 = cosSlope; + let _e494 = cosSlope; + let _e496 = cascadeDepth; + receiverSlope = (((_e486 * sqrt(max((1f - (_e487 * _e488)), 0f))) / _e494) / _e496); found = true; break; } else { break; } continuing { - let _e495 = attempt; - attempt = (_e495 + 1i); + let _e498 = attempt; + attempt = (_e498 + 1i); } } - let _e497 = found; - if !(_e497) { + let _e500 = found; + if !(_e500) { return 1f; } - let _e499 = cascade; - if (_e499 == 0i) { - let _e503 = frag_info.shadow_bias[0u]; - local_10 = _e503; + let _e502 = cascade; + if (_e502 == 0i) { + let _e506 = frag_info.shadow_bias[0u]; + local_10 = _e506; } else { - let _e504 = cascade; - if (_e504 == 1i) { - let _e508 = frag_info.shadow_bias[1u]; - local_11 = _e508; - } else { - let _e511 = frag_info.shadow_bias[2u]; + let _e507 = cascade; + if (_e507 == 1i) { + let _e511 = frag_info.shadow_bias[1u]; local_11 = _e511; - } - let _e512 = local_11; - local_10 = _e512; - } - let _e513 = local_10; - bias = _e513; - let _e516 = frag_info.shadow_params[0u]; - let _e519 = frag_info.shadow_cascades[3u]; - texel_1 = vec2(_e516, _e519); - let _e521 = cascade; - let _e523 = cascadeCount; - let _e527 = texel_1; - tileLo = (vec2((f32(_e521) / f32(_e523)), 0f) + (_e527 * 0.5f)); - let _e530 = cascade; - let _e533 = cascadeCount; - let _e537 = texel_1; - tileHi = (vec2((f32((_e530 + 1i)) / f32(_e533)), 1f) - (_e537 * 0.5f)); - let _e542 = frag_info.shadow_bias[3u]; - if (_e542 > 0.5f) { - let _e544 = uv_4; - let _e545 = tileLo; - let _e546 = tileHi; - let _e548 = textureSampleLevel(shadow_texture_tex, shadow_texture_smp, clamp(_e544, _e545, _e546), 0f); - stored_2 = _e548; - let _e550 = stored_2[1u]; - let _e553 = stored_2[2u]; - let _e556 = stored_2[3u]; - through = clamp(vec3((1f - _e550), (1f - _e553), _e556), vec3(0f), vec3(4f)); - let _e561 = through; - let _e562 = strength_1; - light_transmittance = mix(vec3(1f, 1f, 1f), _e561, vec3(clamp(_e562, 0f, 1f))); - } - let _e568 = frag_info.ambient_ground[3u]; - softness = _e568; + } else { + let _e514 = frag_info.shadow_bias[2u]; + local_11 = _e514; + } + let _e515 = local_11; + local_10 = _e515; + } + let _e516 = local_10; + bias = _e516; + let _e519 = frag_info.shadow_params[0u]; + let _e522 = frag_info.shadow_cascades[3u]; + texel_1 = vec2(_e519, _e522); + let _e524 = cascade; + let _e526 = cascadeCount; + let _e530 = texel_1; + tileLo = (vec2((f32(_e524) / f32(_e526)), 0f) + (_e530 * 0.5f)); + let _e533 = cascade; + let _e536 = cascadeCount; + let _e540 = texel_1; + tileHi = (vec2((f32((_e533 + 1i)) / f32(_e536)), 1f) - (_e540 * 0.5f)); + let _e545 = frag_info.shadow_bias[3u]; + if (_e545 > 0.5f) { + stored_2 = vec4(0f, 0f, 0f, 0f); + y = -1i; + loop { + let _e547 = y; + if (_e547 <= 1i) { + x = -1i; + loop { + let _e549 = x; + if (_e549 <= 1i) { + let _e551 = uv_4; + let _e552 = x; + let _e554 = y; + let _e557 = texel_1; + let _e560 = tileLo; + let _e561 = tileHi; + let _e563 = textureSampleLevel(shadow_texture_tex, shadow_texture_smp, clamp((_e551 + (vec2(f32(_e552), f32(_e554)) * _e557)), _e560, _e561), 0f); + let _e564 = stored_2; + stored_2 = (_e564 + _e563); + continue; + } else { + break; + } + continuing { + let _e566 = x; + x = (_e566 + 1i); + } + } + continue; + } else { + break; + } + continuing { + let _e568 = y; + y = (_e568 + 1i); + } + } + let _e570 = stored_2; + stored_2 = (_e570 * 0.11111111f); + let _e573 = stored_2[1u]; + let _e576 = stored_2[2u]; + let _e579 = stored_2[3u]; + through = clamp(vec3((1f - _e573), (1f - _e576), _e579), vec3(0f), vec3(4f)); + let _e584 = through; + let _e585 = strength_1; + light_transmittance = mix(vec3(1f, 1f, 1f), _e584, vec3(clamp(_e585, 0f, 1f))); + } + let _e591 = frag_info.ambient_ground[3u]; + softness = _e591; lit_2 = 0f; - let _e569 = softness; - if (_e569 < 0f) { - let _e571 = uv_4; - let _e572 = tileLo; - let _e573 = tileHi; - let _e575 = textureSampleLevel(shadow_texture_tex, shadow_texture_smp, clamp(_e571, _e572, _e573), 0f); - moments_2 = _e575; - let _e577 = projected[2u]; - let _e578 = bias; - let _e580 = softness; - let _e584 = moments_2; - param_61 = _e584; - param_62 = (_e577 - _e578); - param_63 = clamp((-(_e580) - 1f), 0f, 0.95f); - let _e585 = EvsmVisibility_u0028_vf4_u003b_f1_u003b_f1_u003b((¶m_61), (¶m_62), (¶m_63)); - lit_2 = _e585; - } else { - let _e586 = softness; - if (_e586 <= 0f) { - y = -1i; + let _e592 = softness; + if (_e592 < 0f) { + let _e594 = uv_4; + let _e595 = tileLo; + let _e596 = tileHi; + let _e598 = textureSampleLevel(shadow_texture_tex, shadow_texture_smp, clamp(_e594, _e595, _e596), 0f); + moments_2 = _e598; + let _e600 = projected[2u]; + let _e601 = bias; + let _e603 = softness; + let _e607 = moments_2; + param_61 = _e607; + param_62 = (_e600 - _e601); + param_63 = clamp((-(_e603) - 1f), 0f, 0.95f); + let _e608 = EvsmVisibility_u0028_vf4_u003b_f1_u003b_f1_u003b((¶m_61), (¶m_62), (¶m_63)); + lit_2 = _e608; + } else { + let _e609 = softness; + if (_e609 <= 0f) { + y_1 = -1i; loop { - let _e588 = y; - if (_e588 <= 1i) { - x = -1i; + let _e611 = y_1; + if (_e611 <= 1i) { + x_1 = -1i; loop { - let _e590 = x; - if (_e590 <= 1i) { - let _e592 = uv_4; - let _e593 = x; - let _e595 = y; - let _e598 = texel_1; - let _e601 = tileLo; - let _e602 = tileHi; - let _e604 = textureSampleLevel(shadow_texture_tex, shadow_texture_smp, clamp((_e592 + (vec2(f32(_e593), f32(_e595)) * _e598)), _e601, _e602), 0f); - occluder = _e604.x; - let _e607 = projected[2u]; - let _e608 = bias; - let _e610 = occluder; - let _e613 = lit_2; - lit_2 = (_e613 + select(1f, 0f, ((_e607 - _e608) > _e610))); + let _e613 = x_1; + if (_e613 <= 1i) { + let _e615 = uv_4; + let _e616 = x_1; + let _e618 = y_1; + let _e621 = texel_1; + let _e624 = tileLo; + let _e625 = tileHi; + let _e627 = textureSampleLevel(shadow_texture_tex, shadow_texture_smp, clamp((_e615 + (vec2(f32(_e616), f32(_e618)) * _e621)), _e624, _e625), 0f); + occluder = _e627.x; + let _e630 = projected[2u]; + let _e631 = bias; + let _e633 = occluder; + let _e636 = lit_2; + lit_2 = (_e636 + select(1f, 0f, ((_e630 - _e631) > _e633))); continue; } else { break; } continuing { - let _e615 = x; - x = (_e615 + 1i); + let _e638 = x_1; + x_1 = (_e638 + 1i); } } continue; @@ -11475,125 +11545,125 @@ fn ShadowFactor_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf break; } continuing { - let _e617 = y; - y = (_e617 + 1i); + let _e640 = y_1; + y_1 = (_e640 + 1i); } } - let _e619 = lit_2; - lit_2 = (_e619 * 0.11111111f); + let _e642 = lit_2; + lit_2 = (_e642 * 0.11111111f); } else { - let _e621 = softness; - spread = tan(min(_e621, 0.5f)); - let _e624 = ShadowNoise_u0028_(); - turn_1 = (_e624 * 6.2831855f); - let _e626 = spread; - let _e628 = projected[2u]; - let _e630 = cascadeDepth; - let _e632 = cascadeTexel; - searchRadius = clamp((((_e626 * _e628) * _e630) / _e632), 1f, 16f); + let _e644 = softness; + spread = tan(min(_e644, 0.5f)); + let _e647 = ShadowNoise_u0028_(); + turn_1 = (_e647 * 6.2831855f); + let _e649 = spread; + let _e651 = projected[2u]; + let _e653 = cascadeDepth; + let _e655 = cascadeTexel; + searchRadius = clamp((((_e649 * _e651) * _e653) / _e655), 1f, 16f); blockerSum = 0f; blockerCount = 0f; i_5 = 0i; loop { - let _e635 = i_5; - if (_e635 < 16i) { - let _e637 = i_5; - param_64 = _e637; + let _e658 = i_5; + if (_e658 < 16i) { + let _e660 = i_5; + param_64 = _e660; param_65 = 16i; - let _e638 = turn_1; - param_66 = _e638; - let _e639 = VogelDisc_u0028_i1_u003b_i1_u003b_f1_u003b((¶m_64), (¶m_65), (¶m_66)); - disc = _e639; - let _e640 = bias; - let _e641 = disc; - let _e643 = searchRadius; - let _e647 = receiverSlope; - tapBias = (_e640 + (max(((length(_e641) * _e643) - 1.5f), 0f) * _e647)); - let _e650 = uv_4; - let _e651 = disc; - let _e652 = texel_1; - let _e654 = searchRadius; - let _e657 = tileLo; - let _e658 = tileHi; - let _e660 = textureSampleLevel(shadow_texture_tex, shadow_texture_smp, clamp((_e650 + ((_e651 * _e652) * _e654)), _e657, _e658), 0f); - occluder_1 = _e660.x; - let _e663 = projected[2u]; - let _e664 = tapBias; - let _e666 = occluder_1; - if ((_e663 - _e664) > _e666) { - let _e668 = occluder_1; - let _e669 = blockerSum; - blockerSum = (_e669 + _e668); - let _e671 = blockerCount; - blockerCount = (_e671 + 1f); + let _e661 = turn_1; + param_66 = _e661; + let _e662 = VogelDisc_u0028_i1_u003b_i1_u003b_f1_u003b((¶m_64), (¶m_65), (¶m_66)); + disc = _e662; + let _e663 = bias; + let _e664 = disc; + let _e666 = searchRadius; + let _e670 = receiverSlope; + tapBias = (_e663 + (max(((length(_e664) * _e666) - 1.5f), 0f) * _e670)); + let _e673 = uv_4; + let _e674 = disc; + let _e675 = texel_1; + let _e677 = searchRadius; + let _e680 = tileLo; + let _e681 = tileHi; + let _e683 = textureSampleLevel(shadow_texture_tex, shadow_texture_smp, clamp((_e673 + ((_e674 * _e675) * _e677)), _e680, _e681), 0f); + occluder_1 = _e683.x; + let _e686 = projected[2u]; + let _e687 = tapBias; + let _e689 = occluder_1; + if ((_e686 - _e687) > _e689) { + let _e691 = occluder_1; + let _e692 = blockerSum; + blockerSum = (_e692 + _e691); + let _e694 = blockerCount; + blockerCount = (_e694 + 1f); } continue; } else { break; } continuing { - let _e673 = i_5; - i_5 = (_e673 + 1i); + let _e696 = i_5; + i_5 = (_e696 + 1i); } } - let _e675 = blockerCount; - if (_e675 <= 0f) { + let _e698 = blockerCount; + if (_e698 <= 0f) { return 1f; } - let _e678 = projected[2u]; - let _e679 = blockerSum; - let _e680 = blockerCount; - let _e684 = cascadeDepth; - gap = (max((_e678 - (_e679 / _e680)), 0f) * _e684); - let _e686 = spread; - let _e687 = gap; - let _e689 = cascadeTexel; - radius_2 = clamp(((_e686 * _e687) / _e689), 1f, 16f); + let _e701 = projected[2u]; + let _e702 = blockerSum; + let _e703 = blockerCount; + let _e707 = cascadeDepth; + gap = (max((_e701 - (_e702 / _e703)), 0f) * _e707); + let _e709 = spread; + let _e710 = gap; + let _e712 = cascadeTexel; + radius_2 = clamp(((_e709 * _e710) / _e712), 1f, 16f); i_6 = 0i; loop { - let _e692 = i_6; - if (_e692 < 16i) { - let _e694 = turn_1; - let _e696 = i_6; - param_67 = _e696; + let _e715 = i_6; + if (_e715 < 16i) { + let _e717 = turn_1; + let _e719 = i_6; + param_67 = _e719; param_68 = 16i; - param_69 = (_e694 + 1f); - let _e697 = VogelDisc_u0028_i1_u003b_i1_u003b_f1_u003b((¶m_67), (¶m_68), (¶m_69)); - disc_1 = _e697; - let _e698 = bias; - let _e699 = disc_1; - let _e701 = radius_2; - let _e705 = receiverSlope; - tapBias_1 = (_e698 + (max(((length(_e699) * _e701) - 1.5f), 0f) * _e705)); - let _e708 = uv_4; - let _e709 = disc_1; - let _e710 = texel_1; - let _e712 = radius_2; - let _e715 = tileLo; - let _e716 = tileHi; - let _e718 = textureSampleLevel(shadow_texture_tex, shadow_texture_smp, clamp((_e708 + ((_e709 * _e710) * _e712)), _e715, _e716), 0f); - occluder_2 = _e718.x; - let _e721 = projected[2u]; - let _e722 = tapBias_1; - let _e724 = occluder_2; - let _e727 = lit_2; - lit_2 = (_e727 + select(1f, 0f, ((_e721 - _e722) > _e724))); + param_69 = (_e717 + 1f); + let _e720 = VogelDisc_u0028_i1_u003b_i1_u003b_f1_u003b((¶m_67), (¶m_68), (¶m_69)); + disc_1 = _e720; + let _e721 = bias; + let _e722 = disc_1; + let _e724 = radius_2; + let _e728 = receiverSlope; + tapBias_1 = (_e721 + (max(((length(_e722) * _e724) - 1.5f), 0f) * _e728)); + let _e731 = uv_4; + let _e732 = disc_1; + let _e733 = texel_1; + let _e735 = radius_2; + let _e738 = tileLo; + let _e739 = tileHi; + let _e741 = textureSampleLevel(shadow_texture_tex, shadow_texture_smp, clamp((_e731 + ((_e732 * _e733) * _e735)), _e738, _e739), 0f); + occluder_2 = _e741.x; + let _e744 = projected[2u]; + let _e745 = tapBias_1; + let _e747 = occluder_2; + let _e750 = lit_2; + lit_2 = (_e750 + select(1f, 0f, ((_e744 - _e745) > _e747))); continue; } else { break; } continuing { - let _e729 = i_6; - i_6 = (_e729 + 1i); + let _e752 = i_6; + i_6 = (_e752 + 1i); } } - let _e731 = lit_2; - lit_2 = (_e731 * 0.0625f); + let _e754 = lit_2; + lit_2 = (_e754 * 0.0625f); } } - let _e733 = lit_2; - let _e734 = strength_1; - return mix(1f, _e733, clamp(_e734, 0f, 1f)); + let _e756 = lit_2; + let _e757 = strength_1; + return mix(1f, _e756, clamp(_e757, 0f, 1f)); } fn LightVisibility_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_struct_u002d_LightSample_u002d_vf3_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf31_u003b_i1_u003b(s_3: ptr, light_2: ptr, index: ptr) -> f32 { @@ -11601,19 +11671,19 @@ fn LightVisibility_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d var param_71: LightSample; var param_72: i32; - let _e193 = (*s_3); - param_70 = _e193; - let _e194 = (*light_2); - param_71 = _e194; - let _e195 = (*index); - param_72 = _e195; - let _e196 = ShadowFactor_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_struct_u002d_LightSample_u002d_vf3_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf31_u003b_i1_u003b((¶m_70), (¶m_71), (¶m_72)); - return _e196; + let _e194 = (*s_3); + param_70 = _e194; + let _e195 = (*light_2); + param_71 = _e195; + let _e196 = (*index); + param_72 = _e196; + let _e197 = ShadowFactor_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_struct_u002d_LightSample_u002d_vf3_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf31_u003b_i1_u003b((¶m_70), (¶m_71), (¶m_72)); + return _e197; } fn LightHasShadow_u0028_i1_u003b(index_1: ptr) -> bool { - let _e188 = (*index_1); - return (_e188 < 8i); + let _e189 = (*index_1); + return (_e189 < 8i); } fn PunctualAttenuation_u0028_f1_u003b_f1_u003b(distance_1: ptr, range_4: ptr) -> f32 { @@ -11621,26 +11691,26 @@ fn PunctualAttenuation_u0028_f1_u003b_f1_u003b(distance_1: ptr, r var ratio: f32; var window: f32; - let _e192 = (*distance_1); let _e193 = (*distance_1); - attenuation = (1f / max((_e192 * _e193), 0.0001f)); - let _e197 = (*range_4); - if (_e197 > 0f) { - let _e199 = (*distance_1); - let _e200 = (*range_4); - ratio = (_e199 / _e200); - let _e202 = ratio; + let _e194 = (*distance_1); + attenuation = (1f / max((_e193 * _e194), 0.0001f)); + let _e198 = (*range_4); + if (_e198 > 0f) { + let _e200 = (*distance_1); + let _e201 = (*range_4); + ratio = (_e200 / _e201); let _e203 = ratio; - let _e205 = ratio; - let _e207 = ratio; - window = clamp((1f - (((_e202 * _e203) * _e205) * _e207)), 0f, 1f); - let _e211 = window; + let _e204 = ratio; + let _e206 = ratio; + let _e208 = ratio; + window = clamp((1f - (((_e203 * _e204) * _e206) * _e208)), 0f, 1f); let _e212 = window; - let _e214 = attenuation; - attenuation = (_e214 * (_e211 * _e212)); + let _e213 = window; + let _e215 = attenuation; + attenuation = (_e215 * (_e212 * _e213)); } - let _e216 = attenuation; - return _e216; + let _e217 = attenuation; + return _e217; } fn RectangleClosestPoint_u0028_vf3_u003b_vf3_u003b_vf3_u003b_vf3_u003b_vf3_u003b(centre: ptr>, halfWidth: ptr>, halfHeight: ptr>, world_2: ptr>, mirror: ptr>) -> vec3 { @@ -11657,111 +11727,111 @@ fn RectangleClosestPoint_u0028_vf3_u003b_vf3_u003b_vf3_u003b_vf3_u003b_vf3_u003b var u: f32; var v: f32; - let _e204 = (*halfWidth); - let _e205 = (*halfHeight); - n_2 = cross(_e204, _e205); - let _e207 = n_2; - nLen = length(_e207); - let _e209 = nLen; - if (_e209 < 0.000000000001f) { - let _e211 = (*centre); - return _e211; + let _e205 = (*halfWidth); + let _e206 = (*halfHeight); + n_2 = cross(_e205, _e206); + let _e208 = n_2; + nLen = length(_e208); + let _e210 = nLen; + if (_e210 < 0.000000000001f) { + let _e212 = (*centre); + return _e212; } - let _e212 = nLen; - let _e213 = n_2; - n_2 = (_e213 / vec3(_e212)); - let _e216 = (*centre); - let _e217 = (*world_2); - toPlane = (_e216 - _e217); - let _e219 = (*mirror); - let _e220 = n_2; - denom = dot(_e219, _e220); - let _e222 = denom; - if (abs(_e222) < 0.00001f) { - let _e225 = toPlane; - let _e226 = n_2; - let _e227 = toPlane; - let _e228 = n_2; - onPlane = (_e225 - (_e226 * dot(_e227, _e228))); + let _e213 = nLen; + let _e214 = n_2; + n_2 = (_e214 / vec3(_e213)); + let _e217 = (*centre); + let _e218 = (*world_2); + toPlane = (_e217 - _e218); + let _e220 = (*mirror); + let _e221 = n_2; + denom = dot(_e220, _e221); + let _e223 = denom; + if (abs(_e223) < 0.00001f) { + let _e226 = toPlane; + let _e227 = n_2; + let _e228 = toPlane; + let _e229 = n_2; + onPlane = (_e226 - (_e227 * dot(_e228, _e229))); } else { - let _e232 = toPlane; - let _e233 = n_2; - let _e235 = denom; - t_1 = (dot(_e232, _e233) / _e235); - let _e237 = t_1; - if (_e237 > 0f) { - let _e239 = (*mirror); - let _e240 = t_1; - local_12 = (_e239 * _e240); + let _e233 = toPlane; + let _e234 = n_2; + let _e236 = denom; + t_1 = (dot(_e233, _e234) / _e236); + let _e238 = t_1; + if (_e238 > 0f) { + let _e240 = (*mirror); + let _e241 = t_1; + local_12 = (_e240 * _e241); } else { - let _e242 = toPlane; - let _e243 = n_2; - let _e244 = toPlane; - let _e245 = n_2; - local_12 = (_e242 - (_e243 * dot(_e244, _e245))); + let _e243 = toPlane; + let _e244 = n_2; + let _e245 = toPlane; + let _e246 = n_2; + local_12 = (_e243 - (_e244 * dot(_e245, _e246))); } - let _e249 = local_12; - onPlane = _e249; + let _e250 = local_12; + onPlane = _e250; } - let _e250 = onPlane; - let _e251 = toPlane; - offset_2 = (_e250 - _e251); - let _e253 = (*halfWidth); + let _e251 = onPlane; + let _e252 = toPlane; + offset_2 = (_e251 - _e252); let _e254 = (*halfWidth); - wLen2_ = max(dot(_e253, _e254), 0.000000000001f); - let _e257 = (*halfHeight); + let _e255 = (*halfWidth); + wLen2_ = max(dot(_e254, _e255), 0.000000000001f); let _e258 = (*halfHeight); - hLen2_ = max(dot(_e257, _e258), 0.000000000001f); - let _e261 = offset_2; - let _e262 = (*halfWidth); - let _e264 = wLen2_; - u = clamp((dot(_e261, _e262) / _e264), -1f, 1f); - let _e267 = offset_2; - let _e268 = (*halfHeight); - let _e270 = hLen2_; - v = clamp((dot(_e267, _e268) / _e270), -1f, 1f); - let _e273 = (*centre); - let _e274 = (*halfWidth); - let _e275 = u; - let _e278 = (*halfHeight); - let _e279 = v; - return ((_e273 + (_e274 * _e275)) + (_e278 * _e279)); -} - -fn LambertEdge_u0028_vf3_u003b_vf3_u003b_vf3_u003b(a_1: ptr>, b: ptr>, n_3: ptr>) -> f32 { - var ua: vec3; - var ub: vec3; - var angle_1: f32; - var axis: vec3; - var len: f32; - var local_13: f32; - - let _e196 = (*a_1); - let _e197 = (*a_1); - ua = (_e196 / vec3(max(length(_e197), 0.000000000001f))); - let _e202 = (*b); + let _e259 = (*halfHeight); + hLen2_ = max(dot(_e258, _e259), 0.000000000001f); + let _e262 = offset_2; + let _e263 = (*halfWidth); + let _e265 = wLen2_; + u = clamp((dot(_e262, _e263) / _e265), -1f, 1f); + let _e268 = offset_2; + let _e269 = (*halfHeight); + let _e271 = hLen2_; + v = clamp((dot(_e268, _e269) / _e271), -1f, 1f); + let _e274 = (*centre); + let _e275 = (*halfWidth); + let _e276 = u; + let _e279 = (*halfHeight); + let _e280 = v; + return ((_e274 + (_e275 * _e276)) + (_e279 * _e280)); +} + +fn LambertEdge_u0028_vf3_u003b_vf3_u003b_vf3_u003b(a_1: ptr>, b: ptr>, n_3: ptr>) -> f32 { + var ua: vec3; + var ub: vec3; + var angle_1: f32; + var axis: vec3; + var len: f32; + var local_13: f32; + + let _e197 = (*a_1); + let _e198 = (*a_1); + ua = (_e197 / vec3(max(length(_e198), 0.000000000001f))); let _e203 = (*b); - ub = (_e202 / vec3(max(length(_e203), 0.000000000001f))); - let _e208 = ua; - let _e209 = ub; - angle_1 = acos(clamp(dot(_e208, _e209), -1f, 1f)); - let _e213 = ua; - let _e214 = ub; - axis = cross(_e213, _e214); - let _e216 = axis; - len = length(_e216); - let _e218 = len; - if (_e218 > 0.000001f) { - let _e220 = angle_1; - let _e221 = axis; - let _e222 = (*n_3); - let _e225 = len; - local_13 = ((_e220 * dot(_e221, _e222)) / _e225); + let _e204 = (*b); + ub = (_e203 / vec3(max(length(_e204), 0.000000000001f))); + let _e209 = ua; + let _e210 = ub; + angle_1 = acos(clamp(dot(_e209, _e210), -1f, 1f)); + let _e214 = ua; + let _e215 = ub; + axis = cross(_e214, _e215); + let _e217 = axis; + len = length(_e217); + let _e219 = len; + if (_e219 > 0.000001f) { + let _e221 = angle_1; + let _e222 = axis; + let _e223 = (*n_3); + let _e226 = len; + local_13 = ((_e221 * dot(_e222, _e223)) / _e226); } else { local_13 = 0f; } - let _e227 = local_13; - return _e227; + let _e228 = local_13; + return _e228; } fn RectangleFormFactor_u0028_vf3_u005b_4_u005d_u003b_vf3_u003b(corners: ptr, 4>>, n_4: ptr>) -> f32 { @@ -11792,98 +11862,98 @@ fn RectangleFormFactor_u0028_vf3_u005b_4_u005d_u003b_vf3_u003b(corners: ptr(0f, 0f, 0f); i_7 = 0i; loop { - let _e210 = i_7; - if (_e210 < 4i) { - let _e212 = i_7; - let _e214 = (*corners)[_e212]; - a_2 = _e214; - let _e215 = i_7; - if (_e215 == 3i) { + let _e211 = i_7; + if (_e211 < 4i) { + let _e213 = i_7; + let _e215 = (*corners)[_e213]; + a_2 = _e215; + let _e216 = i_7; + if (_e216 == 3i) { local_14 = 0i; } else { - let _e217 = i_7; - local_14 = (_e217 + 1i); + let _e218 = i_7; + local_14 = (_e218 + 1i); } - let _e219 = local_14; - let _e221 = (*corners)[_e219]; - b_1 = _e221; - let _e222 = a_2; - let _e223 = (*n_4); - ha = dot(_e222, _e223); - let _e225 = b_1; - let _e226 = (*n_4); - hb = dot(_e225, _e226); - let _e228 = ha; - let _e229 = hb; - d_3 = (_e228 - _e229); - let _e231 = a_2; - let _e232 = b_1; - let _e233 = a_2; - let _e235 = d_3; - if (abs(_e235) > 0.000000000001f) { - let _e238 = ha; - let _e239 = d_3; - local_15 = (_e238 / _e239); + let _e220 = local_14; + let _e222 = (*corners)[_e220]; + b_1 = _e222; + let _e223 = a_2; + let _e224 = (*n_4); + ha = dot(_e223, _e224); + let _e226 = b_1; + let _e227 = (*n_4); + hb = dot(_e226, _e227); + let _e229 = ha; + let _e230 = hb; + d_3 = (_e229 - _e230); + let _e232 = a_2; + let _e233 = b_1; + let _e234 = a_2; + let _e236 = d_3; + if (abs(_e236) > 0.000000000001f) { + let _e239 = ha; + let _e240 = d_3; + local_15 = (_e239 / _e240); } else { local_15 = 0f; } - let _e241 = local_15; - q = (_e231 + ((_e232 - _e233) * _e241)); - let _e244 = ha; - aAbove = (_e244 > 0f); - let _e246 = hb; - bAbove = (_e246 > 0f); - let _e248 = aAbove; - let _e249 = bAbove; - if (_e248 || _e249) { - let _e251 = aAbove; - let _e252 = a_2; - let _e253 = q; - let _e256 = bAbove; - let _e257 = b_1; - let _e258 = q; - param_73 = select(_e253, _e252, vec3(_e251)); - param_74 = select(_e258, _e257, vec3(_e256)); - let _e261 = (*n_4); - param_75 = _e261; - let _e262 = LambertEdge_u0028_vf3_u003b_vf3_u003b_vf3_u003b((¶m_73), (¶m_74), (¶m_75)); - local_16 = _e262; + let _e242 = local_15; + q = (_e232 + ((_e233 - _e234) * _e242)); + let _e245 = ha; + aAbove = (_e245 > 0f); + let _e247 = hb; + bAbove = (_e247 > 0f); + let _e249 = aAbove; + let _e250 = bAbove; + if (_e249 || _e250) { + let _e252 = aAbove; + let _e253 = a_2; + let _e254 = q; + let _e257 = bAbove; + let _e258 = b_1; + let _e259 = q; + param_73 = select(_e254, _e253, vec3(_e252)); + param_74 = select(_e259, _e258, vec3(_e257)); + let _e262 = (*n_4); + param_75 = _e262; + let _e263 = LambertEdge_u0028_vf3_u003b_vf3_u003b_vf3_u003b((¶m_73), (¶m_74), (¶m_75)); + local_16 = _e263; } else { local_16 = 0f; } - let _e263 = local_16; - let _e264 = total; - total = (_e264 + _e263); - let _e266 = aAbove; - let _e267 = bAbove; - let _e270 = q; - let _e271 = exit; - exit = select(_e271, _e270, vec3((_e266 && !(_e267)))); - let _e274 = aAbove; - let _e276 = bAbove; - let _e278 = q; - let _e279 = entry; - entry = select(_e279, _e278, vec3((!(_e274) && _e276))); + let _e264 = local_16; + let _e265 = total; + total = (_e265 + _e264); + let _e267 = aAbove; + let _e268 = bAbove; + let _e271 = q; + let _e272 = exit; + exit = select(_e272, _e271, vec3((_e267 && !(_e268)))); + let _e275 = aAbove; + let _e277 = bAbove; + let _e279 = q; + let _e280 = entry; + entry = select(_e280, _e279, vec3((!(_e275) && _e277))); continue; } else { break; } continuing { - let _e282 = i_7; - i_7 = (_e282 + 1i); + let _e283 = i_7; + i_7 = (_e283 + 1i); } } - let _e284 = exit; - param_76 = _e284; - let _e285 = entry; - param_77 = _e285; - let _e286 = (*n_4); - param_78 = _e286; - let _e287 = LambertEdge_u0028_vf3_u003b_vf3_u003b_vf3_u003b((¶m_76), (¶m_77), (¶m_78)); - let _e288 = total; - total = (_e288 + _e287); - let _e290 = total; - return max((-(_e290) * 0.5f), 0f); + let _e285 = exit; + param_76 = _e285; + let _e286 = entry; + param_77 = _e286; + let _e287 = (*n_4); + param_78 = _e287; + let _e288 = LambertEdge_u0028_vf3_u003b_vf3_u003b_vf3_u003b((¶m_76), (¶m_77), (¶m_78)); + let _e289 = total; + total = (_e289 + _e288); + let _e291 = total; + return max((-(_e291) * 0.5f), 0f); } fn LightListLane_u0028_vf4_u003b_i1_u003b(four: ptr>, slot_1: ptr) -> f32 { @@ -11892,91 +11962,91 @@ fn LightListLane_u0028_vf4_u003b_i1_u003b(four: ptr>, slot_1 var local_18: f32; var local_19: f32; - let _e193 = (*slot_1); let _e194 = (*slot_1); - lane = (_e193 - ((_e194 / 4i) * 4i)); - let _e198 = lane; - if (_e198 == 0i) { - let _e201 = (*four)[0u]; - local_17 = _e201; + let _e195 = (*slot_1); + lane = (_e194 - ((_e195 / 4i) * 4i)); + let _e199 = lane; + if (_e199 == 0i) { + let _e202 = (*four)[0u]; + local_17 = _e202; } else { - let _e202 = lane; - if (_e202 == 1i) { - let _e205 = (*four)[1u]; - local_18 = _e205; + let _e203 = lane; + if (_e203 == 1i) { + let _e206 = (*four)[1u]; + local_18 = _e206; } else { - let _e206 = lane; - if (_e206 == 2i) { - let _e209 = (*four)[2u]; - local_19 = _e209; + let _e207 = lane; + if (_e207 == 2i) { + let _e210 = (*four)[2u]; + local_19 = _e210; } else { - let _e211 = (*four)[3u]; - local_19 = _e211; + let _e212 = (*four)[3u]; + local_19 = _e212; } - let _e212 = local_19; - local_18 = _e212; + let _e213 = local_19; + local_18 = _e213; } - let _e213 = local_18; - local_17 = _e213; + let _e214 = local_18; + local_17 = _e214; } - let _e214 = local_17; - return _e214; + let _e215 = local_17; + return _e215; } fn LightListScale_u0028_i1_u003b(slot_2: ptr) -> f32 { var param_79: vec4; var param_80: i32; - let _e190 = (*slot_2); - let _e194 = light_list_info.scales[(_e190 / 4i)]; - param_79 = _e194; - let _e195 = (*slot_2); - param_80 = _e195; - let _e196 = LightListLane_u0028_vf4_u003b_i1_u003b((¶m_79), (¶m_80)); - return _e196; + let _e191 = (*slot_2); + let _e195 = light_list_info.scales[(_e191 / 4i)]; + param_79 = _e195; + let _e196 = (*slot_2); + param_80 = _e196; + let _e197 = LightListLane_u0028_vf4_u003b_i1_u003b((¶m_79), (¶m_80)); + return _e197; } fn InSlots_u0028_f1_u003b(row: ptr) -> bool { var a_3: vec4; var b_2: vec4; - let _e192 = light_list_info.slot_rows[0i]; - let _e193 = (*row); - a_3 = abs((_e192 - vec4(_e193))); - let _e199 = light_list_info.slot_rows[1i]; - let _e200 = (*row); - b_2 = abs((_e199 - vec4(_e200))); - let _e205 = a_3[0u]; - let _e207 = a_3[1u]; - let _e210 = a_3[2u]; - let _e212 = a_3[3u]; - let _e216 = b_2[0u]; - let _e218 = b_2[1u]; - let _e221 = b_2[2u]; - let _e223 = b_2[3u]; - return (min(min(min(_e205, _e207), min(_e210, _e212)), min(min(_e216, _e218), min(_e221, _e223))) < 0.5f); + let _e193 = light_list_info.slot_rows[0i]; + let _e194 = (*row); + a_3 = abs((_e193 - vec4(_e194))); + let _e200 = light_list_info.slot_rows[1i]; + let _e201 = (*row); + b_2 = abs((_e200 - vec4(_e201))); + let _e206 = a_3[0u]; + let _e208 = a_3[1u]; + let _e211 = a_3[2u]; + let _e213 = a_3[3u]; + let _e217 = b_2[0u]; + let _e219 = b_2[1u]; + let _e222 = b_2[2u]; + let _e224 = b_2[3u]; + return (min(min(min(_e206, _e208), min(_e211, _e213)), min(min(_e217, _e219), min(_e222, _e224))) < 0.5f); } fn LightListRow_u0028_i1_u003b(slot_3: ptr) -> f32 { var param_81: vec4; var param_82: i32; - let _e190 = (*slot_3); - let _e194 = light_list_info.indices[(_e190 / 4i)]; - param_81 = _e194; - let _e195 = (*slot_3); - param_82 = _e195; - let _e196 = LightListLane_u0028_vf4_u003b_i1_u003b((¶m_81), (¶m_82)); - return _e196; + let _e191 = (*slot_3); + let _e195 = light_list_info.indices[(_e191 / 4i)]; + param_81 = _e195; + let _e196 = (*slot_3); + param_82 = _e196; + let _e197 = LightListLane_u0028_vf4_u003b_i1_u003b((¶m_81), (¶m_82)); + return _e197; } fn LightListTexel_u0028_f1_u003b_f1_u003b(texel_2: ptr, row_1: ptr) -> vec4 { - let _e189 = (*texel_2); - let _e193 = light_list_info.list[1u]; - let _e195 = (*row_1); - let _e199 = light_list_info.list[2u]; - let _e202 = textureSampleLevel(light_list_texture_tex, light_list_texture_smp, vec2(((_e189 + 0.5f) * _e193), ((_e195 + 0.5f) * _e199)), 0f); - return _e202; + let _e190 = (*texel_2); + let _e194 = light_list_info.list[1u]; + let _e196 = (*row_1); + let _e200 = light_list_info.list[2u]; + let _e203 = textureSampleLevel(light_list_texture_tex, light_list_texture_smp, vec2(((_e190 + 0.5f) * _e194), ((_e196 + 0.5f) * _e200)), 0f); + return _e203; } fn ClusterRow_u0028_i1_u003b(slot_4: ptr) -> f32 { @@ -11990,35 +12060,35 @@ fn ClusterRow_u0028_i1_u003b(slot_4: ptr) -> f32 { var param_85: vec4; var param_86: i32; - let _e197 = g_cluster_offset; - let _e198 = (*slot_4); - entry_1 = (_e197 + f32(_e198)); - let _e201 = entry_1; - row_2 = floor((_e201 / 16f)); - let _e204 = entry_1; - let _e205 = row_2; - within = (_e204 - (_e205 * 16f)); - let _e208 = within; - texel_3 = floor((_e208 / 4f)); - let _e213 = light_list_info.cluster_depth[3u]; - let _e214 = row_2; - let _e216 = texel_3; - param_83 = _e216; - param_84 = (_e213 + _e214); - let _e217 = LightListTexel_u0028_f1_u003b_f1_u003b((¶m_83), (¶m_84)); - four_1 = _e217; - let _e218 = within; - let _e219 = texel_3; - let _e224 = four_1; - param_85 = _e224; - param_86 = i32(((_e218 - (_e219 * 4f)) + 0.5f)); - let _e225 = LightListLane_u0028_vf4_u003b_i1_u003b((¶m_85), (¶m_86)); - return _e225; + let _e198 = g_cluster_offset; + let _e199 = (*slot_4); + entry_1 = (_e198 + f32(_e199)); + let _e202 = entry_1; + row_2 = floor((_e202 / 16f)); + let _e205 = entry_1; + let _e206 = row_2; + within = (_e205 - (_e206 * 16f)); + let _e209 = within; + texel_3 = floor((_e209 / 4f)); + let _e214 = light_list_info.cluster_depth[3u]; + let _e215 = row_2; + let _e217 = texel_3; + param_83 = _e217; + param_84 = (_e214 + _e215); + let _e218 = LightListTexel_u0028_f1_u003b_f1_u003b((¶m_83), (¶m_84)); + four_1 = _e218; + let _e219 = within; + let _e220 = texel_3; + let _e225 = four_1; + param_85 = _e225; + param_86 = i32(((_e219 - (_e220 * 4f)) + 0.5f)); + let _e226 = LightListLane_u0028_vf4_u003b_i1_u003b((¶m_85), (¶m_86)); + return _e226; } fn Clustered_u0028_() -> bool { - let _e189 = light_list_info.cluster_grid[3u]; - return (_e189 > 0.5f); + let _e190 = light_list_info.cluster_grid[3u]; + return (_e190 > 0.5f); } fn SampleLight_u0028_i1_u003b_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b(index_2: ptr, s_4: ptr) -> LightSample { @@ -12074,264 +12144,264 @@ fn SampleLight_u0028_i1_u003b_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_ light_3.integrated = 0f; light_3.ltc = vec3(0f, 0f, 0f); - let _e240 = (*index_2); - if (_e240 < 8i) { - let _e242 = (*index_2); - let _e245 = frag_info.light_position[_e242]; - position = _e245; - let _e246 = (*index_2); - let _e249 = frag_info.light_color[_e246]; - color_1 = _e249; - let _e250 = (*index_2); - let _e253 = frag_info.light_direction[_e250]; - direction = _e253; - let _e254 = (*index_2); - let _e257 = frag_info.light_cone[_e254]; - cone = _e257; + let _e241 = (*index_2); + if (_e241 < 8i) { + let _e243 = (*index_2); + let _e246 = frag_info.light_position[_e243]; + position = _e246; + let _e247 = (*index_2); + let _e250 = frag_info.light_color[_e247]; + color_1 = _e250; + let _e251 = (*index_2); + let _e254 = frag_info.light_direction[_e251]; + direction = _e254; + let _e255 = (*index_2); + let _e258 = frag_info.light_cone[_e255]; + cone = _e258; } else { - let _e258 = (*index_2); - slot_5 = (_e258 - 8i); - let _e260 = Clustered_u0028_(); - clustered = _e260; - let _e261 = clustered; - if _e261 { - let _e262 = slot_5; - param_87 = _e262; - let _e263 = ClusterRow_u0028_i1_u003b((¶m_87)); - local_20 = _e263; + let _e259 = (*index_2); + slot_5 = (_e259 - 8i); + let _e261 = Clustered_u0028_(); + clustered = _e261; + let _e262 = clustered; + if _e262 { + let _e263 = slot_5; + param_87 = _e263; + let _e264 = ClusterRow_u0028_i1_u003b((¶m_87)); + local_20 = _e264; } else { - let _e264 = slot_5; - param_88 = _e264; - let _e265 = LightListRow_u0028_i1_u003b((¶m_88)); - local_20 = _e265; + let _e265 = slot_5; + param_88 = _e265; + let _e266 = LightListRow_u0028_i1_u003b((¶m_88)); + local_20 = _e266; } - let _e266 = local_20; - listRow = _e266; - let _e267 = listRow; - let _e271 = light_list_info.list[2u]; - v_1 = ((_e267 + 0.5f) * _e271); - let _e275 = light_list_info.list[1u]; - u_1 = _e275; - let _e276 = u_1; - let _e278 = v_1; - let _e280 = textureSampleLevel(light_list_texture_tex, light_list_texture_smp, vec2((0.5f * _e276), _e278), 0f); - position = _e280; - let _e281 = u_1; - let _e283 = v_1; - let _e285 = textureSampleLevel(light_list_texture_tex, light_list_texture_smp, vec2((1.5f * _e281), _e283), 0f); - color_1 = _e285; - let _e286 = u_1; - let _e288 = v_1; - let _e290 = textureSampleLevel(light_list_texture_tex, light_list_texture_smp, vec2((2.5f * _e286), _e288), 0f); - direction = _e290; - let _e291 = u_1; - let _e293 = v_1; - let _e295 = textureSampleLevel(light_list_texture_tex, light_list_texture_smp, vec2((3.5f * _e291), _e293), 0f); - cone = _e295; - let _e296 = clustered; - if _e296 { - let _e297 = listRow; - param_89 = _e297; - let _e298 = InSlots_u0028_f1_u003b((¶m_89)); - local_21 = select(1f, 0f, _e298); + let _e267 = local_20; + listRow = _e267; + let _e268 = listRow; + let _e272 = light_list_info.list[2u]; + v_1 = ((_e268 + 0.5f) * _e272); + let _e276 = light_list_info.list[1u]; + u_1 = _e276; + let _e277 = u_1; + let _e279 = v_1; + let _e281 = textureSampleLevel(light_list_texture_tex, light_list_texture_smp, vec2((0.5f * _e277), _e279), 0f); + position = _e281; + let _e282 = u_1; + let _e284 = v_1; + let _e286 = textureSampleLevel(light_list_texture_tex, light_list_texture_smp, vec2((1.5f * _e282), _e284), 0f); + color_1 = _e286; + let _e287 = u_1; + let _e289 = v_1; + let _e291 = textureSampleLevel(light_list_texture_tex, light_list_texture_smp, vec2((2.5f * _e287), _e289), 0f); + direction = _e291; + let _e292 = u_1; + let _e294 = v_1; + let _e296 = textureSampleLevel(light_list_texture_tex, light_list_texture_smp, vec2((3.5f * _e292), _e294), 0f); + cone = _e296; + let _e297 = clustered; + if _e297 { + let _e298 = listRow; + param_89 = _e298; + let _e299 = InSlots_u0028_f1_u003b((¶m_89)); + local_21 = select(1f, 0f, _e299); } else { - let _e300 = slot_5; - param_90 = _e300; - let _e301 = LightListScale_u0028_i1_u003b((¶m_90)); - local_21 = _e301; + let _e301 = slot_5; + param_90 = _e301; + let _e302 = LightListScale_u0028_i1_u003b((¶m_90)); + local_21 = _e302; } - let _e302 = local_21; - let _e304 = color_1[3u]; - color_1[3u] = (_e304 * _e302); + let _e303 = local_21; + let _e305 = color_1[3u]; + color_1[3u] = (_e305 * _e303); } - let _e308 = position[3u]; - type_39 = _e308; - let _e309 = type_39; - if (_e309 > 2.5f) { - let _e311 = direction; - halfWidth_1 = _e311.xyz; - let _e313 = cone; - halfHeight_1 = _e313.xyz; - let _e315 = position; - let _e317 = v_world_position_1; - toCentre = (_e315.xyz - _e317); - let _e319 = toCentre; - let _e320 = halfWidth_1; - let _e322 = halfHeight_1; - corners_1[0i] = ((_e319 - _e320) - _e322); - let _e325 = toCentre; - let _e326 = halfWidth_1; - let _e328 = halfHeight_1; - corners_1[1i] = ((_e325 + _e326) - _e328); - let _e331 = toCentre; - let _e332 = halfWidth_1; - let _e334 = halfHeight_1; - corners_1[2i] = ((_e331 + _e332) + _e334); - let _e337 = toCentre; - let _e338 = halfWidth_1; - let _e340 = halfHeight_1; - corners_1[3i] = ((_e337 - _e338) + _e340); - let _e343 = toCentre; - let _e344 = halfWidth_1; - let _e345 = halfHeight_1; - behind = (dot(_e343, cross(_e344, _e345)) >= 0f); - let _e349 = behind; - if _e349 { + let _e309 = position[3u]; + type_39 = _e309; + let _e310 = type_39; + if (_e310 > 2.5f) { + let _e312 = direction; + halfWidth_1 = _e312.xyz; + let _e314 = cone; + halfHeight_1 = _e314.xyz; + let _e316 = position; + let _e318 = v_world_position_1; + toCentre = (_e316.xyz - _e318); + let _e320 = toCentre; + let _e321 = halfWidth_1; + let _e323 = halfHeight_1; + corners_1[0i] = ((_e320 - _e321) - _e323); + let _e326 = toCentre; + let _e327 = halfWidth_1; + let _e329 = halfHeight_1; + corners_1[1i] = ((_e326 + _e327) - _e329); + let _e332 = toCentre; + let _e333 = halfWidth_1; + let _e335 = halfHeight_1; + corners_1[2i] = ((_e332 + _e333) + _e335); + let _e338 = toCentre; + let _e339 = halfWidth_1; + let _e341 = halfHeight_1; + corners_1[3i] = ((_e338 - _e339) + _e341); + let _e344 = toCentre; + let _e345 = halfWidth_1; + let _e346 = halfHeight_1; + behind = (dot(_e344, cross(_e345, _e346)) >= 0f); + let _e350 = behind; + if _e350 { local_22 = 0f; } else { - let _e350 = corners_1; - param_91 = _e350; - let _e352 = (*s_4).n; - param_92 = _e352; - let _e353 = RectangleFormFactor_u0028_vf3_u005b_4_u005d_u003b_vf3_u003b((¶m_91), (¶m_92)); - local_22 = _e353; + let _e351 = corners_1; + param_91 = _e351; + let _e353 = (*s_4).n; + param_92 = _e353; + let _e354 = RectangleFormFactor_u0028_vf3_u005b_4_u005d_u003b_vf3_u003b((¶m_91), (¶m_92)); + local_22 = _e354; } - let _e354 = local_22; - formFactor = _e354; - let _e355 = halfWidth_1; - let _e356 = halfHeight_1; - area = (length(cross(_e355, _e356)) * 4f); - let _e360 = area; - if (_e360 > 0.000000001f) { - let _e362 = area; - local_23 = (1f / _e362); + let _e355 = local_22; + formFactor = _e355; + let _e356 = halfWidth_1; + let _e357 = halfHeight_1; + area = (length(cross(_e356, _e357)) * 4f); + let _e361 = area; + if (_e361 > 0.000000001f) { + let _e363 = area; + local_23 = (1f / _e363); } else { local_23 = 0f; } - let _e364 = local_23; - radiance = _e364; - let _e365 = toCentre; - distance_2 = length(_e365); - let _e368 = direction[3u]; - if (_e368 > 0f) { - let _e370 = distance_2; - let _e372 = direction[3u]; - ratio_1 = (_e370 / _e372); - let _e374 = ratio_1; + let _e365 = local_23; + radiance = _e365; + let _e366 = toCentre; + distance_2 = length(_e366); + let _e369 = direction[3u]; + if (_e369 > 0f) { + let _e371 = distance_2; + let _e373 = direction[3u]; + ratio_1 = (_e371 / _e373); let _e375 = ratio_1; - let _e377 = ratio_1; - let _e379 = ratio_1; - window_1 = clamp((1f - (((_e374 * _e375) * _e377) * _e379)), 0f, 1f); - let _e383 = window_1; + let _e376 = ratio_1; + let _e378 = ratio_1; + let _e380 = ratio_1; + window_1 = clamp((1f - (((_e375 * _e376) * _e378) * _e380)), 0f, 1f); let _e384 = window_1; - let _e386 = radiance; - radiance = (_e386 * (_e383 * _e384)); + let _e385 = window_1; + let _e387 = radiance; + radiance = (_e387 * (_e384 * _e385)); } - let _e389 = (*s_4).v; - let _e392 = (*s_4).n; - mirror_1 = reflect(-(_e389), _e392); - let _e394 = position; - param_93 = _e394.xyz; - let _e396 = halfWidth_1; - param_94 = _e396; - let _e397 = halfHeight_1; - param_95 = _e397; - let _e398 = v_world_position_1; - param_96 = _e398; - let _e399 = mirror_1; - param_97 = _e399; - let _e400 = RectangleClosestPoint_u0028_vf3_u003b_vf3_u003b_vf3_u003b_vf3_u003b_vf3_u003b((¶m_93), (¶m_94), (¶m_95), (¶m_96), (¶m_97)); - representative = _e400; - let _e401 = representative; - let _e402 = v_world_position_1; - toPoint = (_e401 - _e402); - let _e404 = toPoint; - pointDistance = length(_e404); - let _e406 = pointDistance; - if (_e406 > 0.000001f) { - let _e408 = toPoint; - let _e409 = pointDistance; - local_24 = (_e408 / vec3(_e409)); + let _e390 = (*s_4).v; + let _e393 = (*s_4).n; + mirror_1 = reflect(-(_e390), _e393); + let _e395 = position; + param_93 = _e395.xyz; + let _e397 = halfWidth_1; + param_94 = _e397; + let _e398 = halfHeight_1; + param_95 = _e398; + let _e399 = v_world_position_1; + param_96 = _e399; + let _e400 = mirror_1; + param_97 = _e400; + let _e401 = RectangleClosestPoint_u0028_vf3_u003b_vf3_u003b_vf3_u003b_vf3_u003b_vf3_u003b((¶m_93), (¶m_94), (¶m_95), (¶m_96), (¶m_97)); + representative = _e401; + let _e402 = representative; + let _e403 = v_world_position_1; + toPoint = (_e402 - _e403); + let _e405 = toPoint; + pointDistance = length(_e405); + let _e407 = pointDistance; + if (_e407 > 0.000001f) { + let _e409 = toPoint; + let _e410 = pointDistance; + local_24 = (_e409 / vec3(_e410)); } else { - let _e413 = (*s_4).n; - local_24 = _e413; + let _e414 = (*s_4).n; + local_24 = _e414; } - let _e414 = local_24; - light_3.l = _e414; - let _e417 = light_3.l; - let _e419 = (*s_4).v; - light_3.h = normalize((_e417 + _e419)); - let _e423 = formFactor; - light_3.n_dot_l = _e423; - let _e426 = (*s_4).n; - let _e428 = light_3.h; - light_3.n_dot_h = max(dot(_e426, _e428), 0f); - let _e433 = (*s_4).v; - let _e435 = light_3.h; - light_3.v_dot_h = max(dot(_e433, _e435), 0f); - let _e439 = color_1; - let _e442 = color_1[3u]; - let _e444 = radiance; - light_3.radiance = ((_e439.xyz * _e442) * _e444); - let _e447 = light_3; - return _e447; + let _e415 = local_24; + light_3.l = _e415; + let _e418 = light_3.l; + let _e420 = (*s_4).v; + light_3.h = normalize((_e418 + _e420)); + let _e424 = formFactor; + light_3.n_dot_l = _e424; + let _e427 = (*s_4).n; + let _e429 = light_3.h; + light_3.n_dot_h = max(dot(_e427, _e429), 0f); + let _e434 = (*s_4).v; + let _e436 = light_3.h; + light_3.v_dot_h = max(dot(_e434, _e436), 0f); + let _e440 = color_1; + let _e443 = color_1[3u]; + let _e445 = radiance; + light_3.radiance = ((_e440.xyz * _e443) * _e445); + let _e448 = light_3; + return _e448; } - let _e448 = direction; - aim = normalize(_e448.xyz); + let _e449 = direction; + aim = normalize(_e449.xyz); attenuation_1 = 1f; - let _e451 = type_39; - if (_e451 < 0.5f) { - let _e453 = aim; - light_3.l = -(_e453); + let _e452 = type_39; + if (_e452 < 0.5f) { + let _e454 = aim; + light_3.l = -(_e454); } else { - let _e456 = position; - let _e458 = v_world_position_1; - toLight_1 = (_e456.xyz - _e458); - let _e460 = toLight_1; - distance_3 = length(_e460); - let _e462 = distance_3; - if (_e462 < 0.000001f) { - let _e465 = (*s_4).n; - light_3.l = _e465; - let _e468 = (*s_4).n; - light_3.h = _e468; + let _e457 = position; + let _e459 = v_world_position_1; + toLight_1 = (_e457.xyz - _e459); + let _e461 = toLight_1; + distance_3 = length(_e461); + let _e463 = distance_3; + if (_e463 < 0.000001f) { + let _e466 = (*s_4).n; + light_3.l = _e466; + let _e469 = (*s_4).n; + light_3.h = _e469; light_3.radiance = vec3(0f, 0f, 0f); light_3.n_dot_l = 0f; light_3.n_dot_h = 0f; light_3.v_dot_h = 0f; - let _e474 = light_3; - return _e474; - } - let _e475 = toLight_1; - let _e476 = distance_3; - light_3.l = (_e475 / vec3(_e476)); - let _e480 = distance_3; - param_98 = _e480; - let _e482 = direction[3u]; - param_99 = _e482; - let _e483 = PunctualAttenuation_u0028_f1_u003b_f1_u003b((¶m_98), (¶m_99)); - attenuation_1 = _e483; - let _e484 = type_39; - if (_e484 > 1.5f) { - let _e486 = aim; - let _e488 = light_3.l; - cosAngle = dot(_e486, -(_e488)); - let _e491 = cosAngle; - let _e493 = cone[1u]; - let _e496 = cone[0u]; - let _e498 = cone[1u]; - let _e502 = attenuation_1; - attenuation_1 = (_e502 * clamp(((_e491 - _e493) / (_e496 - _e498)), 0f, 1f)); + let _e475 = light_3; + return _e475; } - } - let _e505 = light_3.l; - let _e507 = (*s_4).v; - light_3.h = normalize((_e505 + _e507)); - let _e512 = (*s_4).n; - let _e514 = light_3.l; - light_3.n_dot_l = max(dot(_e512, _e514), 0f); - let _e519 = (*s_4).n; - let _e521 = light_3.h; - light_3.n_dot_h = max(dot(_e519, _e521), 0f); - let _e526 = (*s_4).v; - let _e528 = light_3.h; - light_3.v_dot_h = max(dot(_e526, _e528), 0f); - let _e532 = color_1; - let _e535 = color_1[3u]; - let _e537 = attenuation_1; - light_3.radiance = ((_e532.xyz * _e535) * _e537); - let _e540 = light_3; - return _e540; + let _e476 = toLight_1; + let _e477 = distance_3; + light_3.l = (_e476 / vec3(_e477)); + let _e481 = distance_3; + param_98 = _e481; + let _e483 = direction[3u]; + param_99 = _e483; + let _e484 = PunctualAttenuation_u0028_f1_u003b_f1_u003b((¶m_98), (¶m_99)); + attenuation_1 = _e484; + let _e485 = type_39; + if (_e485 > 1.5f) { + let _e487 = aim; + let _e489 = light_3.l; + cosAngle = dot(_e487, -(_e489)); + let _e492 = cosAngle; + let _e494 = cone[1u]; + let _e497 = cone[0u]; + let _e499 = cone[1u]; + let _e503 = attenuation_1; + attenuation_1 = (_e503 * clamp(((_e492 - _e494) / (_e497 - _e499)), 0f, 1f)); + } + } + let _e506 = light_3.l; + let _e508 = (*s_4).v; + light_3.h = normalize((_e506 + _e508)); + let _e513 = (*s_4).n; + let _e515 = light_3.l; + light_3.n_dot_l = max(dot(_e513, _e515), 0f); + let _e520 = (*s_4).n; + let _e522 = light_3.h; + light_3.n_dot_h = max(dot(_e520, _e522), 0f); + let _e527 = (*s_4).v; + let _e529 = light_3.h; + light_3.v_dot_h = max(dot(_e527, _e529), 0f); + let _e533 = color_1; + let _e536 = color_1[3u]; + let _e538 = attenuation_1; + light_3.radiance = ((_e533.xyz * _e536) * _e538); + let _e541 = light_3; + return _e541; } fn FindCluster_u0028_vf3_u003b(world_3: ptr>) { @@ -12349,58 +12419,58 @@ fn FindCluster_u0028_vf3_u003b(world_3: ptr>) { var param_100: f32; var param_101: f32; - let _e202 = light_list_info.cluster_view_projection; - let _e203 = (*world_3); - clip_1 = (_e202 * vec4(_e203.x, _e203.y, _e203.z, 1f)); - let _e209 = clip_1; - let _e212 = clip_1[3u]; - ndc_1 = (_e209.xy / vec2(max(_e212, 0.000001f))); - let _e217 = light_list_info.cluster_grid; - grid = _e217.xyz; - let _e221 = light_list_info.cluster_depth[0u]; - near_1 = _e221; - let _e223 = ndc_1[0u]; - let _e227 = grid[0u]; - let _e231 = grid[0u]; - tx = clamp(floor((((_e223 * 0.5f) + 0.5f) * _e227)), 0f, (_e231 - 1f)); - let _e235 = ndc_1[1u]; - let _e239 = grid[1u]; - let _e243 = grid[1u]; - ty = clamp(floor((((_e235 * 0.5f) + 0.5f) * _e239)), 0f, (_e243 - 1f)); - let _e247 = clip_1[3u]; - let _e248 = near_1; - if (_e247 <= _e248) { + let _e203 = light_list_info.cluster_view_projection; + let _e204 = (*world_3); + clip_1 = (_e203 * vec4(_e204.x, _e204.y, _e204.z, 1f)); + let _e210 = clip_1; + let _e213 = clip_1[3u]; + ndc_1 = (_e210.xy / vec2(max(_e213, 0.000001f))); + let _e218 = light_list_info.cluster_grid; + grid = _e218.xyz; + let _e222 = light_list_info.cluster_depth[0u]; + near_1 = _e222; + let _e224 = ndc_1[0u]; + let _e228 = grid[0u]; + let _e232 = grid[0u]; + tx = clamp(floor((((_e224 * 0.5f) + 0.5f) * _e228)), 0f, (_e232 - 1f)); + let _e236 = ndc_1[1u]; + let _e240 = grid[1u]; + let _e244 = grid[1u]; + ty = clamp(floor((((_e236 * 0.5f) + 0.5f) * _e240)), 0f, (_e244 - 1f)); + let _e248 = clip_1[3u]; + let _e249 = near_1; + if (_e248 <= _e249) { local_25 = 0f; } else { - let _e251 = clip_1[3u]; - let _e252 = near_1; - let _e257 = light_list_info.cluster_depth[1u]; - let _e261 = grid[2u]; - local_25 = clamp(floor((log((_e251 / _e252)) * _e257)), 0f, (_e261 - 1f)); + let _e252 = clip_1[3u]; + let _e253 = near_1; + let _e258 = light_list_info.cluster_depth[1u]; + let _e262 = grid[2u]; + local_25 = clamp(floor((log((_e252 / _e253)) * _e258)), 0f, (_e262 - 1f)); } - let _e264 = local_25; - tz = _e264; - let _e265 = tx; - let _e266 = ty; - let _e268 = grid[0u]; - let _e271 = tz; - let _e273 = grid[0u]; - let _e276 = grid[1u]; - cell = ((_e265 + (_e266 * _e268)) + ((_e271 * _e273) * _e276)); - let _e279 = cell; - row_3 = floor((_e279 / 4f)); - let _e282 = cell; - let _e283 = row_3; - let _e288 = light_list_info.cluster_depth[2u]; - let _e289 = row_3; - param_100 = (_e282 - (_e283 * 4f)); - param_101 = (_e288 + _e289); - let _e291 = LightListTexel_u0028_f1_u003b_f1_u003b((¶m_100), (¶m_101)); - header = _e291; - let _e293 = header[0u]; - g_cluster_offset = _e293; - let _e295 = header[1u]; - g_cluster_count = _e295; + let _e265 = local_25; + tz = _e265; + let _e266 = tx; + let _e267 = ty; + let _e269 = grid[0u]; + let _e272 = tz; + let _e274 = grid[0u]; + let _e277 = grid[1u]; + cell = ((_e266 + (_e267 * _e269)) + ((_e272 * _e274) * _e277)); + let _e280 = cell; + row_3 = floor((_e280 / 4f)); + let _e283 = cell; + let _e284 = row_3; + let _e289 = light_list_info.cluster_depth[2u]; + let _e290 = row_3; + param_100 = (_e283 - (_e284 * 4f)); + param_101 = (_e289 + _e290); + let _e292 = LightListTexel_u0028_f1_u003b_f1_u003b((¶m_100), (¶m_101)); + header = _e292; + let _e294 = header[0u]; + g_cluster_offset = _e294; + let _e296 = header[1u]; + g_cluster_count = _e296; return; } @@ -12408,19 +12478,19 @@ fn LightCount_u0028_() -> i32 { var tail: f32; var param_102: vec3; - let _e191 = light_list_info.list[0u]; - tail = _e191; - let _e192 = Clustered_u0028_(); - if _e192 { - let _e193 = v_world_position_1; - param_102 = _e193; + let _e192 = light_list_info.list[0u]; + tail = _e192; + let _e193 = Clustered_u0028_(); + if _e193 { + let _e194 = v_world_position_1; + param_102 = _e194; FindCluster_u0028_vf3_u003b((¶m_102)); - let _e194 = g_cluster_count; - tail = _e194; + let _e195 = g_cluster_count; + tail = _e195; } - let _e197 = frag_info.frame_params[1u]; - let _e201 = tail; - return (clamp(i32((_e197 + 0.5f)), 0i, 8i) + clamp(i32((_e201 + 0.5f)), 0i, 24i)); + let _e198 = frag_info.frame_params[1u]; + let _e202 = tail; + return (clamp(i32((_e198 + 0.5f)), 0i, 8i) + clamp(i32((_e202 + 0.5f)), 0i, 24i)); } fn AccumulateLights_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b(s_5: ptr) -> vec3 { @@ -12443,109 +12513,109 @@ fn AccumulateLights_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002 var param_113: LightSample; total_1 = vec3(0f, 0f, 0f); - let _e205 = LightCount_u0028_(); - count_1 = _e205; + let _e206 = LightCount_u0028_(); + count_1 = _e206; i_8 = 0i; loop { - let _e206 = i_8; - if (_e206 < 32i) { - let _e208 = i_8; - let _e209 = count_1; - if (_e208 >= _e209) { + let _e207 = i_8; + if (_e207 < 32i) { + let _e209 = i_8; + let _e210 = count_1; + if (_e209 >= _e210) { break; } - let _e211 = i_8; - param_103 = _e211; - let _e212 = (*s_5); - param_104 = _e212; - let _e213 = SampleLight_u0028_i1_u003b_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b((¶m_103), (¶m_104)); - light_4 = _e213; - let _e215 = light_4.n_dot_l; - if (_e215 <= 0f) { + let _e212 = i_8; + param_103 = _e212; + let _e213 = (*s_5); + param_104 = _e213; + let _e214 = SampleLight_u0028_i1_u003b_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b((¶m_103), (¶m_104)); + light_4 = _e214; + let _e216 = light_4.n_dot_l; + if (_e216 <= 0f) { continue; } light_transmittance = vec3(1f, 1f, 1f); - let _e217 = i_8; - param_105 = _e217; - let _e218 = LightHasShadow_u0028_i1_u003b((¶m_105)); - if _e218 { - let _e219 = (*s_5); - param_106 = _e219; - let _e220 = light_4; - param_107 = _e220; - let _e221 = i_8; - param_108 = _e221; - let _e222 = LightVisibility_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_struct_u002d_LightSample_u002d_vf3_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf31_u003b_i1_u003b((¶m_106), (¶m_107), (¶m_108)); - let _e223 = v_world_position_1; - param_109 = _e223; - let _e225 = (*s_5).n; - param_110 = _e225; - let _e226 = i_8; - param_111 = _e226; - let _e227 = PointShadowFactor_u0028_vf3_u003b_vf3_u003b_i1_u003b((¶m_109), (¶m_110), (¶m_111)); - local_26 = (_e222 * _e227); + let _e218 = i_8; + param_105 = _e218; + let _e219 = LightHasShadow_u0028_i1_u003b((¶m_105)); + if _e219 { + let _e220 = (*s_5); + param_106 = _e220; + let _e221 = light_4; + param_107 = _e221; + let _e222 = i_8; + param_108 = _e222; + let _e223 = LightVisibility_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_struct_u002d_LightSample_u002d_vf3_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf31_u003b_i1_u003b((¶m_106), (¶m_107), (¶m_108)); + let _e224 = v_world_position_1; + param_109 = _e224; + let _e226 = (*s_5).n; + param_110 = _e226; + let _e227 = i_8; + param_111 = _e227; + let _e228 = PointShadowFactor_u0028_vf3_u003b_vf3_u003b_i1_u003b((¶m_109), (¶m_110), (¶m_111)); + local_26 = (_e223 * _e228); } else { local_26 = 1f; } - let _e229 = local_26; - visibility = _e229; - let _e230 = visibility; - if (_e230 <= 0f) { + let _e230 = local_26; + visibility = _e230; + let _e231 = visibility; + if (_e231 <= 0f) { continue; } - let _e232 = (*s_5); - param_112 = _e232; - let _e233 = light_4; - param_113 = _e233; - let _e234 = ShadeLight_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_struct_u002d_LightSample_u002d_vf3_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf31_u003b((¶m_112), (¶m_113)); - let _e236 = light_4.radiance; - let _e239 = light_4.n_dot_l; - let _e241 = visibility; - let _e243 = light_transmittance; - let _e245 = total_1; - total_1 = (_e245 + ((((_e234 * _e236) * _e239) * _e241) * _e243)); + let _e233 = (*s_5); + param_112 = _e233; + let _e234 = light_4; + param_113 = _e234; + let _e235 = ShadeLight_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_struct_u002d_LightSample_u002d_vf3_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf31_u003b((¶m_112), (¶m_113)); + let _e237 = light_4.radiance; + let _e240 = light_4.n_dot_l; + let _e242 = visibility; + let _e244 = light_transmittance; + let _e246 = total_1; + total_1 = (_e246 + ((((_e235 * _e237) * _e240) * _e242) * _e244)); continue; } else { break; } - continuing { - let _e247 = i_8; - i_8 = (_e247 + 1i); + continuing { + let _e248 = i_8; + i_8 = (_e248 + 1i); } } - let _e249 = total_1; - return _e249; + let _e250 = total_1; + return _e250; } fn SampleLightmap_u0028_() -> vec3 { var texel_4: vec4; - let _e188 = v_lightmap_uv_1; - let _e189 = textureSample(lightmap_texture_tex, lightmap_texture_smp, _e188); - texel_4 = _e189; - let _e190 = texel_4; - let _e193 = texel_4[3u]; - return ((_e190.xyz * _e193) * 8f); + let _e189 = v_lightmap_uv_1; + let _e190 = textureSample(lightmap_texture_tex, lightmap_texture_smp, _e189); + texel_4 = _e190; + let _e191 = texel_4; + let _e194 = texel_4[3u]; + return ((_e191.xyz * _e194) * 8f); } fn MaterialLodBias_u0028_() -> f32 { - let _e189 = frag_info.target_origin[1u]; - return _e189; + let _e190 = frag_info.target_origin[1u]; + return _e190; } fn ApplyMetallicRoughnessMap_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b(s_6: ptr) { var orm: vec3; - let _e189 = v_texcoord_1; - let _e190 = MaterialLodBias_u0028_(); - let _e191 = textureSampleBias(metallic_roughness_texture_tex, metallic_roughness_texture_smp, _e189, _e190); - orm = _e191.xyz; - let _e194 = (*s_6).metallic; - let _e196 = orm[2u]; - (*s_6).metallic = clamp((_e194 * _e196), 0f, 1f); - let _e201 = (*s_6).roughness; - let _e203 = orm[1u]; - (*s_6).roughness = clamp((_e201 * _e203), 0.02f, 1f); + let _e190 = v_texcoord_1; + let _e191 = MaterialLodBias_u0028_(); + let _e192 = textureSampleBias(metallic_roughness_texture_tex, metallic_roughness_texture_smp, _e190, _e191); + orm = _e192.xyz; + let _e195 = (*s_6).metallic; + let _e197 = orm[2u]; + (*s_6).metallic = clamp((_e195 * _e197), 0f, 1f); + let _e202 = (*s_6).roughness; + let _e204 = orm[1u]; + (*s_6).roughness = clamp((_e202 * _e204), 0.02f, 1f); return; } @@ -12553,29 +12623,29 @@ fn ApplyEmissiveMap_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002 var emissive: vec3; var param_114: vec3; - let _e190 = v_texcoord_1; - let _e191 = MaterialLodBias_u0028_(); - let _e192 = textureSampleBias(emissive_texture_tex, emissive_texture_smp, _e190, _e191); - param_114 = _e192.xyz; - let _e194 = SrgbToLinear_u0028_vf3_u003b((¶m_114)); - emissive = _e194; - let _e195 = emissive; - let _e197 = frag_info.emissive; - let _e202 = frag_info.material2_[3u]; - (*s_7).emissive = ((_e195 * _e197.xyz) * _e202); + let _e191 = v_texcoord_1; + let _e192 = MaterialLodBias_u0028_(); + let _e193 = textureSampleBias(emissive_texture_tex, emissive_texture_smp, _e191, _e192); + param_114 = _e193.xyz; + let _e195 = SrgbToLinear_u0028_vf3_u003b((¶m_114)); + emissive = _e195; + let _e196 = emissive; + let _e198 = frag_info.emissive; + let _e203 = frag_info.material2_[3u]; + (*s_7).emissive = ((_e196 * _e198.xyz) * _e203); return; } fn ApplyOcclusionMap_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b(s_8: ptr) { var occlusion: f32; - let _e189 = v_texcoord_1; - let _e190 = MaterialLodBias_u0028_(); - let _e191 = textureSampleBias(occlusion_texture_tex, occlusion_texture_smp, _e189, _e190); - occlusion = _e191.x; - let _e193 = occlusion; - let _e196 = frag_info.material2_[2u]; - (*s_8).occlusion = mix(1f, _e193, clamp(_e196, 0f, 1f)); + let _e190 = v_texcoord_1; + let _e191 = MaterialLodBias_u0028_(); + let _e192 = textureSampleBias(occlusion_texture_tex, occlusion_texture_smp, _e190, _e191); + occlusion = _e192.x; + let _e194 = occlusion; + let _e197 = frag_info.material2_[2u]; + (*s_8).occlusion = mix(1f, _e194, clamp(_e197, 0f, 1f)); return; } @@ -12585,64 +12655,64 @@ fn ApplyNormalMap_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_ var b_3: vec3; var sampled: vec3; - let _e192 = v_texcoord_1; - let _e193 = MaterialLodBias_u0028_(); - let _e194 = textureSampleBias(normal_texture_tex, normal_texture_smp, _e192, _e193); - sampledTexel = _e194; - let _e195 = v_tangent_1; - t_2 = _e195.xyz; - let _e197 = t_2; - let _e199 = (*s_9).n; - let _e201 = (*s_9).n; - let _e202 = t_2; - t_2 = (_e197 - (_e199 * dot(_e201, _e202))); - let _e206 = t_2; + let _e193 = v_texcoord_1; + let _e194 = MaterialLodBias_u0028_(); + let _e195 = textureSampleBias(normal_texture_tex, normal_texture_smp, _e193, _e194); + sampledTexel = _e195; + let _e196 = v_tangent_1; + t_2 = _e196.xyz; + let _e198 = t_2; + let _e200 = (*s_9).n; + let _e202 = (*s_9).n; + let _e203 = t_2; + t_2 = (_e198 - (_e200 * dot(_e202, _e203))); let _e207 = t_2; - if (dot(_e206, _e207) < 0.000000000001f) { + let _e208 = t_2; + if (dot(_e207, _e208) < 0.000000000001f) { return; } - let _e210 = t_2; - t_2 = normalize(_e210); - let _e213 = (*s_9).n; - let _e214 = t_2; - let _e217 = v_tangent_1[3u]; - b_3 = (cross(_e213, _e214) * _e217); - let _e219 = gl_FrontFacing_1; - if !(_e219) { - let _e221 = t_2; - t_2 = -(_e221); + let _e211 = t_2; + t_2 = normalize(_e211); + let _e214 = (*s_9).n; + let _e215 = t_2; + let _e218 = v_tangent_1[3u]; + b_3 = (cross(_e214, _e215) * _e218); + let _e220 = gl_FrontFacing_1; + if !(_e220) { + let _e222 = t_2; + t_2 = -(_e222); } - let _e223 = sampledTexel; - sampled = ((_e223.xyz * 2f) - vec3(1f)); - let _e230 = frag_info.emissive[3u]; - if (_e230 > 0.5f) { - let _e232 = sampled; - let _e234 = sampled; - sampled[2u] = sqrt(max((1f - dot(_e232.xy, _e234.xy)), 0f)); + let _e224 = sampledTexel; + sampled = ((_e224.xyz * 2f) - vec3(1f)); + let _e231 = frag_info.emissive[3u]; + if (_e231 > 0.5f) { + let _e233 = sampled; + let _e235 = sampled; + sampled[2u] = sqrt(max((1f - dot(_e233.xy, _e235.xy)), 0f)); } - let _e243 = frag_info.material2_[1u]; - let _e244 = sampled; - let _e246 = (_e244.xy * _e243); - sampled[0u] = _e246.x; - sampled[1u] = _e246.y; - let _e251 = t_2; - let _e253 = sampled[0u]; - let _e255 = b_3; - let _e257 = sampled[1u]; - let _e261 = (*s_9).n; - let _e263 = sampled[2u]; - (*s_9).n = normalize((((_e251 * _e253) + (_e255 * _e257)) + (_e261 * _e263))); - let _e269 = (*s_9).n; - let _e271 = (*s_9).v; - (*s_9).n_dot_v = max(dot(_e269, _e271), 0.0001f); + let _e244 = frag_info.material2_[1u]; + let _e245 = sampled; + let _e247 = (_e245.xy * _e244); + sampled[0u] = _e247.x; + sampled[1u] = _e247.y; + let _e252 = t_2; + let _e254 = sampled[0u]; + let _e256 = b_3; + let _e258 = sampled[1u]; + let _e262 = (*s_9).n; + let _e264 = sampled[2u]; + (*s_9).n = normalize((((_e252 * _e254) + (_e256 * _e258)) + (_e262 * _e264))); + let _e270 = (*s_9).n; + let _e272 = (*s_9).v; + (*s_9).n_dot_v = max(dot(_e270, _e272), 0.0001f); return; } fn AtlasTexel_u0028_vf2_u003b(texel_5: ptr>) -> vec4 { - let _e188 = (*texel_5); - let _e192 = irradiance_info.atlas; - let _e195 = textureSampleLevel(irradiance_texture_tex, irradiance_texture_smp, ((_e188 + vec2(0.5f)) * _e192.xy), 0f); - return _e195; + let _e189 = (*texel_5); + let _e193 = irradiance_info.atlas; + let _e196 = textureSampleLevel(irradiance_texture_tex, irradiance_texture_smp, ((_e189 + vec2(0.5f)) * _e193.xy), 0f); + return _e196; } fn TileBilinear_u0028_vf2_u003b_f1_u003b_vf2_u003b(corner: ptr>, interior: ptr, uv_5: ptr>) -> vec4 { @@ -12658,42 +12728,42 @@ fn TileBilinear_u0028_vf2_u003b_f1_u003b_vf2_u003b(corner: ptr; var param_118: vec2; - let _e201 = (*uv_5); - let _e202 = (*interior); - at_1 = ((vec2(1f) + (_e201 * _e202)) - vec2(0.5f)); - let _e208 = at_1; - low = floor(_e208); - let _e210 = at_1; - let _e211 = low; - f = (_e210 - _e211); - let _e213 = (*corner); - let _e214 = low; - param_115 = (_e213 + _e214); - let _e216 = AtlasTexel_u0028_vf2_u003b((¶m_115)); - a_4 = _e216; - let _e217 = (*corner); - let _e218 = low; - param_116 = ((_e217 + _e218) + vec2(1f, 0f)); - let _e221 = AtlasTexel_u0028_vf2_u003b((¶m_116)); - b_4 = _e221; - let _e222 = (*corner); - let _e223 = low; - param_117 = ((_e222 + _e223) + vec2(0f, 1f)); - let _e226 = AtlasTexel_u0028_vf2_u003b((¶m_117)); - c_1 = _e226; - let _e227 = (*corner); - let _e228 = low; - param_118 = ((_e227 + _e228) + vec2(1f, 1f)); - let _e231 = AtlasTexel_u0028_vf2_u003b((¶m_118)); - d_4 = _e231; - let _e232 = a_4; - let _e233 = b_4; - let _e235 = f[0u]; - let _e238 = c_1; - let _e239 = d_4; - let _e241 = f[0u]; - let _e245 = f[1u]; - return mix(mix(_e232, _e233, vec4(_e235)), mix(_e238, _e239, vec4(_e241)), vec4(_e245)); + let _e202 = (*uv_5); + let _e203 = (*interior); + at_1 = ((vec2(1f) + (_e202 * _e203)) - vec2(0.5f)); + let _e209 = at_1; + low = floor(_e209); + let _e211 = at_1; + let _e212 = low; + f = (_e211 - _e212); + let _e214 = (*corner); + let _e215 = low; + param_115 = (_e214 + _e215); + let _e217 = AtlasTexel_u0028_vf2_u003b((¶m_115)); + a_4 = _e217; + let _e218 = (*corner); + let _e219 = low; + param_116 = ((_e218 + _e219) + vec2(1f, 0f)); + let _e222 = AtlasTexel_u0028_vf2_u003b((¶m_116)); + b_4 = _e222; + let _e223 = (*corner); + let _e224 = low; + param_117 = ((_e223 + _e224) + vec2(0f, 1f)); + let _e227 = AtlasTexel_u0028_vf2_u003b((¶m_117)); + c_1 = _e227; + let _e228 = (*corner); + let _e229 = low; + param_118 = ((_e228 + _e229) + vec2(1f, 1f)); + let _e232 = AtlasTexel_u0028_vf2_u003b((¶m_118)); + d_4 = _e232; + let _e233 = a_4; + let _e234 = b_4; + let _e236 = f[0u]; + let _e239 = c_1; + let _e240 = d_4; + let _e242 = f[0u]; + let _e246 = f[1u]; + return mix(mix(_e233, _e234, vec4(_e236)), mix(_e239, _e240, vec4(_e242)), vec4(_e246)); } fn ProbeOctahedral_u0028_vf3_u003b(direction_1: ptr>) -> vec2 { @@ -12701,29 +12771,29 @@ fn ProbeOctahedral_u0028_vf3_u003b(direction_1: ptr>) -> vec var n_5: vec3; var xy: vec2; - let _e192 = (*direction_1)[0u]; - let _e195 = (*direction_1)[1u]; - let _e199 = (*direction_1)[2u]; - sum_1 = ((abs(_e192) + abs(_e195)) + abs(_e199)); - let _e202 = sum_1; - if (_e202 <= 0f) { - return vec2(0.5f, 0.5f); - } - let _e204 = (*direction_1); - let _e205 = sum_1; - n_5 = (_e204 / vec3(_e205)); - let _e208 = n_5; - xy = _e208.xy; - let _e211 = n_5[2u]; - if (_e211 < 0f) { - let _e214 = n_5[1u]; - let _e218 = n_5[0u]; - let _e223 = n_5[0u]; - let _e227 = n_5[1u]; - xy = vec2(((1f - abs(_e214)) * select(-1f, 1f, (_e218 >= 0f))), ((1f - abs(_e223)) * select(-1f, 1f, (_e227 >= 0f)))); + let _e193 = (*direction_1)[0u]; + let _e196 = (*direction_1)[1u]; + let _e200 = (*direction_1)[2u]; + sum_1 = ((abs(_e193) + abs(_e196)) + abs(_e200)); + let _e203 = sum_1; + if (_e203 <= 0f) { + return vec2(0.5f, 0.5f); } - let _e232 = xy; - return ((_e232 * 0.5f) + vec2(0.5f)); + let _e205 = (*direction_1); + let _e206 = sum_1; + n_5 = (_e205 / vec3(_e206)); + let _e209 = n_5; + xy = _e209.xy; + let _e212 = n_5[2u]; + if (_e212 < 0f) { + let _e215 = n_5[1u]; + let _e219 = n_5[0u]; + let _e224 = n_5[0u]; + let _e228 = n_5[1u]; + xy = vec2(((1f - abs(_e215)) * select(-1f, 1f, (_e219 >= 0f))), ((1f - abs(_e224)) * select(-1f, 1f, (_e228 >= 0f)))); + } + let _e233 = xy; + return ((_e233 * 0.5f) + vec2(0.5f)); } fn SampleIrradiance_u0028_vf3_u003b_vf3_u003b_vf3_u003b(world_4: ptr>, normal_1: ptr>, view_1: ptr>) -> vec3 { @@ -12771,190 +12841,190 @@ fn SampleIrradiance_u0028_vf3_u003b_vf3_u003b_vf3_u003b(world_4: ptr; var local_27: vec3; - let _e234 = irradiance_info.origin; - origin_2 = _e234.xyz; - let _e237 = irradiance_info.spacing; - spacing = _e237.xyz; - let _e240 = irradiance_info.counts; - counts = _e240.xyz; - let _e244 = irradiance_info.tiles[0u]; - irradianceTile = _e244; - let _e247 = irradiance_info.tiles[1u]; - depthTile = _e247; - let _e250 = irradiance_info.tiles[2u]; - columns = _e250; - let _e253 = irradiance_info.tiles[3u]; - momentsTop = _e253; - let _e254 = (*normal_1); - unit = normalize(_e254); - let _e256 = (*world_4); - let _e257 = unit; - let _e260 = irradiance_info.spacing[3u]; - let _e263 = (*view_1); - let _e266 = irradiance_info.counts[3u]; - biased = ((_e256 + (_e257 * _e260)) + (_e263 * _e266)); - let _e269 = biased; - let _e270 = origin_2; - let _e272 = spacing; - grid_1 = ((_e269 - _e270) / _e272); - let _e274 = grid_1; - let _e276 = counts; - base = clamp(floor(_e274), vec3(0f, 0f, 0f), (_e276 - vec3(2f))); - let _e280 = grid_1; - let _e281 = base; - f_1 = clamp((_e280 - _e281), vec3(0f, 0f, 0f), vec3(1f, 1f, 1f)); + let _e235 = irradiance_info.origin; + origin_2 = _e235.xyz; + let _e238 = irradiance_info.spacing; + spacing = _e238.xyz; + let _e241 = irradiance_info.counts; + counts = _e241.xyz; + let _e245 = irradiance_info.tiles[0u]; + irradianceTile = _e245; + let _e248 = irradiance_info.tiles[1u]; + depthTile = _e248; + let _e251 = irradiance_info.tiles[2u]; + columns = _e251; + let _e254 = irradiance_info.tiles[3u]; + momentsTop = _e254; + let _e255 = (*normal_1); + unit = normalize(_e255); + let _e257 = (*world_4); + let _e258 = unit; + let _e261 = irradiance_info.spacing[3u]; + let _e264 = (*view_1); + let _e267 = irradiance_info.counts[3u]; + biased = ((_e257 + (_e258 * _e261)) + (_e264 * _e267)); + let _e270 = biased; + let _e271 = origin_2; + let _e273 = spacing; + grid_1 = ((_e270 - _e271) / _e273); + let _e275 = grid_1; + let _e277 = counts; + base = clamp(floor(_e275), vec3(0f, 0f, 0f), (_e277 - vec3(2f))); + let _e281 = grid_1; + let _e282 = base; + f_1 = clamp((_e281 - _e282), vec3(0f, 0f, 0f), vec3(1f, 1f, 1f)); total_2 = vec3(0f, 0f, 0f); weights = 0f; corner_1 = 0i; loop { - let _e284 = corner_1; - if (_e284 < 8i) { - let _e286 = corner_1; - let _e289 = corner_1; - let _e294 = corner_1; - offset_3 = vec3(f32((_e286 & 1i)), f32(((_e289 >> bitcast(1i)) & 1i)), f32(((_e294 >> bitcast(2i)) & 1i))); - let _e300 = base; - let _e301 = offset_3; - cell_1 = (_e300 + _e301); - let _e304 = cell_1[2u]; - let _e306 = counts[1u]; - let _e309 = cell_1[1u]; - let _e312 = counts[0u]; - let _e315 = cell_1[0u]; - probe = ((((_e304 * _e306) + _e309) * _e312) + _e315); - let _e317 = probe; - let _e318 = columns; - let _e323 = probe; - let _e324 = columns; - tile_4 = vec2((_e317 - (floor((_e317 / _e318)) * _e318)), floor((_e323 / _e324))); - let _e328 = tile_4; - let _e329 = irradianceTile; - irradianceCorner = (_e328 * (_e329 + 2f)); - let _e333 = tile_4[0u]; - let _e334 = depthTile; - let _e337 = momentsTop; - let _e339 = tile_4[1u]; - let _e340 = depthTile; - momentCorner = vec2((_e333 * (_e334 + 2f)), (_e337 + (_e339 * (_e340 + 2f)))); - let _e345 = irradianceCorner; - param_119 = (_e345 + vec2(1f)); - let _e348 = AtlasTexel_u0028_vf2_u003b((¶m_119)); - if (_e348.w < 0.5f) { + let _e285 = corner_1; + if (_e285 < 8i) { + let _e287 = corner_1; + let _e290 = corner_1; + let _e295 = corner_1; + offset_3 = vec3(f32((_e287 & 1i)), f32(((_e290 >> bitcast(1i)) & 1i)), f32(((_e295 >> bitcast(2i)) & 1i))); + let _e301 = base; + let _e302 = offset_3; + cell_1 = (_e301 + _e302); + let _e305 = cell_1[2u]; + let _e307 = counts[1u]; + let _e310 = cell_1[1u]; + let _e313 = counts[0u]; + let _e316 = cell_1[0u]; + probe = ((((_e305 * _e307) + _e310) * _e313) + _e316); + let _e318 = probe; + let _e319 = columns; + let _e324 = probe; + let _e325 = columns; + tile_4 = vec2((_e318 - (floor((_e318 / _e319)) * _e319)), floor((_e324 / _e325))); + let _e329 = tile_4; + let _e330 = irradianceTile; + irradianceCorner = (_e329 * (_e330 + 2f)); + let _e334 = tile_4[0u]; + let _e335 = depthTile; + let _e338 = momentsTop; + let _e340 = tile_4[1u]; + let _e341 = depthTile; + momentCorner = vec2((_e334 * (_e335 + 2f)), (_e338 + (_e340 * (_e341 + 2f)))); + let _e346 = irradianceCorner; + param_119 = (_e346 + vec2(1f)); + let _e349 = AtlasTexel_u0028_vf2_u003b((¶m_119)); + if (_e349.w < 0.5f) { continue; } - let _e351 = f_1; - let _e353 = f_1; - let _e354 = offset_3; - trilinear = mix((vec3(1f, 1f, 1f) - _e351), _e353, _e354); - let _e357 = trilinear[0u]; - let _e359 = trilinear[1u]; - let _e362 = trilinear[2u]; - weight_3 = max(((_e357 * _e359) * _e362), 0.001f); - let _e365 = origin_2; - let _e366 = spacing; - let _e367 = cell_1; - probePosition = (_e365 + (_e366 * _e367)); - let _e370 = probePosition; - let _e371 = biased; - toProbe = (_e370 - _e371); - let _e373 = toProbe; - distance_4 = length(_e373); - let _e375 = distance_4; - if (_e375 > 0.000001f) { - let _e377 = toProbe; - let _e378 = distance_4; - direction_2 = (_e377 / vec3(_e378)); - let _e381 = unit; - let _e382 = probePosition; - let _e383 = (*world_4); - facing = ((dot(_e381, normalize((_e382 - _e383))) * 0.5f) + 0.5f); - let _e389 = facing; + let _e352 = f_1; + let _e354 = f_1; + let _e355 = offset_3; + trilinear = mix((vec3(1f, 1f, 1f) - _e352), _e354, _e355); + let _e358 = trilinear[0u]; + let _e360 = trilinear[1u]; + let _e363 = trilinear[2u]; + weight_3 = max(((_e358 * _e360) * _e363), 0.001f); + let _e366 = origin_2; + let _e367 = spacing; + let _e368 = cell_1; + probePosition = (_e366 + (_e367 * _e368)); + let _e371 = probePosition; + let _e372 = biased; + toProbe = (_e371 - _e372); + let _e374 = toProbe; + distance_4 = length(_e374); + let _e376 = distance_4; + if (_e376 > 0.000001f) { + let _e378 = toProbe; + let _e379 = distance_4; + direction_2 = (_e378 / vec3(_e379)); + let _e382 = unit; + let _e383 = probePosition; + let _e384 = (*world_4); + facing = ((dot(_e382, normalize((_e383 - _e384))) * 0.5f) + 0.5f); let _e390 = facing; - probeWeight = ((_e389 * _e390) + 0.2f); - let _e393 = direction_2; - param_120 = -(_e393); - let _e395 = ProbeOctahedral_u0028_vf3_u003b((¶m_120)); - let _e396 = momentCorner; - param_121 = _e396; - let _e397 = depthTile; - param_122 = _e397; - param_123 = _e395; - let _e398 = TileBilinear_u0028_vf2_u003b_f1_u003b_vf2_u003b((¶m_121), (¶m_122), (¶m_123)); - moments_3 = _e398.xy; + let _e391 = facing; + probeWeight = ((_e390 * _e391) + 0.2f); + let _e394 = direction_2; + param_120 = -(_e394); + let _e396 = ProbeOctahedral_u0028_vf3_u003b((¶m_120)); + let _e397 = momentCorner; + param_121 = _e397; + let _e398 = depthTile; + param_122 = _e398; + param_123 = _e396; + let _e399 = TileBilinear_u0028_vf2_u003b_f1_u003b_vf2_u003b((¶m_121), (¶m_122), (¶m_123)); + moments_3 = _e399.xy; chebyshev = 1f; - let _e400 = distance_4; - let _e402 = moments_3[0u]; - if (_e400 > _e402) { - let _e405 = moments_3[1u]; - let _e407 = moments_3[0u]; - let _e409 = moments_3[0u]; - variance_1 = max((_e405 - (_e407 * _e409)), 0.000001f); - let _e413 = distance_4; - let _e415 = moments_3[0u]; - difference = (_e413 - _e415); - let _e417 = variance_1; + let _e401 = distance_4; + let _e403 = moments_3[0u]; + if (_e401 > _e403) { + let _e406 = moments_3[1u]; + let _e408 = moments_3[0u]; + let _e410 = moments_3[0u]; + variance_1 = max((_e406 - (_e408 * _e410)), 0.000001f); + let _e414 = distance_4; + let _e416 = moments_3[0u]; + difference = (_e414 - _e416); let _e418 = variance_1; - let _e419 = difference; + let _e419 = variance_1; let _e420 = difference; - chebyshev = (_e417 / (_e418 + (_e419 * _e420))); - let _e424 = chebyshev; + let _e421 = difference; + chebyshev = (_e418 / (_e419 + (_e420 * _e421))); let _e425 = chebyshev; - let _e427 = chebyshev; - chebyshev = ((_e424 * _e425) * _e427); + let _e426 = chebyshev; + let _e428 = chebyshev; + chebyshev = ((_e425 * _e426) * _e428); } - let _e429 = probeWeight; - let _e430 = chebyshev; - probeWeight = max((_e429 * max(_e430, 0.05f)), 0.000001f); - let _e434 = probeWeight; - if (_e434 < 0.2f) { - let _e436 = probeWeight; + let _e430 = probeWeight; + let _e431 = chebyshev; + probeWeight = max((_e430 * max(_e431, 0.05f)), 0.000001f); + let _e435 = probeWeight; + if (_e435 < 0.2f) { let _e437 = probeWeight; - let _e440 = probeWeight; - probeWeight = (_e440 * ((_e436 * _e437) * 25f)); + let _e438 = probeWeight; + let _e441 = probeWeight; + probeWeight = (_e441 * ((_e437 * _e438) * 25f)); } - let _e442 = probeWeight; - let _e443 = weight_3; - weight_3 = (_e443 * _e442); + let _e443 = probeWeight; + let _e444 = weight_3; + weight_3 = (_e444 * _e443); } - let _e445 = unit; - param_124 = _e445; - let _e446 = ProbeOctahedral_u0028_vf3_u003b((¶m_124)); - let _e447 = irradianceCorner; - param_125 = _e447; - let _e448 = irradianceTile; - param_126 = _e448; - param_127 = _e446; - let _e449 = TileBilinear_u0028_vf2_u003b_f1_u003b_vf2_u003b((¶m_125), (¶m_126), (¶m_127)); - let _e451 = weight_3; - let _e453 = total_2; - total_2 = (_e453 + (_e449.xyz * _e451)); - let _e455 = weight_3; - let _e456 = weights; - weights = (_e456 + _e455); + let _e446 = unit; + param_124 = _e446; + let _e447 = ProbeOctahedral_u0028_vf3_u003b((¶m_124)); + let _e448 = irradianceCorner; + param_125 = _e448; + let _e449 = irradianceTile; + param_126 = _e449; + param_127 = _e447; + let _e450 = TileBilinear_u0028_vf2_u003b_f1_u003b_vf2_u003b((¶m_125), (¶m_126), (¶m_127)); + let _e452 = weight_3; + let _e454 = total_2; + total_2 = (_e454 + (_e450.xyz * _e452)); + let _e456 = weight_3; + let _e457 = weights; + weights = (_e457 + _e456); continue; } else { break; } continuing { - let _e458 = corner_1; - corner_1 = (_e458 + 1i); + let _e459 = corner_1; + corner_1 = (_e459 + 1i); } } - let _e460 = weights; - if (_e460 > 0f) { - let _e462 = total_2; - let _e463 = weights; - local_27 = (_e462 / vec3(_e463)); + let _e461 = weights; + if (_e461 > 0f) { + let _e463 = total_2; + let _e464 = weights; + local_27 = (_e463 / vec3(_e464)); } else { local_27 = vec3(0f, 0f, 0f); } - let _e466 = local_27; - return _e466; + let _e467 = local_27; + return _e467; } fn IrradianceEnabled_u0028_() -> bool { - let _e189 = irradiance_info.origin[3u]; - return (_e189 > 0.5f); + let _e190 = irradiance_info.origin[3u]; + return (_e190 > 0.5f); } fn ApplyCommonMaps_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b(s_10: ptr) { @@ -12965,50 +13035,50 @@ fn ApplyCommonMaps_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d var param_132: Surface; var param_133: Surface; - let _e194 = IrradianceEnabled_u0028_(); - if _e194 { - let _e195 = v_world_position_1; - param_128 = _e195; - let _e197 = (*s_10).n; - param_129 = _e197; - let _e199 = (*s_10).v; - param_130 = _e199; - let _e200 = SampleIrradiance_u0028_vf3_u003b_vf3_u003b_vf3_u003b((¶m_128), (¶m_129), (¶m_130)); - let _e203 = frag_info.material[2u]; - (*s_10).ambient = (_e200 * _e203); + let _e195 = IrradianceEnabled_u0028_(); + if _e195 { + let _e196 = v_world_position_1; + param_128 = _e196; + let _e198 = (*s_10).n; + param_129 = _e198; + let _e200 = (*s_10).v; + param_130 = _e200; + let _e201 = SampleIrradiance_u0028_vf3_u003b_vf3_u003b_vf3_u003b((¶m_128), (¶m_129), (¶m_130)); + let _e204 = frag_info.material[2u]; + (*s_10).ambient = (_e201 * _e204); } - let _e206 = (*s_10); - param_131 = _e206; + let _e207 = (*s_10); + param_131 = _e207; ApplyNormalMap_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b((¶m_131)); - let _e207 = param_131; - (*s_10) = _e207; - let _e208 = (*s_10); - param_132 = _e208; + let _e208 = param_131; + (*s_10) = _e208; + let _e209 = (*s_10); + param_132 = _e209; ApplyOcclusionMap_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b((¶m_132)); - let _e209 = param_132; - (*s_10) = _e209; - let _e210 = (*s_10); - param_133 = _e210; + let _e210 = param_132; + (*s_10) = _e210; + let _e211 = (*s_10); + param_133 = _e211; ApplyEmissiveMap_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b((¶m_133)); - let _e211 = param_133; - (*s_10) = _e211; + let _e212 = param_133; + (*s_10) = _e212; return; } fn TowardsEye_u0028_() -> vec3 { var local_28: vec3; - let _e188 = Orthographic_u0028_(); - if _e188 { - let _e190 = fog_info.forward; - local_28 = -(_e190.xyz); + let _e189 = Orthographic_u0028_(); + if _e189 { + let _e191 = fog_info.forward; + local_28 = -(_e191.xyz); } else { - let _e194 = fog_info.eye; - let _e196 = v_world_position_1; - local_28 = normalize((_e194.xyz - _e196)); + let _e195 = fog_info.eye; + let _e197 = v_world_position_1; + local_28 = normalize((_e195.xyz - _e197)); } - let _e199 = local_28; - return _e199; + let _e200 = local_28; + return _e200; } fn ReadSurface_u0028_() -> Surface { @@ -13021,89 +13091,89 @@ fn ReadSurface_u0028_() -> Surface { var anchored: vec3; var noise_1: f32; - let _e195 = v_texcoord_1; - let _e196 = MaterialLodBias_u0028_(); - let _e197 = textureSampleBias(base_color_texture_tex, base_color_texture_smp, _e195, _e196); - texel_6 = _e197; - let _e198 = texel_6; - param_134 = _e198.xyz; - let _e200 = SrgbToLinear_u0028_vf3_u003b((¶m_134)); - let _e202 = frag_info.base_color; - param_135 = _e202.xyz; - let _e204 = SrgbToLinear_u0028_vf3_u003b((¶m_135)); - let _e206 = v_color_1; - s_11.albedo = ((_e200 * _e204) * _e206.xyz); - let _e211 = texel_6[3u]; - let _e214 = frag_info.base_color[3u]; - let _e217 = v_color_1[3u]; - s_11.alpha = ((_e211 * _e214) * _e217); - let _e221 = s_11.albedo; - g_albedo = _e221; - let _e224 = frag_info.material2_[0u]; - cutoff = _e224; - let _e225 = cutoff; - if (_e225 > 1f) { - let _e227 = cutoff; - edge = (_e227 - 1f); - let _e230 = s_11.alpha; - let _e231 = edge; - let _e234 = s_11.alpha; - let _e235 = fwidth(_e234); - s_11.alpha = clamp((((_e230 - _e231) / max(_e235, 0.0001f)) + 0.5f), 0f, 1f); + let _e196 = v_texcoord_1; + let _e197 = MaterialLodBias_u0028_(); + let _e198 = textureSampleBias(base_color_texture_tex, base_color_texture_smp, _e196, _e197); + texel_6 = _e198; + let _e199 = texel_6; + param_134 = _e199.xyz; + let _e201 = SrgbToLinear_u0028_vf3_u003b((¶m_134)); + let _e203 = frag_info.base_color; + param_135 = _e203.xyz; + let _e205 = SrgbToLinear_u0028_vf3_u003b((¶m_135)); + let _e207 = v_color_1; + s_11.albedo = ((_e201 * _e205) * _e207.xyz); + let _e212 = texel_6[3u]; + let _e215 = frag_info.base_color[3u]; + let _e218 = v_color_1[3u]; + s_11.alpha = ((_e212 * _e215) * _e218); + let _e222 = s_11.albedo; + g_albedo = _e222; + let _e225 = frag_info.material2_[0u]; + cutoff = _e225; + let _e226 = cutoff; + if (_e226 > 1f) { + let _e228 = cutoff; + edge = (_e228 - 1f); + let _e231 = s_11.alpha; + let _e232 = edge; + let _e235 = s_11.alpha; + let _e236 = fwidth(_e235); + s_11.alpha = clamp((((_e231 - _e232) / max(_e236, 0.0001f)) + 0.5f), 0f, 1f); } else { - let _e241 = cutoff; - if (_e241 >= 0f) { - let _e244 = s_11.alpha; - let _e245 = cutoff; - if (_e244 < _e245) { + let _e242 = cutoff; + if (_e242 >= 0f) { + let _e245 = s_11.alpha; + let _e246 = cutoff; + if (_e245 < _e246) { discard; } s_11.alpha = 1f; } else { - let _e248 = cutoff; - if (_e248 < -1.5f) { - let _e250 = v_world_position_1; - anchored = floor((_e250 * 16f)); - let _e253 = anchored; - noise_1 = fract((sin(dot(_e253, vec3(12.9898f, 78.233f, 37.719f))) * 43758.547f)); - let _e259 = s_11.alpha; - let _e260 = noise_1; - if (_e259 < _e260) { + let _e249 = cutoff; + if (_e249 < -1.5f) { + let _e251 = v_world_position_1; + anchored = floor((_e251 * 16f)); + let _e254 = anchored; + noise_1 = fract((sin(dot(_e254, vec3(12.9898f, 78.233f, 37.719f))) * 43758.547f)); + let _e260 = s_11.alpha; + let _e261 = noise_1; + if (_e260 < _e261) { discard; } } } } - let _e262 = cutoff; - let _e264 = cutoff; - g_premultiply = ((_e262 < 0f) && (_e264 > -0.75f)); - let _e267 = v_normal_1; - s_11.n = normalize(_e267); - let _e270 = gl_FrontFacing_1; - if !(_e270) { - let _e273 = s_11.n; - s_11.n = -(_e273); + let _e263 = cutoff; + let _e265 = cutoff; + g_premultiply = ((_e263 < 0f) && (_e265 > -0.75f)); + let _e268 = v_normal_1; + s_11.n = normalize(_e268); + let _e271 = gl_FrontFacing_1; + if !(_e271) { + let _e274 = s_11.n; + s_11.n = -(_e274); } - let _e276 = TowardsEye_u0028_(); - s_11.v = _e276; - let _e279 = s_11.n; - let _e281 = s_11.v; - s_11.n_dot_v = max(dot(_e279, _e281), 0.0001f); - let _e287 = frag_info.material[0u]; - s_11.metallic = clamp(_e287, 0f, 1f); - let _e292 = frag_info.material[1u]; - s_11.roughness = clamp(_e292, 0.02f, 1f); - let _e296 = frag_info.ambient_ground; - let _e299 = frag_info.ambient_sky; - let _e303 = s_11.n[1u]; - let _e310 = frag_info.material[2u]; - s_11.ambient = (mix(_e296.xyz, _e299.xyz, vec3(((_e303 * 0.5f) + 0.5f))) * _e310); - let _e315 = frag_info.frame_params[0u]; - s_11.exposure = max(_e315, 0f); + let _e277 = TowardsEye_u0028_(); + s_11.v = _e277; + let _e280 = s_11.n; + let _e282 = s_11.v; + s_11.n_dot_v = max(dot(_e280, _e282), 0.0001f); + let _e288 = frag_info.material[0u]; + s_11.metallic = clamp(_e288, 0f, 1f); + let _e293 = frag_info.material[1u]; + s_11.roughness = clamp(_e293, 0.02f, 1f); + let _e297 = frag_info.ambient_ground; + let _e300 = frag_info.ambient_sky; + let _e304 = s_11.n[1u]; + let _e311 = frag_info.material[2u]; + s_11.ambient = (mix(_e297.xyz, _e300.xyz, vec3(((_e304 * 0.5f) + 0.5f))) * _e311); + let _e316 = frag_info.frame_params[0u]; + s_11.exposure = max(_e316, 0f); s_11.occlusion = 1f; s_11.emissive = vec3(0f, 0f, 0f); - let _e320 = s_11; - return _e320; + let _e321 = s_11; + return _e321; } fn main_1() { @@ -13127,44 +13197,44 @@ fn main_1() { g_cluster_offset = 0f; g_cluster_count = 0f; light_transmittance = vec3(1f, 1f, 1f); - let _e198 = ReadSurface_u0028_(); - s_12 = _e198; - let _e199 = s_12; - param_136 = _e199; + let _e199 = ReadSurface_u0028_(); + s_12 = _e199; + let _e200 = s_12; + param_136 = _e200; ApplyCommonMaps_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b((¶m_136)); - let _e200 = param_136; - s_12 = _e200; - let _e201 = s_12; - param_137 = _e201; + let _e201 = param_136; + s_12 = _e201; + let _e202 = s_12; + param_137 = _e202; ApplyMetallicRoughnessMap_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b((¶m_137)); - let _e202 = param_137; - s_12 = _e202; - let _e204 = s_12.albedo; - let _e206 = s_12.ambient; - let _e207 = SampleLightmap_u0028_(); - let _e211 = s_12.occlusion; - ambient = ((_e204 * (_e206 + _e207)) * _e211); - let _e213 = s_12; - param_138 = _e213; - let _e214 = AccumulateLights_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b((¶m_138)); - let _e216 = s_12.occlusion; - let _e218 = ambient; - let _e221 = s_12.emissive; - lit_3 = (((_e214 * _e216) + _e218) + _e221); - let _e223 = s_12; - param_139 = _e223; - let _e224 = lit_3; - param_140 = _e224; - let _e225 = WriteDebugView_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_vf3_u003b((¶m_139), (¶m_140)); - if _e225 { + let _e203 = param_137; + s_12 = _e203; + let _e205 = s_12.albedo; + let _e207 = s_12.ambient; + let _e208 = SampleLightmap_u0028_(); + let _e212 = s_12.occlusion; + ambient = ((_e205 * (_e207 + _e208)) * _e212); + let _e214 = s_12; + param_138 = _e214; + let _e215 = AccumulateLights_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b((¶m_138)); + let _e217 = s_12.occlusion; + let _e219 = ambient; + let _e222 = s_12.emissive; + lit_3 = (((_e215 * _e217) + _e219) + _e222); + let _e224 = s_12; + param_139 = _e224; + let _e225 = lit_3; + param_140 = _e225; + let _e226 = WriteDebugView_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_vf3_u003b((¶m_139), (¶m_140)); + if _e226 { return; } - let _e226 = lit_3; - param_141 = _e226; - let _e228 = s_12.alpha; - param_142 = _e228; - let _e230 = s_12.roughness; - param_143 = _e230; + let _e227 = lit_3; + param_141 = _e227; + let _e229 = s_12.alpha; + param_142 = _e229; + let _e231 = s_12.roughness; + param_143 = _e231; WriteSurface_u0028_vf3_u003b_f1_u003b_f1_u003b((¶m_141), (¶m_142), (¶m_143)); return; } @@ -13680,10 +13750,10 @@ var environment_texture_tex: texture_cube; var environment_texture_smp: sampler; fn ViewDepth_u0028_() -> f32 { - let _e206 = v_world_position_1; - let _e208 = fog_info.eye; - let _e212 = fog_info.forward; - return dot((_e206 - _e208.xyz), _e212.xyz); + let _e207 = v_world_position_1; + let _e209 = fog_info.eye; + let _e213 = fog_info.forward; + return dot((_e207 - _e209.xyz), _e213.xyz); } fn WeightedBlendedWeight_u0028_f1_u003b(alpha: ptr) -> f32 { @@ -13692,22 +13762,22 @@ fn WeightedBlendedWeight_u0028_f1_u003b(alpha: ptr) -> f32 { var far: f32; var far3_: f32; - let _e211 = ViewDepth_u0028_(); - z = abs(_e211); - let _e213 = z; - near = (_e213 / 5f); - let _e215 = z; - far = (_e215 / 200f); - let _e217 = far; + let _e212 = ViewDepth_u0028_(); + z = abs(_e212); + let _e214 = z; + near = (_e214 / 5f); + let _e216 = z; + far = (_e216 / 200f); let _e218 = far; - let _e220 = far; - far3_ = ((_e217 * _e218) * _e220); - let _e222 = (*alpha); - let _e223 = near; + let _e219 = far; + let _e221 = far; + far3_ = ((_e218 * _e219) * _e221); + let _e223 = (*alpha); let _e224 = near; - let _e227 = far3_; + let _e225 = near; let _e228 = far3_; - return (_e222 * clamp((10f / ((0.00001f + (_e223 * _e224)) + (_e227 * _e228))), 0.01f, 3000f)); + let _e229 = far3_; + return (_e223 * clamp((10f / ((0.00001f + (_e224 * _e225)) + (_e228 * _e229))), 0.01f, 3000f)); } fn WriteWeightedBlended_u0028_() { @@ -13719,39 +13789,39 @@ fn WriteWeightedBlended_u0028_() { var revealage: bool; var local: vec4; - let _e215 = fog_info.forward[3u]; - mode = _e215; - let _e216 = mode; - if (_e216 > 0.5f) { - let _e219 = frag_color[3u]; - alpha_1 = _e219; - let _e220 = alpha_1; - param = _e220; - let _e221 = WeightedBlendedWeight_u0028_f1_u003b((¶m)); - weight = _e221; - let _e222 = frag_color; - let _e224 = weight; - let _e225 = (_e222.xyz * _e224); - let _e226 = alpha_1; - let _e227 = weight; - accumulate = vec4(_e225.x, _e225.y, _e225.z, (_e226 * _e227)); - let _e233 = mode; - let _e235 = mode; - revealage = ((_e233 > 1.5f) && (_e235 < 2.5f)); - let _e238 = revealage; - if _e238 { - let _e239 = alpha_1; - local = vec4(_e239); + let _e216 = fog_info.forward[3u]; + mode = _e216; + let _e217 = mode; + if (_e217 > 0.5f) { + let _e220 = frag_color[3u]; + alpha_1 = _e220; + let _e221 = alpha_1; + param = _e221; + let _e222 = WeightedBlendedWeight_u0028_f1_u003b((¶m)); + weight = _e222; + let _e223 = frag_color; + let _e225 = weight; + let _e226 = (_e223.xyz * _e225); + let _e227 = alpha_1; + let _e228 = weight; + accumulate = vec4(_e226.x, _e226.y, _e226.z, (_e227 * _e228)); + let _e234 = mode; + let _e236 = mode; + revealage = ((_e234 > 1.5f) && (_e236 < 2.5f)); + let _e239 = revealage; + if _e239 { + let _e240 = alpha_1; + local = vec4(_e240); } else { - let _e241 = accumulate; - local = _e241; + let _e242 = accumulate; + local = _e242; } - let _e242 = local; - frag_color = _e242; - let _e243 = mode; - if (_e243 > 2.5f) { - let _e245 = alpha_1; - frag_surface = vec4(_e245); + let _e243 = local; + frag_color = _e243; + let _e244 = mode; + if (_e244 > 2.5f) { + let _e246 = alpha_1; + frag_surface = vec4(_e246); } } return; @@ -13760,29 +13830,29 @@ fn WriteWeightedBlended_u0028_() { fn EncodeOctahedral_u0028_vf3_u003b(n: ptr>) -> vec2 { var e: vec2; - let _e209 = (*n)[0u]; - let _e212 = (*n)[1u]; - let _e216 = (*n)[2u]; - let _e219 = (*n); - (*n) = (_e219 / vec3(((abs(_e209) + abs(_e212)) + abs(_e216)))); - let _e222 = (*n); - e = _e222.xy; - let _e225 = (*n)[2u]; - if (_e225 < 0f) { - let _e227 = (*n); - let _e233 = (*n)[0u]; - let _e237 = (*n)[1u]; - e = ((vec2(1f) - abs(_e227.yx)) * vec2(select(-1f, 1f, (_e233 >= 0f)), select(-1f, 1f, (_e237 >= 0f)))); + let _e210 = (*n)[0u]; + let _e213 = (*n)[1u]; + let _e217 = (*n)[2u]; + let _e220 = (*n); + (*n) = (_e220 / vec3(((abs(_e210) + abs(_e213)) + abs(_e217)))); + let _e223 = (*n); + e = _e223.xy; + let _e226 = (*n)[2u]; + if (_e226 < 0f) { + let _e228 = (*n); + let _e234 = (*n)[0u]; + let _e238 = (*n)[1u]; + e = ((vec2(1f) - abs(_e228.yx)) * vec2(select(-1f, 1f, (_e234 >= 0f)), select(-1f, 1f, (_e238 >= 0f)))); } - let _e242 = e; - return ((_e242 * 0.5f) + vec2(0.5f)); + let _e243 = e; + return ((_e243 * 0.5f) + vec2(0.5f)); } fn LinearToSrgb_u0028_vf3_u003b(linear: ptr>) -> vec3 { - let _e207 = (*linear); - let _e209 = (*linear); - let _e213 = (*linear); - return mix((_e207 * 12.92f), ((pow(_e209, vec3(0.41666666f, 0.41666666f, 0.41666666f)) * 1.055f) - vec3(0.055f, 0.055f, 0.055f)), step(vec3(0.0031308f, 0.0031308f, 0.0031308f), _e213)); + let _e208 = (*linear); + let _e210 = (*linear); + let _e214 = (*linear); + return mix((_e208 * 12.92f), ((pow(_e210, vec3(0.41666666f, 0.41666666f, 0.41666666f)) * 1.055f) - vec3(0.055f, 0.055f, 0.055f)), step(vec3(0.0031308f, 0.0031308f, 0.0031308f), _e214)); } fn WriteSurfaceGeometry_u0028_f1_u003b(roughness: ptr) { @@ -13790,52 +13860,52 @@ fn WriteSurfaceGeometry_u0028_f1_u003b(roughness: ptr) { var geometric: vec3; var param_2: vec3; - let _e210 = g_albedo; - param_1 = clamp(_e210, vec3(0f, 0f, 0f), vec3(1f, 1f, 1f)); - let _e212 = LinearToSrgb_u0028_vf3_u003b((¶m_1)); - frag_albedo = vec4(_e212.x, _e212.y, _e212.z, 1f); - let _e217 = g_debug_surface_on; - if _e217 { - let _e218 = g_debug_surface; - let _e219 = ViewDepth_u0028_(); - frag_surface = vec4(_e218.x, _e218.y, _e218.z, _e219); + let _e211 = g_albedo; + param_1 = clamp(_e211, vec3(0f, 0f, 0f), vec3(1f, 1f, 1f)); + let _e213 = LinearToSrgb_u0028_vf3_u003b((¶m_1)); + frag_albedo = vec4(_e213.x, _e213.y, _e213.z, 1f); + let _e218 = g_debug_surface_on; + if _e218 { + let _e219 = g_debug_surface; + let _e220 = ViewDepth_u0028_(); + frag_surface = vec4(_e219.x, _e219.y, _e219.z, _e220); return; } - let _e224 = v_normal_1; - geometric = normalize(_e224); - let _e226 = gl_FrontFacing_1; - if !(_e226) { - let _e228 = geometric; - geometric = -(_e228); - } - let _e230 = geometric; - param_2 = _e230; - let _e231 = EncodeOctahedral_u0028_vf3_u003b((¶m_2)); - let _e232 = (*roughness); - let _e234 = ViewDepth_u0028_(); - frag_surface = vec4(_e231.x, _e231.y, clamp(_e232, 0f, 1f), _e234); + let _e225 = v_normal_1; + geometric = normalize(_e225); + let _e227 = gl_FrontFacing_1; + if !(_e227) { + let _e229 = geometric; + geometric = -(_e229); + } + let _e231 = geometric; + param_2 = _e231; + let _e232 = EncodeOctahedral_u0028_vf3_u003b((¶m_2)); + let _e233 = (*roughness); + let _e235 = ViewDepth_u0028_(); + frag_surface = vec4(_e232.x, _e232.y, clamp(_e233, 0f, 1f), _e235); return; } fn Orthographic_u0028_() -> bool { - let _e208 = fog_info.projection[0u]; - return (_e208 > 0.5f); + let _e209 = fog_info.projection[0u]; + return (_e209 > 0.5f); } fn EyeDistance_u0028_() -> f32 { var local_1: f32; - let _e207 = Orthographic_u0028_(); - if _e207 { - let _e208 = ViewDepth_u0028_(); - local_1 = max(_e208, 0f); + let _e208 = Orthographic_u0028_(); + if _e208 { + let _e209 = ViewDepth_u0028_(); + local_1 = max(_e209, 0f); } else { - let _e210 = v_world_position_1; - let _e212 = fog_info.eye; - local_1 = distance(_e210, _e212.xyz); + let _e211 = v_world_position_1; + let _e213 = fog_info.eye; + local_1 = distance(_e211, _e213.xyz); } - let _e215 = local_1; - return _e215; + let _e216 = local_1; + return _e216; } fn ApplyFog_u0028_vf3_u003b(color: ptr>) -> vec3 { @@ -13845,41 +13915,41 @@ fn ApplyFog_u0028_vf3_u003b(color: ptr>) -> vec3 { var k: f32; var local_2: f32; - let _e214 = fog_info.fog[3u]; - density = _e214; - let _e215 = density; - if (_e215 <= 0f) { - let _e217 = (*color); - return _e217; - } - let _e218 = EyeDistance_u0028_(); - d = _e218; - let _e221 = fog_info.eye[3u]; - falloff = _e221; - let _e222 = falloff; - if (_e222 > 0f) { - let _e224 = falloff; - let _e226 = v_world_position_1[1u]; - let _e229 = fog_info.eye[1u]; - k = (_e224 * (_e226 - _e229)); - let _e232 = k; - if (abs(_e232) > 0.001f) { - let _e235 = k; - let _e239 = k; - local_2 = ((1f - exp(-(_e235))) / _e239); + let _e215 = fog_info.fog[3u]; + density = _e215; + let _e216 = density; + if (_e216 <= 0f) { + let _e218 = (*color); + return _e218; + } + let _e219 = EyeDistance_u0028_(); + d = _e219; + let _e222 = fog_info.eye[3u]; + falloff = _e222; + let _e223 = falloff; + if (_e223 > 0f) { + let _e225 = falloff; + let _e227 = v_world_position_1[1u]; + let _e230 = fog_info.eye[1u]; + k = (_e225 * (_e227 - _e230)); + let _e233 = k; + if (abs(_e233) > 0.001f) { + let _e236 = k; + let _e240 = k; + local_2 = ((1f - exp(-(_e236))) / _e240); } else { - let _e241 = k; - local_2 = (1f - (0.5f * _e241)); + let _e242 = k; + local_2 = (1f - (0.5f * _e242)); } - let _e244 = local_2; - let _e245 = density; - density = (_e245 * _e244); + let _e245 = local_2; + let _e246 = density; + density = (_e246 * _e245); } - let _e248 = fog_info.fog; - let _e250 = (*color); - let _e251 = density; - let _e253 = d; - return mix(_e248.xyz, _e250, vec3(clamp(exp((-(_e251) * _e253)), 0f, 1f))); + let _e249 = fog_info.fog; + let _e251 = (*color); + let _e252 = density; + let _e254 = d; + return mix(_e249.xyz, _e251, vec3(clamp(exp((-(_e252) * _e254)), 0f, 1f))); } fn WriteSurface_u0028_vf3_u003b_f1_u003b_f1_u003b(linearColor: ptr>, alpha_2: ptr, roughness_1: ptr) { @@ -13887,44 +13957,44 @@ fn WriteSurface_u0028_vf3_u003b_f1_u003b_f1_u003b(linearColor: ptr; var param_4: f32; - let _e212 = g_premultiply; - let _e213 = (*alpha_2); - weight_1 = select(1f, _e213, _e212); - let _e215 = (*linearColor); - param_3 = _e215; - let _e216 = ApplyFog_u0028_vf3_u003b((¶m_3)); - let _e217 = weight_1; - let _e218 = (_e216 * _e217); - let _e219 = (*alpha_2); - let _e220 = g_pass_through; - frag_color = vec4(_e218.x, _e218.y, _e218.z, (_e219 * (1f - _e220))); - let _e227 = (*roughness_1); - param_4 = _e227; + let _e213 = g_premultiply; + let _e214 = (*alpha_2); + weight_1 = select(1f, _e214, _e213); + let _e216 = (*linearColor); + param_3 = _e216; + let _e217 = ApplyFog_u0028_vf3_u003b((¶m_3)); + let _e218 = weight_1; + let _e219 = (_e217 * _e218); + let _e220 = (*alpha_2); + let _e221 = g_pass_through; + frag_color = vec4(_e219.x, _e219.y, _e219.z, (_e220 * (1f - _e221))); + let _e228 = (*roughness_1); + param_4 = _e228; WriteSurfaceGeometry_u0028_f1_u003b((¶m_4)); WriteWeightedBlended_u0028_(); return; } fn SrgbToLinear_u0028_vf3_u003b(srgb: ptr>) -> vec3 { - let _e207 = (*srgb); - let _e210 = (*srgb); - let _e215 = (*srgb); - return mix((_e207 / vec3(12.92f)), pow(((_e210 + vec3(0.055f, 0.055f, 0.055f)) / vec3(1.055f)), vec3(2.4f, 2.4f, 2.4f)), step(vec3(0.04045f, 0.04045f, 0.04045f), _e215)); + let _e208 = (*srgb); + let _e211 = (*srgb); + let _e216 = (*srgb); + return mix((_e208 / vec3(12.92f)), pow(((_e211 + vec3(0.055f, 0.055f, 0.055f)) / vec3(1.055f)), vec3(2.4f, 2.4f, 2.4f)), step(vec3(0.04045f, 0.04045f, 0.04045f), _e216)); } fn NonFinite_u0028_vf3_u003b(c: ptr>) -> bool { var phi_2901_: bool; - let _e207 = (*c); let _e208 = (*c); - let _e210 = any((_e207 != _e208)); - phi_2901_ = _e210; - if !(_e210) { - let _e212 = (*c); - phi_2901_ = any((abs(_e212) > vec3(300000000000000000000000000000000000000f, 300000000000000000000000000000000000000f, 300000000000000000000000000000000000000f))); - } - let _e217 = phi_2901_; - return _e217; + let _e209 = (*c); + let _e211 = any((_e208 != _e209)); + phi_2901_ = _e211; + if !(_e211) { + let _e213 = (*c); + phi_2901_ = any((abs(_e213) > vec3(300000000000000000000000000000000000000f, 300000000000000000000000000000000000000f, 300000000000000000000000000000000000000f))); + } + let _e218 = phi_2901_; + return _e218; } fn WriteDebugView_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_vf3_u003b(s: ptr, lit: ptr>) -> bool { @@ -13942,78 +14012,78 @@ fn WriteDebugView_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_ var param_9: vec3; var param_10: f32; - let _e223 = frag_info.debug_view[0u]; - view = _e223; - let _e224 = view; - if (_e224 < 0.5f) { + let _e224 = frag_info.debug_view[0u]; + view = _e224; + let _e225 = view; + if (_e225 < 0.5f) { return false; } - let _e227 = gl_FragCoord_1[0u]; - let _e230 = frag_info.debug_view[1u]; - let _e233 = frag_info.debug_view[2u]; - if (_e227 < (_e230 * _e233)) { + let _e228 = gl_FragCoord_1[0u]; + let _e231 = frag_info.debug_view[1u]; + let _e234 = frag_info.debug_view[2u]; + if (_e228 < (_e231 * _e234)) { return false; } - let _e236 = view; - code = i32((_e236 + 0.5f)); + let _e237 = view; + code = i32((_e237 + 0.5f)); shown = vec3(0f, 0f, 0f); - let _e239 = code; - if (_e239 == 1i) { - let _e242 = (*s).albedo; - param_5 = clamp(_e242, vec3(0f, 0f, 0f), vec3(1f, 1f, 1f)); - let _e244 = LinearToSrgb_u0028_vf3_u003b((¶m_5)); - shown = _e244; - } else { - let _e245 = code; - if (_e245 == 2i) { - let _e248 = (*s).n; - shown = ((_e248 * 0.5f) + vec3(0.5f, 0.5f, 0.5f)); + let _e240 = code; + if (_e240 == 1i) { + let _e243 = (*s).albedo; + param_5 = clamp(_e243, vec3(0f, 0f, 0f), vec3(1f, 1f, 1f)); + let _e245 = LinearToSrgb_u0028_vf3_u003b((¶m_5)); + shown = _e245; + } else { + let _e246 = code; + if (_e246 == 2i) { + let _e249 = (*s).n; + shown = ((_e249 * 0.5f) + vec3(0.5f, 0.5f, 0.5f)); } else { - let _e251 = code; - if (_e251 == 3i) { - let _e254 = (*s).roughness; - shown = vec3(clamp(_e254, 0f, 1f)); + let _e252 = code; + if (_e252 == 3i) { + let _e255 = (*s).roughness; + shown = vec3(clamp(_e255, 0f, 1f)); } else { - let _e257 = code; - if (_e257 == 4i) { - let _e260 = (*s).metallic; - shown = vec3(clamp(_e260, 0f, 1f)); + let _e258 = code; + if (_e258 == 4i) { + let _e261 = (*s).metallic; + shown = vec3(clamp(_e261, 0f, 1f)); } else { - let _e263 = code; - if (_e263 == 5i) { - let _e266 = (*s).occlusion; - shown = vec3(clamp(_e266, 0f, 1f)); + let _e264 = code; + if (_e264 == 5i) { + let _e267 = (*s).occlusion; + shown = vec3(clamp(_e267, 0f, 1f)); } else { - let _e269 = code; - if (_e269 == 6i) { - let _e272 = (*s).emissive; - param_6 = clamp(_e272, vec3(0f, 0f, 0f), vec3(1f, 1f, 1f)); - let _e274 = LinearToSrgb_u0028_vf3_u003b((¶m_6)); - shown = _e274; + let _e270 = code; + if (_e270 == 6i) { + let _e273 = (*s).emissive; + param_6 = clamp(_e273, vec3(0f, 0f, 0f), vec3(1f, 1f, 1f)); + let _e275 = LinearToSrgb_u0028_vf3_u003b((¶m_6)); + shown = _e275; } else { - let _e275 = code; - if (_e275 == 7i) { - let _e277 = v_texcoord_1; - let _e278 = fract(_e277); - shown = vec3(_e278.x, _e278.y, 0f); + let _e276 = code; + if (_e276 == 7i) { + let _e278 = v_texcoord_1; + let _e279 = fract(_e278); + shown = vec3(_e279.x, _e279.y, 0f); } else { - let _e282 = code; - if (_e282 == 8i) { - let _e284 = (*lit); - param_7 = clamp(_e284, vec3(0f, 0f, 0f), vec3(1f, 1f, 1f)); - let _e286 = LinearToSrgb_u0028_vf3_u003b((¶m_7)); - grey = dot(_e286, vec3(0.2126f, 0.7152f, 0.0722f)); - let _e288 = (*lit); - param_8 = _e288; - let _e289 = NonFinite_u0028_vf3_u003b((¶m_8)); - if _e289 { + let _e283 = code; + if (_e283 == 8i) { + let _e285 = (*lit); + param_7 = clamp(_e285, vec3(0f, 0f, 0f), vec3(1f, 1f, 1f)); + let _e287 = LinearToSrgb_u0028_vf3_u003b((¶m_7)); + grey = dot(_e287, vec3(0.2126f, 0.7152f, 0.0722f)); + let _e289 = (*lit); + param_8 = _e289; + let _e290 = NonFinite_u0028_vf3_u003b((¶m_8)); + if _e290 { local_3 = vec3(1f, 0f, 1f); } else { - let _e290 = grey; - local_3 = vec3((_e290 * 0.5f)); + let _e291 = grey; + local_3 = vec3((_e291 * 0.5f)); } - let _e293 = local_3; - shown = _e293; + let _e294 = local_3; + shown = _e294; } } } @@ -14022,24 +14092,24 @@ fn WriteDebugView_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_ } } } - let _e294 = g_premultiply; - if _e294 { - let _e296 = (*s).alpha; - local_4 = _e296; + let _e295 = g_premultiply; + if _e295 { + let _e297 = (*s).alpha; + local_4 = _e297; } else { local_4 = 1f; } - let _e297 = local_4; - weight_2 = _e297; - let _e298 = shown; - param_9 = _e298; - let _e299 = SrgbToLinear_u0028_vf3_u003b((¶m_9)); - let _e300 = weight_2; - let _e301 = (_e299 * _e300); - let _e303 = (*s).alpha; - frag_color = vec4(_e301.x, _e301.y, _e301.z, _e303); - let _e309 = (*s).roughness; - param_10 = _e309; + let _e298 = local_4; + weight_2 = _e298; + let _e299 = shown; + param_9 = _e299; + let _e300 = SrgbToLinear_u0028_vf3_u003b((¶m_9)); + let _e301 = weight_2; + let _e302 = (_e300 * _e301); + let _e304 = (*s).alpha; + frag_color = vec4(_e302.x, _e302.y, _e302.z, _e304); + let _e310 = (*s).roughness; + param_10 = _e310; WriteSurfaceGeometry_u0028_f1_u003b((¶m_10)); WriteWeightedBlended_u0028_(); return true; @@ -14049,32 +14119,32 @@ fn FonAlbedo_u0028_f1_u003b_f1_u003b(mu: ptr, r: ptr>, average: ptr) -> vec3 { - let _e208 = (*rho); let _e209 = (*rho); - let _e211 = (*average); - let _e213 = (*rho); - let _e214 = (*average); - return (((_e208 * _e209) * _e211) / (vec3(1f, 1f, 1f) - (_e213 * (1f - _e214)))); + let _e210 = (*rho); + let _e212 = (*average); + let _e214 = (*rho); + let _e215 = (*average); + return (((_e209 * _e210) * _e212) / (vec3(1f, 1f, 1f) - (_e214 * (1f - _e215)))); } fn FonAverage_u0028_f1_u003b(r_1: ptr) -> f32 { - let _e207 = (*r_1); - let _e210 = (*r_1); - return ((1f + (0.07248821f * _e207)) / (1f + (0.2877934f * _e210))); + let _e208 = (*r_1); + let _e211 = (*r_1); + return ((1f + (0.07248821f * _e208)) / (1f + (0.2877934f * _e211))); } fn EonLobe_u0028_vf3_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b(rho_1: ptr>, r_2: ptr, mu_i: ptr, mu_o: ptr, l_dot_v: ptr) -> vec3 { @@ -14093,70 +14163,70 @@ fn EonLobe_u0028_vf3_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b(rho_1: ptr 0f) { - let _e232 = s_1; - let _e233 = (*mu_i); - let _e234 = (*mu_o); - local_5 = (_e232 / max(_e233, _e234)); - } else { - let _e237 = s_1; - local_5 = _e237; - } - let _e238 = local_5; - s_over_t = _e238; - let _e239 = (*r_2); - af = (1f / (1f + (0.2877934f * _e239))); - let _e243 = (*rho_1); - let _e244 = af; - let _e245 = (*r_2); - let _e246 = s_over_t; - single = (_e243 * (_e244 * (1f + (_e245 * _e246)))); - let _e251 = (*r_2); - param_11 = _e251; - let _e252 = FonAverage_u0028_f1_u003b((¶m_11)); - average_1 = _e252; - let _e253 = (*rho_1); - param_12 = _e253; - let _e254 = average_1; - param_13 = _e254; - let _e255 = EonMultiAlbedo_u0028_vf3_u003b_f1_u003b((¶m_12), (¶m_13)); - let _e256 = (*mu_o); - param_14 = _e256; - let _e257 = (*r_2); - param_15 = _e257; - let _e258 = FonAlbedo_u0028_f1_u003b_f1_u003b((¶m_14), (¶m_15)); - let _e261 = (*mu_i); - param_16 = _e261; - let _e262 = (*r_2); - param_17 = _e262; - let _e263 = FonAlbedo_u0028_f1_u003b_f1_u003b((¶m_16), (¶m_17)); - let _e267 = average_1; - multi = (_e255 * ((max((1f - _e258), 0.0000001f) * max((1f - _e263), 0.0000001f)) / max((1f - _e267), 0.0000001f))); - let _e272 = single; - let _e273 = multi; - return ((_e272 + _e273) / vec3(3.1415927f)); + let _e226 = (*l_dot_v); + let _e227 = (*mu_i); + let _e228 = (*mu_o); + s_1 = (_e226 - (_e227 * _e228)); + let _e231 = s_1; + if (_e231 > 0f) { + let _e233 = s_1; + let _e234 = (*mu_i); + let _e235 = (*mu_o); + local_5 = (_e233 / max(_e234, _e235)); + } else { + let _e238 = s_1; + local_5 = _e238; + } + let _e239 = local_5; + s_over_t = _e239; + let _e240 = (*r_2); + af = (1f / (1f + (0.2877934f * _e240))); + let _e244 = (*rho_1); + let _e245 = af; + let _e246 = (*r_2); + let _e247 = s_over_t; + single = (_e244 * (_e245 * (1f + (_e246 * _e247)))); + let _e252 = (*r_2); + param_11 = _e252; + let _e253 = FonAverage_u0028_f1_u003b((¶m_11)); + average_1 = _e253; + let _e254 = (*rho_1); + param_12 = _e254; + let _e255 = average_1; + param_13 = _e255; + let _e256 = EonMultiAlbedo_u0028_vf3_u003b_f1_u003b((¶m_12), (¶m_13)); + let _e257 = (*mu_o); + param_14 = _e257; + let _e258 = (*r_2); + param_15 = _e258; + let _e259 = FonAlbedo_u0028_f1_u003b_f1_u003b((¶m_14), (¶m_15)); + let _e262 = (*mu_i); + param_16 = _e262; + let _e263 = (*r_2); + param_17 = _e263; + let _e264 = FonAlbedo_u0028_f1_u003b_f1_u003b((¶m_16), (¶m_17)); + let _e268 = average_1; + multi = (_e256 * ((max((1f - _e259), 0.0000001f) * max((1f - _e264), 0.0000001f)) / max((1f - _e268), 0.0000001f))); + let _e273 = single; + let _e274 = multi; + return ((_e273 + _e274) / vec3(3.1415927f)); } fn EonDiffuse_u0028_() -> bool { - let _e208 = frag_info.ambient_sky[3u]; - return (_e208 > 0.5f); + let _e209 = frag_info.ambient_sky[3u]; + return (_e209 > 0.5f); } fn LtcUv_u0028_f1_u003b_f1_u003b_f1_u003b(x: ptr, y: ptr, table: ptr) -> vec2 { var inTable: vec2; - let _e210 = (*x); - let _e211 = (*y); - inTable = ((vec2(_e210, _e211) * 0.984375f) + vec2(0.0078125f)); - let _e217 = inTable[0u]; - let _e219 = inTable[1u]; - let _e220 = (*table); - return vec2(_e217, ((_e219 + _e220) * 0.5f)); + let _e211 = (*x); + let _e212 = (*y); + inTable = ((vec2(_e211, _e212) * 0.984375f) + vec2(0.0078125f)); + let _e218 = inTable[0u]; + let _e220 = inTable[1u]; + let _e221 = (*table); + return vec2(_e218, ((_e220 + _e221) * 0.5f)); } fn EnvBrdf_u0028_f1_u003b_f1_u003b(roughness_2: ptr, n_dot_v: ptr) -> vec2 { @@ -14165,18 +14235,18 @@ fn EnvBrdf_u0028_f1_u003b_f1_u003b(roughness_2: ptr, n_dot_v: ptr var param_19: f32; var param_20: f32; - let _e212 = (*roughness_2); - let _e214 = (*n_dot_v); - param_18 = clamp(_e212, 0f, 1f); - param_19 = sqrt(clamp((1f - _e214), 0f, 1f)); + let _e213 = (*roughness_2); + let _e215 = (*n_dot_v); + param_18 = clamp(_e213, 0f, 1f); + param_19 = sqrt(clamp((1f - _e215), 0f, 1f)); param_20 = 1f; - let _e218 = LtcUv_u0028_f1_u003b_f1_u003b_f1_u003b((¶m_18), (¶m_19), (¶m_20)); - let _e219 = textureSampleLevel(ltc_texture_tex, ltc_texture_smp, _e218, 0f); - dfg = _e219.xy; - let _e222 = dfg[0u]; - let _e224 = dfg[1u]; - let _e227 = dfg[1u]; - return vec2((_e222 - _e224), _e227); + let _e219 = LtcUv_u0028_f1_u003b_f1_u003b_f1_u003b((¶m_18), (¶m_19), (¶m_20)); + let _e220 = textureSampleLevel(ltc_texture_tex, ltc_texture_smp, _e219, 0f); + dfg = _e220.xy; + let _e223 = dfg[0u]; + let _e225 = dfg[1u]; + let _e228 = dfg[1u]; + return vec2((_e223 - _e225), _e228); } fn MultiscatterScale_u0028_vf3_u003b_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b(f0_: ptr>, s_2: ptr) -> vec3 { @@ -14185,34 +14255,34 @@ fn MultiscatterScale_u0028_vf3_u003b_struct_u002d_Surface_u002d_vf3_u002d_f1_u00 var param_22: f32; var ess: f32; - let _e213 = (*s_2).roughness; - param_21 = max(_e213, 0.045f); - let _e216 = (*s_2).n_dot_v; - param_22 = _e216; - let _e217 = EnvBrdf_u0028_f1_u003b_f1_u003b((¶m_21), (¶m_22)); - ab = _e217; - let _e219 = ab[0u]; - let _e221 = ab[1u]; - ess = max((_e219 + _e221), 0.0001f); - let _e224 = (*f0_); - let _e225 = ess; - return (vec3(1f, 1f, 1f) + (_e224 * ((1f / _e225) - 1f))); + let _e214 = (*s_2).roughness; + param_21 = max(_e214, 0.045f); + let _e217 = (*s_2).n_dot_v; + param_22 = _e217; + let _e218 = EnvBrdf_u0028_f1_u003b_f1_u003b((¶m_21), (¶m_22)); + ab = _e218; + let _e220 = ab[0u]; + let _e222 = ab[1u]; + ess = max((_e220 + _e222), 0.0001f); + let _e225 = (*f0_); + let _e226 = ess; + return (vec3(1f, 1f, 1f) + (_e225 * ((1f / _e226) - 1f))); } fn EnergyCompensation_u0028_() -> bool { - let _e208 = frag_info.target_origin[2u]; - return (_e208 > 0.5f); + let _e209 = frag_info.target_origin[2u]; + return (_e209 > 0.5f); } fn F_Schlick_u0028_vf3_u003b_f1_u003b(f0_1: ptr>, v_dot_h: ptr) -> vec3 { var f: f32; - let _e209 = (*v_dot_h); - f = pow((1f - _e209), 5f); - let _e212 = (*f0_1); + let _e210 = (*v_dot_h); + f = pow((1f - _e210), 5f); let _e213 = (*f0_1); - let _e215 = f; - return (_e212 + ((vec3(1f, 1f, 1f) - _e213) * _e215)); + let _e214 = (*f0_1); + let _e216 = f; + return (_e213 + ((vec3(1f, 1f, 1f) - _e214) * _e216)); } fn V_SmithGGXCorrelated_u0028_f1_u003b_f1_u003b_f1_u003b(n_dot_v_1: ptr, n_dot_l: ptr, alpha_3: ptr) -> f32 { @@ -14220,42 +14290,42 @@ fn V_SmithGGXCorrelated_u0028_f1_u003b_f1_u003b_f1_u003b(n_dot_v_1: ptr, alpha_4: ptr) -> f32 { var a: f32; var k_1: f32; - let _e210 = (*n_dot_h); - let _e211 = (*alpha_4); - a = (_e210 * _e211); - let _e213 = (*alpha_4); - let _e214 = (*n_dot_h); + let _e211 = (*n_dot_h); + let _e212 = (*alpha_4); + a = (_e211 * _e212); + let _e214 = (*alpha_4); let _e215 = (*n_dot_h); - let _e218 = a; + let _e216 = (*n_dot_h); let _e219 = a; - k_1 = (_e213 / max(((1f - (_e214 * _e215)) + (_e218 * _e219)), 0.0000001f)); - let _e224 = k_1; + let _e220 = a; + k_1 = (_e214 / max(((1f - (_e215 * _e216)) + (_e219 * _e220)), 0.0000001f)); let _e225 = k_1; - return ((_e224 * _e225) * 0.31830987f); + let _e226 = k_1; + return ((_e225 * _e226) * 0.31830987f); } fn ShadeLight_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_struct_u002d_LightSample_u002d_vf3_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf31_u003b(s_3: ptr, light: ptr) -> vec3 { @@ -14283,116 +14353,116 @@ fn ShadeLight_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_ var param_35: f32; var param_36: f32; - let _e232 = (*s_3).roughness; - lobe = max(_e232, 0.045f); - let _e234 = lobe; + let _e233 = (*s_3).roughness; + lobe = max(_e233, 0.045f); let _e235 = lobe; - alpha_5 = (_e234 * _e235); - let _e238 = (*s_3).albedo; - let _e240 = (*s_3).metallic; - f0_2 = mix(vec3(0.04f, 0.04f, 0.04f), _e238, vec3(_e240)); - let _e244 = (*s_3).albedo; - let _e246 = (*s_3).metallic; - diffuseColor = (_e244 * (1f - _e246)); - let _e250 = (*light).n_dot_h; - param_23 = _e250; - let _e251 = alpha_5; - param_24 = _e251; - let _e252 = D_GGX_u0028_f1_u003b_f1_u003b((¶m_23), (¶m_24)); - d_1 = _e252; - let _e254 = (*s_3).n_dot_v; - param_25 = _e254; - let _e256 = (*light).n_dot_l; - param_26 = _e256; - let _e257 = alpha_5; - param_27 = _e257; - let _e258 = V_SmithGGXCorrelated_u0028_f1_u003b_f1_u003b_f1_u003b((¶m_25), (¶m_26), (¶m_27)); - vis = _e258; - let _e259 = f0_2; - param_28 = _e259; - let _e261 = (*light).v_dot_h; - param_29 = _e261; - let _e262 = F_Schlick_u0028_vf3_u003b_f1_u003b((¶m_28), (¶m_29)); - f_1 = _e262; - let _e263 = d_1; - let _e264 = vis; - let _e266 = f_1; - let _e270 = frag_info.material[3u]; - specular = ((_e266 * (_e263 * _e264)) * _e270); - let _e273 = (*light).integrated; - if (_e273 > 0.5f) { - let _e277 = (*light).ltc[0u]; - let _e278 = f0_2; - let _e281 = (*light).ltc[1u]; - let _e283 = f0_2; - let _e288 = (*light).ltc[2u]; - let _e294 = frag_info.material[3u]; - let _e297 = (*light).n_dot_l; - specular = (((((_e278 * _e281) + ((vec3(1f) - _e283) * _e288)) * _e277) * _e294) / vec3(max(_e297, 0.000001f))); - } - let _e301 = EnergyCompensation_u0028_(); - if _e301 { - let _e302 = f0_2; - param_30 = _e302; - let _e303 = (*s_3); - param_31 = _e303; - let _e304 = MultiscatterScale_u0028_vf3_u003b_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b((¶m_30), (¶m_31)); - let _e305 = specular; - specular = (_e305 * _e304); - } - let _e307 = diffuseColor; - let _e308 = f_1; - diffuse = ((_e307 * (vec3(1f, 1f, 1f) - _e308)) / vec3(3.1415927f)); - let _e313 = EonDiffuse_u0028_(); - if _e313 { - let _e315 = (*s_3).n; - let _e317 = (*light).l; - let _e321 = (*light).l; - let _e323 = (*s_3).v; - let _e325 = diffuseColor; - param_32 = _e325; - let _e327 = (*s_3).roughness; - param_33 = _e327; - param_34 = clamp(dot(_e315, _e317), 0.0001f, 1f); - let _e329 = (*s_3).n_dot_v; - param_35 = _e329; - param_36 = dot(_e321, _e323); - let _e330 = EonLobe_u0028_vf3_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b((¶m_32), (¶m_33), (¶m_34), (¶m_35), (¶m_36)); - let _e331 = f_1; - diffuse = (_e330 * (vec3(1f, 1f, 1f) - _e331)); - } - let _e334 = diffuse; - let _e335 = specular; - return ((_e334 + _e335) * 3.1415927f); + let _e236 = lobe; + alpha_5 = (_e235 * _e236); + let _e239 = (*s_3).albedo; + let _e241 = (*s_3).metallic; + f0_2 = mix(vec3(0.04f, 0.04f, 0.04f), _e239, vec3(_e241)); + let _e245 = (*s_3).albedo; + let _e247 = (*s_3).metallic; + diffuseColor = (_e245 * (1f - _e247)); + let _e251 = (*light).n_dot_h; + param_23 = _e251; + let _e252 = alpha_5; + param_24 = _e252; + let _e253 = D_GGX_u0028_f1_u003b_f1_u003b((¶m_23), (¶m_24)); + d_1 = _e253; + let _e255 = (*s_3).n_dot_v; + param_25 = _e255; + let _e257 = (*light).n_dot_l; + param_26 = _e257; + let _e258 = alpha_5; + param_27 = _e258; + let _e259 = V_SmithGGXCorrelated_u0028_f1_u003b_f1_u003b_f1_u003b((¶m_25), (¶m_26), (¶m_27)); + vis = _e259; + let _e260 = f0_2; + param_28 = _e260; + let _e262 = (*light).v_dot_h; + param_29 = _e262; + let _e263 = F_Schlick_u0028_vf3_u003b_f1_u003b((¶m_28), (¶m_29)); + f_1 = _e263; + let _e264 = d_1; + let _e265 = vis; + let _e267 = f_1; + let _e271 = frag_info.material[3u]; + specular = ((_e267 * (_e264 * _e265)) * _e271); + let _e274 = (*light).integrated; + if (_e274 > 0.5f) { + let _e278 = (*light).ltc[0u]; + let _e279 = f0_2; + let _e282 = (*light).ltc[1u]; + let _e284 = f0_2; + let _e289 = (*light).ltc[2u]; + let _e295 = frag_info.material[3u]; + let _e298 = (*light).n_dot_l; + specular = (((((_e279 * _e282) + ((vec3(1f) - _e284) * _e289)) * _e278) * _e295) / vec3(max(_e298, 0.000001f))); + } + let _e302 = EnergyCompensation_u0028_(); + if _e302 { + let _e303 = f0_2; + param_30 = _e303; + let _e304 = (*s_3); + param_31 = _e304; + let _e305 = MultiscatterScale_u0028_vf3_u003b_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b((¶m_30), (¶m_31)); + let _e306 = specular; + specular = (_e306 * _e305); + } + let _e308 = diffuseColor; + let _e309 = f_1; + diffuse = ((_e308 * (vec3(1f, 1f, 1f) - _e309)) / vec3(3.1415927f)); + let _e314 = EonDiffuse_u0028_(); + if _e314 { + let _e316 = (*s_3).n; + let _e318 = (*light).l; + let _e322 = (*light).l; + let _e324 = (*s_3).v; + let _e326 = diffuseColor; + param_32 = _e326; + let _e328 = (*s_3).roughness; + param_33 = _e328; + param_34 = clamp(dot(_e316, _e318), 0.0001f, 1f); + let _e330 = (*s_3).n_dot_v; + param_35 = _e330; + param_36 = dot(_e322, _e324); + let _e331 = EonLobe_u0028_vf3_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b((¶m_32), (¶m_33), (¶m_34), (¶m_35), (¶m_36)); + let _e332 = f_1; + diffuse = (_e331 * (vec3(1f, 1f, 1f) - _e332)); + } + let _e335 = diffuse; + let _e336 = specular; + return ((_e335 + _e336) * 3.1415927f); } fn PointShadowDiskTap_u0028_i1_u003b(i: ptr) -> vec2 { - let _e207 = (*i); - if (_e207 == 0i) { + let _e208 = (*i); + if (_e208 == 0i) { return vec2(-0.94201624f, -0.39906216f); } - let _e209 = (*i); - if (_e209 == 1i) { + let _e210 = (*i); + if (_e210 == 1i) { return vec2(0.9455861f, -0.76890725f); } - let _e211 = (*i); - if (_e211 == 2i) { + let _e212 = (*i); + if (_e212 == 2i) { return vec2(-0.0941841f, -0.9293887f); } - let _e213 = (*i); - if (_e213 == 3i) { + let _e214 = (*i); + if (_e214 == 3i) { return vec2(0.34495938f, 0.2938776f); } - let _e215 = (*i); - if (_e215 == 4i) { + let _e216 = (*i); + if (_e216 == 4i) { return vec2(-0.9158858f, 0.45771432f); } - let _e217 = (*i); - if (_e217 == 5i) { + let _e218 = (*i); + if (_e218 == 5i) { return vec2(-0.8154423f, -0.87912464f); } - let _e219 = (*i); - if (_e219 == 6i) { + let _e220 = (*i); + if (_e220 == 6i) { return vec2(-0.38277543f, 0.27676845f); } return vec2(0.974844f, 0.7564838f); @@ -14402,20 +14472,20 @@ fn PointShadowOffset_u0028_i1_u003b_f1_u003b_f1_u003b_f1_u003b(i_1: ptr; var param_37: i32; - let _e212 = (*i_1); - param_37 = _e212; - let _e213 = PointShadowDiskTap_u0028_i1_u003b((¶m_37)); - p = _e213; - let _e215 = p[0u]; - let _e216 = (*ca); - let _e219 = p[1u]; - let _e220 = (*sa); - let _e224 = p[0u]; - let _e225 = (*sa); - let _e228 = p[1u]; - let _e229 = (*ca); - let _e233 = (*radius); - return (vec2(((_e215 * _e216) - (_e219 * _e220)), ((_e224 * _e225) + (_e228 * _e229))) * _e233); + let _e213 = (*i_1); + param_37 = _e213; + let _e214 = PointShadowDiskTap_u0028_i1_u003b((¶m_37)); + p = _e214; + let _e216 = p[0u]; + let _e217 = (*ca); + let _e220 = p[1u]; + let _e221 = (*sa); + let _e225 = p[0u]; + let _e226 = (*sa); + let _e229 = p[1u]; + let _e230 = (*ca); + let _e234 = (*radius); + return (vec2(((_e216 * _e217) - (_e220 * _e221)), ((_e225 * _e226) + (_e229 * _e230))) * _e234); } fn PointShadowDistance_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b(uv: ptr>, offset: ptr>, tile: ptr>, range: ptr) -> f32 { @@ -14423,27 +14493,27 @@ fn PointShadowDistance_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b(uv: ptr; var atlas: vec2; - let _e215 = point_shadow.params[0u]; - inset = _e215; - let _e216 = (*uv); - let _e217 = (*offset); - let _e219 = inset; + let _e216 = point_shadow.params[0u]; + inset = _e216; + let _e217 = (*uv); + let _e218 = (*offset); let _e220 = inset; - local_6 = clamp((_e216 + _e217), vec2(_e219), vec2((1f - _e220))); - let _e225 = local_6; - let _e226 = (*tile); - atlas = ((_e225 + _e226) * vec2(0.16666667f, 0.16666667f)); - let _e231 = point_shadow.params3_[0u]; - if (_e231 > 0.5f) { - let _e234 = atlas[1u]; - atlas[1u] = (1f - _e234); - } - let _e237 = atlas; - let _e238 = textureSampleLevel(point_shadow_texture_tex, point_shadow_texture_smp, _e237, 0f); - let _e240 = atlas; - let _e241 = textureSampleLevel(point_shadow_static_texture_tex, point_shadow_static_texture_smp, _e240, 0f); - let _e244 = (*range); - return (min(_e238.x, _e241.x) * _e244); + let _e221 = inset; + local_6 = clamp((_e217 + _e218), vec2(_e220), vec2((1f - _e221))); + let _e226 = local_6; + let _e227 = (*tile); + atlas = ((_e226 + _e227) * vec2(0.16666667f, 0.16666667f)); + let _e232 = point_shadow.params3_[0u]; + if (_e232 > 0.5f) { + let _e235 = atlas[1u]; + atlas[1u] = (1f - _e235); + } + let _e238 = atlas; + let _e239 = textureSampleLevel(point_shadow_texture_tex, point_shadow_texture_smp, _e238, 0f); + let _e241 = atlas; + let _e242 = textureSampleLevel(point_shadow_static_texture_tex, point_shadow_static_texture_smp, _e241, 0f); + let _e245 = (*range); + return (min(_e239.x, _e242.x) * _e245); } fn PointShadowTap_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b_f1_u003b(uv_1: ptr>, offset_1: ptr>, tile_1: ptr>, range_1: ptr, receiver: ptr) -> f32 { @@ -14453,24 +14523,24 @@ fn PointShadowTap_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b_f1_u003b(uv_1: pt var param_40: vec2; var param_41: f32; - let _e216 = (*uv_1); - param_38 = _e216; - let _e217 = (*offset_1); - param_39 = _e217; - let _e218 = (*tile_1); - param_40 = _e218; - let _e219 = (*range_1); - param_41 = _e219; - let _e220 = PointShadowDistance_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b((¶m_38), (¶m_39), (¶m_40), (¶m_41)); - stored = _e220; - let _e221 = stored; - let _e222 = (*range_1); - if (_e221 >= (_e222 * 0.999f)) { + let _e217 = (*uv_1); + param_38 = _e217; + let _e218 = (*offset_1); + param_39 = _e218; + let _e219 = (*tile_1); + param_40 = _e219; + let _e220 = (*range_1); + param_41 = _e220; + let _e221 = PointShadowDistance_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b((¶m_38), (¶m_39), (¶m_40), (¶m_41)); + stored = _e221; + let _e222 = stored; + let _e223 = (*range_1); + if (_e222 >= (_e223 * 0.999f)) { return 1f; } - let _e225 = (*receiver); - let _e226 = stored; - return select(1f, 0f, (_e225 > _e226)); + let _e226 = (*receiver); + let _e227 = stored; + return select(1f, 0f, (_e226 > _e227)); } fn PointShadowPenumbra_u0028_vf2_u003b_vf2_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b(uv_2: ptr>, tile_2: ptr>, range_2: ptr, receiver_1: ptr, ca_1: ptr, sa_1: ptr, tanHalf: ptr, blockerOut: ptr) -> f32 { @@ -14497,111 +14567,111 @@ fn PointShadowPenumbra_u0028_vf2_u003b_vf2_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u var world: f32; (*blockerOut) = -1f; - let _e237 = point_shadow.params2_[1u]; - lightRadius = _e237; - let _e240 = point_shadow.params2_[0u]; - minRadius = _e240; - let _e243 = point_shadow.params2_[2u]; - maxRadius = _e243; - let _e244 = lightRadius; - if (_e244 <= 0f) { - let _e246 = (*uv_2); - param_42 = _e246; + let _e238 = point_shadow.params2_[1u]; + lightRadius = _e238; + let _e241 = point_shadow.params2_[0u]; + minRadius = _e241; + let _e244 = point_shadow.params2_[2u]; + maxRadius = _e244; + let _e245 = lightRadius; + if (_e245 <= 0f) { + let _e247 = (*uv_2); + param_42 = _e247; param_43 = vec2(0f, 0f); - let _e247 = (*tile_2); - param_44 = _e247; - let _e248 = (*range_2); - param_45 = _e248; - let _e249 = PointShadowDistance_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b((¶m_42), (¶m_43), (¶m_44), (¶m_45)); - (*blockerOut) = _e249; - let _e250 = minRadius; - return _e250; + let _e248 = (*tile_2); + param_44 = _e248; + let _e249 = (*range_2); + param_45 = _e249; + let _e250 = PointShadowDistance_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b((¶m_42), (¶m_43), (¶m_44), (¶m_45)); + (*blockerOut) = _e250; + let _e251 = minRadius; + return _e251; } sum = 0f; count = 0f; i_2 = 0i; loop { - let _e251 = i_2; - if (_e251 < 8i) { - let _e253 = i_2; - param_46 = _e253; - let _e254 = (*ca_1); - param_47 = _e254; - let _e255 = (*sa_1); - param_48 = _e255; - let _e256 = maxRadius; - param_49 = _e256; - let _e257 = PointShadowOffset_u0028_i1_u003b_f1_u003b_f1_u003b_f1_u003b((¶m_46), (¶m_47), (¶m_48), (¶m_49)); - let _e258 = (*uv_2); - param_50 = _e258; - param_51 = _e257; - let _e259 = (*tile_2); - param_52 = _e259; - let _e260 = (*range_2); - param_53 = _e260; - let _e261 = PointShadowDistance_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b((¶m_50), (¶m_51), (¶m_52), (¶m_53)); - stored_1 = _e261; - let _e262 = stored_1; - let _e263 = (*range_2); - if (_e262 >= (_e263 * 0.999f)) { + let _e252 = i_2; + if (_e252 < 8i) { + let _e254 = i_2; + param_46 = _e254; + let _e255 = (*ca_1); + param_47 = _e255; + let _e256 = (*sa_1); + param_48 = _e256; + let _e257 = maxRadius; + param_49 = _e257; + let _e258 = PointShadowOffset_u0028_i1_u003b_f1_u003b_f1_u003b_f1_u003b((¶m_46), (¶m_47), (¶m_48), (¶m_49)); + let _e259 = (*uv_2); + param_50 = _e259; + param_51 = _e258; + let _e260 = (*tile_2); + param_52 = _e260; + let _e261 = (*range_2); + param_53 = _e261; + let _e262 = PointShadowDistance_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b((¶m_50), (¶m_51), (¶m_52), (¶m_53)); + stored_1 = _e262; + let _e263 = stored_1; + let _e264 = (*range_2); + if (_e263 >= (_e264 * 0.999f)) { continue; } - let _e266 = stored_1; - let _e267 = (*receiver_1); - if (_e266 >= _e267) { + let _e267 = stored_1; + let _e268 = (*receiver_1); + if (_e267 >= _e268) { continue; } - let _e269 = stored_1; - let _e270 = sum; - sum = (_e270 + _e269); - let _e272 = count; - count = (_e272 + 1f); + let _e270 = stored_1; + let _e271 = sum; + sum = (_e271 + _e270); + let _e273 = count; + count = (_e273 + 1f); continue; } else { break; } continuing { - let _e274 = i_2; - i_2 = (_e274 + 1i); + let _e275 = i_2; + i_2 = (_e275 + 1i); } } - let _e276 = count; - if (_e276 < 0.5f) { + let _e277 = count; + if (_e277 < 0.5f) { return -1f; } - let _e278 = sum; - let _e279 = count; - blocker = max((_e278 / _e279), 0.0001f); - let _e282 = blocker; - (*blockerOut) = _e282; - let _e283 = lightRadius; - let _e284 = (*receiver_1); - let _e285 = blocker; - let _e289 = blocker; - world = ((_e283 * max((_e284 - _e285), 0f)) / _e289); - let _e291 = world; - let _e292 = (*receiver_1); - let _e294 = (*tanHalf); - let _e297 = minRadius; - let _e298 = maxRadius; - return clamp((_e291 / ((2f * _e292) * _e294)), _e297, _e298); + let _e279 = sum; + let _e280 = count; + blocker = max((_e279 / _e280), 0.0001f); + let _e283 = blocker; + (*blockerOut) = _e283; + let _e284 = lightRadius; + let _e285 = (*receiver_1); + let _e286 = blocker; + let _e290 = blocker; + world = ((_e284 * max((_e285 - _e286), 0f)) / _e290); + let _e292 = world; + let _e293 = (*receiver_1); + let _e295 = (*tanHalf); + let _e298 = minRadius; + let _e299 = maxRadius; + return clamp((_e292 / ((2f * _e293) * _e295)), _e298, _e299); } fn FragCoordFromTop_u0028_f1_u003b(rows: ptr) -> vec2 { var local_7: vec2; - let _e208 = (*rows); - if (_e208 > 0f) { - let _e211 = gl_FragCoord_1[0u]; - let _e212 = (*rows); - let _e214 = gl_FragCoord_1[1u]; - local_7 = vec2(_e211, (_e212 - _e214)); + let _e209 = (*rows); + if (_e209 > 0f) { + let _e212 = gl_FragCoord_1[0u]; + let _e213 = (*rows); + let _e215 = gl_FragCoord_1[1u]; + local_7 = vec2(_e212, (_e213 - _e215)); } else { - let _e217 = gl_FragCoord_1; - local_7 = _e217.xy; + let _e218 = gl_FragCoord_1; + local_7 = _e218.xy; } - let _e219 = local_7; - return _e219; + let _e220 = local_7; + return _e220; } fn PointShadowFactor_u0028_vf3_u003b_vf3_u003b_i1_u003b(world_1: ptr>, normal: ptr>, lightIndex: ptr) -> f32 { @@ -14659,257 +14729,257 @@ fn PointShadowFactor_u0028_vf3_u003b_vf3_u003b_i1_u003b(world_1: ptr= _e347) { + let _e303 = nDotL; + slope = min((sqrt(max((1f - (_e296 * _e297)), 0f)) / (_e302 * _e303)), 8f); + let _e307 = toLightLength; + let _e309 = (*lightIndex); + let _e313 = point_shadow.slots[_e309][2u]; + let _e318 = point_shadow.params3_[1u]; + texel = (((2f * _e307) * max(_e313, 0.0001f)) * _e318); + let _e320 = (*world_1); + let _e321 = (*normal); + let _e322 = texel; + let _e326 = point_shadow.params[3u]; + let _e328 = slope; + origin = (_e320 + (((_e321 * _e322) * _e326) * (1f + _e328))); + let _e332 = origin; + let _e333 = slot; + let _e336 = point_shadow.lights[_e333]; + toFragment = (_e332 - _e336.xyz); + let _e339 = toFragment; + distance_ = length(_e339); + let _e341 = slot; + let _e345 = point_shadow.lights[_e341][3u]; + range_3 = max(_e345, 0.0001f); + let _e347 = distance_; + let _e348 = range_3; + if (_e347 >= _e348) { return 1f; } face = 0i; - let _e349 = (*lightIndex); - let _e353 = point_shadow.slots[_e349][1u]; - if (_e353 < 0.5f) { - let _e355 = toFragment; - a_1 = abs(_e355); - let _e358 = a_1[0u]; - let _e360 = a_1[1u]; - let _e361 = (_e358 >= _e360); - phi_2590_ = _e361; - if _e361 { - let _e363 = a_1[0u]; - let _e365 = a_1[2u]; - phi_2590_ = (_e363 >= _e365); - } - let _e368 = phi_2590_; - if _e368 { - let _e370 = toFragment[0u]; - face = select(1i, 0i, (_e370 > 0f)); + let _e350 = (*lightIndex); + let _e354 = point_shadow.slots[_e350][1u]; + if (_e354 < 0.5f) { + let _e356 = toFragment; + a_1 = abs(_e356); + let _e359 = a_1[0u]; + let _e361 = a_1[1u]; + let _e362 = (_e359 >= _e361); + phi_2590_ = _e362; + if _e362 { + let _e364 = a_1[0u]; + let _e366 = a_1[2u]; + phi_2590_ = (_e364 >= _e366); + } + let _e369 = phi_2590_; + if _e369 { + let _e371 = toFragment[0u]; + face = select(1i, 0i, (_e371 > 0f)); } else { - let _e374 = a_1[1u]; - let _e376 = a_1[2u]; - if (_e374 >= _e376) { - let _e379 = toFragment[1u]; - face = select(3i, 2i, (_e379 > 0f)); + let _e375 = a_1[1u]; + let _e377 = a_1[2u]; + if (_e375 >= _e377) { + let _e380 = toFragment[1u]; + face = select(3i, 2i, (_e380 > 0f)); } else { - let _e383 = toFragment[2u]; - face = select(5i, 4i, (_e383 > 0f)); + let _e384 = toFragment[2u]; + face = select(5i, 4i, (_e384 > 0f)); } } } - let _e386 = slot; - let _e388 = face; - let _e392 = point_shadow.faces[((_e386 * 6i) + _e388)]; - let _e393 = origin; - clip = (_e392 * vec4(_e393.x, _e393.y, _e393.z, 1f)); - let _e400 = clip[3u]; - if (_e400 <= 0f) { + let _e387 = slot; + let _e389 = face; + let _e393 = point_shadow.faces[((_e387 * 6i) + _e389)]; + let _e394 = origin; + clip = (_e393 * vec4(_e394.x, _e394.y, _e394.z, 1f)); + let _e401 = clip[3u]; + if (_e401 <= 0f) { return 1f; } - let _e402 = clip; - let _e405 = clip[3u]; - ndc = (_e402.xy / vec2(_e405)); - let _e409 = ndc[0u]; - let _e411 = (abs(_e409) > 1f); - phi_2651_ = _e411; - if !(_e411) { - let _e414 = ndc[1u]; - phi_2651_ = (abs(_e414) > 1f); - } - let _e418 = phi_2651_; - if _e418 { + let _e403 = clip; + let _e406 = clip[3u]; + ndc = (_e403.xy / vec2(_e406)); + let _e410 = ndc[0u]; + let _e412 = (abs(_e410) > 1f); + phi_2651_ = _e412; + if !(_e412) { + let _e415 = ndc[1u]; + phi_2651_ = (abs(_e415) > 1f); + } + let _e419 = phi_2651_; + if _e419 { return 1f; } - let _e420 = ndc[0u]; - let _e424 = ndc[1u]; - uv_3 = vec2(((_e420 * 0.5f) + 0.5f), (0.5f - (_e424 * 0.5f))); - let _e428 = face; - let _e430 = slot; - tile_3 = vec2(f32(_e428), f32(_e430)); - let _e433 = distance_; - let _e436 = point_shadow.params[1u]; - receiver_2 = (_e433 - _e436); - let _e440 = frag_info.target_origin[0u]; - param_54 = _e440; - let _e441 = FragCoordFromTop_u0028_f1_u003b((¶m_54)); - noise = fract((52.982918f * fract(dot(_e441, vec2(0.06711056f, 0.00583715f))))); - let _e446 = noise; - angle = (_e446 * 6.2831855f); - let _e448 = angle; - ca_2 = cos(_e448); - let _e450 = angle; - sa_2 = sin(_e450); - let _e452 = (*lightIndex); - let _e456 = point_shadow.slots[_e452][2u]; - tanHalf_1 = max(_e456, 0.0001f); + let _e421 = ndc[0u]; + let _e425 = ndc[1u]; + uv_3 = vec2(((_e421 * 0.5f) + 0.5f), (0.5f - (_e425 * 0.5f))); + let _e429 = face; + let _e431 = slot; + tile_3 = vec2(f32(_e429), f32(_e431)); + let _e434 = distance_; + let _e437 = point_shadow.params[1u]; + receiver_2 = (_e434 - _e437); + let _e441 = frag_info.target_origin[0u]; + param_54 = _e441; + let _e442 = FragCoordFromTop_u0028_f1_u003b((¶m_54)); + noise = fract((52.982918f * fract(dot(_e442, vec2(0.06711056f, 0.00583715f))))); + let _e447 = noise; + angle = (_e447 * 6.2831855f); + let _e449 = angle; + ca_2 = cos(_e449); + let _e451 = angle; + sa_2 = sin(_e451); + let _e453 = (*lightIndex); + let _e457 = point_shadow.slots[_e453][2u]; + tanHalf_1 = max(_e457, 0.0001f); blocker_1 = -1f; - let _e458 = uv_3; - param_55 = _e458; - let _e459 = tile_3; - param_56 = _e459; - let _e460 = range_3; - param_57 = _e460; - let _e461 = receiver_2; - param_58 = _e461; - let _e462 = ca_2; - param_59 = _e462; - let _e463 = sa_2; - param_60 = _e463; - let _e464 = tanHalf_1; - param_61 = _e464; - let _e465 = PointShadowPenumbra_u0028_vf2_u003b_vf2_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b((¶m_55), (¶m_56), (¶m_57), (¶m_58), (¶m_59), (¶m_60), (¶m_61), (¶m_62)); - let _e466 = param_62; - blocker_1 = _e466; - radius_1 = _e465; - let _e469 = point_shadow.params2_[3u]; - if (_e469 > 0.5f) { + let _e459 = uv_3; + param_55 = _e459; + let _e460 = tile_3; + param_56 = _e460; + let _e461 = range_3; + param_57 = _e461; + let _e462 = receiver_2; + param_58 = _e462; + let _e463 = ca_2; + param_59 = _e463; + let _e464 = sa_2; + param_60 = _e464; + let _e465 = tanHalf_1; + param_61 = _e465; + let _e466 = PointShadowPenumbra_u0028_vf2_u003b_vf2_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b((¶m_55), (¶m_56), (¶m_57), (¶m_58), (¶m_59), (¶m_60), (¶m_61), (¶m_62)); + let _e467 = param_62; + blocker_1 = _e467; + radius_1 = _e466; + let _e470 = point_shadow.params2_[3u]; + if (_e470 > 0.5f) { g_debug_surface_on = true; - let _e471 = radius_1; - if (_e471 < 0f) { + let _e472 = radius_1; + if (_e472 < 0f) { local_8 = vec3(0f, 0f, 1f); } else { - let _e473 = radius_1; - let _e476 = point_shadow.params2_[2u]; - let _e480 = blocker_1; - let _e481 = range_3; - local_8 = vec3(clamp((_e473 / max(_e476, 0.000001f)), 0f, 1f), clamp((_e480 / _e481), 0f, 1f), 0f); + let _e474 = radius_1; + let _e477 = point_shadow.params2_[2u]; + let _e481 = blocker_1; + let _e482 = range_3; + local_8 = vec3(clamp((_e474 / max(_e477, 0.000001f)), 0f, 1f), clamp((_e481 / _e482), 0f, 1f), 0f); } - let _e485 = local_8; - g_debug_surface = _e485; + let _e486 = local_8; + g_debug_surface = _e486; } - let _e486 = radius_1; - if (_e486 < 0f) { + let _e487 = radius_1; + if (_e487 < 0f) { return 1f; } - let _e488 = uv_3; - param_63 = _e488; + let _e489 = uv_3; + param_63 = _e489; param_64 = vec2(0f, 0f); - let _e489 = tile_3; - param_65 = _e489; - let _e490 = range_3; - param_66 = _e490; - let _e491 = receiver_2; - param_67 = _e491; - let _e492 = PointShadowTap_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b_f1_u003b((¶m_63), (¶m_64), (¶m_65), (¶m_66), (¶m_67)); - lit_1 = _e492; - let _e493 = radius_1; - if (_e493 > 0f) { + let _e490 = tile_3; + param_65 = _e490; + let _e491 = range_3; + param_66 = _e491; + let _e492 = receiver_2; + param_67 = _e492; + let _e493 = PointShadowTap_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b_f1_u003b((¶m_63), (¶m_64), (¶m_65), (¶m_66), (¶m_67)); + lit_1 = _e493; + let _e494 = radius_1; + if (_e494 > 0f) { i_3 = 0i; loop { - let _e495 = i_3; - if (_e495 < 8i) { - let _e497 = i_3; - param_68 = _e497; - let _e498 = ca_2; - param_69 = _e498; - let _e499 = sa_2; - param_70 = _e499; - let _e500 = radius_1; - param_71 = _e500; - let _e501 = PointShadowOffset_u0028_i1_u003b_f1_u003b_f1_u003b_f1_u003b((¶m_68), (¶m_69), (¶m_70), (¶m_71)); - let _e502 = uv_3; - param_72 = _e502; - param_73 = _e501; - let _e503 = tile_3; - param_74 = _e503; - let _e504 = range_3; - param_75 = _e504; - let _e505 = receiver_2; - param_76 = _e505; - let _e506 = PointShadowTap_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b_f1_u003b((¶m_72), (¶m_73), (¶m_74), (¶m_75), (¶m_76)); - let _e507 = lit_1; - lit_1 = (_e507 + _e506); + let _e496 = i_3; + if (_e496 < 8i) { + let _e498 = i_3; + param_68 = _e498; + let _e499 = ca_2; + param_69 = _e499; + let _e500 = sa_2; + param_70 = _e500; + let _e501 = radius_1; + param_71 = _e501; + let _e502 = PointShadowOffset_u0028_i1_u003b_f1_u003b_f1_u003b_f1_u003b((¶m_68), (¶m_69), (¶m_70), (¶m_71)); + let _e503 = uv_3; + param_72 = _e503; + param_73 = _e502; + let _e504 = tile_3; + param_74 = _e504; + let _e505 = range_3; + param_75 = _e505; + let _e506 = receiver_2; + param_76 = _e506; + let _e507 = PointShadowTap_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b_f1_u003b((¶m_72), (¶m_73), (¶m_74), (¶m_75), (¶m_76)); + let _e508 = lit_1; + lit_1 = (_e508 + _e507); continue; } else { break; } continuing { - let _e509 = i_3; - i_3 = (_e509 + 1i); + let _e510 = i_3; + i_3 = (_e510 + 1i); } } - let _e511 = lit_1; - lit_1 = (_e511 * 0.11111111f); + let _e512 = lit_1; + lit_1 = (_e512 * 0.11111111f); } - let _e513 = lit_1; - let _e514 = strength; - return mix(1f, _e513, clamp(_e514, 0f, 1f)); + let _e514 = lit_1; + let _e515 = strength; + return mix(1f, _e514, clamp(_e515, 0f, 1f)); } fn VogelDisc_u0028_i1_u003b_i1_u003b_f1_u003b(i_4: ptr, n_1: ptr, turn: ptr) -> vec2 { var r_3: f32; var theta: f32; - let _e211 = (*i_4); - let _e214 = (*n_1); - r_3 = sqrt(((f32(_e211) + 0.5f) / f32(_e214))); - let _e218 = (*i_4); - let _e221 = (*turn); - theta = ((f32(_e218) * 2.3999631f) + _e221); - let _e223 = r_3; - let _e224 = theta; - let _e226 = theta; - return (vec2(cos(_e224), sin(_e226)) * _e223); + let _e212 = (*i_4); + let _e215 = (*n_1); + r_3 = sqrt(((f32(_e212) + 0.5f) / f32(_e215))); + let _e219 = (*i_4); + let _e222 = (*turn); + theta = ((f32(_e219) * 2.3999631f) + _e222); + let _e224 = r_3; + let _e225 = theta; + let _e227 = theta; + return (vec2(cos(_e225), sin(_e227)) * _e224); } fn ShadowNoise_u0028_() -> f32 { var at: vec2; var param_77: f32; - let _e210 = frag_info.target_origin[0u]; - param_77 = _e210; - let _e211 = FragCoordFromTop_u0028_f1_u003b((¶m_77)); - let _e214 = frag_info.target_origin[3u]; - at = (_e211 + vec2((5.588238f * max(_e214, 0f)))); - let _e219 = at; - return fract((52.982918f * fract(dot(_e219, vec2(0.06711056f, 0.00583715f))))); + let _e211 = frag_info.target_origin[0u]; + param_77 = _e211; + let _e212 = FragCoordFromTop_u0028_f1_u003b((¶m_77)); + let _e215 = frag_info.target_origin[3u]; + at = (_e212 + vec2((5.588238f * max(_e215, 0f)))); + let _e220 = at; + return fract((52.982918f * fract(dot(_e220, vec2(0.06711056f, 0.00583715f))))); } fn EvsmChebyshev_u0028_vf2_u003b_f1_u003b_f1_u003b_f1_u003b(moments: ptr>, t: ptr, minVariance: ptr, bleed: ptr) -> f32 { @@ -14918,37 +14988,37 @@ fn EvsmChebyshev_u0028_vf2_u003b_f1_u003b_f1_u003b_f1_u003b(moments: ptr) -> vec2 { var d_3: f32; - let _e208 = (*depth); - d_3 = ((2f * clamp(_e208, 0f, 1f)) - 1f); - let _e212 = d_3; - let _e215 = d_3; - return vec2(exp((40f * _e212)), -(exp((-5f * _e215)))); + let _e209 = (*depth); + d_3 = ((2f * clamp(_e209, 0f, 1f)) - 1f); + let _e213 = d_3; + let _e216 = d_3; + return vec2(exp((40f * _e213)), -(exp((-5f * _e216)))); } fn EvsmVisibility_u0028_vf4_u003b_f1_u003b_f1_u003b(moments_1: ptr>, depth_1: ptr, bleed_1: ptr) -> f32 { @@ -14966,37 +15036,37 @@ fn EvsmVisibility_u0028_vf4_u003b_f1_u003b_f1_u003b(moments_1: ptr(0.004f, 0.0005f) * _e224); - let _e227 = scale[0u]; - let _e229 = scale[0u]; - let _e231 = (*moments_1); - param_79 = _e231.xy; - let _e234 = warped[0u]; - param_80 = _e234; - param_81 = (_e227 * _e229); - let _e235 = (*bleed_1); - param_82 = _e235; - let _e236 = EvsmChebyshev_u0028_vf2_u003b_f1_u003b_f1_u003b_f1_u003b((¶m_79), (¶m_80), (¶m_81), (¶m_82)); - positive = _e236; - let _e238 = scale[1u]; - let _e240 = scale[1u]; - let _e242 = (*moments_1); - param_83 = _e242.zw; - let _e245 = warped[1u]; - param_84 = _e245; - param_85 = (_e238 * _e240); - let _e246 = (*bleed_1); - param_86 = _e246; - let _e247 = EvsmChebyshev_u0028_vf2_u003b_f1_u003b_f1_u003b_f1_u003b((¶m_83), (¶m_84), (¶m_85), (¶m_86)); - negative = _e247; - let _e248 = positive; - let _e249 = negative; - return min(_e248, _e249); + let _e223 = (*depth_1); + param_78 = _e223; + let _e224 = EvsmWarp_u0028_f1_u003b((¶m_78)); + warped = _e224; + let _e225 = warped; + scale = (vec2(0.004f, 0.0005f) * _e225); + let _e228 = scale[0u]; + let _e230 = scale[0u]; + let _e232 = (*moments_1); + param_79 = _e232.xy; + let _e235 = warped[0u]; + param_80 = _e235; + param_81 = (_e228 * _e230); + let _e236 = (*bleed_1); + param_82 = _e236; + let _e237 = EvsmChebyshev_u0028_vf2_u003b_f1_u003b_f1_u003b_f1_u003b((¶m_79), (¶m_80), (¶m_81), (¶m_82)); + positive = _e237; + let _e239 = scale[1u]; + let _e241 = scale[1u]; + let _e243 = (*moments_1); + param_83 = _e243.zw; + let _e246 = warped[1u]; + param_84 = _e246; + param_85 = (_e239 * _e241); + let _e247 = (*bleed_1); + param_86 = _e247; + let _e248 = EvsmChebyshev_u0028_vf2_u003b_f1_u003b_f1_u003b_f1_u003b((¶m_83), (¶m_84), (¶m_85), (¶m_86)); + negative = _e248; + let _e249 = positive; + let _e250 = negative; + return min(_e249, _e250); } fn ShadowFactor_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_struct_u002d_LightSample_u002d_vf3_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf31_u003b_i1_u003b(s_4: ptr, light_1: ptr, lightIndex_1: ptr) -> f32 { @@ -15034,6 +15104,8 @@ fn ShadowFactor_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf var tileLo: vec2; var tileHi: vec2; var stored_2: vec4; + var y_1: i32; + var x_1: i32; var through: vec3; var softness: f32; var lit_2: f32; @@ -15041,8 +15113,8 @@ fn ShadowFactor_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf var param_87: vec4; var param_88: f32; var param_89: f32; - var y_1: i32; - var x_1: i32; + var y_2: i32; + var x_2: i32; var occluder: f32; var spread: f32; var turn_1: f32; @@ -15071,45 +15143,45 @@ fn ShadowFactor_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf var phi_4049_: bool; var phi_4056_: bool; - let _e276 = frag_info.shadow_params[3u]; - strength_1 = _e276; - let _e277 = strength_1; - if (_e277 <= 0f) { + let _e279 = frag_info.shadow_params[3u]; + strength_1 = _e279; + let _e280 = strength_1; + if (_e280 <= 0f) { return 1f; } - let _e279 = (*lightIndex_1); - let _e282 = frag_info.frame_params[2u]; - if (_e279 != i32((_e282 + 0.5f))) { + let _e282 = (*lightIndex_1); + let _e285 = frag_info.frame_params[2u]; + if (_e282 != i32((_e285 + 0.5f))) { return 1f; } - let _e288 = frag_info.shadow_cascades[2u]; - cascadeCount = i32((_e288 + 0.5f)); - let _e291 = v_world_position_1; - let _e293 = frag_info.camera_position; - viewDistance = length((_e291 - _e293.xyz)); + let _e291 = frag_info.shadow_cascades[2u]; + cascadeCount = i32((_e291 + 0.5f)); + let _e294 = v_world_position_1; + let _e296 = frag_info.camera_position; + viewDistance = length((_e294 - _e296.xyz)); cascade = 0i; - let _e297 = cascadeCount; - let _e298 = (_e297 > 1i); - phi_3870_ = _e298; - if _e298 { - let _e299 = viewDistance; - let _e302 = frag_info.shadow_cascades[0u]; - phi_3870_ = (_e299 > _e302); + let _e300 = cascadeCount; + let _e301 = (_e300 > 1i); + phi_3870_ = _e301; + if _e301 { + let _e302 = viewDistance; + let _e305 = frag_info.shadow_cascades[0u]; + phi_3870_ = (_e302 > _e305); } - let _e305 = phi_3870_; - if _e305 { + let _e308 = phi_3870_; + if _e308 { cascade = 1i; } - let _e306 = cascadeCount; - let _e307 = (_e306 > 2i); - phi_3881_ = _e307; - if _e307 { - let _e308 = viewDistance; - let _e311 = frag_info.shadow_cascades[1u]; - phi_3881_ = (_e308 > _e311); + let _e309 = cascadeCount; + let _e310 = (_e309 > 2i); + phi_3881_ = _e310; + if _e310 { + let _e311 = viewDistance; + let _e314 = frag_info.shadow_cascades[1u]; + phi_3881_ = (_e311 > _e314); } - let _e314 = phi_3881_; - if _e314 { + let _e317 = phi_3881_; + if _e317 { cascade = 2i; } uv_4 = vec2(0f, 0f); @@ -15120,247 +15192,280 @@ fn ShadowFactor_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf receiverSlope = 0f; attempt = 0i; loop { - let _e315 = attempt; - if (_e315 < 3i) { - let _e317 = cascade; - let _e318 = attempt; - which = (_e317 + _e318); - let _e320 = which; - let _e321 = cascadeCount; - if (_e320 >= _e321) { + let _e318 = attempt; + if (_e318 < 3i) { + let _e320 = cascade; + let _e321 = attempt; + which = (_e320 + _e321); + let _e323 = which; + let _e324 = cascadeCount; + if (_e323 >= _e324) { break; } - let _e323 = which; - if (_e323 == 0i) { - let _e326 = frag_info.shadow_matrix; - local_9 = _e326; + let _e326 = which; + if (_e326 == 0i) { + let _e329 = frag_info.shadow_matrix; + local_9 = _e329; } else { - let _e327 = which; - if (_e327 == 1i) { - let _e330 = frag_info.shadow_matrix_far; - local_10 = _e330; + let _e330 = which; + if (_e330 == 1i) { + let _e333 = frag_info.shadow_matrix_far; + local_10 = _e333; } else { - let _e332 = frag_info.shadow_matrix_farthest; - local_10 = _e332; + let _e335 = frag_info.shadow_matrix_farthest; + local_10 = _e335; } - let _e333 = local_10; - local_9 = _e333; - } - let _e334 = local_9; - matrix = _e334; - let _e337 = matrix[0][0u]; - let _e340 = matrix[1][0u]; - let _e343 = matrix[2][0u]; - axisX = vec3(_e337, _e340, _e343); - let _e347 = matrix[0][1u]; - let _e350 = matrix[1][1u]; - let _e353 = matrix[2][1u]; - axisY = vec3(_e347, _e350, _e353); - let _e355 = axisX; - rowX = max(length(_e355), 0.000001f); - let _e358 = axisY; - rowY = max(length(_e358), 0.000001f); - let _e363 = frag_info.shadow_cascades[3u]; - let _e365 = rowX; - texelMetres = ((2f * _e363) / _e365); - let _e369 = frag_info.shadow_cascades[3u]; - let _e372 = (*s_4).n; - let _e373 = axisX; - let _e376 = rowX; - let _e377 = rowX; - let _e381 = (*s_4).n; - let _e382 = axisY; - let _e385 = rowY; - let _e386 = rowY; - reach = ((3f * _e369) * ((abs(dot(_e372, _e373)) / (_e376 * _e377)) + (abs(dot(_e381, _e382)) / (_e385 * _e386)))); - let _e393 = frag_info.shadow_params[2u]; - let _e394 = texelMetres; - flatOffset = min(_e393, _e394); - let _e396 = v_world_position_1; - let _e398 = (*s_4).n; - let _e399 = flatOffset; - let _e400 = reach; - origin_1 = (_e396 + (_e398 * (_e399 + _e400))); - let _e404 = matrix; - let _e405 = origin_1; - lightSpace = (_e404 * vec4(_e405.x, _e405.y, _e405.z, 1f)); - let _e412 = lightSpace[3u]; - if (_e412 <= 0f) { + let _e336 = local_10; + local_9 = _e336; + } + let _e337 = local_9; + matrix = _e337; + let _e340 = matrix[0][0u]; + let _e343 = matrix[1][0u]; + let _e346 = matrix[2][0u]; + axisX = vec3(_e340, _e343, _e346); + let _e350 = matrix[0][1u]; + let _e353 = matrix[1][1u]; + let _e356 = matrix[2][1u]; + axisY = vec3(_e350, _e353, _e356); + let _e358 = axisX; + rowX = max(length(_e358), 0.000001f); + let _e361 = axisY; + rowY = max(length(_e361), 0.000001f); + let _e366 = frag_info.shadow_cascades[3u]; + let _e368 = rowX; + texelMetres = ((2f * _e366) / _e368); + let _e372 = frag_info.shadow_cascades[3u]; + let _e375 = (*s_4).n; + let _e376 = axisX; + let _e379 = rowX; + let _e380 = rowX; + let _e384 = (*s_4).n; + let _e385 = axisY; + let _e388 = rowY; + let _e389 = rowY; + reach = ((3f * _e372) * ((abs(dot(_e375, _e376)) / (_e379 * _e380)) + (abs(dot(_e384, _e385)) / (_e388 * _e389)))); + let _e396 = frag_info.shadow_params[2u]; + let _e397 = texelMetres; + flatOffset = min(_e396, _e397); + let _e399 = v_world_position_1; + let _e401 = (*s_4).n; + let _e402 = flatOffset; + let _e403 = reach; + origin_1 = (_e399 + (_e401 * (_e402 + _e403))); + let _e407 = matrix; + let _e408 = origin_1; + lightSpace = (_e407 * vec4(_e408.x, _e408.y, _e408.z, 1f)); + let _e415 = lightSpace[3u]; + if (_e415 <= 0f) { continue; } - let _e414 = lightSpace; - let _e417 = lightSpace[3u]; - candidate = (_e414.xyz / vec3(_e417)); - let _e421 = candidate[0u]; - let _e425 = candidate[1u]; - inTile = vec2(((_e421 * 0.5f) + 0.5f), (0.5f - (_e425 * 0.5f))); - let _e430 = inTile[0u]; - let _e431 = (_e430 < 0f); - phi_4042_ = _e431; - if !(_e431) { - let _e434 = inTile[0u]; - phi_4042_ = (_e434 > 1f); - } - let _e437 = phi_4042_; - phi_4049_ = _e437; - if !(_e437) { - let _e440 = inTile[1u]; - phi_4049_ = (_e440 < 0f); - } - let _e443 = phi_4049_; - phi_4056_ = _e443; - if !(_e443) { - let _e446 = inTile[1u]; - phi_4056_ = (_e446 > 1f); - } - let _e449 = phi_4056_; - if _e449 { + let _e417 = lightSpace; + let _e420 = lightSpace[3u]; + candidate = (_e417.xyz / vec3(_e420)); + let _e424 = candidate[0u]; + let _e428 = candidate[1u]; + inTile = vec2(((_e424 * 0.5f) + 0.5f), (0.5f - (_e428 * 0.5f))); + let _e433 = inTile[0u]; + let _e434 = (_e433 < 0f); + phi_4042_ = _e434; + if !(_e434) { + let _e437 = inTile[0u]; + phi_4042_ = (_e437 > 1f); + } + let _e440 = phi_4042_; + phi_4049_ = _e440; + if !(_e440) { + let _e443 = inTile[1u]; + phi_4049_ = (_e443 < 0f); + } + let _e446 = phi_4049_; + phi_4056_ = _e446; + if !(_e446) { + let _e449 = inTile[1u]; + phi_4056_ = (_e449 > 1f); + } + let _e452 = phi_4056_; + if _e452 { continue; } - let _e451 = candidate[2u]; - if (_e451 > 1f) { - let _e453 = which; - let _e454 = cascadeCount; - if (_e453 < (_e454 - 1i)) { + let _e454 = candidate[2u]; + if (_e454 > 1f) { + let _e456 = which; + let _e457 = cascadeCount; + if (_e456 < (_e457 - 1i)) { continue; } candidate[2u] = 1f; } - let _e459 = inTile[0u]; - let _e460 = which; - let _e463 = cascadeCount; - let _e467 = inTile[1u]; - uv_4 = vec2(((_e459 + f32(_e460)) / f32(_e463)), _e467); - let _e469 = candidate; - projected = _e469; - let _e470 = which; - cascade = _e470; - let _e471 = texelMetres; - cascadeTexel = _e471; - let _e474 = matrix[0][2u]; - let _e477 = matrix[1][2u]; - let _e480 = matrix[2][2u]; - cascadeDepth = (1f / max(length(vec3(_e474, _e477, _e480)), 0.000001f)); - let _e486 = (*s_4).n; - let _e489 = matrix[0][2u]; - let _e492 = matrix[1][2u]; - let _e495 = matrix[2][2u]; - let _e499 = cascadeDepth; - cosSlope = clamp((abs(dot(_e486, vec3(_e489, _e492, _e495))) * _e499), 0.1f, 1f); - let _e502 = texelMetres; - let _e503 = cosSlope; - let _e504 = cosSlope; - let _e510 = cosSlope; - let _e512 = cascadeDepth; - receiverSlope = (((_e502 * sqrt(max((1f - (_e503 * _e504)), 0f))) / _e510) / _e512); + let _e462 = inTile[0u]; + let _e463 = which; + let _e466 = cascadeCount; + let _e470 = inTile[1u]; + uv_4 = vec2(((_e462 + f32(_e463)) / f32(_e466)), _e470); + let _e472 = candidate; + projected = _e472; + let _e473 = which; + cascade = _e473; + let _e474 = texelMetres; + cascadeTexel = _e474; + let _e477 = matrix[0][2u]; + let _e480 = matrix[1][2u]; + let _e483 = matrix[2][2u]; + cascadeDepth = (1f / max(length(vec3(_e477, _e480, _e483)), 0.000001f)); + let _e489 = (*s_4).n; + let _e492 = matrix[0][2u]; + let _e495 = matrix[1][2u]; + let _e498 = matrix[2][2u]; + let _e502 = cascadeDepth; + cosSlope = clamp((abs(dot(_e489, vec3(_e492, _e495, _e498))) * _e502), 0.1f, 1f); + let _e505 = texelMetres; + let _e506 = cosSlope; + let _e507 = cosSlope; + let _e513 = cosSlope; + let _e515 = cascadeDepth; + receiverSlope = (((_e505 * sqrt(max((1f - (_e506 * _e507)), 0f))) / _e513) / _e515); found = true; break; } else { break; } continuing { - let _e514 = attempt; - attempt = (_e514 + 1i); + let _e517 = attempt; + attempt = (_e517 + 1i); } } - let _e516 = found; - if !(_e516) { + let _e519 = found; + if !(_e519) { return 1f; } - let _e518 = cascade; - if (_e518 == 0i) { - let _e522 = frag_info.shadow_bias[0u]; - local_11 = _e522; + let _e521 = cascade; + if (_e521 == 0i) { + let _e525 = frag_info.shadow_bias[0u]; + local_11 = _e525; } else { - let _e523 = cascade; - if (_e523 == 1i) { - let _e527 = frag_info.shadow_bias[1u]; - local_12 = _e527; - } else { - let _e530 = frag_info.shadow_bias[2u]; + let _e526 = cascade; + if (_e526 == 1i) { + let _e530 = frag_info.shadow_bias[1u]; local_12 = _e530; - } - let _e531 = local_12; - local_11 = _e531; - } - let _e532 = local_11; - bias = _e532; - let _e535 = frag_info.shadow_params[0u]; - let _e538 = frag_info.shadow_cascades[3u]; - texel_1 = vec2(_e535, _e538); - let _e540 = cascade; - let _e542 = cascadeCount; - let _e546 = texel_1; - tileLo = (vec2((f32(_e540) / f32(_e542)), 0f) + (_e546 * 0.5f)); - let _e549 = cascade; - let _e552 = cascadeCount; - let _e556 = texel_1; - tileHi = (vec2((f32((_e549 + 1i)) / f32(_e552)), 1f) - (_e556 * 0.5f)); - let _e561 = frag_info.shadow_bias[3u]; - if (_e561 > 0.5f) { - let _e563 = uv_4; - let _e564 = tileLo; - let _e565 = tileHi; - let _e567 = textureSampleLevel(shadow_texture_tex, shadow_texture_smp, clamp(_e563, _e564, _e565), 0f); - stored_2 = _e567; - let _e569 = stored_2[1u]; - let _e572 = stored_2[2u]; - let _e575 = stored_2[3u]; - through = clamp(vec3((1f - _e569), (1f - _e572), _e575), vec3(0f), vec3(4f)); - let _e580 = through; - let _e581 = strength_1; - light_transmittance = mix(vec3(1f, 1f, 1f), _e580, vec3(clamp(_e581, 0f, 1f))); - } - let _e587 = frag_info.ambient_ground[3u]; - softness = _e587; + } else { + let _e533 = frag_info.shadow_bias[2u]; + local_12 = _e533; + } + let _e534 = local_12; + local_11 = _e534; + } + let _e535 = local_11; + bias = _e535; + let _e538 = frag_info.shadow_params[0u]; + let _e541 = frag_info.shadow_cascades[3u]; + texel_1 = vec2(_e538, _e541); + let _e543 = cascade; + let _e545 = cascadeCount; + let _e549 = texel_1; + tileLo = (vec2((f32(_e543) / f32(_e545)), 0f) + (_e549 * 0.5f)); + let _e552 = cascade; + let _e555 = cascadeCount; + let _e559 = texel_1; + tileHi = (vec2((f32((_e552 + 1i)) / f32(_e555)), 1f) - (_e559 * 0.5f)); + let _e564 = frag_info.shadow_bias[3u]; + if (_e564 > 0.5f) { + stored_2 = vec4(0f, 0f, 0f, 0f); + y_1 = -1i; + loop { + let _e566 = y_1; + if (_e566 <= 1i) { + x_1 = -1i; + loop { + let _e568 = x_1; + if (_e568 <= 1i) { + let _e570 = uv_4; + let _e571 = x_1; + let _e573 = y_1; + let _e576 = texel_1; + let _e579 = tileLo; + let _e580 = tileHi; + let _e582 = textureSampleLevel(shadow_texture_tex, shadow_texture_smp, clamp((_e570 + (vec2(f32(_e571), f32(_e573)) * _e576)), _e579, _e580), 0f); + let _e583 = stored_2; + stored_2 = (_e583 + _e582); + continue; + } else { + break; + } + continuing { + let _e585 = x_1; + x_1 = (_e585 + 1i); + } + } + continue; + } else { + break; + } + continuing { + let _e587 = y_1; + y_1 = (_e587 + 1i); + } + } + let _e589 = stored_2; + stored_2 = (_e589 * 0.11111111f); + let _e592 = stored_2[1u]; + let _e595 = stored_2[2u]; + let _e598 = stored_2[3u]; + through = clamp(vec3((1f - _e592), (1f - _e595), _e598), vec3(0f), vec3(4f)); + let _e603 = through; + let _e604 = strength_1; + light_transmittance = mix(vec3(1f, 1f, 1f), _e603, vec3(clamp(_e604, 0f, 1f))); + } + let _e610 = frag_info.ambient_ground[3u]; + softness = _e610; lit_2 = 0f; - let _e588 = softness; - if (_e588 < 0f) { - let _e590 = uv_4; - let _e591 = tileLo; - let _e592 = tileHi; - let _e594 = textureSampleLevel(shadow_texture_tex, shadow_texture_smp, clamp(_e590, _e591, _e592), 0f); - moments_2 = _e594; - let _e596 = projected[2u]; - let _e597 = bias; - let _e599 = softness; - let _e603 = moments_2; - param_87 = _e603; - param_88 = (_e596 - _e597); - param_89 = clamp((-(_e599) - 1f), 0f, 0.95f); - let _e604 = EvsmVisibility_u0028_vf4_u003b_f1_u003b_f1_u003b((¶m_87), (¶m_88), (¶m_89)); - lit_2 = _e604; - } else { - let _e605 = softness; - if (_e605 <= 0f) { - y_1 = -1i; + let _e611 = softness; + if (_e611 < 0f) { + let _e613 = uv_4; + let _e614 = tileLo; + let _e615 = tileHi; + let _e617 = textureSampleLevel(shadow_texture_tex, shadow_texture_smp, clamp(_e613, _e614, _e615), 0f); + moments_2 = _e617; + let _e619 = projected[2u]; + let _e620 = bias; + let _e622 = softness; + let _e626 = moments_2; + param_87 = _e626; + param_88 = (_e619 - _e620); + param_89 = clamp((-(_e622) - 1f), 0f, 0.95f); + let _e627 = EvsmVisibility_u0028_vf4_u003b_f1_u003b_f1_u003b((¶m_87), (¶m_88), (¶m_89)); + lit_2 = _e627; + } else { + let _e628 = softness; + if (_e628 <= 0f) { + y_2 = -1i; loop { - let _e607 = y_1; - if (_e607 <= 1i) { - x_1 = -1i; + let _e630 = y_2; + if (_e630 <= 1i) { + x_2 = -1i; loop { - let _e609 = x_1; - if (_e609 <= 1i) { - let _e611 = uv_4; - let _e612 = x_1; - let _e614 = y_1; - let _e617 = texel_1; - let _e620 = tileLo; - let _e621 = tileHi; - let _e623 = textureSampleLevel(shadow_texture_tex, shadow_texture_smp, clamp((_e611 + (vec2(f32(_e612), f32(_e614)) * _e617)), _e620, _e621), 0f); - occluder = _e623.x; - let _e626 = projected[2u]; - let _e627 = bias; - let _e629 = occluder; - let _e632 = lit_2; - lit_2 = (_e632 + select(1f, 0f, ((_e626 - _e627) > _e629))); + let _e632 = x_2; + if (_e632 <= 1i) { + let _e634 = uv_4; + let _e635 = x_2; + let _e637 = y_2; + let _e640 = texel_1; + let _e643 = tileLo; + let _e644 = tileHi; + let _e646 = textureSampleLevel(shadow_texture_tex, shadow_texture_smp, clamp((_e634 + (vec2(f32(_e635), f32(_e637)) * _e640)), _e643, _e644), 0f); + occluder = _e646.x; + let _e649 = projected[2u]; + let _e650 = bias; + let _e652 = occluder; + let _e655 = lit_2; + lit_2 = (_e655 + select(1f, 0f, ((_e649 - _e650) > _e652))); continue; } else { break; } continuing { - let _e634 = x_1; - x_1 = (_e634 + 1i); + let _e657 = x_2; + x_2 = (_e657 + 1i); } } continue; @@ -15368,125 +15473,125 @@ fn ShadowFactor_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf break; } continuing { - let _e636 = y_1; - y_1 = (_e636 + 1i); + let _e659 = y_2; + y_2 = (_e659 + 1i); } } - let _e638 = lit_2; - lit_2 = (_e638 * 0.11111111f); + let _e661 = lit_2; + lit_2 = (_e661 * 0.11111111f); } else { - let _e640 = softness; - spread = tan(min(_e640, 0.5f)); - let _e643 = ShadowNoise_u0028_(); - turn_1 = (_e643 * 6.2831855f); - let _e645 = spread; - let _e647 = projected[2u]; - let _e649 = cascadeDepth; - let _e651 = cascadeTexel; - searchRadius = clamp((((_e645 * _e647) * _e649) / _e651), 1f, 16f); + let _e663 = softness; + spread = tan(min(_e663, 0.5f)); + let _e666 = ShadowNoise_u0028_(); + turn_1 = (_e666 * 6.2831855f); + let _e668 = spread; + let _e670 = projected[2u]; + let _e672 = cascadeDepth; + let _e674 = cascadeTexel; + searchRadius = clamp((((_e668 * _e670) * _e672) / _e674), 1f, 16f); blockerSum = 0f; blockerCount = 0f; i_5 = 0i; loop { - let _e654 = i_5; - if (_e654 < 16i) { - let _e656 = i_5; - param_90 = _e656; + let _e677 = i_5; + if (_e677 < 16i) { + let _e679 = i_5; + param_90 = _e679; param_91 = 16i; - let _e657 = turn_1; - param_92 = _e657; - let _e658 = VogelDisc_u0028_i1_u003b_i1_u003b_f1_u003b((¶m_90), (¶m_91), (¶m_92)); - disc = _e658; - let _e659 = bias; - let _e660 = disc; - let _e662 = searchRadius; - let _e666 = receiverSlope; - tapBias = (_e659 + (max(((length(_e660) * _e662) - 1.5f), 0f) * _e666)); - let _e669 = uv_4; - let _e670 = disc; - let _e671 = texel_1; - let _e673 = searchRadius; - let _e676 = tileLo; - let _e677 = tileHi; - let _e679 = textureSampleLevel(shadow_texture_tex, shadow_texture_smp, clamp((_e669 + ((_e670 * _e671) * _e673)), _e676, _e677), 0f); - occluder_1 = _e679.x; - let _e682 = projected[2u]; - let _e683 = tapBias; - let _e685 = occluder_1; - if ((_e682 - _e683) > _e685) { - let _e687 = occluder_1; - let _e688 = blockerSum; - blockerSum = (_e688 + _e687); - let _e690 = blockerCount; - blockerCount = (_e690 + 1f); + let _e680 = turn_1; + param_92 = _e680; + let _e681 = VogelDisc_u0028_i1_u003b_i1_u003b_f1_u003b((¶m_90), (¶m_91), (¶m_92)); + disc = _e681; + let _e682 = bias; + let _e683 = disc; + let _e685 = searchRadius; + let _e689 = receiverSlope; + tapBias = (_e682 + (max(((length(_e683) * _e685) - 1.5f), 0f) * _e689)); + let _e692 = uv_4; + let _e693 = disc; + let _e694 = texel_1; + let _e696 = searchRadius; + let _e699 = tileLo; + let _e700 = tileHi; + let _e702 = textureSampleLevel(shadow_texture_tex, shadow_texture_smp, clamp((_e692 + ((_e693 * _e694) * _e696)), _e699, _e700), 0f); + occluder_1 = _e702.x; + let _e705 = projected[2u]; + let _e706 = tapBias; + let _e708 = occluder_1; + if ((_e705 - _e706) > _e708) { + let _e710 = occluder_1; + let _e711 = blockerSum; + blockerSum = (_e711 + _e710); + let _e713 = blockerCount; + blockerCount = (_e713 + 1f); } continue; } else { break; } continuing { - let _e692 = i_5; - i_5 = (_e692 + 1i); + let _e715 = i_5; + i_5 = (_e715 + 1i); } } - let _e694 = blockerCount; - if (_e694 <= 0f) { + let _e717 = blockerCount; + if (_e717 <= 0f) { return 1f; } - let _e697 = projected[2u]; - let _e698 = blockerSum; - let _e699 = blockerCount; - let _e703 = cascadeDepth; - gap = (max((_e697 - (_e698 / _e699)), 0f) * _e703); - let _e705 = spread; - let _e706 = gap; - let _e708 = cascadeTexel; - radius_2 = clamp(((_e705 * _e706) / _e708), 1f, 16f); + let _e720 = projected[2u]; + let _e721 = blockerSum; + let _e722 = blockerCount; + let _e726 = cascadeDepth; + gap = (max((_e720 - (_e721 / _e722)), 0f) * _e726); + let _e728 = spread; + let _e729 = gap; + let _e731 = cascadeTexel; + radius_2 = clamp(((_e728 * _e729) / _e731), 1f, 16f); i_6 = 0i; loop { - let _e711 = i_6; - if (_e711 < 16i) { - let _e713 = turn_1; - let _e715 = i_6; - param_93 = _e715; + let _e734 = i_6; + if (_e734 < 16i) { + let _e736 = turn_1; + let _e738 = i_6; + param_93 = _e738; param_94 = 16i; - param_95 = (_e713 + 1f); - let _e716 = VogelDisc_u0028_i1_u003b_i1_u003b_f1_u003b((¶m_93), (¶m_94), (¶m_95)); - disc_1 = _e716; - let _e717 = bias; - let _e718 = disc_1; - let _e720 = radius_2; - let _e724 = receiverSlope; - tapBias_1 = (_e717 + (max(((length(_e718) * _e720) - 1.5f), 0f) * _e724)); - let _e727 = uv_4; - let _e728 = disc_1; - let _e729 = texel_1; - let _e731 = radius_2; - let _e734 = tileLo; - let _e735 = tileHi; - let _e737 = textureSampleLevel(shadow_texture_tex, shadow_texture_smp, clamp((_e727 + ((_e728 * _e729) * _e731)), _e734, _e735), 0f); - occluder_2 = _e737.x; - let _e740 = projected[2u]; - let _e741 = tapBias_1; - let _e743 = occluder_2; - let _e746 = lit_2; - lit_2 = (_e746 + select(1f, 0f, ((_e740 - _e741) > _e743))); + param_95 = (_e736 + 1f); + let _e739 = VogelDisc_u0028_i1_u003b_i1_u003b_f1_u003b((¶m_93), (¶m_94), (¶m_95)); + disc_1 = _e739; + let _e740 = bias; + let _e741 = disc_1; + let _e743 = radius_2; + let _e747 = receiverSlope; + tapBias_1 = (_e740 + (max(((length(_e741) * _e743) - 1.5f), 0f) * _e747)); + let _e750 = uv_4; + let _e751 = disc_1; + let _e752 = texel_1; + let _e754 = radius_2; + let _e757 = tileLo; + let _e758 = tileHi; + let _e760 = textureSampleLevel(shadow_texture_tex, shadow_texture_smp, clamp((_e750 + ((_e751 * _e752) * _e754)), _e757, _e758), 0f); + occluder_2 = _e760.x; + let _e763 = projected[2u]; + let _e764 = tapBias_1; + let _e766 = occluder_2; + let _e769 = lit_2; + lit_2 = (_e769 + select(1f, 0f, ((_e763 - _e764) > _e766))); continue; } else { break; } continuing { - let _e748 = i_6; - i_6 = (_e748 + 1i); + let _e771 = i_6; + i_6 = (_e771 + 1i); } } - let _e750 = lit_2; - lit_2 = (_e750 * 0.0625f); + let _e773 = lit_2; + lit_2 = (_e773 * 0.0625f); } } - let _e752 = lit_2; - let _e753 = strength_1; - return mix(1f, _e752, clamp(_e753, 0f, 1f)); + let _e775 = lit_2; + let _e776 = strength_1; + return mix(1f, _e775, clamp(_e776, 0f, 1f)); } fn LightVisibility_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_struct_u002d_LightSample_u002d_vf3_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf31_u003b_i1_u003b(s_5: ptr, light_2: ptr, index: ptr) -> f32 { @@ -15494,19 +15599,19 @@ fn LightVisibility_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d var param_97: LightSample; var param_98: i32; - let _e212 = (*s_5); - param_96 = _e212; - let _e213 = (*light_2); - param_97 = _e213; - let _e214 = (*index); - param_98 = _e214; - let _e215 = ShadowFactor_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_struct_u002d_LightSample_u002d_vf3_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf31_u003b_i1_u003b((¶m_96), (¶m_97), (¶m_98)); - return _e215; + let _e213 = (*s_5); + param_96 = _e213; + let _e214 = (*light_2); + param_97 = _e214; + let _e215 = (*index); + param_98 = _e215; + let _e216 = ShadowFactor_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_struct_u002d_LightSample_u002d_vf3_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf31_u003b_i1_u003b((¶m_96), (¶m_97), (¶m_98)); + return _e216; } fn LightHasShadow_u0028_i1_u003b(index_1: ptr) -> bool { - let _e207 = (*index_1); - return (_e207 < 8i); + let _e208 = (*index_1); + return (_e208 < 8i); } fn PunctualAttenuation_u0028_f1_u003b_f1_u003b(distance_1: ptr, range_4: ptr) -> f32 { @@ -15514,26 +15619,26 @@ fn PunctualAttenuation_u0028_f1_u003b_f1_u003b(distance_1: ptr, r var ratio: f32; var window: f32; - let _e211 = (*distance_1); let _e212 = (*distance_1); - attenuation = (1f / max((_e211 * _e212), 0.0001f)); - let _e216 = (*range_4); - if (_e216 > 0f) { - let _e218 = (*distance_1); - let _e219 = (*range_4); - ratio = (_e218 / _e219); - let _e221 = ratio; + let _e213 = (*distance_1); + attenuation = (1f / max((_e212 * _e213), 0.0001f)); + let _e217 = (*range_4); + if (_e217 > 0f) { + let _e219 = (*distance_1); + let _e220 = (*range_4); + ratio = (_e219 / _e220); let _e222 = ratio; - let _e224 = ratio; - let _e226 = ratio; - window = clamp((1f - (((_e221 * _e222) * _e224) * _e226)), 0f, 1f); - let _e230 = window; + let _e223 = ratio; + let _e225 = ratio; + let _e227 = ratio; + window = clamp((1f - (((_e222 * _e223) * _e225) * _e227)), 0f, 1f); let _e231 = window; - let _e233 = attenuation; - attenuation = (_e233 * (_e230 * _e231)); + let _e232 = window; + let _e234 = attenuation; + attenuation = (_e234 * (_e231 * _e232)); } - let _e235 = attenuation; - return _e235; + let _e236 = attenuation; + return _e236; } fn LtcEdge_u0028_vf3_u003b_vf3_u003b(a_2: ptr>, b: ptr>) -> vec3 { @@ -15542,25 +15647,25 @@ fn LtcEdge_u0028_vf3_u003b_vf3_u003b(a_2: ptr>, b: ptr; - let _e212 = (*a_2); - let _e213 = (*b); - axis = cross(_e212, _e213); - let _e215 = axis; - len = length(_e215); - let _e217 = (*a_2); - let _e218 = (*b); - angle_1 = acos(clamp(dot(_e217, _e218), -1f, 1f)); - let _e222 = len; - if (_e222 > 0.000001f) { - let _e224 = axis; - let _e225 = angle_1; - let _e226 = len; - local_13 = (_e224 * (_e225 / (_e226 * 6.2831855f))); + let _e213 = (*a_2); + let _e214 = (*b); + axis = cross(_e213, _e214); + let _e216 = axis; + len = length(_e216); + let _e218 = (*a_2); + let _e219 = (*b); + angle_1 = acos(clamp(dot(_e218, _e219), -1f, 1f)); + let _e223 = len; + if (_e223 > 0.000001f) { + let _e225 = axis; + let _e226 = angle_1; + let _e227 = len; + local_13 = (_e225 * (_e226 / (_e227 * 6.2831855f))); } else { local_13 = vec3(0f, 0f, 0f); } - let _e230 = local_13; - return _e230; + let _e231 = local_13; + return _e231; } fn LtcRectangle_u0028_vf3_u003b_vf3_u003b_f1_u003b_vf3_u005b_4_u005d_u003b(n_2: ptr>, v: ptr>, roughness_3: ptr, corners: ptr, 4>>) -> vec3 { @@ -15599,126 +15704,126 @@ fn LtcRectangle_u0028_vf3_u003b_vf3_u003b_f1_u003b_vf3_u005b_4_u005d_u003b(n_2: var param_114: f32; var param_115: f32; - let _e244 = (*roughness_3); - let _e246 = (*n_2); - let _e247 = (*v); - uv_5 = vec2(clamp(_e244, 0f, 1f), sqrt(clamp((1f - dot(_e246, _e247)), 0f, 1f))); - let _e254 = uv_5[0u]; - param_99 = _e254; - let _e256 = uv_5[1u]; - param_100 = _e256; + let _e245 = (*roughness_3); + let _e247 = (*n_2); + let _e248 = (*v); + uv_5 = vec2(clamp(_e245, 0f, 1f), sqrt(clamp((1f - dot(_e247, _e248)), 0f, 1f))); + let _e255 = uv_5[0u]; + param_99 = _e255; + let _e257 = uv_5[1u]; + param_100 = _e257; param_101 = 0f; - let _e257 = LtcUv_u0028_f1_u003b_f1_u003b_f1_u003b((¶m_99), (¶m_100), (¶m_101)); - let _e258 = textureSampleLevel(ltc_texture_tex, ltc_texture_smp, _e257, 0f); - inverse = _e258; - let _e260 = uv_5[0u]; - param_102 = _e260; - let _e262 = uv_5[1u]; - param_103 = _e262; + let _e258 = LtcUv_u0028_f1_u003b_f1_u003b_f1_u003b((¶m_99), (¶m_100), (¶m_101)); + let _e259 = textureSampleLevel(ltc_texture_tex, ltc_texture_smp, _e258, 0f); + inverse = _e259; + let _e261 = uv_5[0u]; + param_102 = _e261; + let _e263 = uv_5[1u]; + param_103 = _e263; param_104 = 1f; - let _e263 = LtcUv_u0028_f1_u003b_f1_u003b_f1_u003b((¶m_102), (¶m_103), (¶m_104)); - let _e264 = textureSampleLevel(ltc_texture_tex, ltc_texture_smp, _e263, 0f); - fit = _e264; - let _e265 = (*v); - let _e266 = (*n_2); - let _e267 = (*v); - let _e268 = (*n_2); - along = (_e265 - (_e266 * dot(_e267, _e268))); - let _e272 = along; - alongLength = length(_e272); - let _e274 = alongLength; - if (_e274 > 0.00001f) { - let _e276 = along; - let _e277 = alongLength; - local_14 = (_e276 / vec3(_e277)); - } else { - let _e280 = (*n_2); - let _e282 = (*n_2)[2u]; - local_14 = normalize(cross(_e280, select(vec3(1f, 0f, 0f), vec3(0f, 0f, 1f), vec3((abs(_e282) < 0.999f))))); - } - let _e289 = local_14; - t1_ = _e289; - let _e290 = (*n_2); - let _e291 = t1_; - t2_ = cross(_e290, _e291); - let _e294 = inverse[0u]; - let _e296 = inverse[1u]; - let _e297 = vec3(_e294, 0f, _e296); - let _e299 = inverse[2u]; - let _e301 = inverse[3u]; - let _e302 = vec3(_e299, 0f, _e301); - minv = mat3x3(vec3(_e297.x, _e297.y, _e297.z), vec3(vec3(0f, 1f, 0f).x, vec3(0f, 1f, 0f).y, vec3(0f, 1f, 0f).z), vec3(_e302.x, _e302.y, _e302.z)); + let _e264 = LtcUv_u0028_f1_u003b_f1_u003b_f1_u003b((¶m_102), (¶m_103), (¶m_104)); + let _e265 = textureSampleLevel(ltc_texture_tex, ltc_texture_smp, _e264, 0f); + fit = _e265; + let _e266 = (*v); + let _e267 = (*n_2); + let _e268 = (*v); + let _e269 = (*n_2); + along = (_e266 - (_e267 * dot(_e268, _e269))); + let _e273 = along; + alongLength = length(_e273); + let _e275 = alongLength; + if (_e275 > 0.00001f) { + let _e277 = along; + let _e278 = alongLength; + local_14 = (_e277 / vec3(_e278)); + } else { + let _e281 = (*n_2); + let _e283 = (*n_2)[2u]; + local_14 = normalize(cross(_e281, select(vec3(1f, 0f, 0f), vec3(0f, 0f, 1f), vec3((abs(_e283) < 0.999f))))); + } + let _e290 = local_14; + t1_ = _e290; + let _e291 = (*n_2); + let _e292 = t1_; + t2_ = cross(_e291, _e292); + let _e295 = inverse[0u]; + let _e297 = inverse[1u]; + let _e298 = vec3(_e295, 0f, _e297); + let _e300 = inverse[2u]; + let _e302 = inverse[3u]; + let _e303 = vec3(_e300, 0f, _e302); + minv = mat3x3(vec3(_e298.x, _e298.y, _e298.z), vec3(vec3(0f, 1f, 0f).x, vec3(0f, 1f, 0f).y, vec3(0f, 1f, 0f).z), vec3(_e303.x, _e303.y, _e303.z)); i_7 = 0i; loop { - let _e316 = i_7; - if (_e316 < 4i) { - let _e318 = i_7; - let _e320 = (*corners)[_e318]; - p_1 = _e320; - let _e321 = i_7; - let _e322 = minv; - let _e323 = p_1; - let _e324 = t1_; - let _e326 = p_1; - let _e327 = t2_; - let _e329 = p_1; - let _e330 = (*n_2); - l[_e321] = normalize((_e322 * vec3(dot(_e323, _e324), dot(_e326, _e327), dot(_e329, _e330)))); + let _e317 = i_7; + if (_e317 < 4i) { + let _e319 = i_7; + let _e321 = (*corners)[_e319]; + p_1 = _e321; + let _e322 = i_7; + let _e323 = minv; + let _e324 = p_1; + let _e325 = t1_; + let _e327 = p_1; + let _e328 = t2_; + let _e330 = p_1; + let _e331 = (*n_2); + l[_e322] = normalize((_e323 * vec3(dot(_e324, _e325), dot(_e327, _e328), dot(_e330, _e331)))); continue; } else { break; } continuing { - let _e336 = i_7; - i_7 = (_e336 + 1i); - } - } - let _e339 = l[0i]; - param_105 = _e339; - let _e341 = l[1i]; - param_106 = _e341; - let _e342 = LtcEdge_u0028_vf3_u003b_vf3_u003b((¶m_105), (¶m_106)); - let _e344 = l[1i]; - param_107 = _e344; - let _e346 = l[2i]; - param_108 = _e346; - let _e347 = LtcEdge_u0028_vf3_u003b_vf3_u003b((¶m_107), (¶m_108)); - let _e350 = l[2i]; - param_109 = _e350; - let _e352 = l[3i]; - param_110 = _e352; - let _e353 = LtcEdge_u0028_vf3_u003b_vf3_u003b((¶m_109), (¶m_110)); - let _e356 = l[3i]; - param_111 = _e356; - let _e358 = l[0i]; - param_112 = _e358; - let _e359 = LtcEdge_u0028_vf3_u003b_vf3_u003b((¶m_111), (¶m_112)); - f_2 = -((((_e342 + _e347) + _e353) + _e359)); - let _e362 = f_2; - len_1 = length(_e362); - let _e364 = len_1; - if (_e364 > 0.000000001f) { - let _e367 = f_2[2u]; - let _e368 = len_1; - local_15 = (_e367 / _e368); + let _e337 = i_7; + i_7 = (_e337 + 1i); + } + } + let _e340 = l[0i]; + param_105 = _e340; + let _e342 = l[1i]; + param_106 = _e342; + let _e343 = LtcEdge_u0028_vf3_u003b_vf3_u003b((¶m_105), (¶m_106)); + let _e345 = l[1i]; + param_107 = _e345; + let _e347 = l[2i]; + param_108 = _e347; + let _e348 = LtcEdge_u0028_vf3_u003b_vf3_u003b((¶m_107), (¶m_108)); + let _e351 = l[2i]; + param_109 = _e351; + let _e353 = l[3i]; + param_110 = _e353; + let _e354 = LtcEdge_u0028_vf3_u003b_vf3_u003b((¶m_109), (¶m_110)); + let _e357 = l[3i]; + param_111 = _e357; + let _e359 = l[0i]; + param_112 = _e359; + let _e360 = LtcEdge_u0028_vf3_u003b_vf3_u003b((¶m_111), (¶m_112)); + f_2 = -((((_e343 + _e348) + _e354) + _e360)); + let _e363 = f_2; + len_1 = length(_e363); + let _e365 = len_1; + if (_e365 > 0.000000001f) { + let _e368 = f_2[2u]; + let _e369 = len_1; + local_15 = (_e368 / _e369); } else { local_15 = 0f; } - let _e370 = local_15; - z_1 = _e370; - let _e371 = z_1; - let _e374 = len_1; - param_113 = ((_e371 * 0.5f) + 0.5f); - param_114 = clamp(_e374, 0f, 1f); + let _e371 = local_15; + z_1 = _e371; + let _e372 = z_1; + let _e375 = len_1; + param_113 = ((_e372 * 0.5f) + 0.5f); + param_114 = clamp(_e375, 0f, 1f); param_115 = 1f; - let _e376 = LtcUv_u0028_f1_u003b_f1_u003b_f1_u003b((¶m_113), (¶m_114), (¶m_115)); - let _e377 = textureSampleLevel(ltc_texture_tex, ltc_texture_smp, _e376, 0f); - sphere = _e377.w; - let _e379 = len_1; - let _e380 = sphere; - let _e384 = fit[0u]; - let _e386 = fit[1u]; - return vec3(max((_e379 * _e380), 0f), _e384, _e386); + let _e377 = LtcUv_u0028_f1_u003b_f1_u003b_f1_u003b((¶m_113), (¶m_114), (¶m_115)); + let _e378 = textureSampleLevel(ltc_texture_tex, ltc_texture_smp, _e377, 0f); + sphere = _e378.w; + let _e380 = len_1; + let _e381 = sphere; + let _e385 = fit[0u]; + let _e387 = fit[1u]; + return vec3(max((_e380 * _e381), 0f), _e385, _e387); } fn RectangleClosestPoint_u0028_vf3_u003b_vf3_u003b_vf3_u003b_vf3_u003b_vf3_u003b(centre: ptr>, halfWidth: ptr>, halfHeight: ptr>, world_2: ptr>, mirror: ptr>) -> vec3 { @@ -15735,75 +15840,75 @@ fn RectangleClosestPoint_u0028_vf3_u003b_vf3_u003b_vf3_u003b_vf3_u003b_vf3_u003b var u: f32; var v_1: f32; - let _e223 = (*halfWidth); - let _e224 = (*halfHeight); - n_3 = cross(_e223, _e224); - let _e226 = n_3; - nLen = length(_e226); - let _e228 = nLen; - if (_e228 < 0.000000000001f) { - let _e230 = (*centre); - return _e230; - } - let _e231 = nLen; - let _e232 = n_3; - n_3 = (_e232 / vec3(_e231)); - let _e235 = (*centre); - let _e236 = (*world_2); - toPlane = (_e235 - _e236); - let _e238 = (*mirror); - let _e239 = n_3; - denom = dot(_e238, _e239); - let _e241 = denom; - if (abs(_e241) < 0.00001f) { - let _e244 = toPlane; - let _e245 = n_3; - let _e246 = toPlane; - let _e247 = n_3; - onPlane = (_e244 - (_e245 * dot(_e246, _e247))); - } else { - let _e251 = toPlane; - let _e252 = n_3; - let _e254 = denom; - t_1 = (dot(_e251, _e252) / _e254); - let _e256 = t_1; - if (_e256 > 0f) { - let _e258 = (*mirror); - let _e259 = t_1; - local_16 = (_e258 * _e259); + let _e224 = (*halfWidth); + let _e225 = (*halfHeight); + n_3 = cross(_e224, _e225); + let _e227 = n_3; + nLen = length(_e227); + let _e229 = nLen; + if (_e229 < 0.000000000001f) { + let _e231 = (*centre); + return _e231; + } + let _e232 = nLen; + let _e233 = n_3; + n_3 = (_e233 / vec3(_e232)); + let _e236 = (*centre); + let _e237 = (*world_2); + toPlane = (_e236 - _e237); + let _e239 = (*mirror); + let _e240 = n_3; + denom = dot(_e239, _e240); + let _e242 = denom; + if (abs(_e242) < 0.00001f) { + let _e245 = toPlane; + let _e246 = n_3; + let _e247 = toPlane; + let _e248 = n_3; + onPlane = (_e245 - (_e246 * dot(_e247, _e248))); + } else { + let _e252 = toPlane; + let _e253 = n_3; + let _e255 = denom; + t_1 = (dot(_e252, _e253) / _e255); + let _e257 = t_1; + if (_e257 > 0f) { + let _e259 = (*mirror); + let _e260 = t_1; + local_16 = (_e259 * _e260); } else { - let _e261 = toPlane; - let _e262 = n_3; - let _e263 = toPlane; - let _e264 = n_3; - local_16 = (_e261 - (_e262 * dot(_e263, _e264))); - } - let _e268 = local_16; - onPlane = _e268; - } - let _e269 = onPlane; - let _e270 = toPlane; - offset_2 = (_e269 - _e270); - let _e272 = (*halfWidth); + let _e262 = toPlane; + let _e263 = n_3; + let _e264 = toPlane; + let _e265 = n_3; + local_16 = (_e262 - (_e263 * dot(_e264, _e265))); + } + let _e269 = local_16; + onPlane = _e269; + } + let _e270 = onPlane; + let _e271 = toPlane; + offset_2 = (_e270 - _e271); let _e273 = (*halfWidth); - wLen2_ = max(dot(_e272, _e273), 0.000000000001f); - let _e276 = (*halfHeight); + let _e274 = (*halfWidth); + wLen2_ = max(dot(_e273, _e274), 0.000000000001f); let _e277 = (*halfHeight); - hLen2_ = max(dot(_e276, _e277), 0.000000000001f); - let _e280 = offset_2; - let _e281 = (*halfWidth); - let _e283 = wLen2_; - u = clamp((dot(_e280, _e281) / _e283), -1f, 1f); - let _e286 = offset_2; - let _e287 = (*halfHeight); - let _e289 = hLen2_; - v_1 = clamp((dot(_e286, _e287) / _e289), -1f, 1f); - let _e292 = (*centre); - let _e293 = (*halfWidth); - let _e294 = u; - let _e297 = (*halfHeight); - let _e298 = v_1; - return ((_e292 + (_e293 * _e294)) + (_e297 * _e298)); + let _e278 = (*halfHeight); + hLen2_ = max(dot(_e277, _e278), 0.000000000001f); + let _e281 = offset_2; + let _e282 = (*halfWidth); + let _e284 = wLen2_; + u = clamp((dot(_e281, _e282) / _e284), -1f, 1f); + let _e287 = offset_2; + let _e288 = (*halfHeight); + let _e290 = hLen2_; + v_1 = clamp((dot(_e287, _e288) / _e290), -1f, 1f); + let _e293 = (*centre); + let _e294 = (*halfWidth); + let _e295 = u; + let _e298 = (*halfHeight); + let _e299 = v_1; + return ((_e293 + (_e294 * _e295)) + (_e298 * _e299)); } fn LambertEdge_u0028_vf3_u003b_vf3_u003b_vf3_u003b(a_3: ptr>, b_1: ptr>, n_4: ptr>) -> f32 { @@ -15814,32 +15919,32 @@ fn LambertEdge_u0028_vf3_u003b_vf3_u003b_vf3_u003b(a_3: ptr> var len_2: f32; var local_17: f32; - let _e215 = (*a_3); let _e216 = (*a_3); - ua = (_e215 / vec3(max(length(_e216), 0.000000000001f))); - let _e221 = (*b_1); + let _e217 = (*a_3); + ua = (_e216 / vec3(max(length(_e217), 0.000000000001f))); let _e222 = (*b_1); - ub = (_e221 / vec3(max(length(_e222), 0.000000000001f))); - let _e227 = ua; - let _e228 = ub; - angle_2 = acos(clamp(dot(_e227, _e228), -1f, 1f)); - let _e232 = ua; - let _e233 = ub; - axis_1 = cross(_e232, _e233); - let _e235 = axis_1; - len_2 = length(_e235); - let _e237 = len_2; - if (_e237 > 0.000001f) { - let _e239 = angle_2; - let _e240 = axis_1; - let _e241 = (*n_4); - let _e244 = len_2; - local_17 = ((_e239 * dot(_e240, _e241)) / _e244); + let _e223 = (*b_1); + ub = (_e222 / vec3(max(length(_e223), 0.000000000001f))); + let _e228 = ua; + let _e229 = ub; + angle_2 = acos(clamp(dot(_e228, _e229), -1f, 1f)); + let _e233 = ua; + let _e234 = ub; + axis_1 = cross(_e233, _e234); + let _e236 = axis_1; + len_2 = length(_e236); + let _e238 = len_2; + if (_e238 > 0.000001f) { + let _e240 = angle_2; + let _e241 = axis_1; + let _e242 = (*n_4); + let _e245 = len_2; + local_17 = ((_e240 * dot(_e241, _e242)) / _e245); } else { local_17 = 0f; } - let _e246 = local_17; - return _e246; + let _e247 = local_17; + return _e247; } fn RectangleFormFactor_u0028_vf3_u005b_4_u005d_u003b_vf3_u003b(corners_1: ptr, 4>>, n_5: ptr>) -> f32 { @@ -15870,98 +15975,98 @@ fn RectangleFormFactor_u0028_vf3_u005b_4_u005d_u003b_vf3_u003b(corners_1: ptr(0f, 0f, 0f); i_8 = 0i; loop { - let _e229 = i_8; - if (_e229 < 4i) { - let _e231 = i_8; - let _e233 = (*corners_1)[_e231]; - a_4 = _e233; - let _e234 = i_8; - if (_e234 == 3i) { + let _e230 = i_8; + if (_e230 < 4i) { + let _e232 = i_8; + let _e234 = (*corners_1)[_e232]; + a_4 = _e234; + let _e235 = i_8; + if (_e235 == 3i) { local_18 = 0i; } else { - let _e236 = i_8; - local_18 = (_e236 + 1i); - } - let _e238 = local_18; - let _e240 = (*corners_1)[_e238]; - b_2 = _e240; - let _e241 = a_4; - let _e242 = (*n_5); - ha = dot(_e241, _e242); - let _e244 = b_2; - let _e245 = (*n_5); - hb = dot(_e244, _e245); - let _e247 = ha; - let _e248 = hb; - d_4 = (_e247 - _e248); - let _e250 = a_4; - let _e251 = b_2; - let _e252 = a_4; - let _e254 = d_4; - if (abs(_e254) > 0.000000000001f) { - let _e257 = ha; - let _e258 = d_4; - local_19 = (_e257 / _e258); + let _e237 = i_8; + local_18 = (_e237 + 1i); + } + let _e239 = local_18; + let _e241 = (*corners_1)[_e239]; + b_2 = _e241; + let _e242 = a_4; + let _e243 = (*n_5); + ha = dot(_e242, _e243); + let _e245 = b_2; + let _e246 = (*n_5); + hb = dot(_e245, _e246); + let _e248 = ha; + let _e249 = hb; + d_4 = (_e248 - _e249); + let _e251 = a_4; + let _e252 = b_2; + let _e253 = a_4; + let _e255 = d_4; + if (abs(_e255) > 0.000000000001f) { + let _e258 = ha; + let _e259 = d_4; + local_19 = (_e258 / _e259); } else { local_19 = 0f; } - let _e260 = local_19; - q = (_e250 + ((_e251 - _e252) * _e260)); - let _e263 = ha; - aAbove = (_e263 > 0f); - let _e265 = hb; - bAbove = (_e265 > 0f); - let _e267 = aAbove; - let _e268 = bAbove; - if (_e267 || _e268) { - let _e270 = aAbove; - let _e271 = a_4; - let _e272 = q; - let _e275 = bAbove; - let _e276 = b_2; - let _e277 = q; - param_116 = select(_e272, _e271, vec3(_e270)); - param_117 = select(_e277, _e276, vec3(_e275)); - let _e280 = (*n_5); - param_118 = _e280; - let _e281 = LambertEdge_u0028_vf3_u003b_vf3_u003b_vf3_u003b((¶m_116), (¶m_117), (¶m_118)); - local_20 = _e281; + let _e261 = local_19; + q = (_e251 + ((_e252 - _e253) * _e261)); + let _e264 = ha; + aAbove = (_e264 > 0f); + let _e266 = hb; + bAbove = (_e266 > 0f); + let _e268 = aAbove; + let _e269 = bAbove; + if (_e268 || _e269) { + let _e271 = aAbove; + let _e272 = a_4; + let _e273 = q; + let _e276 = bAbove; + let _e277 = b_2; + let _e278 = q; + param_116 = select(_e273, _e272, vec3(_e271)); + param_117 = select(_e278, _e277, vec3(_e276)); + let _e281 = (*n_5); + param_118 = _e281; + let _e282 = LambertEdge_u0028_vf3_u003b_vf3_u003b_vf3_u003b((¶m_116), (¶m_117), (¶m_118)); + local_20 = _e282; } else { local_20 = 0f; } - let _e282 = local_20; - let _e283 = total; - total = (_e283 + _e282); - let _e285 = aAbove; - let _e286 = bAbove; - let _e289 = q; - let _e290 = exit; - exit = select(_e290, _e289, vec3((_e285 && !(_e286)))); - let _e293 = aAbove; - let _e295 = bAbove; - let _e297 = q; - let _e298 = entry; - entry = select(_e298, _e297, vec3((!(_e293) && _e295))); + let _e283 = local_20; + let _e284 = total; + total = (_e284 + _e283); + let _e286 = aAbove; + let _e287 = bAbove; + let _e290 = q; + let _e291 = exit; + exit = select(_e291, _e290, vec3((_e286 && !(_e287)))); + let _e294 = aAbove; + let _e296 = bAbove; + let _e298 = q; + let _e299 = entry; + entry = select(_e299, _e298, vec3((!(_e294) && _e296))); continue; } else { break; } continuing { - let _e301 = i_8; - i_8 = (_e301 + 1i); + let _e302 = i_8; + i_8 = (_e302 + 1i); } } - let _e303 = exit; - param_119 = _e303; - let _e304 = entry; - param_120 = _e304; - let _e305 = (*n_5); - param_121 = _e305; - let _e306 = LambertEdge_u0028_vf3_u003b_vf3_u003b_vf3_u003b((¶m_119), (¶m_120), (¶m_121)); - let _e307 = total; - total = (_e307 + _e306); - let _e309 = total; - return max((-(_e309) * 0.5f), 0f); + let _e304 = exit; + param_119 = _e304; + let _e305 = entry; + param_120 = _e305; + let _e306 = (*n_5); + param_121 = _e306; + let _e307 = LambertEdge_u0028_vf3_u003b_vf3_u003b_vf3_u003b((¶m_119), (¶m_120), (¶m_121)); + let _e308 = total; + total = (_e308 + _e307); + let _e310 = total; + return max((-(_e310) * 0.5f), 0f); } fn LightListLane_u0028_vf4_u003b_i1_u003b(four: ptr>, slot_1: ptr) -> f32 { @@ -15970,91 +16075,91 @@ fn LightListLane_u0028_vf4_u003b_i1_u003b(four: ptr>, slot_1 var local_22: f32; var local_23: f32; - let _e212 = (*slot_1); let _e213 = (*slot_1); - lane = (_e212 - ((_e213 / 4i) * 4i)); - let _e217 = lane; - if (_e217 == 0i) { - let _e220 = (*four)[0u]; - local_21 = _e220; - } else { - let _e221 = lane; - if (_e221 == 1i) { - let _e224 = (*four)[1u]; - local_22 = _e224; + let _e214 = (*slot_1); + lane = (_e213 - ((_e214 / 4i) * 4i)); + let _e218 = lane; + if (_e218 == 0i) { + let _e221 = (*four)[0u]; + local_21 = _e221; + } else { + let _e222 = lane; + if (_e222 == 1i) { + let _e225 = (*four)[1u]; + local_22 = _e225; } else { - let _e225 = lane; - if (_e225 == 2i) { - let _e228 = (*four)[2u]; - local_23 = _e228; + let _e226 = lane; + if (_e226 == 2i) { + let _e229 = (*four)[2u]; + local_23 = _e229; } else { - let _e230 = (*four)[3u]; - local_23 = _e230; + let _e231 = (*four)[3u]; + local_23 = _e231; } - let _e231 = local_23; - local_22 = _e231; + let _e232 = local_23; + local_22 = _e232; } - let _e232 = local_22; - local_21 = _e232; + let _e233 = local_22; + local_21 = _e233; } - let _e233 = local_21; - return _e233; + let _e234 = local_21; + return _e234; } fn LightListScale_u0028_i1_u003b(slot_2: ptr) -> f32 { var param_122: vec4; var param_123: i32; - let _e209 = (*slot_2); - let _e213 = light_list_info.scales[(_e209 / 4i)]; - param_122 = _e213; - let _e214 = (*slot_2); - param_123 = _e214; - let _e215 = LightListLane_u0028_vf4_u003b_i1_u003b((¶m_122), (¶m_123)); - return _e215; + let _e210 = (*slot_2); + let _e214 = light_list_info.scales[(_e210 / 4i)]; + param_122 = _e214; + let _e215 = (*slot_2); + param_123 = _e215; + let _e216 = LightListLane_u0028_vf4_u003b_i1_u003b((¶m_122), (¶m_123)); + return _e216; } fn InSlots_u0028_f1_u003b(row: ptr) -> bool { var a_5: vec4; var b_3: vec4; - let _e211 = light_list_info.slot_rows[0i]; - let _e212 = (*row); - a_5 = abs((_e211 - vec4(_e212))); - let _e218 = light_list_info.slot_rows[1i]; - let _e219 = (*row); - b_3 = abs((_e218 - vec4(_e219))); - let _e224 = a_5[0u]; - let _e226 = a_5[1u]; - let _e229 = a_5[2u]; - let _e231 = a_5[3u]; - let _e235 = b_3[0u]; - let _e237 = b_3[1u]; - let _e240 = b_3[2u]; - let _e242 = b_3[3u]; - return (min(min(min(_e224, _e226), min(_e229, _e231)), min(min(_e235, _e237), min(_e240, _e242))) < 0.5f); + let _e212 = light_list_info.slot_rows[0i]; + let _e213 = (*row); + a_5 = abs((_e212 - vec4(_e213))); + let _e219 = light_list_info.slot_rows[1i]; + let _e220 = (*row); + b_3 = abs((_e219 - vec4(_e220))); + let _e225 = a_5[0u]; + let _e227 = a_5[1u]; + let _e230 = a_5[2u]; + let _e232 = a_5[3u]; + let _e236 = b_3[0u]; + let _e238 = b_3[1u]; + let _e241 = b_3[2u]; + let _e243 = b_3[3u]; + return (min(min(min(_e225, _e227), min(_e230, _e232)), min(min(_e236, _e238), min(_e241, _e243))) < 0.5f); } fn LightListRow_u0028_i1_u003b(slot_3: ptr) -> f32 { var param_124: vec4; var param_125: i32; - let _e209 = (*slot_3); - let _e213 = light_list_info.indices[(_e209 / 4i)]; - param_124 = _e213; - let _e214 = (*slot_3); - param_125 = _e214; - let _e215 = LightListLane_u0028_vf4_u003b_i1_u003b((¶m_124), (¶m_125)); - return _e215; + let _e210 = (*slot_3); + let _e214 = light_list_info.indices[(_e210 / 4i)]; + param_124 = _e214; + let _e215 = (*slot_3); + param_125 = _e215; + let _e216 = LightListLane_u0028_vf4_u003b_i1_u003b((¶m_124), (¶m_125)); + return _e216; } fn LightListTexel_u0028_f1_u003b_f1_u003b(texel_2: ptr, row_1: ptr) -> vec4 { - let _e208 = (*texel_2); - let _e212 = light_list_info.list[1u]; - let _e214 = (*row_1); - let _e218 = light_list_info.list[2u]; - let _e221 = textureSampleLevel(light_list_texture_tex, light_list_texture_smp, vec2(((_e208 + 0.5f) * _e212), ((_e214 + 0.5f) * _e218)), 0f); - return _e221; + let _e209 = (*texel_2); + let _e213 = light_list_info.list[1u]; + let _e215 = (*row_1); + let _e219 = light_list_info.list[2u]; + let _e222 = textureSampleLevel(light_list_texture_tex, light_list_texture_smp, vec2(((_e209 + 0.5f) * _e213), ((_e215 + 0.5f) * _e219)), 0f); + return _e222; } fn ClusterRow_u0028_i1_u003b(slot_4: ptr) -> f32 { @@ -16068,35 +16173,35 @@ fn ClusterRow_u0028_i1_u003b(slot_4: ptr) -> f32 { var param_128: vec4; var param_129: i32; - let _e216 = g_cluster_offset; - let _e217 = (*slot_4); - entry_1 = (_e216 + f32(_e217)); - let _e220 = entry_1; - row_2 = floor((_e220 / 16f)); - let _e223 = entry_1; - let _e224 = row_2; - within = (_e223 - (_e224 * 16f)); - let _e227 = within; - texel_3 = floor((_e227 / 4f)); - let _e232 = light_list_info.cluster_depth[3u]; - let _e233 = row_2; - let _e235 = texel_3; - param_126 = _e235; - param_127 = (_e232 + _e233); - let _e236 = LightListTexel_u0028_f1_u003b_f1_u003b((¶m_126), (¶m_127)); - four_1 = _e236; - let _e237 = within; - let _e238 = texel_3; - let _e243 = four_1; - param_128 = _e243; - param_129 = i32(((_e237 - (_e238 * 4f)) + 0.5f)); - let _e244 = LightListLane_u0028_vf4_u003b_i1_u003b((¶m_128), (¶m_129)); - return _e244; + let _e217 = g_cluster_offset; + let _e218 = (*slot_4); + entry_1 = (_e217 + f32(_e218)); + let _e221 = entry_1; + row_2 = floor((_e221 / 16f)); + let _e224 = entry_1; + let _e225 = row_2; + within = (_e224 - (_e225 * 16f)); + let _e228 = within; + texel_3 = floor((_e228 / 4f)); + let _e233 = light_list_info.cluster_depth[3u]; + let _e234 = row_2; + let _e236 = texel_3; + param_126 = _e236; + param_127 = (_e233 + _e234); + let _e237 = LightListTexel_u0028_f1_u003b_f1_u003b((¶m_126), (¶m_127)); + four_1 = _e237; + let _e238 = within; + let _e239 = texel_3; + let _e244 = four_1; + param_128 = _e244; + param_129 = i32(((_e238 - (_e239 * 4f)) + 0.5f)); + let _e245 = LightListLane_u0028_vf4_u003b_i1_u003b((¶m_128), (¶m_129)); + return _e245; } fn Clustered_u0028_() -> bool { - let _e208 = light_list_info.cluster_grid[3u]; - return (_e208 > 0.5f); + let _e209 = light_list_info.cluster_grid[3u]; + return (_e209 > 0.5f); } fn SampleLight_u0028_i1_u003b_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b(index_2: ptr, s_6: ptr) -> LightSample { @@ -16156,275 +16261,275 @@ fn SampleLight_u0028_i1_u003b_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_ light_3.integrated = 0f; light_3.ltc = vec3(0f, 0f, 0f); - let _e263 = (*index_2); - if (_e263 < 8i) { - let _e265 = (*index_2); - let _e268 = frag_info.light_position[_e265]; - position = _e268; - let _e269 = (*index_2); - let _e272 = frag_info.light_color[_e269]; - color_1 = _e272; - let _e273 = (*index_2); - let _e276 = frag_info.light_direction[_e273]; - direction = _e276; - let _e277 = (*index_2); - let _e280 = frag_info.light_cone[_e277]; - cone = _e280; - } else { - let _e281 = (*index_2); - slot_5 = (_e281 - 8i); - let _e283 = Clustered_u0028_(); - clustered = _e283; - let _e284 = clustered; - if _e284 { - let _e285 = slot_5; - param_130 = _e285; - let _e286 = ClusterRow_u0028_i1_u003b((¶m_130)); - local_24 = _e286; + let _e264 = (*index_2); + if (_e264 < 8i) { + let _e266 = (*index_2); + let _e269 = frag_info.light_position[_e266]; + position = _e269; + let _e270 = (*index_2); + let _e273 = frag_info.light_color[_e270]; + color_1 = _e273; + let _e274 = (*index_2); + let _e277 = frag_info.light_direction[_e274]; + direction = _e277; + let _e278 = (*index_2); + let _e281 = frag_info.light_cone[_e278]; + cone = _e281; + } else { + let _e282 = (*index_2); + slot_5 = (_e282 - 8i); + let _e284 = Clustered_u0028_(); + clustered = _e284; + let _e285 = clustered; + if _e285 { + let _e286 = slot_5; + param_130 = _e286; + let _e287 = ClusterRow_u0028_i1_u003b((¶m_130)); + local_24 = _e287; } else { - let _e287 = slot_5; - param_131 = _e287; - let _e288 = LightListRow_u0028_i1_u003b((¶m_131)); - local_24 = _e288; - } - let _e289 = local_24; - listRow = _e289; - let _e290 = listRow; - let _e294 = light_list_info.list[2u]; - v_2 = ((_e290 + 0.5f) * _e294); - let _e298 = light_list_info.list[1u]; - u_1 = _e298; - let _e299 = u_1; - let _e301 = v_2; - let _e303 = textureSampleLevel(light_list_texture_tex, light_list_texture_smp, vec2((0.5f * _e299), _e301), 0f); - position = _e303; - let _e304 = u_1; - let _e306 = v_2; - let _e308 = textureSampleLevel(light_list_texture_tex, light_list_texture_smp, vec2((1.5f * _e304), _e306), 0f); - color_1 = _e308; - let _e309 = u_1; - let _e311 = v_2; - let _e313 = textureSampleLevel(light_list_texture_tex, light_list_texture_smp, vec2((2.5f * _e309), _e311), 0f); - direction = _e313; - let _e314 = u_1; - let _e316 = v_2; - let _e318 = textureSampleLevel(light_list_texture_tex, light_list_texture_smp, vec2((3.5f * _e314), _e316), 0f); - cone = _e318; - let _e319 = clustered; - if _e319 { - let _e320 = listRow; - param_132 = _e320; - let _e321 = InSlots_u0028_f1_u003b((¶m_132)); - local_25 = select(1f, 0f, _e321); + let _e288 = slot_5; + param_131 = _e288; + let _e289 = LightListRow_u0028_i1_u003b((¶m_131)); + local_24 = _e289; + } + let _e290 = local_24; + listRow = _e290; + let _e291 = listRow; + let _e295 = light_list_info.list[2u]; + v_2 = ((_e291 + 0.5f) * _e295); + let _e299 = light_list_info.list[1u]; + u_1 = _e299; + let _e300 = u_1; + let _e302 = v_2; + let _e304 = textureSampleLevel(light_list_texture_tex, light_list_texture_smp, vec2((0.5f * _e300), _e302), 0f); + position = _e304; + let _e305 = u_1; + let _e307 = v_2; + let _e309 = textureSampleLevel(light_list_texture_tex, light_list_texture_smp, vec2((1.5f * _e305), _e307), 0f); + color_1 = _e309; + let _e310 = u_1; + let _e312 = v_2; + let _e314 = textureSampleLevel(light_list_texture_tex, light_list_texture_smp, vec2((2.5f * _e310), _e312), 0f); + direction = _e314; + let _e315 = u_1; + let _e317 = v_2; + let _e319 = textureSampleLevel(light_list_texture_tex, light_list_texture_smp, vec2((3.5f * _e315), _e317), 0f); + cone = _e319; + let _e320 = clustered; + if _e320 { + let _e321 = listRow; + param_132 = _e321; + let _e322 = InSlots_u0028_f1_u003b((¶m_132)); + local_25 = select(1f, 0f, _e322); } else { - let _e323 = slot_5; - param_133 = _e323; - let _e324 = LightListScale_u0028_i1_u003b((¶m_133)); - local_25 = _e324; - } - let _e325 = local_25; - let _e327 = color_1[3u]; - color_1[3u] = (_e327 * _e325); - } - let _e331 = position[3u]; - type_42 = _e331; - let _e332 = type_42; - if (_e332 > 2.5f) { - let _e334 = direction; - halfWidth_1 = _e334.xyz; - let _e336 = cone; - halfHeight_1 = _e336.xyz; - let _e338 = position; - let _e340 = v_world_position_1; - toCentre = (_e338.xyz - _e340); - let _e342 = toCentre; - let _e343 = halfWidth_1; - let _e345 = halfHeight_1; - corners_2[0i] = ((_e342 - _e343) - _e345); - let _e348 = toCentre; - let _e349 = halfWidth_1; - let _e351 = halfHeight_1; - corners_2[1i] = ((_e348 + _e349) - _e351); - let _e354 = toCentre; - let _e355 = halfWidth_1; - let _e357 = halfHeight_1; - corners_2[2i] = ((_e354 + _e355) + _e357); - let _e360 = toCentre; - let _e361 = halfWidth_1; - let _e363 = halfHeight_1; - corners_2[3i] = ((_e360 - _e361) + _e363); - let _e366 = toCentre; - let _e367 = halfWidth_1; - let _e368 = halfHeight_1; - behind = (dot(_e366, cross(_e367, _e368)) >= 0f); - let _e372 = behind; - if _e372 { + let _e324 = slot_5; + param_133 = _e324; + let _e325 = LightListScale_u0028_i1_u003b((¶m_133)); + local_25 = _e325; + } + let _e326 = local_25; + let _e328 = color_1[3u]; + color_1[3u] = (_e328 * _e326); + } + let _e332 = position[3u]; + type_42 = _e332; + let _e333 = type_42; + if (_e333 > 2.5f) { + let _e335 = direction; + halfWidth_1 = _e335.xyz; + let _e337 = cone; + halfHeight_1 = _e337.xyz; + let _e339 = position; + let _e341 = v_world_position_1; + toCentre = (_e339.xyz - _e341); + let _e343 = toCentre; + let _e344 = halfWidth_1; + let _e346 = halfHeight_1; + corners_2[0i] = ((_e343 - _e344) - _e346); + let _e349 = toCentre; + let _e350 = halfWidth_1; + let _e352 = halfHeight_1; + corners_2[1i] = ((_e349 + _e350) - _e352); + let _e355 = toCentre; + let _e356 = halfWidth_1; + let _e358 = halfHeight_1; + corners_2[2i] = ((_e355 + _e356) + _e358); + let _e361 = toCentre; + let _e362 = halfWidth_1; + let _e364 = halfHeight_1; + corners_2[3i] = ((_e361 - _e362) + _e364); + let _e367 = toCentre; + let _e368 = halfWidth_1; + let _e369 = halfHeight_1; + behind = (dot(_e367, cross(_e368, _e369)) >= 0f); + let _e373 = behind; + if _e373 { local_26 = 0f; } else { - let _e373 = corners_2; - param_134 = _e373; - let _e375 = (*s_6).n; - param_135 = _e375; - let _e376 = RectangleFormFactor_u0028_vf3_u005b_4_u005d_u003b_vf3_u003b((¶m_134), (¶m_135)); - local_26 = _e376; - } - let _e377 = local_26; - formFactor = _e377; - let _e378 = halfWidth_1; - let _e379 = halfHeight_1; - area = (length(cross(_e378, _e379)) * 4f); - let _e383 = area; - if (_e383 > 0.000000001f) { - let _e385 = area; - local_27 = (1f / _e385); + let _e374 = corners_2; + param_134 = _e374; + let _e376 = (*s_6).n; + param_135 = _e376; + let _e377 = RectangleFormFactor_u0028_vf3_u005b_4_u005d_u003b_vf3_u003b((¶m_134), (¶m_135)); + local_26 = _e377; + } + let _e378 = local_26; + formFactor = _e378; + let _e379 = halfWidth_1; + let _e380 = halfHeight_1; + area = (length(cross(_e379, _e380)) * 4f); + let _e384 = area; + if (_e384 > 0.000000001f) { + let _e386 = area; + local_27 = (1f / _e386); } else { local_27 = 0f; } - let _e387 = local_27; - radiance = _e387; - let _e388 = toCentre; - distance_2 = length(_e388); - let _e391 = direction[3u]; - if (_e391 > 0f) { - let _e393 = distance_2; - let _e395 = direction[3u]; - ratio_1 = (_e393 / _e395); - let _e397 = ratio_1; + let _e388 = local_27; + radiance = _e388; + let _e389 = toCentre; + distance_2 = length(_e389); + let _e392 = direction[3u]; + if (_e392 > 0f) { + let _e394 = distance_2; + let _e396 = direction[3u]; + ratio_1 = (_e394 / _e396); let _e398 = ratio_1; - let _e400 = ratio_1; - let _e402 = ratio_1; - window_1 = clamp((1f - (((_e397 * _e398) * _e400) * _e402)), 0f, 1f); - let _e406 = window_1; + let _e399 = ratio_1; + let _e401 = ratio_1; + let _e403 = ratio_1; + window_1 = clamp((1f - (((_e398 * _e399) * _e401) * _e403)), 0f, 1f); let _e407 = window_1; - let _e409 = radiance; - radiance = (_e409 * (_e406 * _e407)); - } - let _e412 = (*s_6).v; - let _e415 = (*s_6).n; - mirror_1 = reflect(-(_e412), _e415); - let _e417 = position; - param_136 = _e417.xyz; - let _e419 = halfWidth_1; - param_137 = _e419; - let _e420 = halfHeight_1; - param_138 = _e420; - let _e421 = v_world_position_1; - param_139 = _e421; - let _e422 = mirror_1; - param_140 = _e422; - let _e423 = RectangleClosestPoint_u0028_vf3_u003b_vf3_u003b_vf3_u003b_vf3_u003b_vf3_u003b((¶m_136), (¶m_137), (¶m_138), (¶m_139), (¶m_140)); - representative = _e423; - let _e424 = representative; - let _e425 = v_world_position_1; - toPoint = (_e424 - _e425); - let _e427 = toPoint; - pointDistance = length(_e427); - let _e429 = pointDistance; - if (_e429 > 0.000001f) { - let _e431 = toPoint; - let _e432 = pointDistance; - local_28 = (_e431 / vec3(_e432)); + let _e408 = window_1; + let _e410 = radiance; + radiance = (_e410 * (_e407 * _e408)); + } + let _e413 = (*s_6).v; + let _e416 = (*s_6).n; + mirror_1 = reflect(-(_e413), _e416); + let _e418 = position; + param_136 = _e418.xyz; + let _e420 = halfWidth_1; + param_137 = _e420; + let _e421 = halfHeight_1; + param_138 = _e421; + let _e422 = v_world_position_1; + param_139 = _e422; + let _e423 = mirror_1; + param_140 = _e423; + let _e424 = RectangleClosestPoint_u0028_vf3_u003b_vf3_u003b_vf3_u003b_vf3_u003b_vf3_u003b((¶m_136), (¶m_137), (¶m_138), (¶m_139), (¶m_140)); + representative = _e424; + let _e425 = representative; + let _e426 = v_world_position_1; + toPoint = (_e425 - _e426); + let _e428 = toPoint; + pointDistance = length(_e428); + let _e430 = pointDistance; + if (_e430 > 0.000001f) { + let _e432 = toPoint; + let _e433 = pointDistance; + local_28 = (_e432 / vec3(_e433)); } else { - let _e436 = (*s_6).n; - local_28 = _e436; - } - let _e437 = local_28; - light_3.l = _e437; - let _e440 = light_3.l; - let _e442 = (*s_6).v; - light_3.h = normalize((_e440 + _e442)); - let _e446 = formFactor; - light_3.n_dot_l = _e446; - let _e449 = (*s_6).n; - let _e451 = light_3.h; - light_3.n_dot_h = max(dot(_e449, _e451), 0f); - let _e456 = (*s_6).v; - let _e458 = light_3.h; - light_3.v_dot_h = max(dot(_e456, _e458), 0f); - let _e462 = color_1; - let _e465 = color_1[3u]; - let _e467 = radiance; - light_3.radiance = ((_e462.xyz * _e465) * _e467); + let _e437 = (*s_6).n; + local_28 = _e437; + } + let _e438 = local_28; + light_3.l = _e438; + let _e441 = light_3.l; + let _e443 = (*s_6).v; + light_3.h = normalize((_e441 + _e443)); + let _e447 = formFactor; + light_3.n_dot_l = _e447; + let _e450 = (*s_6).n; + let _e452 = light_3.h; + light_3.n_dot_h = max(dot(_e450, _e452), 0f); + let _e457 = (*s_6).v; + let _e459 = light_3.h; + light_3.v_dot_h = max(dot(_e457, _e459), 0f); + let _e463 = color_1; + let _e466 = color_1[3u]; + let _e468 = radiance; + light_3.radiance = ((_e463.xyz * _e466) * _e468); light_3.integrated = 1f; - let _e472 = (*s_6).n; - param_141 = _e472; - let _e474 = (*s_6).v; - param_142 = _e474; - let _e476 = (*s_6).roughness; - param_143 = _e476; - let _e477 = corners_2; - param_144 = _e477; - let _e478 = LtcRectangle_u0028_vf3_u003b_vf3_u003b_f1_u003b_vf3_u005b_4_u005d_u003b((¶m_141), (¶m_142), (¶m_143), (¶m_144)); - light_3.ltc = _e478; - let _e480 = light_3; - return _e480; - } - let _e481 = direction; - aim = normalize(_e481.xyz); + let _e473 = (*s_6).n; + param_141 = _e473; + let _e475 = (*s_6).v; + param_142 = _e475; + let _e477 = (*s_6).roughness; + param_143 = _e477; + let _e478 = corners_2; + param_144 = _e478; + let _e479 = LtcRectangle_u0028_vf3_u003b_vf3_u003b_f1_u003b_vf3_u005b_4_u005d_u003b((¶m_141), (¶m_142), (¶m_143), (¶m_144)); + light_3.ltc = _e479; + let _e481 = light_3; + return _e481; + } + let _e482 = direction; + aim = normalize(_e482.xyz); attenuation_1 = 1f; - let _e484 = type_42; - if (_e484 < 0.5f) { - let _e486 = aim; - light_3.l = -(_e486); - } else { - let _e489 = position; - let _e491 = v_world_position_1; - toLight_1 = (_e489.xyz - _e491); - let _e493 = toLight_1; - distance_3 = length(_e493); - let _e495 = distance_3; - if (_e495 < 0.000001f) { - let _e498 = (*s_6).n; - light_3.l = _e498; - let _e501 = (*s_6).n; - light_3.h = _e501; + let _e485 = type_42; + if (_e485 < 0.5f) { + let _e487 = aim; + light_3.l = -(_e487); + } else { + let _e490 = position; + let _e492 = v_world_position_1; + toLight_1 = (_e490.xyz - _e492); + let _e494 = toLight_1; + distance_3 = length(_e494); + let _e496 = distance_3; + if (_e496 < 0.000001f) { + let _e499 = (*s_6).n; + light_3.l = _e499; + let _e502 = (*s_6).n; + light_3.h = _e502; light_3.radiance = vec3(0f, 0f, 0f); light_3.n_dot_l = 0f; light_3.n_dot_h = 0f; light_3.v_dot_h = 0f; - let _e507 = light_3; - return _e507; - } - let _e508 = toLight_1; - let _e509 = distance_3; - light_3.l = (_e508 / vec3(_e509)); - let _e513 = distance_3; - param_145 = _e513; - let _e515 = direction[3u]; - param_146 = _e515; - let _e516 = PunctualAttenuation_u0028_f1_u003b_f1_u003b((¶m_145), (¶m_146)); - attenuation_1 = _e516; - let _e517 = type_42; - if (_e517 > 1.5f) { - let _e519 = aim; - let _e521 = light_3.l; - cosAngle = dot(_e519, -(_e521)); - let _e524 = cosAngle; - let _e526 = cone[1u]; - let _e529 = cone[0u]; - let _e531 = cone[1u]; - let _e535 = attenuation_1; - attenuation_1 = (_e535 * clamp(((_e524 - _e526) / (_e529 - _e531)), 0f, 1f)); - } - } - let _e538 = light_3.l; - let _e540 = (*s_6).v; - light_3.h = normalize((_e538 + _e540)); - let _e545 = (*s_6).n; - let _e547 = light_3.l; - light_3.n_dot_l = max(dot(_e545, _e547), 0f); - let _e552 = (*s_6).n; - let _e554 = light_3.h; - light_3.n_dot_h = max(dot(_e552, _e554), 0f); - let _e559 = (*s_6).v; - let _e561 = light_3.h; - light_3.v_dot_h = max(dot(_e559, _e561), 0f); - let _e565 = color_1; - let _e568 = color_1[3u]; - let _e570 = attenuation_1; - light_3.radiance = ((_e565.xyz * _e568) * _e570); - let _e573 = light_3; - return _e573; + let _e508 = light_3; + return _e508; + } + let _e509 = toLight_1; + let _e510 = distance_3; + light_3.l = (_e509 / vec3(_e510)); + let _e514 = distance_3; + param_145 = _e514; + let _e516 = direction[3u]; + param_146 = _e516; + let _e517 = PunctualAttenuation_u0028_f1_u003b_f1_u003b((¶m_145), (¶m_146)); + attenuation_1 = _e517; + let _e518 = type_42; + if (_e518 > 1.5f) { + let _e520 = aim; + let _e522 = light_3.l; + cosAngle = dot(_e520, -(_e522)); + let _e525 = cosAngle; + let _e527 = cone[1u]; + let _e530 = cone[0u]; + let _e532 = cone[1u]; + let _e536 = attenuation_1; + attenuation_1 = (_e536 * clamp(((_e525 - _e527) / (_e530 - _e532)), 0f, 1f)); + } + } + let _e539 = light_3.l; + let _e541 = (*s_6).v; + light_3.h = normalize((_e539 + _e541)); + let _e546 = (*s_6).n; + let _e548 = light_3.l; + light_3.n_dot_l = max(dot(_e546, _e548), 0f); + let _e553 = (*s_6).n; + let _e555 = light_3.h; + light_3.n_dot_h = max(dot(_e553, _e555), 0f); + let _e560 = (*s_6).v; + let _e562 = light_3.h; + light_3.v_dot_h = max(dot(_e560, _e562), 0f); + let _e566 = color_1; + let _e569 = color_1[3u]; + let _e571 = attenuation_1; + light_3.radiance = ((_e566.xyz * _e569) * _e571); + let _e574 = light_3; + return _e574; } fn FindCluster_u0028_vf3_u003b(world_3: ptr>) { @@ -16442,58 +16547,58 @@ fn FindCluster_u0028_vf3_u003b(world_3: ptr>) { var param_147: f32; var param_148: f32; - let _e221 = light_list_info.cluster_view_projection; - let _e222 = (*world_3); - clip_1 = (_e221 * vec4(_e222.x, _e222.y, _e222.z, 1f)); - let _e228 = clip_1; - let _e231 = clip_1[3u]; - ndc_1 = (_e228.xy / vec2(max(_e231, 0.000001f))); - let _e236 = light_list_info.cluster_grid; - grid = _e236.xyz; - let _e240 = light_list_info.cluster_depth[0u]; - near_1 = _e240; - let _e242 = ndc_1[0u]; - let _e246 = grid[0u]; - let _e250 = grid[0u]; - tx = clamp(floor((((_e242 * 0.5f) + 0.5f) * _e246)), 0f, (_e250 - 1f)); - let _e254 = ndc_1[1u]; - let _e258 = grid[1u]; - let _e262 = grid[1u]; - ty = clamp(floor((((_e254 * 0.5f) + 0.5f) * _e258)), 0f, (_e262 - 1f)); - let _e266 = clip_1[3u]; - let _e267 = near_1; - if (_e266 <= _e267) { + let _e222 = light_list_info.cluster_view_projection; + let _e223 = (*world_3); + clip_1 = (_e222 * vec4(_e223.x, _e223.y, _e223.z, 1f)); + let _e229 = clip_1; + let _e232 = clip_1[3u]; + ndc_1 = (_e229.xy / vec2(max(_e232, 0.000001f))); + let _e237 = light_list_info.cluster_grid; + grid = _e237.xyz; + let _e241 = light_list_info.cluster_depth[0u]; + near_1 = _e241; + let _e243 = ndc_1[0u]; + let _e247 = grid[0u]; + let _e251 = grid[0u]; + tx = clamp(floor((((_e243 * 0.5f) + 0.5f) * _e247)), 0f, (_e251 - 1f)); + let _e255 = ndc_1[1u]; + let _e259 = grid[1u]; + let _e263 = grid[1u]; + ty = clamp(floor((((_e255 * 0.5f) + 0.5f) * _e259)), 0f, (_e263 - 1f)); + let _e267 = clip_1[3u]; + let _e268 = near_1; + if (_e267 <= _e268) { local_29 = 0f; } else { - let _e270 = clip_1[3u]; - let _e271 = near_1; - let _e276 = light_list_info.cluster_depth[1u]; - let _e280 = grid[2u]; - local_29 = clamp(floor((log((_e270 / _e271)) * _e276)), 0f, (_e280 - 1f)); - } - let _e283 = local_29; - tz = _e283; - let _e284 = tx; - let _e285 = ty; - let _e287 = grid[0u]; - let _e290 = tz; - let _e292 = grid[0u]; - let _e295 = grid[1u]; - cell = ((_e284 + (_e285 * _e287)) + ((_e290 * _e292) * _e295)); - let _e298 = cell; - row_3 = floor((_e298 / 4f)); - let _e301 = cell; - let _e302 = row_3; - let _e307 = light_list_info.cluster_depth[2u]; - let _e308 = row_3; - param_147 = (_e301 - (_e302 * 4f)); - param_148 = (_e307 + _e308); - let _e310 = LightListTexel_u0028_f1_u003b_f1_u003b((¶m_147), (¶m_148)); - header = _e310; - let _e312 = header[0u]; - g_cluster_offset = _e312; - let _e314 = header[1u]; - g_cluster_count = _e314; + let _e271 = clip_1[3u]; + let _e272 = near_1; + let _e277 = light_list_info.cluster_depth[1u]; + let _e281 = grid[2u]; + local_29 = clamp(floor((log((_e271 / _e272)) * _e277)), 0f, (_e281 - 1f)); + } + let _e284 = local_29; + tz = _e284; + let _e285 = tx; + let _e286 = ty; + let _e288 = grid[0u]; + let _e291 = tz; + let _e293 = grid[0u]; + let _e296 = grid[1u]; + cell = ((_e285 + (_e286 * _e288)) + ((_e291 * _e293) * _e296)); + let _e299 = cell; + row_3 = floor((_e299 / 4f)); + let _e302 = cell; + let _e303 = row_3; + let _e308 = light_list_info.cluster_depth[2u]; + let _e309 = row_3; + param_147 = (_e302 - (_e303 * 4f)); + param_148 = (_e308 + _e309); + let _e311 = LightListTexel_u0028_f1_u003b_f1_u003b((¶m_147), (¶m_148)); + header = _e311; + let _e313 = header[0u]; + g_cluster_offset = _e313; + let _e315 = header[1u]; + g_cluster_count = _e315; return; } @@ -16501,19 +16606,19 @@ fn LightCount_u0028_() -> i32 { var tail: f32; var param_149: vec3; - let _e210 = light_list_info.list[0u]; - tail = _e210; - let _e211 = Clustered_u0028_(); - if _e211 { - let _e212 = v_world_position_1; - param_149 = _e212; + let _e211 = light_list_info.list[0u]; + tail = _e211; + let _e212 = Clustered_u0028_(); + if _e212 { + let _e213 = v_world_position_1; + param_149 = _e213; FindCluster_u0028_vf3_u003b((¶m_149)); - let _e213 = g_cluster_count; - tail = _e213; + let _e214 = g_cluster_count; + tail = _e214; } - let _e216 = frag_info.frame_params[1u]; - let _e220 = tail; - return (clamp(i32((_e216 + 0.5f)), 0i, 8i) + clamp(i32((_e220 + 0.5f)), 0i, 24i)); + let _e217 = frag_info.frame_params[1u]; + let _e221 = tail; + return (clamp(i32((_e217 + 0.5f)), 0i, 8i) + clamp(i32((_e221 + 0.5f)), 0i, 24i)); } fn AccumulateLights_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b(s_7: ptr) -> vec3 { @@ -16536,89 +16641,89 @@ fn AccumulateLights_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002 var param_160: LightSample; total_1 = vec3(0f, 0f, 0f); - let _e224 = LightCount_u0028_(); - count_1 = _e224; + let _e225 = LightCount_u0028_(); + count_1 = _e225; i_9 = 0i; loop { - let _e225 = i_9; - if (_e225 < 32i) { - let _e227 = i_9; - let _e228 = count_1; - if (_e227 >= _e228) { + let _e226 = i_9; + if (_e226 < 32i) { + let _e228 = i_9; + let _e229 = count_1; + if (_e228 >= _e229) { break; } - let _e230 = i_9; - param_150 = _e230; - let _e231 = (*s_7); - param_151 = _e231; - let _e232 = SampleLight_u0028_i1_u003b_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b((¶m_150), (¶m_151)); - light_4 = _e232; - let _e234 = light_4.n_dot_l; - if (_e234 <= 0f) { + let _e231 = i_9; + param_150 = _e231; + let _e232 = (*s_7); + param_151 = _e232; + let _e233 = SampleLight_u0028_i1_u003b_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b((¶m_150), (¶m_151)); + light_4 = _e233; + let _e235 = light_4.n_dot_l; + if (_e235 <= 0f) { continue; } light_transmittance = vec3(1f, 1f, 1f); - let _e236 = i_9; - param_152 = _e236; - let _e237 = LightHasShadow_u0028_i1_u003b((¶m_152)); - if _e237 { - let _e238 = (*s_7); - param_153 = _e238; - let _e239 = light_4; - param_154 = _e239; - let _e240 = i_9; - param_155 = _e240; - let _e241 = LightVisibility_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_struct_u002d_LightSample_u002d_vf3_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf31_u003b_i1_u003b((¶m_153), (¶m_154), (¶m_155)); - let _e242 = v_world_position_1; - param_156 = _e242; - let _e244 = (*s_7).n; - param_157 = _e244; - let _e245 = i_9; - param_158 = _e245; - let _e246 = PointShadowFactor_u0028_vf3_u003b_vf3_u003b_i1_u003b((¶m_156), (¶m_157), (¶m_158)); - local_30 = (_e241 * _e246); + let _e237 = i_9; + param_152 = _e237; + let _e238 = LightHasShadow_u0028_i1_u003b((¶m_152)); + if _e238 { + let _e239 = (*s_7); + param_153 = _e239; + let _e240 = light_4; + param_154 = _e240; + let _e241 = i_9; + param_155 = _e241; + let _e242 = LightVisibility_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_struct_u002d_LightSample_u002d_vf3_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf31_u003b_i1_u003b((¶m_153), (¶m_154), (¶m_155)); + let _e243 = v_world_position_1; + param_156 = _e243; + let _e245 = (*s_7).n; + param_157 = _e245; + let _e246 = i_9; + param_158 = _e246; + let _e247 = PointShadowFactor_u0028_vf3_u003b_vf3_u003b_i1_u003b((¶m_156), (¶m_157), (¶m_158)); + local_30 = (_e242 * _e247); } else { local_30 = 1f; } - let _e248 = local_30; - visibility = _e248; - let _e249 = visibility; - if (_e249 <= 0f) { + let _e249 = local_30; + visibility = _e249; + let _e250 = visibility; + if (_e250 <= 0f) { continue; } - let _e251 = (*s_7); - param_159 = _e251; - let _e252 = light_4; - param_160 = _e252; - let _e253 = ShadeLight_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_struct_u002d_LightSample_u002d_vf3_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf31_u003b((¶m_159), (¶m_160)); - let _e255 = light_4.radiance; - let _e258 = light_4.n_dot_l; - let _e260 = visibility; - let _e262 = light_transmittance; - let _e264 = total_1; - total_1 = (_e264 + ((((_e253 * _e255) * _e258) * _e260) * _e262)); + let _e252 = (*s_7); + param_159 = _e252; + let _e253 = light_4; + param_160 = _e253; + let _e254 = ShadeLight_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_struct_u002d_LightSample_u002d_vf3_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf31_u003b((¶m_159), (¶m_160)); + let _e256 = light_4.radiance; + let _e259 = light_4.n_dot_l; + let _e261 = visibility; + let _e263 = light_transmittance; + let _e265 = total_1; + total_1 = (_e265 + ((((_e254 * _e256) * _e259) * _e261) * _e263)); continue; } else { break; } continuing { - let _e266 = i_9; - i_9 = (_e266 + 1i); + let _e267 = i_9; + i_9 = (_e267 + 1i); } } - let _e268 = total_1; - return _e268; + let _e269 = total_1; + return _e269; } fn SampleLightmap_u0028_() -> vec3 { var texel_4: vec4; - let _e207 = v_lightmap_uv_1; - let _e208 = textureSample(lightmap_texture_tex, lightmap_texture_smp, _e207); - texel_4 = _e208; - let _e209 = texel_4; - let _e212 = texel_4[3u]; - return ((_e209.xyz * _e212) * 8f); + let _e208 = v_lightmap_uv_1; + let _e209 = textureSample(lightmap_texture_tex, lightmap_texture_smp, _e208); + texel_4 = _e209; + let _e210 = texel_4; + let _e213 = texel_4[3u]; + return ((_e210.xyz * _e213) * 8f); } fn EonAlbedo_u0028_vf3_u003b_f1_u003b_f1_u003b(rho_2: ptr>, r_4: ptr, mu_1: ptr) -> vec3 { @@ -16629,43 +16734,43 @@ fn EonAlbedo_u0028_vf3_u003b_f1_u003b_f1_u003b(rho_2: ptr>, var param_164: vec3; var param_165: f32; - let _e215 = (*mu_1); - param_161 = _e215; - let _e216 = (*r_4); - param_162 = _e216; - let _e217 = FonAlbedo_u0028_f1_u003b_f1_u003b((¶m_161), (¶m_162)); - e_1 = _e217; - let _e218 = (*rho_2); - let _e219 = e_1; - let _e221 = (*r_4); - param_163 = _e221; - let _e222 = FonAverage_u0028_f1_u003b((¶m_163)); - let _e223 = (*rho_2); - param_164 = _e223; - param_165 = _e222; - let _e224 = EonMultiAlbedo_u0028_vf3_u003b_f1_u003b((¶m_164), (¶m_165)); - let _e225 = e_1; - return ((_e218 * _e219) + (_e224 * (1f - _e225))); + let _e216 = (*mu_1); + param_161 = _e216; + let _e217 = (*r_4); + param_162 = _e217; + let _e218 = FonAlbedo_u0028_f1_u003b_f1_u003b((¶m_161), (¶m_162)); + e_1 = _e218; + let _e219 = (*rho_2); + let _e220 = e_1; + let _e222 = (*r_4); + param_163 = _e222; + let _e223 = FonAverage_u0028_f1_u003b((¶m_163)); + let _e224 = (*rho_2); + param_164 = _e224; + param_165 = _e223; + let _e225 = EonMultiAlbedo_u0028_vf3_u003b_f1_u003b((¶m_164), (¶m_165)); + let _e226 = e_1; + return ((_e219 * _e220) + (_e225 * (1f - _e226))); } fn MaterialLodBias_u0028_() -> f32 { - let _e208 = frag_info.target_origin[1u]; - return _e208; + let _e209 = frag_info.target_origin[1u]; + return _e209; } fn ApplyMetallicRoughnessMap_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b(s_8: ptr) { var orm: vec3; - let _e208 = v_texcoord_1; - let _e209 = MaterialLodBias_u0028_(); - let _e210 = textureSampleBias(metallic_roughness_texture_tex, metallic_roughness_texture_smp, _e208, _e209); - orm = _e210.xyz; - let _e213 = (*s_8).metallic; - let _e215 = orm[2u]; - (*s_8).metallic = clamp((_e213 * _e215), 0f, 1f); - let _e220 = (*s_8).roughness; - let _e222 = orm[1u]; - (*s_8).roughness = clamp((_e220 * _e222), 0.02f, 1f); + let _e209 = v_texcoord_1; + let _e210 = MaterialLodBias_u0028_(); + let _e211 = textureSampleBias(metallic_roughness_texture_tex, metallic_roughness_texture_smp, _e209, _e210); + orm = _e211.xyz; + let _e214 = (*s_8).metallic; + let _e216 = orm[2u]; + (*s_8).metallic = clamp((_e214 * _e216), 0f, 1f); + let _e221 = (*s_8).roughness; + let _e223 = orm[1u]; + (*s_8).roughness = clamp((_e221 * _e223), 0.02f, 1f); return; } @@ -16673,29 +16778,29 @@ fn ApplyEmissiveMap_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002 var emissive: vec3; var param_166: vec3; - let _e209 = v_texcoord_1; - let _e210 = MaterialLodBias_u0028_(); - let _e211 = textureSampleBias(emissive_texture_tex, emissive_texture_smp, _e209, _e210); - param_166 = _e211.xyz; - let _e213 = SrgbToLinear_u0028_vf3_u003b((¶m_166)); - emissive = _e213; - let _e214 = emissive; - let _e216 = frag_info.emissive; - let _e221 = frag_info.material2_[3u]; - (*s_9).emissive = ((_e214 * _e216.xyz) * _e221); + let _e210 = v_texcoord_1; + let _e211 = MaterialLodBias_u0028_(); + let _e212 = textureSampleBias(emissive_texture_tex, emissive_texture_smp, _e210, _e211); + param_166 = _e212.xyz; + let _e214 = SrgbToLinear_u0028_vf3_u003b((¶m_166)); + emissive = _e214; + let _e215 = emissive; + let _e217 = frag_info.emissive; + let _e222 = frag_info.material2_[3u]; + (*s_9).emissive = ((_e215 * _e217.xyz) * _e222); return; } fn ApplyOcclusionMap_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b(s_10: ptr) { var occlusion: f32; - let _e208 = v_texcoord_1; - let _e209 = MaterialLodBias_u0028_(); - let _e210 = textureSampleBias(occlusion_texture_tex, occlusion_texture_smp, _e208, _e209); - occlusion = _e210.x; - let _e212 = occlusion; - let _e215 = frag_info.material2_[2u]; - (*s_10).occlusion = mix(1f, _e212, clamp(_e215, 0f, 1f)); + let _e209 = v_texcoord_1; + let _e210 = MaterialLodBias_u0028_(); + let _e211 = textureSampleBias(occlusion_texture_tex, occlusion_texture_smp, _e209, _e210); + occlusion = _e211.x; + let _e213 = occlusion; + let _e216 = frag_info.material2_[2u]; + (*s_10).occlusion = mix(1f, _e213, clamp(_e216, 0f, 1f)); return; } @@ -16705,64 +16810,64 @@ fn ApplyNormalMap_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_ var b_4: vec3; var sampled: vec3; - let _e211 = v_texcoord_1; - let _e212 = MaterialLodBias_u0028_(); - let _e213 = textureSampleBias(normal_texture_tex, normal_texture_smp, _e211, _e212); - sampledTexel = _e213; - let _e214 = v_tangent_1; - t_2 = _e214.xyz; - let _e216 = t_2; - let _e218 = (*s_11).n; - let _e220 = (*s_11).n; - let _e221 = t_2; - t_2 = (_e216 - (_e218 * dot(_e220, _e221))); - let _e225 = t_2; + let _e212 = v_texcoord_1; + let _e213 = MaterialLodBias_u0028_(); + let _e214 = textureSampleBias(normal_texture_tex, normal_texture_smp, _e212, _e213); + sampledTexel = _e214; + let _e215 = v_tangent_1; + t_2 = _e215.xyz; + let _e217 = t_2; + let _e219 = (*s_11).n; + let _e221 = (*s_11).n; + let _e222 = t_2; + t_2 = (_e217 - (_e219 * dot(_e221, _e222))); let _e226 = t_2; - if (dot(_e225, _e226) < 0.000000000001f) { + let _e227 = t_2; + if (dot(_e226, _e227) < 0.000000000001f) { return; } - let _e229 = t_2; - t_2 = normalize(_e229); - let _e232 = (*s_11).n; - let _e233 = t_2; - let _e236 = v_tangent_1[3u]; - b_4 = (cross(_e232, _e233) * _e236); - let _e238 = gl_FrontFacing_1; - if !(_e238) { - let _e240 = t_2; - t_2 = -(_e240); - } - let _e242 = sampledTexel; - sampled = ((_e242.xyz * 2f) - vec3(1f)); - let _e249 = frag_info.emissive[3u]; - if (_e249 > 0.5f) { - let _e251 = sampled; - let _e253 = sampled; - sampled[2u] = sqrt(max((1f - dot(_e251.xy, _e253.xy)), 0f)); - } - let _e262 = frag_info.material2_[1u]; - let _e263 = sampled; - let _e265 = (_e263.xy * _e262); - sampled[0u] = _e265.x; - sampled[1u] = _e265.y; - let _e270 = t_2; - let _e272 = sampled[0u]; - let _e274 = b_4; - let _e276 = sampled[1u]; - let _e280 = (*s_11).n; - let _e282 = sampled[2u]; - (*s_11).n = normalize((((_e270 * _e272) + (_e274 * _e276)) + (_e280 * _e282))); - let _e288 = (*s_11).n; - let _e290 = (*s_11).v; - (*s_11).n_dot_v = max(dot(_e288, _e290), 0.0001f); + let _e230 = t_2; + t_2 = normalize(_e230); + let _e233 = (*s_11).n; + let _e234 = t_2; + let _e237 = v_tangent_1[3u]; + b_4 = (cross(_e233, _e234) * _e237); + let _e239 = gl_FrontFacing_1; + if !(_e239) { + let _e241 = t_2; + t_2 = -(_e241); + } + let _e243 = sampledTexel; + sampled = ((_e243.xyz * 2f) - vec3(1f)); + let _e250 = frag_info.emissive[3u]; + if (_e250 > 0.5f) { + let _e252 = sampled; + let _e254 = sampled; + sampled[2u] = sqrt(max((1f - dot(_e252.xy, _e254.xy)), 0f)); + } + let _e263 = frag_info.material2_[1u]; + let _e264 = sampled; + let _e266 = (_e264.xy * _e263); + sampled[0u] = _e266.x; + sampled[1u] = _e266.y; + let _e271 = t_2; + let _e273 = sampled[0u]; + let _e275 = b_4; + let _e277 = sampled[1u]; + let _e281 = (*s_11).n; + let _e283 = sampled[2u]; + (*s_11).n = normalize((((_e271 * _e273) + (_e275 * _e277)) + (_e281 * _e283))); + let _e289 = (*s_11).n; + let _e291 = (*s_11).v; + (*s_11).n_dot_v = max(dot(_e289, _e291), 0.0001f); return; } fn AtlasTexel_u0028_vf2_u003b(texel_5: ptr>) -> vec4 { - let _e207 = (*texel_5); - let _e211 = irradiance_info.atlas; - let _e214 = textureSampleLevel(irradiance_texture_tex, irradiance_texture_smp, ((_e207 + vec2(0.5f)) * _e211.xy), 0f); - return _e214; + let _e208 = (*texel_5); + let _e212 = irradiance_info.atlas; + let _e215 = textureSampleLevel(irradiance_texture_tex, irradiance_texture_smp, ((_e208 + vec2(0.5f)) * _e212.xy), 0f); + return _e215; } fn TileBilinear_u0028_vf2_u003b_f1_u003b_vf2_u003b(corner: ptr>, interior: ptr, uv_6: ptr>) -> vec4 { @@ -16778,42 +16883,42 @@ fn TileBilinear_u0028_vf2_u003b_f1_u003b_vf2_u003b(corner: ptr; var param_170: vec2; - let _e220 = (*uv_6); - let _e221 = (*interior); - at_1 = ((vec2(1f) + (_e220 * _e221)) - vec2(0.5f)); - let _e227 = at_1; - low = floor(_e227); - let _e229 = at_1; - let _e230 = low; - f_3 = (_e229 - _e230); - let _e232 = (*corner); - let _e233 = low; - param_167 = (_e232 + _e233); - let _e235 = AtlasTexel_u0028_vf2_u003b((¶m_167)); - a_6 = _e235; - let _e236 = (*corner); - let _e237 = low; - param_168 = ((_e236 + _e237) + vec2(1f, 0f)); - let _e240 = AtlasTexel_u0028_vf2_u003b((¶m_168)); - b_5 = _e240; - let _e241 = (*corner); - let _e242 = low; - param_169 = ((_e241 + _e242) + vec2(0f, 1f)); - let _e245 = AtlasTexel_u0028_vf2_u003b((¶m_169)); - c_1 = _e245; - let _e246 = (*corner); - let _e247 = low; - param_170 = ((_e246 + _e247) + vec2(1f, 1f)); - let _e250 = AtlasTexel_u0028_vf2_u003b((¶m_170)); - d_5 = _e250; - let _e251 = a_6; - let _e252 = b_5; - let _e254 = f_3[0u]; - let _e257 = c_1; - let _e258 = d_5; - let _e260 = f_3[0u]; - let _e264 = f_3[1u]; - return mix(mix(_e251, _e252, vec4(_e254)), mix(_e257, _e258, vec4(_e260)), vec4(_e264)); + let _e221 = (*uv_6); + let _e222 = (*interior); + at_1 = ((vec2(1f) + (_e221 * _e222)) - vec2(0.5f)); + let _e228 = at_1; + low = floor(_e228); + let _e230 = at_1; + let _e231 = low; + f_3 = (_e230 - _e231); + let _e233 = (*corner); + let _e234 = low; + param_167 = (_e233 + _e234); + let _e236 = AtlasTexel_u0028_vf2_u003b((¶m_167)); + a_6 = _e236; + let _e237 = (*corner); + let _e238 = low; + param_168 = ((_e237 + _e238) + vec2(1f, 0f)); + let _e241 = AtlasTexel_u0028_vf2_u003b((¶m_168)); + b_5 = _e241; + let _e242 = (*corner); + let _e243 = low; + param_169 = ((_e242 + _e243) + vec2(0f, 1f)); + let _e246 = AtlasTexel_u0028_vf2_u003b((¶m_169)); + c_1 = _e246; + let _e247 = (*corner); + let _e248 = low; + param_170 = ((_e247 + _e248) + vec2(1f, 1f)); + let _e251 = AtlasTexel_u0028_vf2_u003b((¶m_170)); + d_5 = _e251; + let _e252 = a_6; + let _e253 = b_5; + let _e255 = f_3[0u]; + let _e258 = c_1; + let _e259 = d_5; + let _e261 = f_3[0u]; + let _e265 = f_3[1u]; + return mix(mix(_e252, _e253, vec4(_e255)), mix(_e258, _e259, vec4(_e261)), vec4(_e265)); } fn ProbeOctahedral_u0028_vf3_u003b(direction_1: ptr>) -> vec2 { @@ -16821,29 +16926,29 @@ fn ProbeOctahedral_u0028_vf3_u003b(direction_1: ptr>) -> vec var n_6: vec3; var xy: vec2; - let _e211 = (*direction_1)[0u]; - let _e214 = (*direction_1)[1u]; - let _e218 = (*direction_1)[2u]; - sum_1 = ((abs(_e211) + abs(_e214)) + abs(_e218)); - let _e221 = sum_1; - if (_e221 <= 0f) { + let _e212 = (*direction_1)[0u]; + let _e215 = (*direction_1)[1u]; + let _e219 = (*direction_1)[2u]; + sum_1 = ((abs(_e212) + abs(_e215)) + abs(_e219)); + let _e222 = sum_1; + if (_e222 <= 0f) { return vec2(0.5f, 0.5f); } - let _e223 = (*direction_1); - let _e224 = sum_1; - n_6 = (_e223 / vec3(_e224)); - let _e227 = n_6; - xy = _e227.xy; - let _e230 = n_6[2u]; - if (_e230 < 0f) { - let _e233 = n_6[1u]; - let _e237 = n_6[0u]; - let _e242 = n_6[0u]; - let _e246 = n_6[1u]; - xy = vec2(((1f - abs(_e233)) * select(-1f, 1f, (_e237 >= 0f))), ((1f - abs(_e242)) * select(-1f, 1f, (_e246 >= 0f)))); + let _e224 = (*direction_1); + let _e225 = sum_1; + n_6 = (_e224 / vec3(_e225)); + let _e228 = n_6; + xy = _e228.xy; + let _e231 = n_6[2u]; + if (_e231 < 0f) { + let _e234 = n_6[1u]; + let _e238 = n_6[0u]; + let _e243 = n_6[0u]; + let _e247 = n_6[1u]; + xy = vec2(((1f - abs(_e234)) * select(-1f, 1f, (_e238 >= 0f))), ((1f - abs(_e243)) * select(-1f, 1f, (_e247 >= 0f)))); } - let _e251 = xy; - return ((_e251 * 0.5f) + vec2(0.5f)); + let _e252 = xy; + return ((_e252 * 0.5f) + vec2(0.5f)); } fn SampleIrradiance_u0028_vf3_u003b_vf3_u003b_vf3_u003b(world_4: ptr>, normal_1: ptr>, view_1: ptr>) -> vec3 { @@ -16891,190 +16996,190 @@ fn SampleIrradiance_u0028_vf3_u003b_vf3_u003b_vf3_u003b(world_4: ptr; var local_31: vec3; - let _e253 = irradiance_info.origin; - origin_2 = _e253.xyz; - let _e256 = irradiance_info.spacing; - spacing = _e256.xyz; - let _e259 = irradiance_info.counts; - counts = _e259.xyz; - let _e263 = irradiance_info.tiles[0u]; - irradianceTile = _e263; - let _e266 = irradiance_info.tiles[1u]; - depthTile = _e266; - let _e269 = irradiance_info.tiles[2u]; - columns = _e269; - let _e272 = irradiance_info.tiles[3u]; - momentsTop = _e272; - let _e273 = (*normal_1); - unit = normalize(_e273); - let _e275 = (*world_4); - let _e276 = unit; - let _e279 = irradiance_info.spacing[3u]; - let _e282 = (*view_1); - let _e285 = irradiance_info.counts[3u]; - biased = ((_e275 + (_e276 * _e279)) + (_e282 * _e285)); - let _e288 = biased; - let _e289 = origin_2; - let _e291 = spacing; - grid_1 = ((_e288 - _e289) / _e291); - let _e293 = grid_1; - let _e295 = counts; - base = clamp(floor(_e293), vec3(0f, 0f, 0f), (_e295 - vec3(2f))); - let _e299 = grid_1; - let _e300 = base; - f_4 = clamp((_e299 - _e300), vec3(0f, 0f, 0f), vec3(1f, 1f, 1f)); + let _e254 = irradiance_info.origin; + origin_2 = _e254.xyz; + let _e257 = irradiance_info.spacing; + spacing = _e257.xyz; + let _e260 = irradiance_info.counts; + counts = _e260.xyz; + let _e264 = irradiance_info.tiles[0u]; + irradianceTile = _e264; + let _e267 = irradiance_info.tiles[1u]; + depthTile = _e267; + let _e270 = irradiance_info.tiles[2u]; + columns = _e270; + let _e273 = irradiance_info.tiles[3u]; + momentsTop = _e273; + let _e274 = (*normal_1); + unit = normalize(_e274); + let _e276 = (*world_4); + let _e277 = unit; + let _e280 = irradiance_info.spacing[3u]; + let _e283 = (*view_1); + let _e286 = irradiance_info.counts[3u]; + biased = ((_e276 + (_e277 * _e280)) + (_e283 * _e286)); + let _e289 = biased; + let _e290 = origin_2; + let _e292 = spacing; + grid_1 = ((_e289 - _e290) / _e292); + let _e294 = grid_1; + let _e296 = counts; + base = clamp(floor(_e294), vec3(0f, 0f, 0f), (_e296 - vec3(2f))); + let _e300 = grid_1; + let _e301 = base; + f_4 = clamp((_e300 - _e301), vec3(0f, 0f, 0f), vec3(1f, 1f, 1f)); total_2 = vec3(0f, 0f, 0f); weights = 0f; corner_1 = 0i; loop { - let _e303 = corner_1; - if (_e303 < 8i) { - let _e305 = corner_1; - let _e308 = corner_1; - let _e313 = corner_1; - offset_3 = vec3(f32((_e305 & 1i)), f32(((_e308 >> bitcast(1i)) & 1i)), f32(((_e313 >> bitcast(2i)) & 1i))); - let _e319 = base; - let _e320 = offset_3; - cell_1 = (_e319 + _e320); - let _e323 = cell_1[2u]; - let _e325 = counts[1u]; - let _e328 = cell_1[1u]; - let _e331 = counts[0u]; - let _e334 = cell_1[0u]; - probe = ((((_e323 * _e325) + _e328) * _e331) + _e334); - let _e336 = probe; - let _e337 = columns; - let _e342 = probe; - let _e343 = columns; - tile_4 = vec2((_e336 - (floor((_e336 / _e337)) * _e337)), floor((_e342 / _e343))); - let _e347 = tile_4; - let _e348 = irradianceTile; - irradianceCorner = (_e347 * (_e348 + 2f)); - let _e352 = tile_4[0u]; - let _e353 = depthTile; - let _e356 = momentsTop; - let _e358 = tile_4[1u]; - let _e359 = depthTile; - momentCorner = vec2((_e352 * (_e353 + 2f)), (_e356 + (_e358 * (_e359 + 2f)))); - let _e364 = irradianceCorner; - param_171 = (_e364 + vec2(1f)); - let _e367 = AtlasTexel_u0028_vf2_u003b((¶m_171)); - if (_e367.w < 0.5f) { + let _e304 = corner_1; + if (_e304 < 8i) { + let _e306 = corner_1; + let _e309 = corner_1; + let _e314 = corner_1; + offset_3 = vec3(f32((_e306 & 1i)), f32(((_e309 >> bitcast(1i)) & 1i)), f32(((_e314 >> bitcast(2i)) & 1i))); + let _e320 = base; + let _e321 = offset_3; + cell_1 = (_e320 + _e321); + let _e324 = cell_1[2u]; + let _e326 = counts[1u]; + let _e329 = cell_1[1u]; + let _e332 = counts[0u]; + let _e335 = cell_1[0u]; + probe = ((((_e324 * _e326) + _e329) * _e332) + _e335); + let _e337 = probe; + let _e338 = columns; + let _e343 = probe; + let _e344 = columns; + tile_4 = vec2((_e337 - (floor((_e337 / _e338)) * _e338)), floor((_e343 / _e344))); + let _e348 = tile_4; + let _e349 = irradianceTile; + irradianceCorner = (_e348 * (_e349 + 2f)); + let _e353 = tile_4[0u]; + let _e354 = depthTile; + let _e357 = momentsTop; + let _e359 = tile_4[1u]; + let _e360 = depthTile; + momentCorner = vec2((_e353 * (_e354 + 2f)), (_e357 + (_e359 * (_e360 + 2f)))); + let _e365 = irradianceCorner; + param_171 = (_e365 + vec2(1f)); + let _e368 = AtlasTexel_u0028_vf2_u003b((¶m_171)); + if (_e368.w < 0.5f) { continue; } - let _e370 = f_4; - let _e372 = f_4; - let _e373 = offset_3; - trilinear = mix((vec3(1f, 1f, 1f) - _e370), _e372, _e373); - let _e376 = trilinear[0u]; - let _e378 = trilinear[1u]; - let _e381 = trilinear[2u]; - weight_3 = max(((_e376 * _e378) * _e381), 0.001f); - let _e384 = origin_2; - let _e385 = spacing; - let _e386 = cell_1; - probePosition = (_e384 + (_e385 * _e386)); - let _e389 = probePosition; - let _e390 = biased; - toProbe = (_e389 - _e390); - let _e392 = toProbe; - distance_4 = length(_e392); - let _e394 = distance_4; - if (_e394 > 0.000001f) { - let _e396 = toProbe; - let _e397 = distance_4; - direction_2 = (_e396 / vec3(_e397)); - let _e400 = unit; - let _e401 = probePosition; - let _e402 = (*world_4); - facing = ((dot(_e400, normalize((_e401 - _e402))) * 0.5f) + 0.5f); - let _e408 = facing; + let _e371 = f_4; + let _e373 = f_4; + let _e374 = offset_3; + trilinear = mix((vec3(1f, 1f, 1f) - _e371), _e373, _e374); + let _e377 = trilinear[0u]; + let _e379 = trilinear[1u]; + let _e382 = trilinear[2u]; + weight_3 = max(((_e377 * _e379) * _e382), 0.001f); + let _e385 = origin_2; + let _e386 = spacing; + let _e387 = cell_1; + probePosition = (_e385 + (_e386 * _e387)); + let _e390 = probePosition; + let _e391 = biased; + toProbe = (_e390 - _e391); + let _e393 = toProbe; + distance_4 = length(_e393); + let _e395 = distance_4; + if (_e395 > 0.000001f) { + let _e397 = toProbe; + let _e398 = distance_4; + direction_2 = (_e397 / vec3(_e398)); + let _e401 = unit; + let _e402 = probePosition; + let _e403 = (*world_4); + facing = ((dot(_e401, normalize((_e402 - _e403))) * 0.5f) + 0.5f); let _e409 = facing; - probeWeight = ((_e408 * _e409) + 0.2f); - let _e412 = direction_2; - param_172 = -(_e412); - let _e414 = ProbeOctahedral_u0028_vf3_u003b((¶m_172)); - let _e415 = momentCorner; - param_173 = _e415; - let _e416 = depthTile; - param_174 = _e416; - param_175 = _e414; - let _e417 = TileBilinear_u0028_vf2_u003b_f1_u003b_vf2_u003b((¶m_173), (¶m_174), (¶m_175)); - moments_3 = _e417.xy; + let _e410 = facing; + probeWeight = ((_e409 * _e410) + 0.2f); + let _e413 = direction_2; + param_172 = -(_e413); + let _e415 = ProbeOctahedral_u0028_vf3_u003b((¶m_172)); + let _e416 = momentCorner; + param_173 = _e416; + let _e417 = depthTile; + param_174 = _e417; + param_175 = _e415; + let _e418 = TileBilinear_u0028_vf2_u003b_f1_u003b_vf2_u003b((¶m_173), (¶m_174), (¶m_175)); + moments_3 = _e418.xy; chebyshev = 1f; - let _e419 = distance_4; - let _e421 = moments_3[0u]; - if (_e419 > _e421) { - let _e424 = moments_3[1u]; - let _e426 = moments_3[0u]; - let _e428 = moments_3[0u]; - variance_1 = max((_e424 - (_e426 * _e428)), 0.000001f); - let _e432 = distance_4; - let _e434 = moments_3[0u]; - difference = (_e432 - _e434); - let _e436 = variance_1; + let _e420 = distance_4; + let _e422 = moments_3[0u]; + if (_e420 > _e422) { + let _e425 = moments_3[1u]; + let _e427 = moments_3[0u]; + let _e429 = moments_3[0u]; + variance_1 = max((_e425 - (_e427 * _e429)), 0.000001f); + let _e433 = distance_4; + let _e435 = moments_3[0u]; + difference = (_e433 - _e435); let _e437 = variance_1; - let _e438 = difference; + let _e438 = variance_1; let _e439 = difference; - chebyshev = (_e436 / (_e437 + (_e438 * _e439))); - let _e443 = chebyshev; + let _e440 = difference; + chebyshev = (_e437 / (_e438 + (_e439 * _e440))); let _e444 = chebyshev; - let _e446 = chebyshev; - chebyshev = ((_e443 * _e444) * _e446); + let _e445 = chebyshev; + let _e447 = chebyshev; + chebyshev = ((_e444 * _e445) * _e447); } - let _e448 = probeWeight; - let _e449 = chebyshev; - probeWeight = max((_e448 * max(_e449, 0.05f)), 0.000001f); - let _e453 = probeWeight; - if (_e453 < 0.2f) { - let _e455 = probeWeight; + let _e449 = probeWeight; + let _e450 = chebyshev; + probeWeight = max((_e449 * max(_e450, 0.05f)), 0.000001f); + let _e454 = probeWeight; + if (_e454 < 0.2f) { let _e456 = probeWeight; - let _e459 = probeWeight; - probeWeight = (_e459 * ((_e455 * _e456) * 25f)); + let _e457 = probeWeight; + let _e460 = probeWeight; + probeWeight = (_e460 * ((_e456 * _e457) * 25f)); } - let _e461 = probeWeight; - let _e462 = weight_3; - weight_3 = (_e462 * _e461); - } - let _e464 = unit; - param_176 = _e464; - let _e465 = ProbeOctahedral_u0028_vf3_u003b((¶m_176)); - let _e466 = irradianceCorner; - param_177 = _e466; - let _e467 = irradianceTile; - param_178 = _e467; - param_179 = _e465; - let _e468 = TileBilinear_u0028_vf2_u003b_f1_u003b_vf2_u003b((¶m_177), (¶m_178), (¶m_179)); - let _e470 = weight_3; - let _e472 = total_2; - total_2 = (_e472 + (_e468.xyz * _e470)); - let _e474 = weight_3; - let _e475 = weights; - weights = (_e475 + _e474); + let _e462 = probeWeight; + let _e463 = weight_3; + weight_3 = (_e463 * _e462); + } + let _e465 = unit; + param_176 = _e465; + let _e466 = ProbeOctahedral_u0028_vf3_u003b((¶m_176)); + let _e467 = irradianceCorner; + param_177 = _e467; + let _e468 = irradianceTile; + param_178 = _e468; + param_179 = _e466; + let _e469 = TileBilinear_u0028_vf2_u003b_f1_u003b_vf2_u003b((¶m_177), (¶m_178), (¶m_179)); + let _e471 = weight_3; + let _e473 = total_2; + total_2 = (_e473 + (_e469.xyz * _e471)); + let _e475 = weight_3; + let _e476 = weights; + weights = (_e476 + _e475); continue; } else { break; } continuing { - let _e477 = corner_1; - corner_1 = (_e477 + 1i); + let _e478 = corner_1; + corner_1 = (_e478 + 1i); } } - let _e479 = weights; - if (_e479 > 0f) { - let _e481 = total_2; - let _e482 = weights; - local_31 = (_e481 / vec3(_e482)); + let _e480 = weights; + if (_e480 > 0f) { + let _e482 = total_2; + let _e483 = weights; + local_31 = (_e482 / vec3(_e483)); } else { local_31 = vec3(0f, 0f, 0f); } - let _e485 = local_31; - return _e485; + let _e486 = local_31; + return _e486; } fn IrradianceEnabled_u0028_() -> bool { - let _e208 = irradiance_info.origin[3u]; - return (_e208 > 0.5f); + let _e209 = irradiance_info.origin[3u]; + return (_e209 > 0.5f); } fn ApplyCommonMaps_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b(s_12: ptr) { @@ -17085,50 +17190,50 @@ fn ApplyCommonMaps_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d var param_184: Surface; var param_185: Surface; - let _e213 = IrradianceEnabled_u0028_(); - if _e213 { - let _e214 = v_world_position_1; - param_180 = _e214; - let _e216 = (*s_12).n; - param_181 = _e216; - let _e218 = (*s_12).v; - param_182 = _e218; - let _e219 = SampleIrradiance_u0028_vf3_u003b_vf3_u003b_vf3_u003b((¶m_180), (¶m_181), (¶m_182)); - let _e222 = frag_info.material[2u]; - (*s_12).ambient = (_e219 * _e222); - } - let _e225 = (*s_12); - param_183 = _e225; + let _e214 = IrradianceEnabled_u0028_(); + if _e214 { + let _e215 = v_world_position_1; + param_180 = _e215; + let _e217 = (*s_12).n; + param_181 = _e217; + let _e219 = (*s_12).v; + param_182 = _e219; + let _e220 = SampleIrradiance_u0028_vf3_u003b_vf3_u003b_vf3_u003b((¶m_180), (¶m_181), (¶m_182)); + let _e223 = frag_info.material[2u]; + (*s_12).ambient = (_e220 * _e223); + } + let _e226 = (*s_12); + param_183 = _e226; ApplyNormalMap_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b((¶m_183)); - let _e226 = param_183; - (*s_12) = _e226; - let _e227 = (*s_12); - param_184 = _e227; + let _e227 = param_183; + (*s_12) = _e227; + let _e228 = (*s_12); + param_184 = _e228; ApplyOcclusionMap_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b((¶m_184)); - let _e228 = param_184; - (*s_12) = _e228; - let _e229 = (*s_12); - param_185 = _e229; + let _e229 = param_184; + (*s_12) = _e229; + let _e230 = (*s_12); + param_185 = _e230; ApplyEmissiveMap_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b((¶m_185)); - let _e230 = param_185; - (*s_12) = _e230; + let _e231 = param_185; + (*s_12) = _e231; return; } fn TowardsEye_u0028_() -> vec3 { var local_32: vec3; - let _e207 = Orthographic_u0028_(); - if _e207 { - let _e209 = fog_info.forward; - local_32 = -(_e209.xyz); + let _e208 = Orthographic_u0028_(); + if _e208 { + let _e210 = fog_info.forward; + local_32 = -(_e210.xyz); } else { - let _e213 = fog_info.eye; - let _e215 = v_world_position_1; - local_32 = normalize((_e213.xyz - _e215)); + let _e214 = fog_info.eye; + let _e216 = v_world_position_1; + local_32 = normalize((_e214.xyz - _e216)); } - let _e218 = local_32; - return _e218; + let _e219 = local_32; + return _e219; } fn ReadSurface_u0028_() -> Surface { @@ -17141,89 +17246,89 @@ fn ReadSurface_u0028_() -> Surface { var anchored: vec3; var noise_1: f32; - let _e214 = v_texcoord_1; - let _e215 = MaterialLodBias_u0028_(); - let _e216 = textureSampleBias(base_color_texture_tex, base_color_texture_smp, _e214, _e215); - texel_6 = _e216; - let _e217 = texel_6; - param_186 = _e217.xyz; - let _e219 = SrgbToLinear_u0028_vf3_u003b((¶m_186)); - let _e221 = frag_info.base_color; - param_187 = _e221.xyz; - let _e223 = SrgbToLinear_u0028_vf3_u003b((¶m_187)); - let _e225 = v_color_1; - s_13.albedo = ((_e219 * _e223) * _e225.xyz); - let _e230 = texel_6[3u]; - let _e233 = frag_info.base_color[3u]; - let _e236 = v_color_1[3u]; - s_13.alpha = ((_e230 * _e233) * _e236); - let _e240 = s_13.albedo; - g_albedo = _e240; - let _e243 = frag_info.material2_[0u]; - cutoff = _e243; - let _e244 = cutoff; - if (_e244 > 1f) { - let _e246 = cutoff; - edge = (_e246 - 1f); - let _e249 = s_13.alpha; - let _e250 = edge; - let _e253 = s_13.alpha; - let _e254 = fwidth(_e253); - s_13.alpha = clamp((((_e249 - _e250) / max(_e254, 0.0001f)) + 0.5f), 0f, 1f); - } else { - let _e260 = cutoff; - if (_e260 >= 0f) { - let _e263 = s_13.alpha; - let _e264 = cutoff; - if (_e263 < _e264) { + let _e215 = v_texcoord_1; + let _e216 = MaterialLodBias_u0028_(); + let _e217 = textureSampleBias(base_color_texture_tex, base_color_texture_smp, _e215, _e216); + texel_6 = _e217; + let _e218 = texel_6; + param_186 = _e218.xyz; + let _e220 = SrgbToLinear_u0028_vf3_u003b((¶m_186)); + let _e222 = frag_info.base_color; + param_187 = _e222.xyz; + let _e224 = SrgbToLinear_u0028_vf3_u003b((¶m_187)); + let _e226 = v_color_1; + s_13.albedo = ((_e220 * _e224) * _e226.xyz); + let _e231 = texel_6[3u]; + let _e234 = frag_info.base_color[3u]; + let _e237 = v_color_1[3u]; + s_13.alpha = ((_e231 * _e234) * _e237); + let _e241 = s_13.albedo; + g_albedo = _e241; + let _e244 = frag_info.material2_[0u]; + cutoff = _e244; + let _e245 = cutoff; + if (_e245 > 1f) { + let _e247 = cutoff; + edge = (_e247 - 1f); + let _e250 = s_13.alpha; + let _e251 = edge; + let _e254 = s_13.alpha; + let _e255 = fwidth(_e254); + s_13.alpha = clamp((((_e250 - _e251) / max(_e255, 0.0001f)) + 0.5f), 0f, 1f); + } else { + let _e261 = cutoff; + if (_e261 >= 0f) { + let _e264 = s_13.alpha; + let _e265 = cutoff; + if (_e264 < _e265) { discard; } s_13.alpha = 1f; } else { - let _e267 = cutoff; - if (_e267 < -1.5f) { - let _e269 = v_world_position_1; - anchored = floor((_e269 * 16f)); - let _e272 = anchored; - noise_1 = fract((sin(dot(_e272, vec3(12.9898f, 78.233f, 37.719f))) * 43758.547f)); - let _e278 = s_13.alpha; - let _e279 = noise_1; - if (_e278 < _e279) { + let _e268 = cutoff; + if (_e268 < -1.5f) { + let _e270 = v_world_position_1; + anchored = floor((_e270 * 16f)); + let _e273 = anchored; + noise_1 = fract((sin(dot(_e273, vec3(12.9898f, 78.233f, 37.719f))) * 43758.547f)); + let _e279 = s_13.alpha; + let _e280 = noise_1; + if (_e279 < _e280) { discard; } } } } - let _e281 = cutoff; - let _e283 = cutoff; - g_premultiply = ((_e281 < 0f) && (_e283 > -0.75f)); - let _e286 = v_normal_1; - s_13.n = normalize(_e286); - let _e289 = gl_FrontFacing_1; - if !(_e289) { - let _e292 = s_13.n; - s_13.n = -(_e292); - } - let _e295 = TowardsEye_u0028_(); - s_13.v = _e295; - let _e298 = s_13.n; - let _e300 = s_13.v; - s_13.n_dot_v = max(dot(_e298, _e300), 0.0001f); - let _e306 = frag_info.material[0u]; - s_13.metallic = clamp(_e306, 0f, 1f); - let _e311 = frag_info.material[1u]; - s_13.roughness = clamp(_e311, 0.02f, 1f); - let _e315 = frag_info.ambient_ground; - let _e318 = frag_info.ambient_sky; - let _e322 = s_13.n[1u]; - let _e329 = frag_info.material[2u]; - s_13.ambient = (mix(_e315.xyz, _e318.xyz, vec3(((_e322 * 0.5f) + 0.5f))) * _e329); - let _e334 = frag_info.frame_params[0u]; - s_13.exposure = max(_e334, 0f); + let _e282 = cutoff; + let _e284 = cutoff; + g_premultiply = ((_e282 < 0f) && (_e284 > -0.75f)); + let _e287 = v_normal_1; + s_13.n = normalize(_e287); + let _e290 = gl_FrontFacing_1; + if !(_e290) { + let _e293 = s_13.n; + s_13.n = -(_e293); + } + let _e296 = TowardsEye_u0028_(); + s_13.v = _e296; + let _e299 = s_13.n; + let _e301 = s_13.v; + s_13.n_dot_v = max(dot(_e299, _e301), 0.0001f); + let _e307 = frag_info.material[0u]; + s_13.metallic = clamp(_e307, 0f, 1f); + let _e312 = frag_info.material[1u]; + s_13.roughness = clamp(_e312, 0.02f, 1f); + let _e316 = frag_info.ambient_ground; + let _e319 = frag_info.ambient_sky; + let _e323 = s_13.n[1u]; + let _e330 = frag_info.material[2u]; + s_13.ambient = (mix(_e316.xyz, _e319.xyz, vec3(((_e323 * 0.5f) + 0.5f))) * _e330); + let _e335 = frag_info.frame_params[0u]; + s_13.exposure = max(_e335, 0f); s_13.occlusion = 1f; s_13.emissive = vec3(0f, 0f, 0f); - let _e339 = s_13; - return _e339; + let _e340 = s_13; + return _e340; } fn main_1() { @@ -17265,122 +17370,122 @@ fn main_1() { g_cluster_offset = 0f; g_cluster_count = 0f; light_transmittance = vec3(1f, 1f, 1f); - let _e235 = ReadSurface_u0028_(); - s_14 = _e235; - let _e236 = s_14; - param_188 = _e236; + let _e236 = ReadSurface_u0028_(); + s_14 = _e236; + let _e237 = s_14; + param_188 = _e237; ApplyCommonMaps_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b((¶m_188)); - let _e237 = param_188; - s_14 = _e237; - let _e238 = s_14; - param_189 = _e238; + let _e238 = param_188; + s_14 = _e238; + let _e239 = s_14; + param_189 = _e239; ApplyMetallicRoughnessMap_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b((¶m_189)); - let _e239 = param_189; - s_14 = _e239; - let _e241 = s_14.metallic; - metallic = clamp(_e241, 0f, 1f); - let _e244 = s_14.albedo; - let _e245 = metallic; - diffuseColor_1 = (_e244 * (1f - _e245)); - let _e248 = EonDiffuse_u0028_(); - if _e248 { - let _e249 = diffuseColor_1; - param_190 = _e249; - let _e251 = s_14.roughness; - param_191 = _e251; - let _e253 = s_14.n_dot_v; - param_192 = _e253; - let _e254 = EonAlbedo_u0028_vf3_u003b_f1_u003b_f1_u003b((¶m_190), (¶m_191), (¶m_192)); - diffuseColor_1 = _e254; - } - let _e255 = diffuseColor_1; - let _e257 = s_14.ambient; - let _e260 = s_14.occlusion; - ambient = ((_e255 * _e257) * _e260); - let _e264 = frag_info.frame_params[3u]; - levels = _e264; - let _e265 = levels; - if (_e265 > 0f) { - let _e268 = s_14.albedo; - let _e269 = metallic; - f0_3 = mix(vec3(0.04f, 0.04f, 0.04f), _e268, vec3(_e269)); - let _e273 = s_14.v; - let _e276 = s_14.n; - reflected = reflect(-(_e273), _e276); - let _e279 = s_14.n; - let _e280 = levels; - let _e281 = textureSampleLevel(environment_texture_tex, environment_texture_smp, _e279, _e280); - irradiance = _e281.xyz; - let _e283 = reflected; - let _e285 = s_14.roughness; - let _e286 = levels; - let _e288 = textureSampleLevel(environment_texture_tex, environment_texture_smp, _e283, (_e285 * _e286)); - prefiltered = _e288.xyz; - let _e291 = s_14.roughness; - param_193 = _e291; - let _e293 = s_14.n_dot_v; - param_194 = _e293; - let _e294 = EnvBrdf_u0028_f1_u003b_f1_u003b((¶m_193), (¶m_194)); - ab_1 = _e294; - let _e295 = f0_3; - let _e297 = ab_1[0u]; - let _e300 = ab_1[1u]; - single_1 = ((_e295 * _e297) + vec3(_e300)); - let _e303 = prefiltered; - let _e304 = single_1; - specular_1 = (_e303 * _e304); - let _e306 = EnergyCompensation_u0028_(); - if _e306 { - let _e308 = ab_1[0u]; - let _e310 = ab_1[1u]; - missed = (1f - (_e308 + _e310)); - let _e313 = f0_3; + let _e240 = param_189; + s_14 = _e240; + let _e242 = s_14.metallic; + metallic = clamp(_e242, 0f, 1f); + let _e245 = s_14.albedo; + let _e246 = metallic; + diffuseColor_1 = (_e245 * (1f - _e246)); + let _e249 = EonDiffuse_u0028_(); + if _e249 { + let _e250 = diffuseColor_1; + param_190 = _e250; + let _e252 = s_14.roughness; + param_191 = _e252; + let _e254 = s_14.n_dot_v; + param_192 = _e254; + let _e255 = EonAlbedo_u0028_vf3_u003b_f1_u003b_f1_u003b((¶m_190), (¶m_191), (¶m_192)); + diffuseColor_1 = _e255; + } + let _e256 = diffuseColor_1; + let _e258 = s_14.ambient; + let _e261 = s_14.occlusion; + ambient = ((_e256 * _e258) * _e261); + let _e265 = frag_info.frame_params[3u]; + levels = _e265; + let _e266 = levels; + if (_e266 > 0f) { + let _e269 = s_14.albedo; + let _e270 = metallic; + f0_3 = mix(vec3(0.04f, 0.04f, 0.04f), _e269, vec3(_e270)); + let _e274 = s_14.v; + let _e277 = s_14.n; + reflected = reflect(-(_e274), _e277); + let _e280 = s_14.n; + let _e281 = levels; + let _e282 = textureSampleLevel(environment_texture_tex, environment_texture_smp, _e280, _e281); + irradiance = _e282.xyz; + let _e284 = reflected; + let _e286 = s_14.roughness; + let _e287 = levels; + let _e289 = textureSampleLevel(environment_texture_tex, environment_texture_smp, _e284, (_e286 * _e287)); + prefiltered = _e289.xyz; + let _e292 = s_14.roughness; + param_193 = _e292; + let _e294 = s_14.n_dot_v; + param_194 = _e294; + let _e295 = EnvBrdf_u0028_f1_u003b_f1_u003b((¶m_193), (¶m_194)); + ab_1 = _e295; + let _e296 = f0_3; + let _e298 = ab_1[0u]; + let _e301 = ab_1[1u]; + single_1 = ((_e296 * _e298) + vec3(_e301)); + let _e304 = prefiltered; + let _e305 = single_1; + specular_1 = (_e304 * _e305); + let _e307 = EnergyCompensation_u0028_(); + if _e307 { + let _e309 = ab_1[0u]; + let _e311 = ab_1[1u]; + missed = (1f - (_e309 + _e311)); let _e314 = f0_3; - average_2 = (_e313 + ((vec3(1f, 1f, 1f) - _e314) / vec3(21f))); - let _e319 = single_1; - let _e320 = average_2; - let _e322 = missed; - let _e323 = average_2; - multiple = ((_e319 * _e320) / (vec3(1f, 1f, 1f) - (_e323 * _e322))); - let _e327 = multiple; - let _e328 = missed; - let _e330 = irradiance; - let _e332 = specular_1; - specular_1 = (_e332 + ((_e327 * _e328) * _e330)); - } - let _e334 = diffuseColor_1; - let _e335 = irradiance; - let _e337 = specular_1; - let _e341 = frag_info.material[2u]; - let _e344 = s_14.occlusion; - ambient = ((((_e334 * _e335) + _e337) * _e341) * _e344); - } - let _e346 = diffuseColor_1; - let _e347 = SampleLightmap_u0028_(); - let _e350 = s_14.occlusion; - let _e352 = ambient; - ambient = (_e352 + ((_e346 * _e347) * _e350)); - let _e354 = s_14; - param_195 = _e354; - let _e355 = AccumulateLights_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b((¶m_195)); - let _e357 = s_14.occlusion; - let _e359 = ambient; - let _e362 = s_14.emissive; - lit_3 = (((_e355 * _e357) + _e359) + _e362); - let _e364 = s_14; - param_196 = _e364; - let _e365 = lit_3; - param_197 = _e365; - let _e366 = WriteDebugView_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_vf3_u003b((¶m_196), (¶m_197)); - if _e366 { + let _e315 = f0_3; + average_2 = (_e314 + ((vec3(1f, 1f, 1f) - _e315) / vec3(21f))); + let _e320 = single_1; + let _e321 = average_2; + let _e323 = missed; + let _e324 = average_2; + multiple = ((_e320 * _e321) / (vec3(1f, 1f, 1f) - (_e324 * _e323))); + let _e328 = multiple; + let _e329 = missed; + let _e331 = irradiance; + let _e333 = specular_1; + specular_1 = (_e333 + ((_e328 * _e329) * _e331)); + } + let _e335 = diffuseColor_1; + let _e336 = irradiance; + let _e338 = specular_1; + let _e342 = frag_info.material[2u]; + let _e345 = s_14.occlusion; + ambient = ((((_e335 * _e336) + _e338) * _e342) * _e345); + } + let _e347 = diffuseColor_1; + let _e348 = SampleLightmap_u0028_(); + let _e351 = s_14.occlusion; + let _e353 = ambient; + ambient = (_e353 + ((_e347 * _e348) * _e351)); + let _e355 = s_14; + param_195 = _e355; + let _e356 = AccumulateLights_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b((¶m_195)); + let _e358 = s_14.occlusion; + let _e360 = ambient; + let _e363 = s_14.emissive; + lit_3 = (((_e356 * _e358) + _e360) + _e363); + let _e365 = s_14; + param_196 = _e365; + let _e366 = lit_3; + param_197 = _e366; + let _e367 = WriteDebugView_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_vf3_u003b((¶m_196), (¶m_197)); + if _e367 { return; } - let _e367 = lit_3; - param_198 = _e367; - let _e369 = s_14.alpha; - param_199 = _e369; - let _e371 = s_14.roughness; - param_200 = _e371; + let _e368 = lit_3; + param_198 = _e368; + let _e370 = s_14.alpha; + param_199 = _e370; + let _e372 = s_14.roughness; + param_200 = _e372; WriteSurface_u0028_vf3_u003b_f1_u003b_f1_u003b((¶m_198), (¶m_199), (¶m_200)); return; } @@ -17960,10 +18065,10 @@ var scene_colour_texture_tex: texture_2d; var scene_colour_texture_smp: sampler; fn ViewDepth_u0028_() -> f32 { - let _e273 = v_world_position_1; - let _e275 = fog_info.eye; - let _e279 = fog_info.forward; - return dot((_e273 - _e275.xyz), _e279.xyz); + let _e274 = v_world_position_1; + let _e276 = fog_info.eye; + let _e280 = fog_info.forward; + return dot((_e274 - _e276.xyz), _e280.xyz); } fn WeightedBlendedWeight_u0028_f1_u003b(alpha: ptr) -> f32 { @@ -17972,22 +18077,22 @@ fn WeightedBlendedWeight_u0028_f1_u003b(alpha: ptr) -> f32 { var far: f32; var far3_: f32; - let _e278 = ViewDepth_u0028_(); - z = abs(_e278); - let _e280 = z; - near = (_e280 / 5f); - let _e282 = z; - far = (_e282 / 200f); - let _e284 = far; + let _e279 = ViewDepth_u0028_(); + z = abs(_e279); + let _e281 = z; + near = (_e281 / 5f); + let _e283 = z; + far = (_e283 / 200f); let _e285 = far; - let _e287 = far; - far3_ = ((_e284 * _e285) * _e287); - let _e289 = (*alpha); - let _e290 = near; + let _e286 = far; + let _e288 = far; + far3_ = ((_e285 * _e286) * _e288); + let _e290 = (*alpha); let _e291 = near; - let _e294 = far3_; + let _e292 = near; let _e295 = far3_; - return (_e289 * clamp((10f / ((0.00001f + (_e290 * _e291)) + (_e294 * _e295))), 0.01f, 3000f)); + let _e296 = far3_; + return (_e290 * clamp((10f / ((0.00001f + (_e291 * _e292)) + (_e295 * _e296))), 0.01f, 3000f)); } fn WriteWeightedBlended_u0028_() { @@ -17999,39 +18104,39 @@ fn WriteWeightedBlended_u0028_() { var revealage: bool; var local: vec4; - let _e282 = fog_info.forward[3u]; - mode = _e282; - let _e283 = mode; - if (_e283 > 0.5f) { - let _e286 = frag_color[3u]; - alpha_1 = _e286; - let _e287 = alpha_1; - param = _e287; - let _e288 = WeightedBlendedWeight_u0028_f1_u003b((¶m)); - weight = _e288; - let _e289 = frag_color; - let _e291 = weight; - let _e292 = (_e289.xyz * _e291); - let _e293 = alpha_1; - let _e294 = weight; - accumulate = vec4(_e292.x, _e292.y, _e292.z, (_e293 * _e294)); - let _e300 = mode; - let _e302 = mode; - revealage = ((_e300 > 1.5f) && (_e302 < 2.5f)); - let _e305 = revealage; - if _e305 { - let _e306 = alpha_1; - local = vec4(_e306); + let _e283 = fog_info.forward[3u]; + mode = _e283; + let _e284 = mode; + if (_e284 > 0.5f) { + let _e287 = frag_color[3u]; + alpha_1 = _e287; + let _e288 = alpha_1; + param = _e288; + let _e289 = WeightedBlendedWeight_u0028_f1_u003b((¶m)); + weight = _e289; + let _e290 = frag_color; + let _e292 = weight; + let _e293 = (_e290.xyz * _e292); + let _e294 = alpha_1; + let _e295 = weight; + accumulate = vec4(_e293.x, _e293.y, _e293.z, (_e294 * _e295)); + let _e301 = mode; + let _e303 = mode; + revealage = ((_e301 > 1.5f) && (_e303 < 2.5f)); + let _e306 = revealage; + if _e306 { + let _e307 = alpha_1; + local = vec4(_e307); } else { - let _e308 = accumulate; - local = _e308; + let _e309 = accumulate; + local = _e309; } - let _e309 = local; - frag_color = _e309; - let _e310 = mode; - if (_e310 > 2.5f) { - let _e312 = alpha_1; - frag_surface = vec4(_e312); + let _e310 = local; + frag_color = _e310; + let _e311 = mode; + if (_e311 > 2.5f) { + let _e313 = alpha_1; + frag_surface = vec4(_e313); } } return; @@ -18040,29 +18145,29 @@ fn WriteWeightedBlended_u0028_() { fn EncodeOctahedral_u0028_vf3_u003b(n: ptr>) -> vec2 { var e: vec2; - let _e276 = (*n)[0u]; - let _e279 = (*n)[1u]; - let _e283 = (*n)[2u]; - let _e286 = (*n); - (*n) = (_e286 / vec3(((abs(_e276) + abs(_e279)) + abs(_e283)))); - let _e289 = (*n); - e = _e289.xy; - let _e292 = (*n)[2u]; - if (_e292 < 0f) { - let _e294 = (*n); - let _e300 = (*n)[0u]; - let _e304 = (*n)[1u]; - e = ((vec2(1f) - abs(_e294.yx)) * vec2(select(-1f, 1f, (_e300 >= 0f)), select(-1f, 1f, (_e304 >= 0f)))); + let _e277 = (*n)[0u]; + let _e280 = (*n)[1u]; + let _e284 = (*n)[2u]; + let _e287 = (*n); + (*n) = (_e287 / vec3(((abs(_e277) + abs(_e280)) + abs(_e284)))); + let _e290 = (*n); + e = _e290.xy; + let _e293 = (*n)[2u]; + if (_e293 < 0f) { + let _e295 = (*n); + let _e301 = (*n)[0u]; + let _e305 = (*n)[1u]; + e = ((vec2(1f) - abs(_e295.yx)) * vec2(select(-1f, 1f, (_e301 >= 0f)), select(-1f, 1f, (_e305 >= 0f)))); } - let _e309 = e; - return ((_e309 * 0.5f) + vec2(0.5f)); + let _e310 = e; + return ((_e310 * 0.5f) + vec2(0.5f)); } fn LinearToSrgb_u0028_vf3_u003b(linear: ptr>) -> vec3 { - let _e274 = (*linear); - let _e276 = (*linear); - let _e280 = (*linear); - return mix((_e274 * 12.92f), ((pow(_e276, vec3(0.41666666f, 0.41666666f, 0.41666666f)) * 1.055f) - vec3(0.055f, 0.055f, 0.055f)), step(vec3(0.0031308f, 0.0031308f, 0.0031308f), _e280)); + let _e275 = (*linear); + let _e277 = (*linear); + let _e281 = (*linear); + return mix((_e275 * 12.92f), ((pow(_e277, vec3(0.41666666f, 0.41666666f, 0.41666666f)) * 1.055f) - vec3(0.055f, 0.055f, 0.055f)), step(vec3(0.0031308f, 0.0031308f, 0.0031308f), _e281)); } fn WriteSurfaceGeometry_u0028_f1_u003b(roughness: ptr) { @@ -18070,52 +18175,52 @@ fn WriteSurfaceGeometry_u0028_f1_u003b(roughness: ptr) { var geometric: vec3; var param_2: vec3; - let _e277 = g_albedo; - param_1 = clamp(_e277, vec3(0f, 0f, 0f), vec3(1f, 1f, 1f)); - let _e279 = LinearToSrgb_u0028_vf3_u003b((¶m_1)); - frag_albedo = vec4(_e279.x, _e279.y, _e279.z, 1f); - let _e284 = g_debug_surface_on; - if _e284 { - let _e285 = g_debug_surface; - let _e286 = ViewDepth_u0028_(); - frag_surface = vec4(_e285.x, _e285.y, _e285.z, _e286); + let _e278 = g_albedo; + param_1 = clamp(_e278, vec3(0f, 0f, 0f), vec3(1f, 1f, 1f)); + let _e280 = LinearToSrgb_u0028_vf3_u003b((¶m_1)); + frag_albedo = vec4(_e280.x, _e280.y, _e280.z, 1f); + let _e285 = g_debug_surface_on; + if _e285 { + let _e286 = g_debug_surface; + let _e287 = ViewDepth_u0028_(); + frag_surface = vec4(_e286.x, _e286.y, _e286.z, _e287); return; } - let _e291 = v_normal_1; - geometric = normalize(_e291); - let _e293 = gl_FrontFacing_1; - if !(_e293) { - let _e295 = geometric; - geometric = -(_e295); - } - let _e297 = geometric; - param_2 = _e297; - let _e298 = EncodeOctahedral_u0028_vf3_u003b((¶m_2)); - let _e299 = (*roughness); - let _e301 = ViewDepth_u0028_(); - frag_surface = vec4(_e298.x, _e298.y, clamp(_e299, 0f, 1f), _e301); + let _e292 = v_normal_1; + geometric = normalize(_e292); + let _e294 = gl_FrontFacing_1; + if !(_e294) { + let _e296 = geometric; + geometric = -(_e296); + } + let _e298 = geometric; + param_2 = _e298; + let _e299 = EncodeOctahedral_u0028_vf3_u003b((¶m_2)); + let _e300 = (*roughness); + let _e302 = ViewDepth_u0028_(); + frag_surface = vec4(_e299.x, _e299.y, clamp(_e300, 0f, 1f), _e302); return; } fn Orthographic_u0028_() -> bool { - let _e275 = fog_info.projection[0u]; - return (_e275 > 0.5f); + let _e276 = fog_info.projection[0u]; + return (_e276 > 0.5f); } fn EyeDistance_u0028_() -> f32 { var local_1: f32; - let _e274 = Orthographic_u0028_(); - if _e274 { - let _e275 = ViewDepth_u0028_(); - local_1 = max(_e275, 0f); + let _e275 = Orthographic_u0028_(); + if _e275 { + let _e276 = ViewDepth_u0028_(); + local_1 = max(_e276, 0f); } else { - let _e277 = v_world_position_1; - let _e279 = fog_info.eye; - local_1 = distance(_e277, _e279.xyz); + let _e278 = v_world_position_1; + let _e280 = fog_info.eye; + local_1 = distance(_e278, _e280.xyz); } - let _e282 = local_1; - return _e282; + let _e283 = local_1; + return _e283; } fn ApplyFog_u0028_vf3_u003b(color: ptr>) -> vec3 { @@ -18125,41 +18230,41 @@ fn ApplyFog_u0028_vf3_u003b(color: ptr>) -> vec3 { var k: f32; var local_2: f32; - let _e281 = fog_info.fog[3u]; - density = _e281; - let _e282 = density; - if (_e282 <= 0f) { - let _e284 = (*color); - return _e284; - } - let _e285 = EyeDistance_u0028_(); - d = _e285; - let _e288 = fog_info.eye[3u]; - falloff = _e288; - let _e289 = falloff; - if (_e289 > 0f) { - let _e291 = falloff; - let _e293 = v_world_position_1[1u]; - let _e296 = fog_info.eye[1u]; - k = (_e291 * (_e293 - _e296)); - let _e299 = k; - if (abs(_e299) > 0.001f) { - let _e302 = k; - let _e306 = k; - local_2 = ((1f - exp(-(_e302))) / _e306); + let _e282 = fog_info.fog[3u]; + density = _e282; + let _e283 = density; + if (_e283 <= 0f) { + let _e285 = (*color); + return _e285; + } + let _e286 = EyeDistance_u0028_(); + d = _e286; + let _e289 = fog_info.eye[3u]; + falloff = _e289; + let _e290 = falloff; + if (_e290 > 0f) { + let _e292 = falloff; + let _e294 = v_world_position_1[1u]; + let _e297 = fog_info.eye[1u]; + k = (_e292 * (_e294 - _e297)); + let _e300 = k; + if (abs(_e300) > 0.001f) { + let _e303 = k; + let _e307 = k; + local_2 = ((1f - exp(-(_e303))) / _e307); } else { - let _e308 = k; - local_2 = (1f - (0.5f * _e308)); + let _e309 = k; + local_2 = (1f - (0.5f * _e309)); } - let _e311 = local_2; - let _e312 = density; - density = (_e312 * _e311); + let _e312 = local_2; + let _e313 = density; + density = (_e313 * _e312); } - let _e315 = fog_info.fog; - let _e317 = (*color); - let _e318 = density; - let _e320 = d; - return mix(_e315.xyz, _e317, vec3(clamp(exp((-(_e318) * _e320)), 0f, 1f))); + let _e316 = fog_info.fog; + let _e318 = (*color); + let _e319 = density; + let _e321 = d; + return mix(_e316.xyz, _e318, vec3(clamp(exp((-(_e319) * _e321)), 0f, 1f))); } fn WriteSurface_u0028_vf3_u003b_f1_u003b_f1_u003b(linearColor: ptr>, alpha_2: ptr, roughness_1: ptr) { @@ -18167,58 +18272,58 @@ fn WriteSurface_u0028_vf3_u003b_f1_u003b_f1_u003b(linearColor: ptr; var param_4: f32; - let _e279 = g_premultiply; - let _e280 = (*alpha_2); - weight_1 = select(1f, _e280, _e279); - let _e282 = (*linearColor); - param_3 = _e282; - let _e283 = ApplyFog_u0028_vf3_u003b((¶m_3)); - let _e284 = weight_1; - let _e285 = (_e283 * _e284); - let _e286 = (*alpha_2); - let _e287 = g_pass_through; - frag_color = vec4(_e285.x, _e285.y, _e285.z, (_e286 * (1f - _e287))); - let _e294 = (*roughness_1); - param_4 = _e294; + let _e280 = g_premultiply; + let _e281 = (*alpha_2); + weight_1 = select(1f, _e281, _e280); + let _e283 = (*linearColor); + param_3 = _e283; + let _e284 = ApplyFog_u0028_vf3_u003b((¶m_3)); + let _e285 = weight_1; + let _e286 = (_e284 * _e285); + let _e287 = (*alpha_2); + let _e288 = g_pass_through; + frag_color = vec4(_e286.x, _e286.y, _e286.z, (_e287 * (1f - _e288))); + let _e295 = (*roughness_1); + param_4 = _e295; WriteSurfaceGeometry_u0028_f1_u003b((¶m_4)); WriteWeightedBlended_u0028_(); return; } fn SrgbToLinear_u0028_vf3_u003b(srgb: ptr>) -> vec3 { - let _e274 = (*srgb); - let _e277 = (*srgb); - let _e282 = (*srgb); - return mix((_e274 / vec3(12.92f)), pow(((_e277 + vec3(0.055f, 0.055f, 0.055f)) / vec3(1.055f)), vec3(2.4f, 2.4f, 2.4f)), step(vec3(0.04045f, 0.04045f, 0.04045f), _e282)); + let _e275 = (*srgb); + let _e278 = (*srgb); + let _e283 = (*srgb); + return mix((_e275 / vec3(12.92f)), pow(((_e278 + vec3(0.055f, 0.055f, 0.055f)) / vec3(1.055f)), vec3(2.4f, 2.4f, 2.4f)), step(vec3(0.04045f, 0.04045f, 0.04045f), _e283)); } fn NonFinite_u0028_vf3_u003b(c: ptr>) -> bool { var phi_3014_: bool; - let _e274 = (*c); let _e275 = (*c); - let _e277 = any((_e274 != _e275)); - phi_3014_ = _e277; - if !(_e277) { - let _e279 = (*c); - phi_3014_ = any((abs(_e279) > vec3(300000000000000000000000000000000000000f, 300000000000000000000000000000000000000f, 300000000000000000000000000000000000000f))); - } - let _e284 = phi_3014_; - return _e284; + let _e276 = (*c); + let _e278 = any((_e275 != _e276)); + phi_3014_ = _e278; + if !(_e278) { + let _e280 = (*c); + phi_3014_ = any((abs(_e280) > vec3(300000000000000000000000000000000000000f, 300000000000000000000000000000000000000f, 300000000000000000000000000000000000000f))); + } + let _e285 = phi_3014_; + return _e285; } fn MapUv_u0028_i1_u003b(slot: ptr) -> vec2 { var uvw: vec3; - let _e275 = v_texcoord_1; - uvw = vec3(_e275.x, _e275.y, 1f); - let _e279 = (*slot); - let _e283 = layer_info.uv_transform[(_e279 * 2i)]; - let _e285 = uvw; - let _e287 = (*slot); - let _e292 = layer_info.uv_transform[((_e287 * 2i) + 1i)]; - let _e294 = uvw; - return vec2(dot(_e283.xyz, _e285), dot(_e292.xyz, _e294)); + let _e276 = v_texcoord_1; + uvw = vec3(_e276.x, _e276.y, 1f); + let _e280 = (*slot); + let _e284 = layer_info.uv_transform[(_e280 * 2i)]; + let _e286 = uvw; + let _e288 = (*slot); + let _e293 = layer_info.uv_transform[((_e288 * 2i) + 1i)]; + let _e295 = uvw; + return vec2(dot(_e284.xyz, _e286), dot(_e293.xyz, _e295)); } fn WriteDebugView_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_vf3_u003b(s: ptr, lit: ptr>) -> bool { @@ -18237,79 +18342,79 @@ fn WriteDebugView_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_ var param_10: vec3; var param_11: f32; - let _e291 = frag_info.debug_view[0u]; - view = _e291; - let _e292 = view; - if (_e292 < 0.5f) { + let _e292 = frag_info.debug_view[0u]; + view = _e292; + let _e293 = view; + if (_e293 < 0.5f) { return false; } - let _e295 = gl_FragCoord_1[0u]; - let _e298 = frag_info.debug_view[1u]; - let _e301 = frag_info.debug_view[2u]; - if (_e295 < (_e298 * _e301)) { + let _e296 = gl_FragCoord_1[0u]; + let _e299 = frag_info.debug_view[1u]; + let _e302 = frag_info.debug_view[2u]; + if (_e296 < (_e299 * _e302)) { return false; } - let _e304 = view; - code = i32((_e304 + 0.5f)); + let _e305 = view; + code = i32((_e305 + 0.5f)); shown = vec3(0f, 0f, 0f); - let _e307 = code; - if (_e307 == 1i) { - let _e310 = (*s).albedo; - param_5 = clamp(_e310, vec3(0f, 0f, 0f), vec3(1f, 1f, 1f)); - let _e312 = LinearToSrgb_u0028_vf3_u003b((¶m_5)); - shown = _e312; - } else { - let _e313 = code; - if (_e313 == 2i) { - let _e316 = (*s).n; - shown = ((_e316 * 0.5f) + vec3(0.5f, 0.5f, 0.5f)); + let _e308 = code; + if (_e308 == 1i) { + let _e311 = (*s).albedo; + param_5 = clamp(_e311, vec3(0f, 0f, 0f), vec3(1f, 1f, 1f)); + let _e313 = LinearToSrgb_u0028_vf3_u003b((¶m_5)); + shown = _e313; + } else { + let _e314 = code; + if (_e314 == 2i) { + let _e317 = (*s).n; + shown = ((_e317 * 0.5f) + vec3(0.5f, 0.5f, 0.5f)); } else { - let _e319 = code; - if (_e319 == 3i) { - let _e322 = (*s).roughness; - shown = vec3(clamp(_e322, 0f, 1f)); + let _e320 = code; + if (_e320 == 3i) { + let _e323 = (*s).roughness; + shown = vec3(clamp(_e323, 0f, 1f)); } else { - let _e325 = code; - if (_e325 == 4i) { - let _e328 = (*s).metallic; - shown = vec3(clamp(_e328, 0f, 1f)); + let _e326 = code; + if (_e326 == 4i) { + let _e329 = (*s).metallic; + shown = vec3(clamp(_e329, 0f, 1f)); } else { - let _e331 = code; - if (_e331 == 5i) { - let _e334 = (*s).occlusion; - shown = vec3(clamp(_e334, 0f, 1f)); + let _e332 = code; + if (_e332 == 5i) { + let _e335 = (*s).occlusion; + shown = vec3(clamp(_e335, 0f, 1f)); } else { - let _e337 = code; - if (_e337 == 6i) { - let _e340 = (*s).emissive; - param_6 = clamp(_e340, vec3(0f, 0f, 0f), vec3(1f, 1f, 1f)); - let _e342 = LinearToSrgb_u0028_vf3_u003b((¶m_6)); - shown = _e342; + let _e338 = code; + if (_e338 == 6i) { + let _e341 = (*s).emissive; + param_6 = clamp(_e341, vec3(0f, 0f, 0f), vec3(1f, 1f, 1f)); + let _e343 = LinearToSrgb_u0028_vf3_u003b((¶m_6)); + shown = _e343; } else { - let _e343 = code; - if (_e343 == 7i) { + let _e344 = code; + if (_e344 == 7i) { param_7 = 0i; - let _e345 = MapUv_u0028_i1_u003b((¶m_7)); - let _e346 = fract(_e345); - shown = vec3(_e346.x, _e346.y, 0f); + let _e346 = MapUv_u0028_i1_u003b((¶m_7)); + let _e347 = fract(_e346); + shown = vec3(_e347.x, _e347.y, 0f); } else { - let _e350 = code; - if (_e350 == 8i) { - let _e352 = (*lit); - param_8 = clamp(_e352, vec3(0f, 0f, 0f), vec3(1f, 1f, 1f)); - let _e354 = LinearToSrgb_u0028_vf3_u003b((¶m_8)); - grey = dot(_e354, vec3(0.2126f, 0.7152f, 0.0722f)); - let _e356 = (*lit); - param_9 = _e356; - let _e357 = NonFinite_u0028_vf3_u003b((¶m_9)); - if _e357 { + let _e351 = code; + if (_e351 == 8i) { + let _e353 = (*lit); + param_8 = clamp(_e353, vec3(0f, 0f, 0f), vec3(1f, 1f, 1f)); + let _e355 = LinearToSrgb_u0028_vf3_u003b((¶m_8)); + grey = dot(_e355, vec3(0.2126f, 0.7152f, 0.0722f)); + let _e357 = (*lit); + param_9 = _e357; + let _e358 = NonFinite_u0028_vf3_u003b((¶m_9)); + if _e358 { local_3 = vec3(1f, 0f, 1f); } else { - let _e358 = grey; - local_3 = vec3((_e358 * 0.5f)); + let _e359 = grey; + local_3 = vec3((_e359 * 0.5f)); } - let _e361 = local_3; - shown = _e361; + let _e362 = local_3; + shown = _e362; } } } @@ -18318,24 +18423,24 @@ fn WriteDebugView_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_ } } } - let _e362 = g_premultiply; - if _e362 { - let _e364 = (*s).alpha; - local_4 = _e364; + let _e363 = g_premultiply; + if _e363 { + let _e365 = (*s).alpha; + local_4 = _e365; } else { local_4 = 1f; } - let _e365 = local_4; - weight_2 = _e365; - let _e366 = shown; - param_10 = _e366; - let _e367 = SrgbToLinear_u0028_vf3_u003b((¶m_10)); - let _e368 = weight_2; - let _e369 = (_e367 * _e368); - let _e371 = (*s).alpha; - frag_color = vec4(_e369.x, _e369.y, _e369.z, _e371); - let _e377 = (*s).roughness; - param_11 = _e377; + let _e366 = local_4; + weight_2 = _e366; + let _e367 = shown; + param_10 = _e367; + let _e368 = SrgbToLinear_u0028_vf3_u003b((¶m_10)); + let _e369 = weight_2; + let _e370 = (_e368 * _e369); + let _e372 = (*s).alpha; + frag_color = vec4(_e370.x, _e370.y, _e370.z, _e372); + let _e378 = (*s).roughness; + param_11 = _e378; WriteSurfaceGeometry_u0028_f1_u003b((¶m_11)); WriteWeightedBlended_u0028_(); return true; @@ -18346,42 +18451,42 @@ fn V_SmithGGXCorrelated_u0028_f1_u003b_f1_u003b_f1_u003b(n_dot_v: ptr, alpha_4: ptr) -> f32 { var a: f32; var k_1: f32; - let _e277 = (*n_dot_h); - let _e278 = (*alpha_4); - a = (_e277 * _e278); - let _e280 = (*alpha_4); - let _e281 = (*n_dot_h); + let _e278 = (*n_dot_h); + let _e279 = (*alpha_4); + a = (_e278 * _e279); + let _e281 = (*alpha_4); let _e282 = (*n_dot_h); - let _e285 = a; + let _e283 = (*n_dot_h); let _e286 = a; - k_1 = (_e280 / max(((1f - (_e281 * _e282)) + (_e285 * _e286)), 0.0000001f)); - let _e291 = k_1; + let _e287 = a; + k_1 = (_e281 / max(((1f - (_e282 * _e283)) + (_e286 * _e287)), 0.0000001f)); let _e292 = k_1; - return ((_e291 * _e292) * 0.31830987f); + let _e293 = k_1; + return ((_e292 * _e293) * 0.31830987f); } fn LtcEdge_u0028_vf3_u003b_vf3_u003b(a_1: ptr>, b: ptr>) -> vec3 { @@ -18390,37 +18495,37 @@ fn LtcEdge_u0028_vf3_u003b_vf3_u003b(a_1: ptr>, b: ptr; - let _e279 = (*a_1); - let _e280 = (*b); - axis = cross(_e279, _e280); - let _e282 = axis; - len = length(_e282); - let _e284 = (*a_1); - let _e285 = (*b); - angle = acos(clamp(dot(_e284, _e285), -1f, 1f)); - let _e289 = len; - if (_e289 > 0.000001f) { - let _e291 = axis; - let _e292 = angle; - let _e293 = len; - local_5 = (_e291 * (_e292 / (_e293 * 6.2831855f))); + let _e280 = (*a_1); + let _e281 = (*b); + axis = cross(_e280, _e281); + let _e283 = axis; + len = length(_e283); + let _e285 = (*a_1); + let _e286 = (*b); + angle = acos(clamp(dot(_e285, _e286), -1f, 1f)); + let _e290 = len; + if (_e290 > 0.000001f) { + let _e292 = axis; + let _e293 = angle; + let _e294 = len; + local_5 = (_e292 * (_e293 / (_e294 * 6.2831855f))); } else { local_5 = vec3(0f, 0f, 0f); } - let _e297 = local_5; - return _e297; + let _e298 = local_5; + return _e298; } fn LtcUv_u0028_f1_u003b_f1_u003b_f1_u003b(x: ptr, y: ptr, table: ptr) -> vec2 { var inTable: vec2; - let _e277 = (*x); - let _e278 = (*y); - inTable = ((vec2(_e277, _e278) * 0.984375f) + vec2(0.0078125f)); - let _e284 = inTable[0u]; - let _e286 = inTable[1u]; - let _e287 = (*table); - return vec2(_e284, ((_e286 + _e287) * 0.5f)); + let _e278 = (*x); + let _e279 = (*y); + inTable = ((vec2(_e278, _e279) * 0.984375f) + vec2(0.0078125f)); + let _e285 = inTable[0u]; + let _e287 = inTable[1u]; + let _e288 = (*table); + return vec2(_e285, ((_e287 + _e288) * 0.5f)); } fn LtcRectangle_u0028_vf3_u003b_vf3_u003b_f1_u003b_vf3_u005b_4_u005d_u003b(n_1: ptr>, v: ptr>, roughness_2: ptr, corners: ptr, 4>>) -> vec3 { @@ -18459,126 +18564,126 @@ fn LtcRectangle_u0028_vf3_u003b_vf3_u003b_f1_u003b_vf3_u005b_4_u005d_u003b(n_1: var param_27: f32; var param_28: f32; - let _e311 = (*roughness_2); - let _e313 = (*n_1); - let _e314 = (*v); - uv = vec2(clamp(_e311, 0f, 1f), sqrt(clamp((1f - dot(_e313, _e314)), 0f, 1f))); - let _e321 = uv[0u]; - param_12 = _e321; - let _e323 = uv[1u]; - param_13 = _e323; + let _e312 = (*roughness_2); + let _e314 = (*n_1); + let _e315 = (*v); + uv = vec2(clamp(_e312, 0f, 1f), sqrt(clamp((1f - dot(_e314, _e315)), 0f, 1f))); + let _e322 = uv[0u]; + param_12 = _e322; + let _e324 = uv[1u]; + param_13 = _e324; param_14 = 0f; - let _e324 = LtcUv_u0028_f1_u003b_f1_u003b_f1_u003b((¶m_12), (¶m_13), (¶m_14)); - let _e325 = textureSampleLevel(ltc_texture_tex, ltc_texture_smp, _e324, 0f); - inverse = _e325; - let _e327 = uv[0u]; - param_15 = _e327; - let _e329 = uv[1u]; - param_16 = _e329; + let _e325 = LtcUv_u0028_f1_u003b_f1_u003b_f1_u003b((¶m_12), (¶m_13), (¶m_14)); + let _e326 = textureSampleLevel(ltc_texture_tex, ltc_texture_smp, _e325, 0f); + inverse = _e326; + let _e328 = uv[0u]; + param_15 = _e328; + let _e330 = uv[1u]; + param_16 = _e330; param_17 = 1f; - let _e330 = LtcUv_u0028_f1_u003b_f1_u003b_f1_u003b((¶m_15), (¶m_16), (¶m_17)); - let _e331 = textureSampleLevel(ltc_texture_tex, ltc_texture_smp, _e330, 0f); - fit = _e331; - let _e332 = (*v); - let _e333 = (*n_1); - let _e334 = (*v); - let _e335 = (*n_1); - along = (_e332 - (_e333 * dot(_e334, _e335))); - let _e339 = along; - alongLength = length(_e339); - let _e341 = alongLength; - if (_e341 > 0.00001f) { - let _e343 = along; - let _e344 = alongLength; - local_6 = (_e343 / vec3(_e344)); - } else { - let _e347 = (*n_1); - let _e349 = (*n_1)[2u]; - local_6 = normalize(cross(_e347, select(vec3(1f, 0f, 0f), vec3(0f, 0f, 1f), vec3((abs(_e349) < 0.999f))))); - } - let _e356 = local_6; - t1_ = _e356; - let _e357 = (*n_1); - let _e358 = t1_; - t2_ = cross(_e357, _e358); - let _e361 = inverse[0u]; - let _e363 = inverse[1u]; - let _e364 = vec3(_e361, 0f, _e363); - let _e366 = inverse[2u]; - let _e368 = inverse[3u]; - let _e369 = vec3(_e366, 0f, _e368); - minv = mat3x3(vec3(_e364.x, _e364.y, _e364.z), vec3(vec3(0f, 1f, 0f).x, vec3(0f, 1f, 0f).y, vec3(0f, 1f, 0f).z), vec3(_e369.x, _e369.y, _e369.z)); + let _e331 = LtcUv_u0028_f1_u003b_f1_u003b_f1_u003b((¶m_15), (¶m_16), (¶m_17)); + let _e332 = textureSampleLevel(ltc_texture_tex, ltc_texture_smp, _e331, 0f); + fit = _e332; + let _e333 = (*v); + let _e334 = (*n_1); + let _e335 = (*v); + let _e336 = (*n_1); + along = (_e333 - (_e334 * dot(_e335, _e336))); + let _e340 = along; + alongLength = length(_e340); + let _e342 = alongLength; + if (_e342 > 0.00001f) { + let _e344 = along; + let _e345 = alongLength; + local_6 = (_e344 / vec3(_e345)); + } else { + let _e348 = (*n_1); + let _e350 = (*n_1)[2u]; + local_6 = normalize(cross(_e348, select(vec3(1f, 0f, 0f), vec3(0f, 0f, 1f), vec3((abs(_e350) < 0.999f))))); + } + let _e357 = local_6; + t1_ = _e357; + let _e358 = (*n_1); + let _e359 = t1_; + t2_ = cross(_e358, _e359); + let _e362 = inverse[0u]; + let _e364 = inverse[1u]; + let _e365 = vec3(_e362, 0f, _e364); + let _e367 = inverse[2u]; + let _e369 = inverse[3u]; + let _e370 = vec3(_e367, 0f, _e369); + minv = mat3x3(vec3(_e365.x, _e365.y, _e365.z), vec3(vec3(0f, 1f, 0f).x, vec3(0f, 1f, 0f).y, vec3(0f, 1f, 0f).z), vec3(_e370.x, _e370.y, _e370.z)); i = 0i; loop { - let _e383 = i; - if (_e383 < 4i) { - let _e385 = i; - let _e387 = (*corners)[_e385]; - p = _e387; - let _e388 = i; - let _e389 = minv; - let _e390 = p; - let _e391 = t1_; - let _e393 = p; - let _e394 = t2_; - let _e396 = p; - let _e397 = (*n_1); - l[_e388] = normalize((_e389 * vec3(dot(_e390, _e391), dot(_e393, _e394), dot(_e396, _e397)))); + let _e384 = i; + if (_e384 < 4i) { + let _e386 = i; + let _e388 = (*corners)[_e386]; + p = _e388; + let _e389 = i; + let _e390 = minv; + let _e391 = p; + let _e392 = t1_; + let _e394 = p; + let _e395 = t2_; + let _e397 = p; + let _e398 = (*n_1); + l[_e389] = normalize((_e390 * vec3(dot(_e391, _e392), dot(_e394, _e395), dot(_e397, _e398)))); continue; } else { break; } continuing { - let _e403 = i; - i = (_e403 + 1i); - } - } - let _e406 = l[0i]; - param_18 = _e406; - let _e408 = l[1i]; - param_19 = _e408; - let _e409 = LtcEdge_u0028_vf3_u003b_vf3_u003b((¶m_18), (¶m_19)); - let _e411 = l[1i]; - param_20 = _e411; - let _e413 = l[2i]; - param_21 = _e413; - let _e414 = LtcEdge_u0028_vf3_u003b_vf3_u003b((¶m_20), (¶m_21)); - let _e417 = l[2i]; - param_22 = _e417; - let _e419 = l[3i]; - param_23 = _e419; - let _e420 = LtcEdge_u0028_vf3_u003b_vf3_u003b((¶m_22), (¶m_23)); - let _e423 = l[3i]; - param_24 = _e423; - let _e425 = l[0i]; - param_25 = _e425; - let _e426 = LtcEdge_u0028_vf3_u003b_vf3_u003b((¶m_24), (¶m_25)); - f = -((((_e409 + _e414) + _e420) + _e426)); - let _e429 = f; - len_1 = length(_e429); - let _e431 = len_1; - if (_e431 > 0.000000001f) { - let _e434 = f[2u]; - let _e435 = len_1; - local_7 = (_e434 / _e435); + let _e404 = i; + i = (_e404 + 1i); + } + } + let _e407 = l[0i]; + param_18 = _e407; + let _e409 = l[1i]; + param_19 = _e409; + let _e410 = LtcEdge_u0028_vf3_u003b_vf3_u003b((¶m_18), (¶m_19)); + let _e412 = l[1i]; + param_20 = _e412; + let _e414 = l[2i]; + param_21 = _e414; + let _e415 = LtcEdge_u0028_vf3_u003b_vf3_u003b((¶m_20), (¶m_21)); + let _e418 = l[2i]; + param_22 = _e418; + let _e420 = l[3i]; + param_23 = _e420; + let _e421 = LtcEdge_u0028_vf3_u003b_vf3_u003b((¶m_22), (¶m_23)); + let _e424 = l[3i]; + param_24 = _e424; + let _e426 = l[0i]; + param_25 = _e426; + let _e427 = LtcEdge_u0028_vf3_u003b_vf3_u003b((¶m_24), (¶m_25)); + f = -((((_e410 + _e415) + _e421) + _e427)); + let _e430 = f; + len_1 = length(_e430); + let _e432 = len_1; + if (_e432 > 0.000000001f) { + let _e435 = f[2u]; + let _e436 = len_1; + local_7 = (_e435 / _e436); } else { local_7 = 0f; } - let _e437 = local_7; - z_1 = _e437; - let _e438 = z_1; - let _e441 = len_1; - param_26 = ((_e438 * 0.5f) + 0.5f); - param_27 = clamp(_e441, 0f, 1f); + let _e438 = local_7; + z_1 = _e438; + let _e439 = z_1; + let _e442 = len_1; + param_26 = ((_e439 * 0.5f) + 0.5f); + param_27 = clamp(_e442, 0f, 1f); param_28 = 1f; - let _e443 = LtcUv_u0028_f1_u003b_f1_u003b_f1_u003b((¶m_26), (¶m_27), (¶m_28)); - let _e444 = textureSampleLevel(ltc_texture_tex, ltc_texture_smp, _e443, 0f); - sphere = _e444.w; - let _e446 = len_1; - let _e447 = sphere; - let _e451 = fit[0u]; - let _e453 = fit[1u]; - return vec3(max((_e446 * _e447), 0f), _e451, _e453); + let _e444 = LtcUv_u0028_f1_u003b_f1_u003b_f1_u003b((¶m_26), (¶m_27), (¶m_28)); + let _e445 = textureSampleLevel(ltc_texture_tex, ltc_texture_smp, _e444, 0f); + sphere = _e445.w; + let _e447 = len_1; + let _e448 = sphere; + let _e452 = fit[0u]; + let _e454 = fit[1u]; + return vec3(max((_e447 * _e448), 0f), _e452, _e454); } fn CoatLobe_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_struct_u002d_LightSample_u002d_vf3_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf31_u003b(s_1: ptr, light: ptr) -> f32 { @@ -18600,115 +18705,115 @@ fn CoatLobe_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u0 var param_37: f32; var f_1: f32; - let _e293 = (*light).integrated; - if (_e293 > 0.5f) { - let _e295 = g_coat_n; - param_29 = _e295; - let _e297 = (*s_1).v; - param_30 = _e297; - let _e298 = g_coat_roughness; - param_31 = _e298; - let _e299 = g_rect_corners; - param_32 = _e299; - let _e300 = LtcRectangle_u0028_vf3_u003b_vf3_u003b_f1_u003b_vf3_u005b_4_u005d_u003b((¶m_29), (¶m_30), (¶m_31), (¶m_32)); - ltc = _e300; - let _e302 = ltc[0u]; - let _e304 = ltc[1u]; - let _e307 = ltc[2u]; - let _e313 = frag_info.material[3u]; - let _e316 = (*light).n_dot_l; - return (((_e302 * ((0.04f * _e304) + (0.96f * _e307))) * _e313) / max(_e316, 0.000001f)); - } - let _e319 = g_coat_roughness; - lobe = max(_e319, 0.045f); - let _e321 = lobe; + let _e294 = (*light).integrated; + if (_e294 > 0.5f) { + let _e296 = g_coat_n; + param_29 = _e296; + let _e298 = (*s_1).v; + param_30 = _e298; + let _e299 = g_coat_roughness; + param_31 = _e299; + let _e300 = g_rect_corners; + param_32 = _e300; + let _e301 = LtcRectangle_u0028_vf3_u003b_vf3_u003b_f1_u003b_vf3_u005b_4_u005d_u003b((¶m_29), (¶m_30), (¶m_31), (¶m_32)); + ltc = _e301; + let _e303 = ltc[0u]; + let _e305 = ltc[1u]; + let _e308 = ltc[2u]; + let _e314 = frag_info.material[3u]; + let _e317 = (*light).n_dot_l; + return (((_e303 * ((0.04f * _e305) + (0.96f * _e308))) * _e314) / max(_e317, 0.000001f)); + } + let _e320 = g_coat_roughness; + lobe = max(_e320, 0.045f); let _e322 = lobe; - alpha_5 = (_e321 * _e322); - let _e324 = g_coat_n; - let _e326 = (*light).l; - n_dot_l_1 = max(dot(_e324, _e326), 0f); - let _e329 = g_coat_n; - let _e331 = (*light).h; - n_dot_h_1 = max(dot(_e329, _e331), 0f); - let _e334 = n_dot_h_1; - param_33 = _e334; - let _e335 = alpha_5; - param_34 = _e335; - let _e336 = D_GGX_u0028_f1_u003b_f1_u003b((¶m_33), (¶m_34)); - d_1 = _e336; - let _e337 = g_coat_n_dot_v; - param_35 = _e337; - let _e338 = n_dot_l_1; - param_36 = _e338; - let _e339 = alpha_5; - param_37 = _e339; - let _e340 = V_SmithGGXCorrelated_u0028_f1_u003b_f1_u003b_f1_u003b((¶m_35), (¶m_36), (¶m_37)); - vis = _e340; - let _e342 = (*light).v_dot_h; - f_1 = (0.04f + (0.96f * pow((1f - _e342), 5f))); - let _e347 = d_1; - let _e348 = vis; - let _e350 = f_1; - let _e354 = frag_info.material[3u]; - let _e356 = n_dot_l_1; - let _e359 = (*light).n_dot_l; - return (((((_e347 * _e348) * _e350) * _e354) * _e356) / max(_e359, 0.000001f)); + let _e323 = lobe; + alpha_5 = (_e322 * _e323); + let _e325 = g_coat_n; + let _e327 = (*light).l; + n_dot_l_1 = max(dot(_e325, _e327), 0f); + let _e330 = g_coat_n; + let _e332 = (*light).h; + n_dot_h_1 = max(dot(_e330, _e332), 0f); + let _e335 = n_dot_h_1; + param_33 = _e335; + let _e336 = alpha_5; + param_34 = _e336; + let _e337 = D_GGX_u0028_f1_u003b_f1_u003b((¶m_33), (¶m_34)); + d_1 = _e337; + let _e338 = g_coat_n_dot_v; + param_35 = _e338; + let _e339 = n_dot_l_1; + param_36 = _e339; + let _e340 = alpha_5; + param_37 = _e340; + let _e341 = V_SmithGGXCorrelated_u0028_f1_u003b_f1_u003b_f1_u003b((¶m_35), (¶m_36), (¶m_37)); + vis = _e341; + let _e343 = (*light).v_dot_h; + f_1 = (0.04f + (0.96f * pow((1f - _e343), 5f))); + let _e348 = d_1; + let _e349 = vis; + let _e351 = f_1; + let _e355 = frag_info.material[3u]; + let _e357 = n_dot_l_1; + let _e360 = (*light).n_dot_l; + return (((((_e348 * _e349) * _e351) * _e355) * _e357) / max(_e360, 0.000001f)); } fn V_Neubelt_u0028_f1_u003b_f1_u003b(n_dot_v_1: ptr, n_dot_l_2: ptr) -> f32 { - let _e275 = (*n_dot_l_2); - let _e276 = (*n_dot_v_1); - let _e278 = (*n_dot_l_2); - let _e279 = (*n_dot_v_1); - return (1f / (4f * ((_e275 + _e276) - (_e278 * _e279)))); + let _e276 = (*n_dot_l_2); + let _e277 = (*n_dot_v_1); + let _e279 = (*n_dot_l_2); + let _e280 = (*n_dot_v_1); + return (1f / (4f * ((_e276 + _e277) - (_e279 * _e280)))); } fn D_Charlie_u0028_f1_u003b_f1_u003b(roughness_3: ptr, n_dot_h_2: ptr) -> f32 { var inv_alpha: f32; var sin2h: f32; - let _e277 = (*roughness_3); let _e278 = (*roughness_3); - inv_alpha = (1f / (_e277 * _e278)); - let _e281 = (*n_dot_h_2); + let _e279 = (*roughness_3); + inv_alpha = (1f / (_e278 * _e279)); let _e282 = (*n_dot_h_2); - sin2h = max((1f - (_e281 * _e282)), 0.0078125f); - let _e286 = inv_alpha; - let _e288 = sin2h; - let _e289 = inv_alpha; - return (((2f + _e286) * pow(_e288, (_e289 * 0.5f))) / 6.2831855f); + let _e283 = (*n_dot_h_2); + sin2h = max((1f - (_e282 * _e283)), 0.0078125f); + let _e287 = inv_alpha; + let _e289 = sin2h; + let _e290 = inv_alpha; + return (((2f + _e287) * pow(_e289, (_e290 * 0.5f))) / 6.2831855f); } fn FonAlbedo_u0028_f1_u003b_f1_u003b(mu: ptr, r: ptr) -> f32 { var m: f32; var g: f32; - let _e277 = (*mu); - m = (1f - _e277); - let _e279 = m; + let _e278 = (*mu); + m = (1f - _e278); let _e280 = m; let _e281 = m; let _e282 = m; - g = (_e279 * (0.05710853f + (_e280 * (0.49188188f + (_e281 * (-0.33218145f + (_e282 * 0.071443f))))))); - let _e290 = (*r); - let _e291 = g; - let _e294 = (*r); - return ((1f + (_e290 * _e291)) / (1f + (0.2877934f * _e294))); + let _e283 = m; + g = (_e280 * (0.05710853f + (_e281 * (0.49188188f + (_e282 * (-0.33218145f + (_e283 * 0.071443f))))))); + let _e291 = (*r); + let _e292 = g; + let _e295 = (*r); + return ((1f + (_e291 * _e292)) / (1f + (0.2877934f * _e295))); } fn EonMultiAlbedo_u0028_vf3_u003b_f1_u003b(rho: ptr>, average: ptr) -> vec3 { - let _e275 = (*rho); let _e276 = (*rho); - let _e278 = (*average); - let _e280 = (*rho); - let _e281 = (*average); - return (((_e275 * _e276) * _e278) / (vec3(1f, 1f, 1f) - (_e280 * (1f - _e281)))); + let _e277 = (*rho); + let _e279 = (*average); + let _e281 = (*rho); + let _e282 = (*average); + return (((_e276 * _e277) * _e279) / (vec3(1f, 1f, 1f) - (_e281 * (1f - _e282)))); } fn FonAverage_u0028_f1_u003b(r_1: ptr) -> f32 { - let _e274 = (*r_1); - let _e277 = (*r_1); - return ((1f + (0.07248821f * _e274)) / (1f + (0.2877934f * _e277))); + let _e275 = (*r_1); + let _e278 = (*r_1); + return ((1f + (0.07248821f * _e275)) / (1f + (0.2877934f * _e278))); } fn EonLobe_u0028_vf3_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b(rho_1: ptr>, r_2: ptr, mu_i: ptr, mu_o: ptr, l_dot_v: ptr) -> vec3 { @@ -18727,58 +18832,58 @@ fn EonLobe_u0028_vf3_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b(rho_1: ptr 0f) { - let _e299 = s_2; - let _e300 = (*mu_i); - let _e301 = (*mu_o); - local_8 = (_e299 / max(_e300, _e301)); - } else { - let _e304 = s_2; - local_8 = _e304; - } - let _e305 = local_8; - s_over_t = _e305; - let _e306 = (*r_2); - af = (1f / (1f + (0.2877934f * _e306))); - let _e310 = (*rho_1); - let _e311 = af; - let _e312 = (*r_2); - let _e313 = s_over_t; - single = (_e310 * (_e311 * (1f + (_e312 * _e313)))); - let _e318 = (*r_2); - param_38 = _e318; - let _e319 = FonAverage_u0028_f1_u003b((¶m_38)); - average_1 = _e319; - let _e320 = (*rho_1); - param_39 = _e320; - let _e321 = average_1; - param_40 = _e321; - let _e322 = EonMultiAlbedo_u0028_vf3_u003b_f1_u003b((¶m_39), (¶m_40)); - let _e323 = (*mu_o); - param_41 = _e323; - let _e324 = (*r_2); - param_42 = _e324; - let _e325 = FonAlbedo_u0028_f1_u003b_f1_u003b((¶m_41), (¶m_42)); - let _e328 = (*mu_i); - param_43 = _e328; - let _e329 = (*r_2); - param_44 = _e329; - let _e330 = FonAlbedo_u0028_f1_u003b_f1_u003b((¶m_43), (¶m_44)); - let _e334 = average_1; - multi = (_e322 * ((max((1f - _e325), 0.0000001f) * max((1f - _e330), 0.0000001f)) / max((1f - _e334), 0.0000001f))); - let _e339 = single; - let _e340 = multi; - return ((_e339 + _e340) / vec3(3.1415927f)); + let _e293 = (*l_dot_v); + let _e294 = (*mu_i); + let _e295 = (*mu_o); + s_2 = (_e293 - (_e294 * _e295)); + let _e298 = s_2; + if (_e298 > 0f) { + let _e300 = s_2; + let _e301 = (*mu_i); + let _e302 = (*mu_o); + local_8 = (_e300 / max(_e301, _e302)); + } else { + let _e305 = s_2; + local_8 = _e305; + } + let _e306 = local_8; + s_over_t = _e306; + let _e307 = (*r_2); + af = (1f / (1f + (0.2877934f * _e307))); + let _e311 = (*rho_1); + let _e312 = af; + let _e313 = (*r_2); + let _e314 = s_over_t; + single = (_e311 * (_e312 * (1f + (_e313 * _e314)))); + let _e319 = (*r_2); + param_38 = _e319; + let _e320 = FonAverage_u0028_f1_u003b((¶m_38)); + average_1 = _e320; + let _e321 = (*rho_1); + param_39 = _e321; + let _e322 = average_1; + param_40 = _e322; + let _e323 = EonMultiAlbedo_u0028_vf3_u003b_f1_u003b((¶m_39), (¶m_40)); + let _e324 = (*mu_o); + param_41 = _e324; + let _e325 = (*r_2); + param_42 = _e325; + let _e326 = FonAlbedo_u0028_f1_u003b_f1_u003b((¶m_41), (¶m_42)); + let _e329 = (*mu_i); + param_43 = _e329; + let _e330 = (*r_2); + param_44 = _e330; + let _e331 = FonAlbedo_u0028_f1_u003b_f1_u003b((¶m_43), (¶m_44)); + let _e335 = average_1; + multi = (_e323 * ((max((1f - _e326), 0.0000001f) * max((1f - _e331), 0.0000001f)) / max((1f - _e335), 0.0000001f))); + let _e340 = single; + let _e341 = multi; + return ((_e340 + _e341) / vec3(3.1415927f)); } fn EonDiffuse_u0028_() -> bool { - let _e275 = frag_info.ambient_sky[3u]; - return (_e275 > 0.5f); + let _e276 = frag_info.ambient_sky[3u]; + return (_e276 > 0.5f); } fn EnvBrdf_u0028_f1_u003b_f1_u003b(roughness_4: ptr, n_dot_v_2: ptr) -> vec2 { @@ -18787,18 +18892,18 @@ fn EnvBrdf_u0028_f1_u003b_f1_u003b(roughness_4: ptr, n_dot_v_2: p var param_46: f32; var param_47: f32; - let _e279 = (*roughness_4); - let _e281 = (*n_dot_v_2); - param_45 = clamp(_e279, 0f, 1f); - param_46 = sqrt(clamp((1f - _e281), 0f, 1f)); + let _e280 = (*roughness_4); + let _e282 = (*n_dot_v_2); + param_45 = clamp(_e280, 0f, 1f); + param_46 = sqrt(clamp((1f - _e282), 0f, 1f)); param_47 = 1f; - let _e285 = LtcUv_u0028_f1_u003b_f1_u003b_f1_u003b((¶m_45), (¶m_46), (¶m_47)); - let _e286 = textureSampleLevel(ltc_texture_tex, ltc_texture_smp, _e285, 0f); - dfg = _e286.xy; - let _e289 = dfg[0u]; - let _e291 = dfg[1u]; - let _e294 = dfg[1u]; - return vec2((_e289 - _e291), _e294); + let _e286 = LtcUv_u0028_f1_u003b_f1_u003b_f1_u003b((¶m_45), (¶m_46), (¶m_47)); + let _e287 = textureSampleLevel(ltc_texture_tex, ltc_texture_smp, _e286, 0f); + dfg = _e287.xy; + let _e290 = dfg[0u]; + let _e292 = dfg[1u]; + let _e295 = dfg[1u]; + return vec2((_e290 - _e292), _e295); } fn MultiscatterScale_u0028_vf3_u003b_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b(f0_: ptr>, s_3: ptr) -> vec3 { @@ -18807,58 +18912,58 @@ fn MultiscatterScale_u0028_vf3_u003b_struct_u002d_Surface_u002d_vf3_u002d_f1_u00 var param_49: f32; var ess: f32; - let _e280 = (*s_3).roughness; - param_48 = max(_e280, 0.045f); - let _e283 = (*s_3).n_dot_v; - param_49 = _e283; - let _e284 = EnvBrdf_u0028_f1_u003b_f1_u003b((¶m_48), (¶m_49)); - ab = _e284; - let _e286 = ab[0u]; - let _e288 = ab[1u]; - ess = max((_e286 + _e288), 0.0001f); - let _e291 = (*f0_); - let _e292 = ess; - return (vec3(1f, 1f, 1f) + (_e291 * ((1f / _e292) - 1f))); + let _e281 = (*s_3).roughness; + param_48 = max(_e281, 0.045f); + let _e284 = (*s_3).n_dot_v; + param_49 = _e284; + let _e285 = EnvBrdf_u0028_f1_u003b_f1_u003b((¶m_48), (¶m_49)); + ab = _e285; + let _e287 = ab[0u]; + let _e289 = ab[1u]; + ess = max((_e287 + _e289), 0.0001f); + let _e292 = (*f0_); + let _e293 = ess; + return (vec3(1f, 1f, 1f) + (_e292 * ((1f / _e293) - 1f))); } fn EnergyCompensation_u0028_() -> bool { - let _e275 = frag_info.target_origin[2u]; - return (_e275 > 0.5f); + let _e276 = frag_info.target_origin[2u]; + return (_e276 > 0.5f); } fn F_SchlickF90_u0028_vf3_u003b_vf3_u003b_f1_u003b(f0_1: ptr>, f90_: ptr>, v_dot_h: ptr) -> vec3 { var f_2: f32; - let _e277 = (*v_dot_h); - f_2 = pow((1f - _e277), 5f); - let _e280 = (*f0_1); - let _e281 = (*f90_); - let _e282 = (*f0_1); - let _e284 = f_2; - return (_e280 + ((_e281 - _e282) * _e284)); + let _e278 = (*v_dot_h); + f_2 = pow((1f - _e278), 5f); + let _e281 = (*f0_1); + let _e282 = (*f90_); + let _e283 = (*f0_1); + let _e285 = f_2; + return (_e281 + ((_e282 - _e283) * _e285)); } fn V_GGXAnisotropic_u0028_f1_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b(n_dot_l_3: ptr, n_dot_v_3: ptr, b_dot_v: ptr, t_dot_v: ptr, t_dot_l: ptr, b_dot_l: ptr, at: ptr, ab_1: ptr) -> f32 { var ggx_v: f32; var ggx_l: f32; - let _e283 = (*n_dot_l_3); - let _e284 = (*at); - let _e285 = (*t_dot_v); - let _e287 = (*ab_1); - let _e288 = (*b_dot_v); - let _e290 = (*n_dot_v_3); - ggx_v = (_e283 * length(vec3((_e284 * _e285), (_e287 * _e288), _e290))); - let _e294 = (*n_dot_v_3); - let _e295 = (*at); - let _e296 = (*t_dot_l); - let _e298 = (*ab_1); - let _e299 = (*b_dot_l); - let _e301 = (*n_dot_l_3); - ggx_l = (_e294 * length(vec3((_e295 * _e296), (_e298 * _e299), _e301))); - let _e305 = ggx_v; - let _e306 = ggx_l; - return clamp((0.5f / max((_e305 + _e306), 0.00001f)), 0f, 1f); + let _e284 = (*n_dot_l_3); + let _e285 = (*at); + let _e286 = (*t_dot_v); + let _e288 = (*ab_1); + let _e289 = (*b_dot_v); + let _e291 = (*n_dot_v_3); + ggx_v = (_e284 * length(vec3((_e285 * _e286), (_e288 * _e289), _e291))); + let _e295 = (*n_dot_v_3); + let _e296 = (*at); + let _e297 = (*t_dot_l); + let _e299 = (*ab_1); + let _e300 = (*b_dot_l); + let _e302 = (*n_dot_l_3); + ggx_l = (_e295 * length(vec3((_e296 * _e297), (_e299 * _e300), _e302))); + let _e306 = ggx_v; + let _e307 = ggx_l; + return clamp((0.5f / max((_e306 + _e307), 0.00001f)), 0f, 1f); } fn D_GGXAnisotropic_u0028_f1_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b(n_dot_h_3: ptr, t_dot_h: ptr, b_dot_h: ptr, at_1: ptr, ab_2: ptr) -> f32 { @@ -18866,24 +18971,24 @@ fn D_GGXAnisotropic_u0028_f1_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b(n_dot_h_3 var f_3: vec3; var w2_: f32; - let _e281 = (*at_1); - let _e282 = (*ab_2); - a2_1 = (_e281 * _e282); - let _e284 = (*ab_2); - let _e285 = (*t_dot_h); - let _e287 = (*at_1); - let _e288 = (*b_dot_h); - let _e290 = a2_1; - let _e291 = (*n_dot_h_3); - f_3 = vec3((_e284 * _e285), (_e287 * _e288), (_e290 * _e291)); - let _e294 = a2_1; - let _e295 = f_3; + let _e282 = (*at_1); + let _e283 = (*ab_2); + a2_1 = (_e282 * _e283); + let _e285 = (*ab_2); + let _e286 = (*t_dot_h); + let _e288 = (*at_1); + let _e289 = (*b_dot_h); + let _e291 = a2_1; + let _e292 = (*n_dot_h_3); + f_3 = vec3((_e285 * _e286), (_e288 * _e289), (_e291 * _e292)); + let _e295 = a2_1; let _e296 = f_3; - w2_ = (_e294 / max(dot(_e295, _e296), 0.000000000001f)); - let _e300 = a2_1; - let _e301 = w2_; - let _e303 = w2_; - return (((_e300 * _e301) * _e303) / 3.1415927f); + let _e297 = f_3; + w2_ = (_e295 / max(dot(_e296, _e297), 0.000000000001f)); + let _e301 = a2_1; + let _e302 = w2_; + let _e304 = w2_; + return (((_e301 * _e302) * _e304) / 3.1415927f); } fn ShadeLight_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_struct_u002d_LightSample_u002d_vf3_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf31_u003b(s_4: ptr, light_1: ptr) -> vec3 { @@ -18935,197 +19040,197 @@ fn ShadeLight_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_ var param_82: Surface; var param_83: LightSample; - let _e323 = (*s_4).roughness; - lobe_1 = max(_e323, 0.045f); - let _e325 = lobe_1; + let _e324 = (*s_4).roughness; + lobe_1 = max(_e324, 0.045f); let _e326 = lobe_1; - alpha_6 = (_e325 * _e326); - let _e328 = g_f0_dielectric; - let _e330 = (*s_4).albedo; - let _e332 = (*s_4).metallic; - f0_2 = mix(_e328, _e330, vec3(_e332)); - let _e335 = g_f90_; - let _e337 = (*s_4).metallic; - f90_1 = vec3(mix(_e335, 1f, _e337)); - let _e341 = (*s_4).albedo; - let _e343 = (*s_4).metallic; - diffuseColor = (_e341 * (1f - _e343)); - let _e347 = (*light_1).n_dot_h; - param_50 = _e347; - let _e348 = alpha_6; - param_51 = _e348; - let _e349 = D_GGX_u0028_f1_u003b_f1_u003b((¶m_50), (¶m_51)); - d_2 = _e349; - let _e351 = (*s_4).n_dot_v; - param_52 = _e351; - let _e353 = (*light_1).n_dot_l; - param_53 = _e353; - let _e354 = alpha_6; - param_54 = _e354; - let _e355 = V_SmithGGXCorrelated_u0028_f1_u003b_f1_u003b_f1_u003b((¶m_52), (¶m_53), (¶m_54)); - vis_1 = _e355; - let _e356 = g_aniso; - if (_e356 > 0f) { - let _e358 = alpha_6; - let _e359 = g_aniso; + let _e327 = lobe_1; + alpha_6 = (_e326 * _e327); + let _e329 = g_f0_dielectric; + let _e331 = (*s_4).albedo; + let _e333 = (*s_4).metallic; + f0_2 = mix(_e329, _e331, vec3(_e333)); + let _e336 = g_f90_; + let _e338 = (*s_4).metallic; + f90_1 = vec3(mix(_e336, 1f, _e338)); + let _e342 = (*s_4).albedo; + let _e344 = (*s_4).metallic; + diffuseColor = (_e342 * (1f - _e344)); + let _e348 = (*light_1).n_dot_h; + param_50 = _e348; + let _e349 = alpha_6; + param_51 = _e349; + let _e350 = D_GGX_u0028_f1_u003b_f1_u003b((¶m_50), (¶m_51)); + d_2 = _e350; + let _e352 = (*s_4).n_dot_v; + param_52 = _e352; + let _e354 = (*light_1).n_dot_l; + param_53 = _e354; + let _e355 = alpha_6; + param_54 = _e355; + let _e356 = V_SmithGGXCorrelated_u0028_f1_u003b_f1_u003b_f1_u003b((¶m_52), (¶m_53), (¶m_54)); + vis_1 = _e356; + let _e357 = g_aniso; + if (_e357 > 0f) { + let _e359 = alpha_6; let _e360 = g_aniso; - at_2 = mix(_e358, 1f, (_e359 * _e360)); - let _e363 = alpha_6; - ab_3 = max(_e363, 0.001f); - let _e365 = g_aniso_t; - let _e367 = (*light_1).h; - let _e369 = g_aniso_b; - let _e371 = (*light_1).h; - let _e374 = (*light_1).n_dot_h; - param_55 = _e374; - param_56 = dot(_e365, _e367); - param_57 = dot(_e369, _e371); - let _e375 = at_2; - param_58 = _e375; - let _e376 = ab_3; - param_59 = _e376; - let _e377 = D_GGXAnisotropic_u0028_f1_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b((¶m_55), (¶m_56), (¶m_57), (¶m_58), (¶m_59)); - d_2 = _e377; - let _e378 = g_aniso_b; - let _e380 = (*s_4).v; - let _e382 = g_aniso_t; - let _e384 = (*s_4).v; - let _e386 = g_aniso_t; - let _e388 = (*light_1).l; - let _e390 = g_aniso_b; - let _e392 = (*light_1).l; - let _e395 = (*light_1).n_dot_l; - param_60 = _e395; - let _e397 = (*s_4).n_dot_v; - param_61 = _e397; - param_62 = dot(_e378, _e380); - param_63 = dot(_e382, _e384); - param_64 = dot(_e386, _e388); - param_65 = dot(_e390, _e392); - let _e398 = at_2; - param_66 = _e398; - let _e399 = ab_3; - param_67 = _e399; - let _e400 = V_GGXAnisotropic_u0028_f1_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b((¶m_60), (¶m_61), (¶m_62), (¶m_63), (¶m_64), (¶m_65), (¶m_66), (¶m_67)); - vis_1 = _e400; - } - let _e401 = f0_2; - param_68 = _e401; - let _e402 = f90_1; - param_69 = _e402; - let _e404 = (*light_1).v_dot_h; - param_70 = _e404; - let _e405 = F_SchlickF90_u0028_vf3_u003b_vf3_u003b_f1_u003b((¶m_68), (¶m_69), (¶m_70)); - f_4 = _e405; - let _e406 = f_4; - let _e407 = g_irid_fresnel; - let _e408 = g_iridescence; - f_4 = mix(_e406, _e407, vec3(_e408)); - let _e411 = d_2; - let _e412 = vis_1; - let _e414 = f_4; - let _e418 = frag_info.material[3u]; - specular = ((_e414 * (_e411 * _e412)) * _e418); - let _e421 = (*light_1).integrated; - if (_e421 > 0.5f) { - let _e425 = (*light_1).ltc[0u]; - let _e426 = f0_2; - let _e429 = (*light_1).ltc[1u]; - let _e431 = f90_1; - let _e432 = f0_2; - let _e436 = (*light_1).ltc[2u]; - let _e442 = frag_info.material[3u]; - let _e445 = (*light_1).n_dot_l; - specular = (((((_e426 * _e429) + ((_e431 - _e432) * _e436)) * _e425) * _e442) / vec3(max(_e445, 0.000001f))); - } - let _e449 = EnergyCompensation_u0028_(); - if _e449 { - let _e450 = f0_2; - param_71 = _e450; - let _e451 = (*s_4); - param_72 = _e451; - let _e452 = MultiscatterScale_u0028_vf3_u003b_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b((¶m_71), (¶m_72)); - let _e453 = specular; - specular = (_e453 * _e452); - } - let _e455 = diffuseColor; - let _e456 = f_4; - diffuse = ((_e455 * (vec3(1f, 1f, 1f) - _e456)) / vec3(3.1415927f)); - let _e461 = EonDiffuse_u0028_(); - if _e461 { - let _e463 = (*s_4).n; - let _e465 = (*light_1).l; - let _e469 = (*light_1).l; - let _e471 = (*s_4).v; - let _e473 = diffuseColor; - param_73 = _e473; - let _e475 = (*s_4).roughness; - param_74 = _e475; - param_75 = clamp(dot(_e463, _e465), 0.0001f, 1f); - let _e477 = (*s_4).n_dot_v; - param_76 = _e477; - param_77 = dot(_e469, _e471); - let _e478 = EonLobe_u0028_vf3_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b((¶m_73), (¶m_74), (¶m_75), (¶m_76), (¶m_77)); - let _e479 = f_4; - diffuse = (_e478 * (vec3(1f, 1f, 1f) - _e479)); - } - let _e482 = g_transmission; - let _e484 = diffuse; - diffuse = (_e484 * (1f - _e482)); - let _e486 = g_sheen; - let _e487 = g_sheen_roughness; - param_78 = _e487; - let _e489 = (*light_1).n_dot_h; - param_79 = _e489; - let _e490 = D_Charlie_u0028_f1_u003b_f1_u003b((¶m_78), (¶m_79)); - let _e493 = (*s_4).n; - let _e495 = (*light_1).l; - let _e499 = (*s_4).n_dot_v; - param_80 = _e499; - param_81 = clamp(dot(_e493, _e495), 0f, 1f); - let _e500 = V_Neubelt_u0028_f1_u003b_f1_u003b((¶m_80), (¶m_81)); - sheen = ((_e486 * _e490) * _e500); - let _e502 = diffuse; - let _e503 = specular; - let _e505 = g_sheen_scale; - let _e507 = sheen; - let _e509 = g_coat_through; - let _e511 = g_coat; - let _e512 = (*s_4); - param_82 = _e512; - let _e513 = (*light_1); - param_83 = _e513; - let _e514 = CoatLobe_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_struct_u002d_LightSample_u002d_vf3_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf31_u003b((¶m_82), (¶m_83)); - return ((((((_e502 + _e503) * _e505) + _e507) * _e509) + vec3((_e511 * _e514))) * 3.1415927f); + let _e361 = g_aniso; + at_2 = mix(_e359, 1f, (_e360 * _e361)); + let _e364 = alpha_6; + ab_3 = max(_e364, 0.001f); + let _e366 = g_aniso_t; + let _e368 = (*light_1).h; + let _e370 = g_aniso_b; + let _e372 = (*light_1).h; + let _e375 = (*light_1).n_dot_h; + param_55 = _e375; + param_56 = dot(_e366, _e368); + param_57 = dot(_e370, _e372); + let _e376 = at_2; + param_58 = _e376; + let _e377 = ab_3; + param_59 = _e377; + let _e378 = D_GGXAnisotropic_u0028_f1_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b((¶m_55), (¶m_56), (¶m_57), (¶m_58), (¶m_59)); + d_2 = _e378; + let _e379 = g_aniso_b; + let _e381 = (*s_4).v; + let _e383 = g_aniso_t; + let _e385 = (*s_4).v; + let _e387 = g_aniso_t; + let _e389 = (*light_1).l; + let _e391 = g_aniso_b; + let _e393 = (*light_1).l; + let _e396 = (*light_1).n_dot_l; + param_60 = _e396; + let _e398 = (*s_4).n_dot_v; + param_61 = _e398; + param_62 = dot(_e379, _e381); + param_63 = dot(_e383, _e385); + param_64 = dot(_e387, _e389); + param_65 = dot(_e391, _e393); + let _e399 = at_2; + param_66 = _e399; + let _e400 = ab_3; + param_67 = _e400; + let _e401 = V_GGXAnisotropic_u0028_f1_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b((¶m_60), (¶m_61), (¶m_62), (¶m_63), (¶m_64), (¶m_65), (¶m_66), (¶m_67)); + vis_1 = _e401; + } + let _e402 = f0_2; + param_68 = _e402; + let _e403 = f90_1; + param_69 = _e403; + let _e405 = (*light_1).v_dot_h; + param_70 = _e405; + let _e406 = F_SchlickF90_u0028_vf3_u003b_vf3_u003b_f1_u003b((¶m_68), (¶m_69), (¶m_70)); + f_4 = _e406; + let _e407 = f_4; + let _e408 = g_irid_fresnel; + let _e409 = g_iridescence; + f_4 = mix(_e407, _e408, vec3(_e409)); + let _e412 = d_2; + let _e413 = vis_1; + let _e415 = f_4; + let _e419 = frag_info.material[3u]; + specular = ((_e415 * (_e412 * _e413)) * _e419); + let _e422 = (*light_1).integrated; + if (_e422 > 0.5f) { + let _e426 = (*light_1).ltc[0u]; + let _e427 = f0_2; + let _e430 = (*light_1).ltc[1u]; + let _e432 = f90_1; + let _e433 = f0_2; + let _e437 = (*light_1).ltc[2u]; + let _e443 = frag_info.material[3u]; + let _e446 = (*light_1).n_dot_l; + specular = (((((_e427 * _e430) + ((_e432 - _e433) * _e437)) * _e426) * _e443) / vec3(max(_e446, 0.000001f))); + } + let _e450 = EnergyCompensation_u0028_(); + if _e450 { + let _e451 = f0_2; + param_71 = _e451; + let _e452 = (*s_4); + param_72 = _e452; + let _e453 = MultiscatterScale_u0028_vf3_u003b_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b((¶m_71), (¶m_72)); + let _e454 = specular; + specular = (_e454 * _e453); + } + let _e456 = diffuseColor; + let _e457 = f_4; + diffuse = ((_e456 * (vec3(1f, 1f, 1f) - _e457)) / vec3(3.1415927f)); + let _e462 = EonDiffuse_u0028_(); + if _e462 { + let _e464 = (*s_4).n; + let _e466 = (*light_1).l; + let _e470 = (*light_1).l; + let _e472 = (*s_4).v; + let _e474 = diffuseColor; + param_73 = _e474; + let _e476 = (*s_4).roughness; + param_74 = _e476; + param_75 = clamp(dot(_e464, _e466), 0.0001f, 1f); + let _e478 = (*s_4).n_dot_v; + param_76 = _e478; + param_77 = dot(_e470, _e472); + let _e479 = EonLobe_u0028_vf3_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b((¶m_73), (¶m_74), (¶m_75), (¶m_76), (¶m_77)); + let _e480 = f_4; + diffuse = (_e479 * (vec3(1f, 1f, 1f) - _e480)); + } + let _e483 = g_transmission; + let _e485 = diffuse; + diffuse = (_e485 * (1f - _e483)); + let _e487 = g_sheen; + let _e488 = g_sheen_roughness; + param_78 = _e488; + let _e490 = (*light_1).n_dot_h; + param_79 = _e490; + let _e491 = D_Charlie_u0028_f1_u003b_f1_u003b((¶m_78), (¶m_79)); + let _e494 = (*s_4).n; + let _e496 = (*light_1).l; + let _e500 = (*s_4).n_dot_v; + param_80 = _e500; + param_81 = clamp(dot(_e494, _e496), 0f, 1f); + let _e501 = V_Neubelt_u0028_f1_u003b_f1_u003b((¶m_80), (¶m_81)); + sheen = ((_e487 * _e491) * _e501); + let _e503 = diffuse; + let _e504 = specular; + let _e506 = g_sheen_scale; + let _e508 = sheen; + let _e510 = g_coat_through; + let _e512 = g_coat; + let _e513 = (*s_4); + param_82 = _e513; + let _e514 = (*light_1); + param_83 = _e514; + let _e515 = CoatLobe_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_struct_u002d_LightSample_u002d_vf3_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf31_u003b((¶m_82), (¶m_83)); + return ((((((_e503 + _e504) * _e506) + _e508) * _e510) + vec3((_e512 * _e515))) * 3.1415927f); } fn PointShadowDiskTap_u0028_i1_u003b(i_1: ptr) -> vec2 { - let _e274 = (*i_1); - if (_e274 == 0i) { + let _e275 = (*i_1); + if (_e275 == 0i) { return vec2(-0.94201624f, -0.39906216f); } - let _e276 = (*i_1); - if (_e276 == 1i) { + let _e277 = (*i_1); + if (_e277 == 1i) { return vec2(0.9455861f, -0.76890725f); } - let _e278 = (*i_1); - if (_e278 == 2i) { + let _e279 = (*i_1); + if (_e279 == 2i) { return vec2(-0.0941841f, -0.9293887f); } - let _e280 = (*i_1); - if (_e280 == 3i) { + let _e281 = (*i_1); + if (_e281 == 3i) { return vec2(0.34495938f, 0.2938776f); } - let _e282 = (*i_1); - if (_e282 == 4i) { + let _e283 = (*i_1); + if (_e283 == 4i) { return vec2(-0.9158858f, 0.45771432f); } - let _e284 = (*i_1); - if (_e284 == 5i) { + let _e285 = (*i_1); + if (_e285 == 5i) { return vec2(-0.8154423f, -0.87912464f); } - let _e286 = (*i_1); - if (_e286 == 6i) { + let _e287 = (*i_1); + if (_e287 == 6i) { return vec2(-0.38277543f, 0.27676845f); } return vec2(0.974844f, 0.7564838f); @@ -19135,20 +19240,20 @@ fn PointShadowOffset_u0028_i1_u003b_f1_u003b_f1_u003b_f1_u003b(i_2: ptr; var param_84: i32; - let _e279 = (*i_2); - param_84 = _e279; - let _e280 = PointShadowDiskTap_u0028_i1_u003b((¶m_84)); - p_1 = _e280; - let _e282 = p_1[0u]; - let _e283 = (*ca); - let _e286 = p_1[1u]; - let _e287 = (*sa); - let _e291 = p_1[0u]; - let _e292 = (*sa); - let _e295 = p_1[1u]; - let _e296 = (*ca); - let _e300 = (*radius); - return (vec2(((_e282 * _e283) - (_e286 * _e287)), ((_e291 * _e292) + (_e295 * _e296))) * _e300); + let _e280 = (*i_2); + param_84 = _e280; + let _e281 = PointShadowDiskTap_u0028_i1_u003b((¶m_84)); + p_1 = _e281; + let _e283 = p_1[0u]; + let _e284 = (*ca); + let _e287 = p_1[1u]; + let _e288 = (*sa); + let _e292 = p_1[0u]; + let _e293 = (*sa); + let _e296 = p_1[1u]; + let _e297 = (*ca); + let _e301 = (*radius); + return (vec2(((_e283 * _e284) - (_e287 * _e288)), ((_e292 * _e293) + (_e296 * _e297))) * _e301); } fn PointShadowDistance_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b(uv_1: ptr>, offset: ptr>, tile: ptr>, range: ptr) -> f32 { @@ -19156,27 +19261,27 @@ fn PointShadowDistance_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b(uv_1: ptr; var atlas: vec2; - let _e282 = point_shadow.params[0u]; - inset = _e282; - let _e283 = (*uv_1); - let _e284 = (*offset); - let _e286 = inset; + let _e283 = point_shadow.params[0u]; + inset = _e283; + let _e284 = (*uv_1); + let _e285 = (*offset); let _e287 = inset; - local_9 = clamp((_e283 + _e284), vec2(_e286), vec2((1f - _e287))); - let _e292 = local_9; - let _e293 = (*tile); - atlas = ((_e292 + _e293) * vec2(0.16666667f, 0.16666667f)); - let _e298 = point_shadow.params3_[0u]; - if (_e298 > 0.5f) { - let _e301 = atlas[1u]; - atlas[1u] = (1f - _e301); - } - let _e304 = atlas; - let _e305 = textureSampleLevel(point_shadow_texture_tex, point_shadow_texture_smp, _e304, 0f); - let _e307 = atlas; - let _e308 = textureSampleLevel(point_shadow_static_texture_tex, point_shadow_static_texture_smp, _e307, 0f); - let _e311 = (*range); - return (min(_e305.x, _e308.x) * _e311); + let _e288 = inset; + local_9 = clamp((_e284 + _e285), vec2(_e287), vec2((1f - _e288))); + let _e293 = local_9; + let _e294 = (*tile); + atlas = ((_e293 + _e294) * vec2(0.16666667f, 0.16666667f)); + let _e299 = point_shadow.params3_[0u]; + if (_e299 > 0.5f) { + let _e302 = atlas[1u]; + atlas[1u] = (1f - _e302); + } + let _e305 = atlas; + let _e306 = textureSampleLevel(point_shadow_texture_tex, point_shadow_texture_smp, _e305, 0f); + let _e308 = atlas; + let _e309 = textureSampleLevel(point_shadow_static_texture_tex, point_shadow_static_texture_smp, _e308, 0f); + let _e312 = (*range); + return (min(_e306.x, _e309.x) * _e312); } fn PointShadowTap_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b_f1_u003b(uv_2: ptr>, offset_1: ptr>, tile_1: ptr>, range_1: ptr, receiver: ptr) -> f32 { @@ -19186,24 +19291,24 @@ fn PointShadowTap_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b_f1_u003b(uv_2: pt var param_87: vec2; var param_88: f32; - let _e283 = (*uv_2); - param_85 = _e283; - let _e284 = (*offset_1); - param_86 = _e284; - let _e285 = (*tile_1); - param_87 = _e285; - let _e286 = (*range_1); - param_88 = _e286; - let _e287 = PointShadowDistance_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b((¶m_85), (¶m_86), (¶m_87), (¶m_88)); - stored = _e287; - let _e288 = stored; - let _e289 = (*range_1); - if (_e288 >= (_e289 * 0.999f)) { + let _e284 = (*uv_2); + param_85 = _e284; + let _e285 = (*offset_1); + param_86 = _e285; + let _e286 = (*tile_1); + param_87 = _e286; + let _e287 = (*range_1); + param_88 = _e287; + let _e288 = PointShadowDistance_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b((¶m_85), (¶m_86), (¶m_87), (¶m_88)); + stored = _e288; + let _e289 = stored; + let _e290 = (*range_1); + if (_e289 >= (_e290 * 0.999f)) { return 1f; } - let _e292 = (*receiver); - let _e293 = stored; - return select(1f, 0f, (_e292 > _e293)); + let _e293 = (*receiver); + let _e294 = stored; + return select(1f, 0f, (_e293 > _e294)); } fn PointShadowPenumbra_u0028_vf2_u003b_vf2_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b(uv_3: ptr>, tile_2: ptr>, range_2: ptr, receiver_1: ptr, ca_1: ptr, sa_1: ptr, tanHalf: ptr, blockerOut: ptr) -> f32 { @@ -19230,111 +19335,111 @@ fn PointShadowPenumbra_u0028_vf2_u003b_vf2_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u var world: f32; (*blockerOut) = -1f; - let _e304 = point_shadow.params2_[1u]; - lightRadius = _e304; - let _e307 = point_shadow.params2_[0u]; - minRadius = _e307; - let _e310 = point_shadow.params2_[2u]; - maxRadius = _e310; - let _e311 = lightRadius; - if (_e311 <= 0f) { - let _e313 = (*uv_3); - param_89 = _e313; + let _e305 = point_shadow.params2_[1u]; + lightRadius = _e305; + let _e308 = point_shadow.params2_[0u]; + minRadius = _e308; + let _e311 = point_shadow.params2_[2u]; + maxRadius = _e311; + let _e312 = lightRadius; + if (_e312 <= 0f) { + let _e314 = (*uv_3); + param_89 = _e314; param_90 = vec2(0f, 0f); - let _e314 = (*tile_2); - param_91 = _e314; - let _e315 = (*range_2); - param_92 = _e315; - let _e316 = PointShadowDistance_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b((¶m_89), (¶m_90), (¶m_91), (¶m_92)); - (*blockerOut) = _e316; - let _e317 = minRadius; - return _e317; + let _e315 = (*tile_2); + param_91 = _e315; + let _e316 = (*range_2); + param_92 = _e316; + let _e317 = PointShadowDistance_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b((¶m_89), (¶m_90), (¶m_91), (¶m_92)); + (*blockerOut) = _e317; + let _e318 = minRadius; + return _e318; } sum = 0f; count = 0f; i_3 = 0i; loop { - let _e318 = i_3; - if (_e318 < 8i) { - let _e320 = i_3; - param_93 = _e320; - let _e321 = (*ca_1); - param_94 = _e321; - let _e322 = (*sa_1); - param_95 = _e322; - let _e323 = maxRadius; - param_96 = _e323; - let _e324 = PointShadowOffset_u0028_i1_u003b_f1_u003b_f1_u003b_f1_u003b((¶m_93), (¶m_94), (¶m_95), (¶m_96)); - let _e325 = (*uv_3); - param_97 = _e325; - param_98 = _e324; - let _e326 = (*tile_2); - param_99 = _e326; - let _e327 = (*range_2); - param_100 = _e327; - let _e328 = PointShadowDistance_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b((¶m_97), (¶m_98), (¶m_99), (¶m_100)); - stored_1 = _e328; - let _e329 = stored_1; - let _e330 = (*range_2); - if (_e329 >= (_e330 * 0.999f)) { + let _e319 = i_3; + if (_e319 < 8i) { + let _e321 = i_3; + param_93 = _e321; + let _e322 = (*ca_1); + param_94 = _e322; + let _e323 = (*sa_1); + param_95 = _e323; + let _e324 = maxRadius; + param_96 = _e324; + let _e325 = PointShadowOffset_u0028_i1_u003b_f1_u003b_f1_u003b_f1_u003b((¶m_93), (¶m_94), (¶m_95), (¶m_96)); + let _e326 = (*uv_3); + param_97 = _e326; + param_98 = _e325; + let _e327 = (*tile_2); + param_99 = _e327; + let _e328 = (*range_2); + param_100 = _e328; + let _e329 = PointShadowDistance_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b((¶m_97), (¶m_98), (¶m_99), (¶m_100)); + stored_1 = _e329; + let _e330 = stored_1; + let _e331 = (*range_2); + if (_e330 >= (_e331 * 0.999f)) { continue; } - let _e333 = stored_1; - let _e334 = (*receiver_1); - if (_e333 >= _e334) { + let _e334 = stored_1; + let _e335 = (*receiver_1); + if (_e334 >= _e335) { continue; } - let _e336 = stored_1; - let _e337 = sum; - sum = (_e337 + _e336); - let _e339 = count; - count = (_e339 + 1f); + let _e337 = stored_1; + let _e338 = sum; + sum = (_e338 + _e337); + let _e340 = count; + count = (_e340 + 1f); continue; } else { break; } continuing { - let _e341 = i_3; - i_3 = (_e341 + 1i); + let _e342 = i_3; + i_3 = (_e342 + 1i); } } - let _e343 = count; - if (_e343 < 0.5f) { + let _e344 = count; + if (_e344 < 0.5f) { return -1f; } - let _e345 = sum; - let _e346 = count; - blocker = max((_e345 / _e346), 0.0001f); - let _e349 = blocker; - (*blockerOut) = _e349; - let _e350 = lightRadius; - let _e351 = (*receiver_1); - let _e352 = blocker; - let _e356 = blocker; - world = ((_e350 * max((_e351 - _e352), 0f)) / _e356); - let _e358 = world; - let _e359 = (*receiver_1); - let _e361 = (*tanHalf); - let _e364 = minRadius; - let _e365 = maxRadius; - return clamp((_e358 / ((2f * _e359) * _e361)), _e364, _e365); + let _e346 = sum; + let _e347 = count; + blocker = max((_e346 / _e347), 0.0001f); + let _e350 = blocker; + (*blockerOut) = _e350; + let _e351 = lightRadius; + let _e352 = (*receiver_1); + let _e353 = blocker; + let _e357 = blocker; + world = ((_e351 * max((_e352 - _e353), 0f)) / _e357); + let _e359 = world; + let _e360 = (*receiver_1); + let _e362 = (*tanHalf); + let _e365 = minRadius; + let _e366 = maxRadius; + return clamp((_e359 / ((2f * _e360) * _e362)), _e365, _e366); } fn FragCoordFromTop_u0028_f1_u003b(rows: ptr) -> vec2 { var local_10: vec2; - let _e275 = (*rows); - if (_e275 > 0f) { - let _e278 = gl_FragCoord_1[0u]; - let _e279 = (*rows); - let _e281 = gl_FragCoord_1[1u]; - local_10 = vec2(_e278, (_e279 - _e281)); + let _e276 = (*rows); + if (_e276 > 0f) { + let _e279 = gl_FragCoord_1[0u]; + let _e280 = (*rows); + let _e282 = gl_FragCoord_1[1u]; + local_10 = vec2(_e279, (_e280 - _e282)); } else { - let _e284 = gl_FragCoord_1; - local_10 = _e284.xy; + let _e285 = gl_FragCoord_1; + local_10 = _e285.xy; } - let _e286 = local_10; - return _e286; + let _e287 = local_10; + return _e287; } fn PointShadowFactor_u0028_vf3_u003b_vf3_u003b_i1_u003b(world_1: ptr>, normal: ptr>, lightIndex: ptr) -> f32 { @@ -19392,257 +19497,257 @@ fn PointShadowFactor_u0028_vf3_u003b_vf3_u003b_i1_u003b(world_1: ptr= _e414) { + let _e370 = nDotL; + slope = min((sqrt(max((1f - (_e363 * _e364)), 0f)) / (_e369 * _e370)), 8f); + let _e374 = toLightLength; + let _e376 = (*lightIndex); + let _e380 = point_shadow.slots[_e376][2u]; + let _e385 = point_shadow.params3_[1u]; + texel = (((2f * _e374) * max(_e380, 0.0001f)) * _e385); + let _e387 = (*world_1); + let _e388 = (*normal); + let _e389 = texel; + let _e393 = point_shadow.params[3u]; + let _e395 = slope; + origin = (_e387 + (((_e388 * _e389) * _e393) * (1f + _e395))); + let _e399 = origin; + let _e400 = slot_1; + let _e403 = point_shadow.lights[_e400]; + toFragment = (_e399 - _e403.xyz); + let _e406 = toFragment; + distance_ = length(_e406); + let _e408 = slot_1; + let _e412 = point_shadow.lights[_e408][3u]; + range_3 = max(_e412, 0.0001f); + let _e414 = distance_; + let _e415 = range_3; + if (_e414 >= _e415) { return 1f; } face = 0i; - let _e416 = (*lightIndex); - let _e420 = point_shadow.slots[_e416][1u]; - if (_e420 < 0.5f) { - let _e422 = toFragment; - a_2 = abs(_e422); - let _e425 = a_2[0u]; - let _e427 = a_2[1u]; - let _e428 = (_e425 >= _e427); - phi_2703_ = _e428; - if _e428 { - let _e430 = a_2[0u]; - let _e432 = a_2[2u]; - phi_2703_ = (_e430 >= _e432); - } - let _e435 = phi_2703_; - if _e435 { - let _e437 = toFragment[0u]; - face = select(1i, 0i, (_e437 > 0f)); + let _e417 = (*lightIndex); + let _e421 = point_shadow.slots[_e417][1u]; + if (_e421 < 0.5f) { + let _e423 = toFragment; + a_2 = abs(_e423); + let _e426 = a_2[0u]; + let _e428 = a_2[1u]; + let _e429 = (_e426 >= _e428); + phi_2703_ = _e429; + if _e429 { + let _e431 = a_2[0u]; + let _e433 = a_2[2u]; + phi_2703_ = (_e431 >= _e433); + } + let _e436 = phi_2703_; + if _e436 { + let _e438 = toFragment[0u]; + face = select(1i, 0i, (_e438 > 0f)); } else { - let _e441 = a_2[1u]; - let _e443 = a_2[2u]; - if (_e441 >= _e443) { - let _e446 = toFragment[1u]; - face = select(3i, 2i, (_e446 > 0f)); + let _e442 = a_2[1u]; + let _e444 = a_2[2u]; + if (_e442 >= _e444) { + let _e447 = toFragment[1u]; + face = select(3i, 2i, (_e447 > 0f)); } else { - let _e450 = toFragment[2u]; - face = select(5i, 4i, (_e450 > 0f)); + let _e451 = toFragment[2u]; + face = select(5i, 4i, (_e451 > 0f)); } } } - let _e453 = slot_1; - let _e455 = face; - let _e459 = point_shadow.faces[((_e453 * 6i) + _e455)]; - let _e460 = origin; - clip = (_e459 * vec4(_e460.x, _e460.y, _e460.z, 1f)); - let _e467 = clip[3u]; - if (_e467 <= 0f) { + let _e454 = slot_1; + let _e456 = face; + let _e460 = point_shadow.faces[((_e454 * 6i) + _e456)]; + let _e461 = origin; + clip = (_e460 * vec4(_e461.x, _e461.y, _e461.z, 1f)); + let _e468 = clip[3u]; + if (_e468 <= 0f) { return 1f; } - let _e469 = clip; - let _e472 = clip[3u]; - ndc = (_e469.xy / vec2(_e472)); - let _e476 = ndc[0u]; - let _e478 = (abs(_e476) > 1f); - phi_2764_ = _e478; - if !(_e478) { - let _e481 = ndc[1u]; - phi_2764_ = (abs(_e481) > 1f); - } - let _e485 = phi_2764_; - if _e485 { + let _e470 = clip; + let _e473 = clip[3u]; + ndc = (_e470.xy / vec2(_e473)); + let _e477 = ndc[0u]; + let _e479 = (abs(_e477) > 1f); + phi_2764_ = _e479; + if !(_e479) { + let _e482 = ndc[1u]; + phi_2764_ = (abs(_e482) > 1f); + } + let _e486 = phi_2764_; + if _e486 { return 1f; } - let _e487 = ndc[0u]; - let _e491 = ndc[1u]; - uv_4 = vec2(((_e487 * 0.5f) + 0.5f), (0.5f - (_e491 * 0.5f))); - let _e495 = face; - let _e497 = slot_1; - tile_3 = vec2(f32(_e495), f32(_e497)); - let _e500 = distance_; - let _e503 = point_shadow.params[1u]; - receiver_2 = (_e500 - _e503); - let _e507 = frag_info.target_origin[0u]; - param_101 = _e507; - let _e508 = FragCoordFromTop_u0028_f1_u003b((¶m_101)); - noise = fract((52.982918f * fract(dot(_e508, vec2(0.06711056f, 0.00583715f))))); - let _e513 = noise; - angle_1 = (_e513 * 6.2831855f); - let _e515 = angle_1; - ca_2 = cos(_e515); - let _e517 = angle_1; - sa_2 = sin(_e517); - let _e519 = (*lightIndex); - let _e523 = point_shadow.slots[_e519][2u]; - tanHalf_1 = max(_e523, 0.0001f); + let _e488 = ndc[0u]; + let _e492 = ndc[1u]; + uv_4 = vec2(((_e488 * 0.5f) + 0.5f), (0.5f - (_e492 * 0.5f))); + let _e496 = face; + let _e498 = slot_1; + tile_3 = vec2(f32(_e496), f32(_e498)); + let _e501 = distance_; + let _e504 = point_shadow.params[1u]; + receiver_2 = (_e501 - _e504); + let _e508 = frag_info.target_origin[0u]; + param_101 = _e508; + let _e509 = FragCoordFromTop_u0028_f1_u003b((¶m_101)); + noise = fract((52.982918f * fract(dot(_e509, vec2(0.06711056f, 0.00583715f))))); + let _e514 = noise; + angle_1 = (_e514 * 6.2831855f); + let _e516 = angle_1; + ca_2 = cos(_e516); + let _e518 = angle_1; + sa_2 = sin(_e518); + let _e520 = (*lightIndex); + let _e524 = point_shadow.slots[_e520][2u]; + tanHalf_1 = max(_e524, 0.0001f); blocker_1 = -1f; - let _e525 = uv_4; - param_102 = _e525; - let _e526 = tile_3; - param_103 = _e526; - let _e527 = range_3; - param_104 = _e527; - let _e528 = receiver_2; - param_105 = _e528; - let _e529 = ca_2; - param_106 = _e529; - let _e530 = sa_2; - param_107 = _e530; - let _e531 = tanHalf_1; - param_108 = _e531; - let _e532 = PointShadowPenumbra_u0028_vf2_u003b_vf2_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b((¶m_102), (¶m_103), (¶m_104), (¶m_105), (¶m_106), (¶m_107), (¶m_108), (¶m_109)); - let _e533 = param_109; - blocker_1 = _e533; - radius_1 = _e532; - let _e536 = point_shadow.params2_[3u]; - if (_e536 > 0.5f) { + let _e526 = uv_4; + param_102 = _e526; + let _e527 = tile_3; + param_103 = _e527; + let _e528 = range_3; + param_104 = _e528; + let _e529 = receiver_2; + param_105 = _e529; + let _e530 = ca_2; + param_106 = _e530; + let _e531 = sa_2; + param_107 = _e531; + let _e532 = tanHalf_1; + param_108 = _e532; + let _e533 = PointShadowPenumbra_u0028_vf2_u003b_vf2_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b((¶m_102), (¶m_103), (¶m_104), (¶m_105), (¶m_106), (¶m_107), (¶m_108), (¶m_109)); + let _e534 = param_109; + blocker_1 = _e534; + radius_1 = _e533; + let _e537 = point_shadow.params2_[3u]; + if (_e537 > 0.5f) { g_debug_surface_on = true; - let _e538 = radius_1; - if (_e538 < 0f) { + let _e539 = radius_1; + if (_e539 < 0f) { local_11 = vec3(0f, 0f, 1f); } else { - let _e540 = radius_1; - let _e543 = point_shadow.params2_[2u]; - let _e547 = blocker_1; - let _e548 = range_3; - local_11 = vec3(clamp((_e540 / max(_e543, 0.000001f)), 0f, 1f), clamp((_e547 / _e548), 0f, 1f), 0f); + let _e541 = radius_1; + let _e544 = point_shadow.params2_[2u]; + let _e548 = blocker_1; + let _e549 = range_3; + local_11 = vec3(clamp((_e541 / max(_e544, 0.000001f)), 0f, 1f), clamp((_e548 / _e549), 0f, 1f), 0f); } - let _e552 = local_11; - g_debug_surface = _e552; + let _e553 = local_11; + g_debug_surface = _e553; } - let _e553 = radius_1; - if (_e553 < 0f) { + let _e554 = radius_1; + if (_e554 < 0f) { return 1f; } - let _e555 = uv_4; - param_110 = _e555; + let _e556 = uv_4; + param_110 = _e556; param_111 = vec2(0f, 0f); - let _e556 = tile_3; - param_112 = _e556; - let _e557 = range_3; - param_113 = _e557; - let _e558 = receiver_2; - param_114 = _e558; - let _e559 = PointShadowTap_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b_f1_u003b((¶m_110), (¶m_111), (¶m_112), (¶m_113), (¶m_114)); - lit_1 = _e559; - let _e560 = radius_1; - if (_e560 > 0f) { + let _e557 = tile_3; + param_112 = _e557; + let _e558 = range_3; + param_113 = _e558; + let _e559 = receiver_2; + param_114 = _e559; + let _e560 = PointShadowTap_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b_f1_u003b((¶m_110), (¶m_111), (¶m_112), (¶m_113), (¶m_114)); + lit_1 = _e560; + let _e561 = radius_1; + if (_e561 > 0f) { i_4 = 0i; loop { - let _e562 = i_4; - if (_e562 < 8i) { - let _e564 = i_4; - param_115 = _e564; - let _e565 = ca_2; - param_116 = _e565; - let _e566 = sa_2; - param_117 = _e566; - let _e567 = radius_1; - param_118 = _e567; - let _e568 = PointShadowOffset_u0028_i1_u003b_f1_u003b_f1_u003b_f1_u003b((¶m_115), (¶m_116), (¶m_117), (¶m_118)); - let _e569 = uv_4; - param_119 = _e569; - param_120 = _e568; - let _e570 = tile_3; - param_121 = _e570; - let _e571 = range_3; - param_122 = _e571; - let _e572 = receiver_2; - param_123 = _e572; - let _e573 = PointShadowTap_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b_f1_u003b((¶m_119), (¶m_120), (¶m_121), (¶m_122), (¶m_123)); - let _e574 = lit_1; - lit_1 = (_e574 + _e573); + let _e563 = i_4; + if (_e563 < 8i) { + let _e565 = i_4; + param_115 = _e565; + let _e566 = ca_2; + param_116 = _e566; + let _e567 = sa_2; + param_117 = _e567; + let _e568 = radius_1; + param_118 = _e568; + let _e569 = PointShadowOffset_u0028_i1_u003b_f1_u003b_f1_u003b_f1_u003b((¶m_115), (¶m_116), (¶m_117), (¶m_118)); + let _e570 = uv_4; + param_119 = _e570; + param_120 = _e569; + let _e571 = tile_3; + param_121 = _e571; + let _e572 = range_3; + param_122 = _e572; + let _e573 = receiver_2; + param_123 = _e573; + let _e574 = PointShadowTap_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b_f1_u003b((¶m_119), (¶m_120), (¶m_121), (¶m_122), (¶m_123)); + let _e575 = lit_1; + lit_1 = (_e575 + _e574); continue; } else { break; } continuing { - let _e576 = i_4; - i_4 = (_e576 + 1i); + let _e577 = i_4; + i_4 = (_e577 + 1i); } } - let _e578 = lit_1; - lit_1 = (_e578 * 0.11111111f); + let _e579 = lit_1; + lit_1 = (_e579 * 0.11111111f); } - let _e580 = lit_1; - let _e581 = strength; - return mix(1f, _e580, clamp(_e581, 0f, 1f)); + let _e581 = lit_1; + let _e582 = strength; + return mix(1f, _e581, clamp(_e582, 0f, 1f)); } fn VogelDisc_u0028_i1_u003b_i1_u003b_f1_u003b(i_5: ptr, n_2: ptr, turn: ptr) -> vec2 { var r_3: f32; var theta: f32; - let _e278 = (*i_5); - let _e281 = (*n_2); - r_3 = sqrt(((f32(_e278) + 0.5f) / f32(_e281))); - let _e285 = (*i_5); - let _e288 = (*turn); - theta = ((f32(_e285) * 2.3999631f) + _e288); - let _e290 = r_3; - let _e291 = theta; - let _e293 = theta; - return (vec2(cos(_e291), sin(_e293)) * _e290); + let _e279 = (*i_5); + let _e282 = (*n_2); + r_3 = sqrt(((f32(_e279) + 0.5f) / f32(_e282))); + let _e286 = (*i_5); + let _e289 = (*turn); + theta = ((f32(_e286) * 2.3999631f) + _e289); + let _e291 = r_3; + let _e292 = theta; + let _e294 = theta; + return (vec2(cos(_e292), sin(_e294)) * _e291); } fn ShadowNoise_u0028_() -> f32 { var at_3: vec2; var param_124: f32; - let _e277 = frag_info.target_origin[0u]; - param_124 = _e277; - let _e278 = FragCoordFromTop_u0028_f1_u003b((¶m_124)); - let _e281 = frag_info.target_origin[3u]; - at_3 = (_e278 + vec2((5.588238f * max(_e281, 0f)))); - let _e286 = at_3; - return fract((52.982918f * fract(dot(_e286, vec2(0.06711056f, 0.00583715f))))); + let _e278 = frag_info.target_origin[0u]; + param_124 = _e278; + let _e279 = FragCoordFromTop_u0028_f1_u003b((¶m_124)); + let _e282 = frag_info.target_origin[3u]; + at_3 = (_e279 + vec2((5.588238f * max(_e282, 0f)))); + let _e287 = at_3; + return fract((52.982918f * fract(dot(_e287, vec2(0.06711056f, 0.00583715f))))); } fn EvsmChebyshev_u0028_vf2_u003b_f1_u003b_f1_u003b_f1_u003b(moments: ptr>, t: ptr, minVariance: ptr, bleed: ptr) -> f32 { @@ -19651,37 +19756,37 @@ fn EvsmChebyshev_u0028_vf2_u003b_f1_u003b_f1_u003b_f1_u003b(moments: ptr) -> vec2 { var d_4: f32; - let _e275 = (*depth); - d_4 = ((2f * clamp(_e275, 0f, 1f)) - 1f); - let _e279 = d_4; - let _e282 = d_4; - return vec2(exp((40f * _e279)), -(exp((-5f * _e282)))); + let _e276 = (*depth); + d_4 = ((2f * clamp(_e276, 0f, 1f)) - 1f); + let _e280 = d_4; + let _e283 = d_4; + return vec2(exp((40f * _e280)), -(exp((-5f * _e283)))); } fn EvsmVisibility_u0028_vf4_u003b_f1_u003b_f1_u003b(moments_1: ptr>, depth_1: ptr, bleed_1: ptr) -> f32 { @@ -19699,37 +19804,37 @@ fn EvsmVisibility_u0028_vf4_u003b_f1_u003b_f1_u003b(moments_1: ptr(0.004f, 0.0005f) * _e291); - let _e294 = scale[0u]; - let _e296 = scale[0u]; - let _e298 = (*moments_1); - param_126 = _e298.xy; - let _e301 = warped[0u]; - param_127 = _e301; - param_128 = (_e294 * _e296); - let _e302 = (*bleed_1); - param_129 = _e302; - let _e303 = EvsmChebyshev_u0028_vf2_u003b_f1_u003b_f1_u003b_f1_u003b((¶m_126), (¶m_127), (¶m_128), (¶m_129)); - positive = _e303; - let _e305 = scale[1u]; - let _e307 = scale[1u]; - let _e309 = (*moments_1); - param_130 = _e309.zw; - let _e312 = warped[1u]; - param_131 = _e312; - param_132 = (_e305 * _e307); - let _e313 = (*bleed_1); - param_133 = _e313; - let _e314 = EvsmChebyshev_u0028_vf2_u003b_f1_u003b_f1_u003b_f1_u003b((¶m_130), (¶m_131), (¶m_132), (¶m_133)); - negative = _e314; - let _e315 = positive; - let _e316 = negative; - return min(_e315, _e316); + let _e290 = (*depth_1); + param_125 = _e290; + let _e291 = EvsmWarp_u0028_f1_u003b((¶m_125)); + warped = _e291; + let _e292 = warped; + scale = (vec2(0.004f, 0.0005f) * _e292); + let _e295 = scale[0u]; + let _e297 = scale[0u]; + let _e299 = (*moments_1); + param_126 = _e299.xy; + let _e302 = warped[0u]; + param_127 = _e302; + param_128 = (_e295 * _e297); + let _e303 = (*bleed_1); + param_129 = _e303; + let _e304 = EvsmChebyshev_u0028_vf2_u003b_f1_u003b_f1_u003b_f1_u003b((¶m_126), (¶m_127), (¶m_128), (¶m_129)); + positive = _e304; + let _e306 = scale[1u]; + let _e308 = scale[1u]; + let _e310 = (*moments_1); + param_130 = _e310.zw; + let _e313 = warped[1u]; + param_131 = _e313; + param_132 = (_e306 * _e308); + let _e314 = (*bleed_1); + param_133 = _e314; + let _e315 = EvsmChebyshev_u0028_vf2_u003b_f1_u003b_f1_u003b_f1_u003b((¶m_130), (¶m_131), (¶m_132), (¶m_133)); + negative = _e315; + let _e316 = positive; + let _e317 = negative; + return min(_e316, _e317); } fn ShadowFactor_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_struct_u002d_LightSample_u002d_vf3_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf31_u003b_i1_u003b(s_5: ptr, light_2: ptr, lightIndex_1: ptr) -> f32 { @@ -19767,6 +19872,8 @@ fn ShadowFactor_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf var tileLo: vec2; var tileHi: vec2; var stored_2: vec4; + var y_1: i32; + var x_1: i32; var through: vec3; var softness: f32; var lit_2: f32; @@ -19774,8 +19881,8 @@ fn ShadowFactor_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf var param_134: vec4; var param_135: f32; var param_136: f32; - var y_1: i32; - var x_1: i32; + var y_2: i32; + var x_2: i32; var occluder: f32; var spread: f32; var turn_1: f32; @@ -19804,45 +19911,45 @@ fn ShadowFactor_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf var phi_4266_: bool; var phi_4273_: bool; - let _e343 = frag_info.shadow_params[3u]; - strength_1 = _e343; - let _e344 = strength_1; - if (_e344 <= 0f) { + let _e346 = frag_info.shadow_params[3u]; + strength_1 = _e346; + let _e347 = strength_1; + if (_e347 <= 0f) { return 1f; } - let _e346 = (*lightIndex_1); - let _e349 = frag_info.frame_params[2u]; - if (_e346 != i32((_e349 + 0.5f))) { + let _e349 = (*lightIndex_1); + let _e352 = frag_info.frame_params[2u]; + if (_e349 != i32((_e352 + 0.5f))) { return 1f; } - let _e355 = frag_info.shadow_cascades[2u]; - cascadeCount = i32((_e355 + 0.5f)); - let _e358 = v_world_position_1; - let _e360 = frag_info.camera_position; - viewDistance = length((_e358 - _e360.xyz)); + let _e358 = frag_info.shadow_cascades[2u]; + cascadeCount = i32((_e358 + 0.5f)); + let _e361 = v_world_position_1; + let _e363 = frag_info.camera_position; + viewDistance = length((_e361 - _e363.xyz)); cascade = 0i; - let _e364 = cascadeCount; - let _e365 = (_e364 > 1i); - phi_4087_ = _e365; - if _e365 { - let _e366 = viewDistance; - let _e369 = frag_info.shadow_cascades[0u]; - phi_4087_ = (_e366 > _e369); - } - let _e372 = phi_4087_; - if _e372 { + let _e367 = cascadeCount; + let _e368 = (_e367 > 1i); + phi_4087_ = _e368; + if _e368 { + let _e369 = viewDistance; + let _e372 = frag_info.shadow_cascades[0u]; + phi_4087_ = (_e369 > _e372); + } + let _e375 = phi_4087_; + if _e375 { cascade = 1i; } - let _e373 = cascadeCount; - let _e374 = (_e373 > 2i); - phi_4098_ = _e374; - if _e374 { - let _e375 = viewDistance; - let _e378 = frag_info.shadow_cascades[1u]; - phi_4098_ = (_e375 > _e378); + let _e376 = cascadeCount; + let _e377 = (_e376 > 2i); + phi_4098_ = _e377; + if _e377 { + let _e378 = viewDistance; + let _e381 = frag_info.shadow_cascades[1u]; + phi_4098_ = (_e378 > _e381); } - let _e381 = phi_4098_; - if _e381 { + let _e384 = phi_4098_; + if _e384 { cascade = 2i; } uv_5 = vec2(0f, 0f); @@ -19853,247 +19960,280 @@ fn ShadowFactor_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf receiverSlope = 0f; attempt = 0i; loop { - let _e382 = attempt; - if (_e382 < 3i) { - let _e384 = cascade; - let _e385 = attempt; - which = (_e384 + _e385); - let _e387 = which; - let _e388 = cascadeCount; - if (_e387 >= _e388) { + let _e385 = attempt; + if (_e385 < 3i) { + let _e387 = cascade; + let _e388 = attempt; + which = (_e387 + _e388); + let _e390 = which; + let _e391 = cascadeCount; + if (_e390 >= _e391) { break; } - let _e390 = which; - if (_e390 == 0i) { - let _e393 = frag_info.shadow_matrix; - local_12 = _e393; + let _e393 = which; + if (_e393 == 0i) { + let _e396 = frag_info.shadow_matrix; + local_12 = _e396; } else { - let _e394 = which; - if (_e394 == 1i) { - let _e397 = frag_info.shadow_matrix_far; - local_13 = _e397; + let _e397 = which; + if (_e397 == 1i) { + let _e400 = frag_info.shadow_matrix_far; + local_13 = _e400; } else { - let _e399 = frag_info.shadow_matrix_farthest; - local_13 = _e399; + let _e402 = frag_info.shadow_matrix_farthest; + local_13 = _e402; } - let _e400 = local_13; - local_12 = _e400; - } - let _e401 = local_12; - matrix = _e401; - let _e404 = matrix[0][0u]; - let _e407 = matrix[1][0u]; - let _e410 = matrix[2][0u]; - axisX = vec3(_e404, _e407, _e410); - let _e414 = matrix[0][1u]; - let _e417 = matrix[1][1u]; - let _e420 = matrix[2][1u]; - axisY = vec3(_e414, _e417, _e420); - let _e422 = axisX; - rowX = max(length(_e422), 0.000001f); - let _e425 = axisY; - rowY = max(length(_e425), 0.000001f); - let _e430 = frag_info.shadow_cascades[3u]; - let _e432 = rowX; - texelMetres = ((2f * _e430) / _e432); - let _e436 = frag_info.shadow_cascades[3u]; - let _e439 = (*s_5).n; - let _e440 = axisX; - let _e443 = rowX; - let _e444 = rowX; - let _e448 = (*s_5).n; - let _e449 = axisY; - let _e452 = rowY; - let _e453 = rowY; - reach = ((3f * _e436) * ((abs(dot(_e439, _e440)) / (_e443 * _e444)) + (abs(dot(_e448, _e449)) / (_e452 * _e453)))); - let _e460 = frag_info.shadow_params[2u]; - let _e461 = texelMetres; - flatOffset = min(_e460, _e461); - let _e463 = v_world_position_1; - let _e465 = (*s_5).n; - let _e466 = flatOffset; - let _e467 = reach; - origin_1 = (_e463 + (_e465 * (_e466 + _e467))); - let _e471 = matrix; - let _e472 = origin_1; - lightSpace = (_e471 * vec4(_e472.x, _e472.y, _e472.z, 1f)); - let _e479 = lightSpace[3u]; - if (_e479 <= 0f) { + let _e403 = local_13; + local_12 = _e403; + } + let _e404 = local_12; + matrix = _e404; + let _e407 = matrix[0][0u]; + let _e410 = matrix[1][0u]; + let _e413 = matrix[2][0u]; + axisX = vec3(_e407, _e410, _e413); + let _e417 = matrix[0][1u]; + let _e420 = matrix[1][1u]; + let _e423 = matrix[2][1u]; + axisY = vec3(_e417, _e420, _e423); + let _e425 = axisX; + rowX = max(length(_e425), 0.000001f); + let _e428 = axisY; + rowY = max(length(_e428), 0.000001f); + let _e433 = frag_info.shadow_cascades[3u]; + let _e435 = rowX; + texelMetres = ((2f * _e433) / _e435); + let _e439 = frag_info.shadow_cascades[3u]; + let _e442 = (*s_5).n; + let _e443 = axisX; + let _e446 = rowX; + let _e447 = rowX; + let _e451 = (*s_5).n; + let _e452 = axisY; + let _e455 = rowY; + let _e456 = rowY; + reach = ((3f * _e439) * ((abs(dot(_e442, _e443)) / (_e446 * _e447)) + (abs(dot(_e451, _e452)) / (_e455 * _e456)))); + let _e463 = frag_info.shadow_params[2u]; + let _e464 = texelMetres; + flatOffset = min(_e463, _e464); + let _e466 = v_world_position_1; + let _e468 = (*s_5).n; + let _e469 = flatOffset; + let _e470 = reach; + origin_1 = (_e466 + (_e468 * (_e469 + _e470))); + let _e474 = matrix; + let _e475 = origin_1; + lightSpace = (_e474 * vec4(_e475.x, _e475.y, _e475.z, 1f)); + let _e482 = lightSpace[3u]; + if (_e482 <= 0f) { continue; } - let _e481 = lightSpace; - let _e484 = lightSpace[3u]; - candidate = (_e481.xyz / vec3(_e484)); - let _e488 = candidate[0u]; - let _e492 = candidate[1u]; - inTile = vec2(((_e488 * 0.5f) + 0.5f), (0.5f - (_e492 * 0.5f))); - let _e497 = inTile[0u]; - let _e498 = (_e497 < 0f); - phi_4259_ = _e498; - if !(_e498) { - let _e501 = inTile[0u]; - phi_4259_ = (_e501 > 1f); - } - let _e504 = phi_4259_; - phi_4266_ = _e504; - if !(_e504) { - let _e507 = inTile[1u]; - phi_4266_ = (_e507 < 0f); - } - let _e510 = phi_4266_; - phi_4273_ = _e510; - if !(_e510) { - let _e513 = inTile[1u]; - phi_4273_ = (_e513 > 1f); - } - let _e516 = phi_4273_; - if _e516 { + let _e484 = lightSpace; + let _e487 = lightSpace[3u]; + candidate = (_e484.xyz / vec3(_e487)); + let _e491 = candidate[0u]; + let _e495 = candidate[1u]; + inTile = vec2(((_e491 * 0.5f) + 0.5f), (0.5f - (_e495 * 0.5f))); + let _e500 = inTile[0u]; + let _e501 = (_e500 < 0f); + phi_4259_ = _e501; + if !(_e501) { + let _e504 = inTile[0u]; + phi_4259_ = (_e504 > 1f); + } + let _e507 = phi_4259_; + phi_4266_ = _e507; + if !(_e507) { + let _e510 = inTile[1u]; + phi_4266_ = (_e510 < 0f); + } + let _e513 = phi_4266_; + phi_4273_ = _e513; + if !(_e513) { + let _e516 = inTile[1u]; + phi_4273_ = (_e516 > 1f); + } + let _e519 = phi_4273_; + if _e519 { continue; } - let _e518 = candidate[2u]; - if (_e518 > 1f) { - let _e520 = which; - let _e521 = cascadeCount; - if (_e520 < (_e521 - 1i)) { + let _e521 = candidate[2u]; + if (_e521 > 1f) { + let _e523 = which; + let _e524 = cascadeCount; + if (_e523 < (_e524 - 1i)) { continue; } candidate[2u] = 1f; } - let _e526 = inTile[0u]; - let _e527 = which; - let _e530 = cascadeCount; - let _e534 = inTile[1u]; - uv_5 = vec2(((_e526 + f32(_e527)) / f32(_e530)), _e534); - let _e536 = candidate; - projected = _e536; - let _e537 = which; - cascade = _e537; - let _e538 = texelMetres; - cascadeTexel = _e538; - let _e541 = matrix[0][2u]; - let _e544 = matrix[1][2u]; - let _e547 = matrix[2][2u]; - cascadeDepth = (1f / max(length(vec3(_e541, _e544, _e547)), 0.000001f)); - let _e553 = (*s_5).n; - let _e556 = matrix[0][2u]; - let _e559 = matrix[1][2u]; - let _e562 = matrix[2][2u]; - let _e566 = cascadeDepth; - cosSlope = clamp((abs(dot(_e553, vec3(_e556, _e559, _e562))) * _e566), 0.1f, 1f); - let _e569 = texelMetres; - let _e570 = cosSlope; - let _e571 = cosSlope; - let _e577 = cosSlope; - let _e579 = cascadeDepth; - receiverSlope = (((_e569 * sqrt(max((1f - (_e570 * _e571)), 0f))) / _e577) / _e579); + let _e529 = inTile[0u]; + let _e530 = which; + let _e533 = cascadeCount; + let _e537 = inTile[1u]; + uv_5 = vec2(((_e529 + f32(_e530)) / f32(_e533)), _e537); + let _e539 = candidate; + projected = _e539; + let _e540 = which; + cascade = _e540; + let _e541 = texelMetres; + cascadeTexel = _e541; + let _e544 = matrix[0][2u]; + let _e547 = matrix[1][2u]; + let _e550 = matrix[2][2u]; + cascadeDepth = (1f / max(length(vec3(_e544, _e547, _e550)), 0.000001f)); + let _e556 = (*s_5).n; + let _e559 = matrix[0][2u]; + let _e562 = matrix[1][2u]; + let _e565 = matrix[2][2u]; + let _e569 = cascadeDepth; + cosSlope = clamp((abs(dot(_e556, vec3(_e559, _e562, _e565))) * _e569), 0.1f, 1f); + let _e572 = texelMetres; + let _e573 = cosSlope; + let _e574 = cosSlope; + let _e580 = cosSlope; + let _e582 = cascadeDepth; + receiverSlope = (((_e572 * sqrt(max((1f - (_e573 * _e574)), 0f))) / _e580) / _e582); found = true; break; } else { break; } continuing { - let _e581 = attempt; - attempt = (_e581 + 1i); + let _e584 = attempt; + attempt = (_e584 + 1i); } } - let _e583 = found; - if !(_e583) { + let _e586 = found; + if !(_e586) { return 1f; } - let _e585 = cascade; - if (_e585 == 0i) { - let _e589 = frag_info.shadow_bias[0u]; - local_14 = _e589; + let _e588 = cascade; + if (_e588 == 0i) { + let _e592 = frag_info.shadow_bias[0u]; + local_14 = _e592; } else { - let _e590 = cascade; - if (_e590 == 1i) { - let _e594 = frag_info.shadow_bias[1u]; - local_15 = _e594; - } else { - let _e597 = frag_info.shadow_bias[2u]; + let _e593 = cascade; + if (_e593 == 1i) { + let _e597 = frag_info.shadow_bias[1u]; local_15 = _e597; - } - let _e598 = local_15; - local_14 = _e598; - } - let _e599 = local_14; - bias = _e599; - let _e602 = frag_info.shadow_params[0u]; - let _e605 = frag_info.shadow_cascades[3u]; - texel_1 = vec2(_e602, _e605); - let _e607 = cascade; - let _e609 = cascadeCount; - let _e613 = texel_1; - tileLo = (vec2((f32(_e607) / f32(_e609)), 0f) + (_e613 * 0.5f)); - let _e616 = cascade; - let _e619 = cascadeCount; - let _e623 = texel_1; - tileHi = (vec2((f32((_e616 + 1i)) / f32(_e619)), 1f) - (_e623 * 0.5f)); - let _e628 = frag_info.shadow_bias[3u]; - if (_e628 > 0.5f) { - let _e630 = uv_5; - let _e631 = tileLo; - let _e632 = tileHi; - let _e634 = textureSampleLevel(shadow_texture_tex, shadow_texture_smp, clamp(_e630, _e631, _e632), 0f); - stored_2 = _e634; - let _e636 = stored_2[1u]; - let _e639 = stored_2[2u]; - let _e642 = stored_2[3u]; - through = clamp(vec3((1f - _e636), (1f - _e639), _e642), vec3(0f), vec3(4f)); - let _e647 = through; - let _e648 = strength_1; - light_transmittance = mix(vec3(1f, 1f, 1f), _e647, vec3(clamp(_e648, 0f, 1f))); - } - let _e654 = frag_info.ambient_ground[3u]; - softness = _e654; + } else { + let _e600 = frag_info.shadow_bias[2u]; + local_15 = _e600; + } + let _e601 = local_15; + local_14 = _e601; + } + let _e602 = local_14; + bias = _e602; + let _e605 = frag_info.shadow_params[0u]; + let _e608 = frag_info.shadow_cascades[3u]; + texel_1 = vec2(_e605, _e608); + let _e610 = cascade; + let _e612 = cascadeCount; + let _e616 = texel_1; + tileLo = (vec2((f32(_e610) / f32(_e612)), 0f) + (_e616 * 0.5f)); + let _e619 = cascade; + let _e622 = cascadeCount; + let _e626 = texel_1; + tileHi = (vec2((f32((_e619 + 1i)) / f32(_e622)), 1f) - (_e626 * 0.5f)); + let _e631 = frag_info.shadow_bias[3u]; + if (_e631 > 0.5f) { + stored_2 = vec4(0f, 0f, 0f, 0f); + y_1 = -1i; + loop { + let _e633 = y_1; + if (_e633 <= 1i) { + x_1 = -1i; + loop { + let _e635 = x_1; + if (_e635 <= 1i) { + let _e637 = uv_5; + let _e638 = x_1; + let _e640 = y_1; + let _e643 = texel_1; + let _e646 = tileLo; + let _e647 = tileHi; + let _e649 = textureSampleLevel(shadow_texture_tex, shadow_texture_smp, clamp((_e637 + (vec2(f32(_e638), f32(_e640)) * _e643)), _e646, _e647), 0f); + let _e650 = stored_2; + stored_2 = (_e650 + _e649); + continue; + } else { + break; + } + continuing { + let _e652 = x_1; + x_1 = (_e652 + 1i); + } + } + continue; + } else { + break; + } + continuing { + let _e654 = y_1; + y_1 = (_e654 + 1i); + } + } + let _e656 = stored_2; + stored_2 = (_e656 * 0.11111111f); + let _e659 = stored_2[1u]; + let _e662 = stored_2[2u]; + let _e665 = stored_2[3u]; + through = clamp(vec3((1f - _e659), (1f - _e662), _e665), vec3(0f), vec3(4f)); + let _e670 = through; + let _e671 = strength_1; + light_transmittance = mix(vec3(1f, 1f, 1f), _e670, vec3(clamp(_e671, 0f, 1f))); + } + let _e677 = frag_info.ambient_ground[3u]; + softness = _e677; lit_2 = 0f; - let _e655 = softness; - if (_e655 < 0f) { - let _e657 = uv_5; - let _e658 = tileLo; - let _e659 = tileHi; - let _e661 = textureSampleLevel(shadow_texture_tex, shadow_texture_smp, clamp(_e657, _e658, _e659), 0f); - moments_2 = _e661; - let _e663 = projected[2u]; - let _e664 = bias; - let _e666 = softness; - let _e670 = moments_2; - param_134 = _e670; - param_135 = (_e663 - _e664); - param_136 = clamp((-(_e666) - 1f), 0f, 0.95f); - let _e671 = EvsmVisibility_u0028_vf4_u003b_f1_u003b_f1_u003b((¶m_134), (¶m_135), (¶m_136)); - lit_2 = _e671; - } else { - let _e672 = softness; - if (_e672 <= 0f) { - y_1 = -1i; + let _e678 = softness; + if (_e678 < 0f) { + let _e680 = uv_5; + let _e681 = tileLo; + let _e682 = tileHi; + let _e684 = textureSampleLevel(shadow_texture_tex, shadow_texture_smp, clamp(_e680, _e681, _e682), 0f); + moments_2 = _e684; + let _e686 = projected[2u]; + let _e687 = bias; + let _e689 = softness; + let _e693 = moments_2; + param_134 = _e693; + param_135 = (_e686 - _e687); + param_136 = clamp((-(_e689) - 1f), 0f, 0.95f); + let _e694 = EvsmVisibility_u0028_vf4_u003b_f1_u003b_f1_u003b((¶m_134), (¶m_135), (¶m_136)); + lit_2 = _e694; + } else { + let _e695 = softness; + if (_e695 <= 0f) { + y_2 = -1i; loop { - let _e674 = y_1; - if (_e674 <= 1i) { - x_1 = -1i; + let _e697 = y_2; + if (_e697 <= 1i) { + x_2 = -1i; loop { - let _e676 = x_1; - if (_e676 <= 1i) { - let _e678 = uv_5; - let _e679 = x_1; - let _e681 = y_1; - let _e684 = texel_1; - let _e687 = tileLo; - let _e688 = tileHi; - let _e690 = textureSampleLevel(shadow_texture_tex, shadow_texture_smp, clamp((_e678 + (vec2(f32(_e679), f32(_e681)) * _e684)), _e687, _e688), 0f); - occluder = _e690.x; - let _e693 = projected[2u]; - let _e694 = bias; - let _e696 = occluder; - let _e699 = lit_2; - lit_2 = (_e699 + select(1f, 0f, ((_e693 - _e694) > _e696))); + let _e699 = x_2; + if (_e699 <= 1i) { + let _e701 = uv_5; + let _e702 = x_2; + let _e704 = y_2; + let _e707 = texel_1; + let _e710 = tileLo; + let _e711 = tileHi; + let _e713 = textureSampleLevel(shadow_texture_tex, shadow_texture_smp, clamp((_e701 + (vec2(f32(_e702), f32(_e704)) * _e707)), _e710, _e711), 0f); + occluder = _e713.x; + let _e716 = projected[2u]; + let _e717 = bias; + let _e719 = occluder; + let _e722 = lit_2; + lit_2 = (_e722 + select(1f, 0f, ((_e716 - _e717) > _e719))); continue; } else { break; } continuing { - let _e701 = x_1; - x_1 = (_e701 + 1i); + let _e724 = x_2; + x_2 = (_e724 + 1i); } } continue; @@ -20101,125 +20241,125 @@ fn ShadowFactor_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf break; } continuing { - let _e703 = y_1; - y_1 = (_e703 + 1i); + let _e726 = y_2; + y_2 = (_e726 + 1i); } } - let _e705 = lit_2; - lit_2 = (_e705 * 0.11111111f); + let _e728 = lit_2; + lit_2 = (_e728 * 0.11111111f); } else { - let _e707 = softness; - spread = tan(min(_e707, 0.5f)); - let _e710 = ShadowNoise_u0028_(); - turn_1 = (_e710 * 6.2831855f); - let _e712 = spread; - let _e714 = projected[2u]; - let _e716 = cascadeDepth; - let _e718 = cascadeTexel; - searchRadius = clamp((((_e712 * _e714) * _e716) / _e718), 1f, 16f); + let _e730 = softness; + spread = tan(min(_e730, 0.5f)); + let _e733 = ShadowNoise_u0028_(); + turn_1 = (_e733 * 6.2831855f); + let _e735 = spread; + let _e737 = projected[2u]; + let _e739 = cascadeDepth; + let _e741 = cascadeTexel; + searchRadius = clamp((((_e735 * _e737) * _e739) / _e741), 1f, 16f); blockerSum = 0f; blockerCount = 0f; i_6 = 0i; loop { - let _e721 = i_6; - if (_e721 < 16i) { - let _e723 = i_6; - param_137 = _e723; + let _e744 = i_6; + if (_e744 < 16i) { + let _e746 = i_6; + param_137 = _e746; param_138 = 16i; - let _e724 = turn_1; - param_139 = _e724; - let _e725 = VogelDisc_u0028_i1_u003b_i1_u003b_f1_u003b((¶m_137), (¶m_138), (¶m_139)); - disc = _e725; - let _e726 = bias; - let _e727 = disc; - let _e729 = searchRadius; - let _e733 = receiverSlope; - tapBias = (_e726 + (max(((length(_e727) * _e729) - 1.5f), 0f) * _e733)); - let _e736 = uv_5; - let _e737 = disc; - let _e738 = texel_1; - let _e740 = searchRadius; - let _e743 = tileLo; - let _e744 = tileHi; - let _e746 = textureSampleLevel(shadow_texture_tex, shadow_texture_smp, clamp((_e736 + ((_e737 * _e738) * _e740)), _e743, _e744), 0f); - occluder_1 = _e746.x; - let _e749 = projected[2u]; - let _e750 = tapBias; - let _e752 = occluder_1; - if ((_e749 - _e750) > _e752) { - let _e754 = occluder_1; - let _e755 = blockerSum; - blockerSum = (_e755 + _e754); - let _e757 = blockerCount; - blockerCount = (_e757 + 1f); + let _e747 = turn_1; + param_139 = _e747; + let _e748 = VogelDisc_u0028_i1_u003b_i1_u003b_f1_u003b((¶m_137), (¶m_138), (¶m_139)); + disc = _e748; + let _e749 = bias; + let _e750 = disc; + let _e752 = searchRadius; + let _e756 = receiverSlope; + tapBias = (_e749 + (max(((length(_e750) * _e752) - 1.5f), 0f) * _e756)); + let _e759 = uv_5; + let _e760 = disc; + let _e761 = texel_1; + let _e763 = searchRadius; + let _e766 = tileLo; + let _e767 = tileHi; + let _e769 = textureSampleLevel(shadow_texture_tex, shadow_texture_smp, clamp((_e759 + ((_e760 * _e761) * _e763)), _e766, _e767), 0f); + occluder_1 = _e769.x; + let _e772 = projected[2u]; + let _e773 = tapBias; + let _e775 = occluder_1; + if ((_e772 - _e773) > _e775) { + let _e777 = occluder_1; + let _e778 = blockerSum; + blockerSum = (_e778 + _e777); + let _e780 = blockerCount; + blockerCount = (_e780 + 1f); } continue; } else { break; } continuing { - let _e759 = i_6; - i_6 = (_e759 + 1i); + let _e782 = i_6; + i_6 = (_e782 + 1i); } } - let _e761 = blockerCount; - if (_e761 <= 0f) { + let _e784 = blockerCount; + if (_e784 <= 0f) { return 1f; } - let _e764 = projected[2u]; - let _e765 = blockerSum; - let _e766 = blockerCount; - let _e770 = cascadeDepth; - gap = (max((_e764 - (_e765 / _e766)), 0f) * _e770); - let _e772 = spread; - let _e773 = gap; - let _e775 = cascadeTexel; - radius_2 = clamp(((_e772 * _e773) / _e775), 1f, 16f); + let _e787 = projected[2u]; + let _e788 = blockerSum; + let _e789 = blockerCount; + let _e793 = cascadeDepth; + gap = (max((_e787 - (_e788 / _e789)), 0f) * _e793); + let _e795 = spread; + let _e796 = gap; + let _e798 = cascadeTexel; + radius_2 = clamp(((_e795 * _e796) / _e798), 1f, 16f); i_7 = 0i; loop { - let _e778 = i_7; - if (_e778 < 16i) { - let _e780 = turn_1; - let _e782 = i_7; - param_140 = _e782; + let _e801 = i_7; + if (_e801 < 16i) { + let _e803 = turn_1; + let _e805 = i_7; + param_140 = _e805; param_141 = 16i; - param_142 = (_e780 + 1f); - let _e783 = VogelDisc_u0028_i1_u003b_i1_u003b_f1_u003b((¶m_140), (¶m_141), (¶m_142)); - disc_1 = _e783; - let _e784 = bias; - let _e785 = disc_1; - let _e787 = radius_2; - let _e791 = receiverSlope; - tapBias_1 = (_e784 + (max(((length(_e785) * _e787) - 1.5f), 0f) * _e791)); - let _e794 = uv_5; - let _e795 = disc_1; - let _e796 = texel_1; - let _e798 = radius_2; - let _e801 = tileLo; - let _e802 = tileHi; - let _e804 = textureSampleLevel(shadow_texture_tex, shadow_texture_smp, clamp((_e794 + ((_e795 * _e796) * _e798)), _e801, _e802), 0f); - occluder_2 = _e804.x; - let _e807 = projected[2u]; - let _e808 = tapBias_1; - let _e810 = occluder_2; - let _e813 = lit_2; - lit_2 = (_e813 + select(1f, 0f, ((_e807 - _e808) > _e810))); + param_142 = (_e803 + 1f); + let _e806 = VogelDisc_u0028_i1_u003b_i1_u003b_f1_u003b((¶m_140), (¶m_141), (¶m_142)); + disc_1 = _e806; + let _e807 = bias; + let _e808 = disc_1; + let _e810 = radius_2; + let _e814 = receiverSlope; + tapBias_1 = (_e807 + (max(((length(_e808) * _e810) - 1.5f), 0f) * _e814)); + let _e817 = uv_5; + let _e818 = disc_1; + let _e819 = texel_1; + let _e821 = radius_2; + let _e824 = tileLo; + let _e825 = tileHi; + let _e827 = textureSampleLevel(shadow_texture_tex, shadow_texture_smp, clamp((_e817 + ((_e818 * _e819) * _e821)), _e824, _e825), 0f); + occluder_2 = _e827.x; + let _e830 = projected[2u]; + let _e831 = tapBias_1; + let _e833 = occluder_2; + let _e836 = lit_2; + lit_2 = (_e836 + select(1f, 0f, ((_e830 - _e831) > _e833))); continue; } else { break; } continuing { - let _e815 = i_7; - i_7 = (_e815 + 1i); + let _e838 = i_7; + i_7 = (_e838 + 1i); } } - let _e817 = lit_2; - lit_2 = (_e817 * 0.0625f); + let _e840 = lit_2; + lit_2 = (_e840 * 0.0625f); } } - let _e819 = lit_2; - let _e820 = strength_1; - return mix(1f, _e819, clamp(_e820, 0f, 1f)); + let _e842 = lit_2; + let _e843 = strength_1; + return mix(1f, _e842, clamp(_e843, 0f, 1f)); } fn LightVisibility_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_struct_u002d_LightSample_u002d_vf3_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf31_u003b_i1_u003b(s_6: ptr, light_3: ptr, index: ptr) -> f32 { @@ -20227,19 +20367,19 @@ fn LightVisibility_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d var param_144: LightSample; var param_145: i32; - let _e279 = (*s_6); - param_143 = _e279; - let _e280 = (*light_3); - param_144 = _e280; - let _e281 = (*index); - param_145 = _e281; - let _e282 = ShadowFactor_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_struct_u002d_LightSample_u002d_vf3_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf31_u003b_i1_u003b((¶m_143), (¶m_144), (¶m_145)); - return _e282; + let _e280 = (*s_6); + param_143 = _e280; + let _e281 = (*light_3); + param_144 = _e281; + let _e282 = (*index); + param_145 = _e282; + let _e283 = ShadowFactor_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_struct_u002d_LightSample_u002d_vf3_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf31_u003b_i1_u003b((¶m_143), (¶m_144), (¶m_145)); + return _e283; } fn LightHasShadow_u0028_i1_u003b(index_1: ptr) -> bool { - let _e274 = (*index_1); - return (_e274 < 8i); + let _e275 = (*index_1); + return (_e275 < 8i); } fn PunctualAttenuation_u0028_f1_u003b_f1_u003b(distance_1: ptr, range_4: ptr) -> f32 { @@ -20247,26 +20387,26 @@ fn PunctualAttenuation_u0028_f1_u003b_f1_u003b(distance_1: ptr, r var ratio: f32; var window: f32; - let _e278 = (*distance_1); let _e279 = (*distance_1); - attenuation = (1f / max((_e278 * _e279), 0.0001f)); - let _e283 = (*range_4); - if (_e283 > 0f) { - let _e285 = (*distance_1); - let _e286 = (*range_4); - ratio = (_e285 / _e286); - let _e288 = ratio; + let _e280 = (*distance_1); + attenuation = (1f / max((_e279 * _e280), 0.0001f)); + let _e284 = (*range_4); + if (_e284 > 0f) { + let _e286 = (*distance_1); + let _e287 = (*range_4); + ratio = (_e286 / _e287); let _e289 = ratio; - let _e291 = ratio; - let _e293 = ratio; - window = clamp((1f - (((_e288 * _e289) * _e291) * _e293)), 0f, 1f); - let _e297 = window; + let _e290 = ratio; + let _e292 = ratio; + let _e294 = ratio; + window = clamp((1f - (((_e289 * _e290) * _e292) * _e294)), 0f, 1f); let _e298 = window; - let _e300 = attenuation; - attenuation = (_e300 * (_e297 * _e298)); + let _e299 = window; + let _e301 = attenuation; + attenuation = (_e301 * (_e298 * _e299)); } - let _e302 = attenuation; - return _e302; + let _e303 = attenuation; + return _e303; } fn RectangleClosestPoint_u0028_vf3_u003b_vf3_u003b_vf3_u003b_vf3_u003b_vf3_u003b(centre: ptr>, halfWidth: ptr>, halfHeight: ptr>, world_2: ptr>, mirror: ptr>) -> vec3 { @@ -20283,75 +20423,75 @@ fn RectangleClosestPoint_u0028_vf3_u003b_vf3_u003b_vf3_u003b_vf3_u003b_vf3_u003b var u: f32; var v_1: f32; - let _e290 = (*halfWidth); - let _e291 = (*halfHeight); - n_3 = cross(_e290, _e291); - let _e293 = n_3; - nLen = length(_e293); - let _e295 = nLen; - if (_e295 < 0.000000000001f) { - let _e297 = (*centre); - return _e297; - } - let _e298 = nLen; - let _e299 = n_3; - n_3 = (_e299 / vec3(_e298)); - let _e302 = (*centre); - let _e303 = (*world_2); - toPlane = (_e302 - _e303); - let _e305 = (*mirror); - let _e306 = n_3; - denom = dot(_e305, _e306); - let _e308 = denom; - if (abs(_e308) < 0.00001f) { - let _e311 = toPlane; - let _e312 = n_3; - let _e313 = toPlane; - let _e314 = n_3; - onPlane = (_e311 - (_e312 * dot(_e313, _e314))); - } else { - let _e318 = toPlane; - let _e319 = n_3; - let _e321 = denom; - t_1 = (dot(_e318, _e319) / _e321); - let _e323 = t_1; - if (_e323 > 0f) { - let _e325 = (*mirror); - let _e326 = t_1; - local_16 = (_e325 * _e326); + let _e291 = (*halfWidth); + let _e292 = (*halfHeight); + n_3 = cross(_e291, _e292); + let _e294 = n_3; + nLen = length(_e294); + let _e296 = nLen; + if (_e296 < 0.000000000001f) { + let _e298 = (*centre); + return _e298; + } + let _e299 = nLen; + let _e300 = n_3; + n_3 = (_e300 / vec3(_e299)); + let _e303 = (*centre); + let _e304 = (*world_2); + toPlane = (_e303 - _e304); + let _e306 = (*mirror); + let _e307 = n_3; + denom = dot(_e306, _e307); + let _e309 = denom; + if (abs(_e309) < 0.00001f) { + let _e312 = toPlane; + let _e313 = n_3; + let _e314 = toPlane; + let _e315 = n_3; + onPlane = (_e312 - (_e313 * dot(_e314, _e315))); + } else { + let _e319 = toPlane; + let _e320 = n_3; + let _e322 = denom; + t_1 = (dot(_e319, _e320) / _e322); + let _e324 = t_1; + if (_e324 > 0f) { + let _e326 = (*mirror); + let _e327 = t_1; + local_16 = (_e326 * _e327); } else { - let _e328 = toPlane; - let _e329 = n_3; - let _e330 = toPlane; - let _e331 = n_3; - local_16 = (_e328 - (_e329 * dot(_e330, _e331))); - } - let _e335 = local_16; - onPlane = _e335; - } - let _e336 = onPlane; - let _e337 = toPlane; - offset_2 = (_e336 - _e337); - let _e339 = (*halfWidth); + let _e329 = toPlane; + let _e330 = n_3; + let _e331 = toPlane; + let _e332 = n_3; + local_16 = (_e329 - (_e330 * dot(_e331, _e332))); + } + let _e336 = local_16; + onPlane = _e336; + } + let _e337 = onPlane; + let _e338 = toPlane; + offset_2 = (_e337 - _e338); let _e340 = (*halfWidth); - wLen2_ = max(dot(_e339, _e340), 0.000000000001f); - let _e343 = (*halfHeight); + let _e341 = (*halfWidth); + wLen2_ = max(dot(_e340, _e341), 0.000000000001f); let _e344 = (*halfHeight); - hLen2_ = max(dot(_e343, _e344), 0.000000000001f); - let _e347 = offset_2; - let _e348 = (*halfWidth); - let _e350 = wLen2_; - u = clamp((dot(_e347, _e348) / _e350), -1f, 1f); - let _e353 = offset_2; - let _e354 = (*halfHeight); - let _e356 = hLen2_; - v_1 = clamp((dot(_e353, _e354) / _e356), -1f, 1f); - let _e359 = (*centre); - let _e360 = (*halfWidth); - let _e361 = u; - let _e364 = (*halfHeight); - let _e365 = v_1; - return ((_e359 + (_e360 * _e361)) + (_e364 * _e365)); + let _e345 = (*halfHeight); + hLen2_ = max(dot(_e344, _e345), 0.000000000001f); + let _e348 = offset_2; + let _e349 = (*halfWidth); + let _e351 = wLen2_; + u = clamp((dot(_e348, _e349) / _e351), -1f, 1f); + let _e354 = offset_2; + let _e355 = (*halfHeight); + let _e357 = hLen2_; + v_1 = clamp((dot(_e354, _e355) / _e357), -1f, 1f); + let _e360 = (*centre); + let _e361 = (*halfWidth); + let _e362 = u; + let _e365 = (*halfHeight); + let _e366 = v_1; + return ((_e360 + (_e361 * _e362)) + (_e365 * _e366)); } fn LambertEdge_u0028_vf3_u003b_vf3_u003b_vf3_u003b(a_3: ptr>, b_1: ptr>, n_4: ptr>) -> f32 { @@ -20362,32 +20502,32 @@ fn LambertEdge_u0028_vf3_u003b_vf3_u003b_vf3_u003b(a_3: ptr> var len_2: f32; var local_17: f32; - let _e282 = (*a_3); let _e283 = (*a_3); - ua = (_e282 / vec3(max(length(_e283), 0.000000000001f))); - let _e288 = (*b_1); + let _e284 = (*a_3); + ua = (_e283 / vec3(max(length(_e284), 0.000000000001f))); let _e289 = (*b_1); - ub = (_e288 / vec3(max(length(_e289), 0.000000000001f))); - let _e294 = ua; - let _e295 = ub; - angle_2 = acos(clamp(dot(_e294, _e295), -1f, 1f)); - let _e299 = ua; - let _e300 = ub; - axis_1 = cross(_e299, _e300); - let _e302 = axis_1; - len_2 = length(_e302); - let _e304 = len_2; - if (_e304 > 0.000001f) { - let _e306 = angle_2; - let _e307 = axis_1; - let _e308 = (*n_4); - let _e311 = len_2; - local_17 = ((_e306 * dot(_e307, _e308)) / _e311); + let _e290 = (*b_1); + ub = (_e289 / vec3(max(length(_e290), 0.000000000001f))); + let _e295 = ua; + let _e296 = ub; + angle_2 = acos(clamp(dot(_e295, _e296), -1f, 1f)); + let _e300 = ua; + let _e301 = ub; + axis_1 = cross(_e300, _e301); + let _e303 = axis_1; + len_2 = length(_e303); + let _e305 = len_2; + if (_e305 > 0.000001f) { + let _e307 = angle_2; + let _e308 = axis_1; + let _e309 = (*n_4); + let _e312 = len_2; + local_17 = ((_e307 * dot(_e308, _e309)) / _e312); } else { local_17 = 0f; } - let _e313 = local_17; - return _e313; + let _e314 = local_17; + return _e314; } fn RectangleFormFactor_u0028_vf3_u005b_4_u005d_u003b_vf3_u003b(corners_1: ptr, 4>>, n_5: ptr>) -> f32 { @@ -20418,98 +20558,98 @@ fn RectangleFormFactor_u0028_vf3_u005b_4_u005d_u003b_vf3_u003b(corners_1: ptr(0f, 0f, 0f); i_8 = 0i; loop { - let _e296 = i_8; - if (_e296 < 4i) { - let _e298 = i_8; - let _e300 = (*corners_1)[_e298]; - a_4 = _e300; - let _e301 = i_8; - if (_e301 == 3i) { + let _e297 = i_8; + if (_e297 < 4i) { + let _e299 = i_8; + let _e301 = (*corners_1)[_e299]; + a_4 = _e301; + let _e302 = i_8; + if (_e302 == 3i) { local_18 = 0i; } else { - let _e303 = i_8; - local_18 = (_e303 + 1i); - } - let _e305 = local_18; - let _e307 = (*corners_1)[_e305]; - b_2 = _e307; - let _e308 = a_4; - let _e309 = (*n_5); - ha = dot(_e308, _e309); - let _e311 = b_2; - let _e312 = (*n_5); - hb = dot(_e311, _e312); - let _e314 = ha; - let _e315 = hb; - d_5 = (_e314 - _e315); - let _e317 = a_4; - let _e318 = b_2; - let _e319 = a_4; - let _e321 = d_5; - if (abs(_e321) > 0.000000000001f) { - let _e324 = ha; - let _e325 = d_5; - local_19 = (_e324 / _e325); + let _e304 = i_8; + local_18 = (_e304 + 1i); + } + let _e306 = local_18; + let _e308 = (*corners_1)[_e306]; + b_2 = _e308; + let _e309 = a_4; + let _e310 = (*n_5); + ha = dot(_e309, _e310); + let _e312 = b_2; + let _e313 = (*n_5); + hb = dot(_e312, _e313); + let _e315 = ha; + let _e316 = hb; + d_5 = (_e315 - _e316); + let _e318 = a_4; + let _e319 = b_2; + let _e320 = a_4; + let _e322 = d_5; + if (abs(_e322) > 0.000000000001f) { + let _e325 = ha; + let _e326 = d_5; + local_19 = (_e325 / _e326); } else { local_19 = 0f; } - let _e327 = local_19; - q = (_e317 + ((_e318 - _e319) * _e327)); - let _e330 = ha; - aAbove = (_e330 > 0f); - let _e332 = hb; - bAbove = (_e332 > 0f); - let _e334 = aAbove; - let _e335 = bAbove; - if (_e334 || _e335) { - let _e337 = aAbove; - let _e338 = a_4; - let _e339 = q; - let _e342 = bAbove; - let _e343 = b_2; - let _e344 = q; - param_146 = select(_e339, _e338, vec3(_e337)); - param_147 = select(_e344, _e343, vec3(_e342)); - let _e347 = (*n_5); - param_148 = _e347; - let _e348 = LambertEdge_u0028_vf3_u003b_vf3_u003b_vf3_u003b((¶m_146), (¶m_147), (¶m_148)); - local_20 = _e348; + let _e328 = local_19; + q = (_e318 + ((_e319 - _e320) * _e328)); + let _e331 = ha; + aAbove = (_e331 > 0f); + let _e333 = hb; + bAbove = (_e333 > 0f); + let _e335 = aAbove; + let _e336 = bAbove; + if (_e335 || _e336) { + let _e338 = aAbove; + let _e339 = a_4; + let _e340 = q; + let _e343 = bAbove; + let _e344 = b_2; + let _e345 = q; + param_146 = select(_e340, _e339, vec3(_e338)); + param_147 = select(_e345, _e344, vec3(_e343)); + let _e348 = (*n_5); + param_148 = _e348; + let _e349 = LambertEdge_u0028_vf3_u003b_vf3_u003b_vf3_u003b((¶m_146), (¶m_147), (¶m_148)); + local_20 = _e349; } else { local_20 = 0f; } - let _e349 = local_20; - let _e350 = total; - total = (_e350 + _e349); - let _e352 = aAbove; - let _e353 = bAbove; - let _e356 = q; - let _e357 = exit; - exit = select(_e357, _e356, vec3((_e352 && !(_e353)))); - let _e360 = aAbove; - let _e362 = bAbove; - let _e364 = q; - let _e365 = entry; - entry = select(_e365, _e364, vec3((!(_e360) && _e362))); + let _e350 = local_20; + let _e351 = total; + total = (_e351 + _e350); + let _e353 = aAbove; + let _e354 = bAbove; + let _e357 = q; + let _e358 = exit; + exit = select(_e358, _e357, vec3((_e353 && !(_e354)))); + let _e361 = aAbove; + let _e363 = bAbove; + let _e365 = q; + let _e366 = entry; + entry = select(_e366, _e365, vec3((!(_e361) && _e363))); continue; } else { break; } continuing { - let _e368 = i_8; - i_8 = (_e368 + 1i); + let _e369 = i_8; + i_8 = (_e369 + 1i); } } - let _e370 = exit; - param_149 = _e370; - let _e371 = entry; - param_150 = _e371; - let _e372 = (*n_5); - param_151 = _e372; - let _e373 = LambertEdge_u0028_vf3_u003b_vf3_u003b_vf3_u003b((¶m_149), (¶m_150), (¶m_151)); - let _e374 = total; - total = (_e374 + _e373); - let _e376 = total; - return max((-(_e376) * 0.5f), 0f); + let _e371 = exit; + param_149 = _e371; + let _e372 = entry; + param_150 = _e372; + let _e373 = (*n_5); + param_151 = _e373; + let _e374 = LambertEdge_u0028_vf3_u003b_vf3_u003b_vf3_u003b((¶m_149), (¶m_150), (¶m_151)); + let _e375 = total; + total = (_e375 + _e374); + let _e377 = total; + return max((-(_e377) * 0.5f), 0f); } fn LightListLane_u0028_vf4_u003b_i1_u003b(four: ptr>, slot_2: ptr) -> f32 { @@ -20518,91 +20658,91 @@ fn LightListLane_u0028_vf4_u003b_i1_u003b(four: ptr>, slot_2 var local_22: f32; var local_23: f32; - let _e279 = (*slot_2); let _e280 = (*slot_2); - lane = (_e279 - ((_e280 / 4i) * 4i)); - let _e284 = lane; - if (_e284 == 0i) { - let _e287 = (*four)[0u]; - local_21 = _e287; - } else { - let _e288 = lane; - if (_e288 == 1i) { - let _e291 = (*four)[1u]; - local_22 = _e291; + let _e281 = (*slot_2); + lane = (_e280 - ((_e281 / 4i) * 4i)); + let _e285 = lane; + if (_e285 == 0i) { + let _e288 = (*four)[0u]; + local_21 = _e288; + } else { + let _e289 = lane; + if (_e289 == 1i) { + let _e292 = (*four)[1u]; + local_22 = _e292; } else { - let _e292 = lane; - if (_e292 == 2i) { - let _e295 = (*four)[2u]; - local_23 = _e295; + let _e293 = lane; + if (_e293 == 2i) { + let _e296 = (*four)[2u]; + local_23 = _e296; } else { - let _e297 = (*four)[3u]; - local_23 = _e297; + let _e298 = (*four)[3u]; + local_23 = _e298; } - let _e298 = local_23; - local_22 = _e298; + let _e299 = local_23; + local_22 = _e299; } - let _e299 = local_22; - local_21 = _e299; + let _e300 = local_22; + local_21 = _e300; } - let _e300 = local_21; - return _e300; + let _e301 = local_21; + return _e301; } fn LightListScale_u0028_i1_u003b(slot_3: ptr) -> f32 { var param_152: vec4; var param_153: i32; - let _e276 = (*slot_3); - let _e280 = light_list_info.scales[(_e276 / 4i)]; - param_152 = _e280; - let _e281 = (*slot_3); - param_153 = _e281; - let _e282 = LightListLane_u0028_vf4_u003b_i1_u003b((¶m_152), (¶m_153)); - return _e282; + let _e277 = (*slot_3); + let _e281 = light_list_info.scales[(_e277 / 4i)]; + param_152 = _e281; + let _e282 = (*slot_3); + param_153 = _e282; + let _e283 = LightListLane_u0028_vf4_u003b_i1_u003b((¶m_152), (¶m_153)); + return _e283; } fn InSlots_u0028_f1_u003b(row: ptr) -> bool { var a_5: vec4; var b_3: vec4; - let _e278 = light_list_info.slot_rows[0i]; - let _e279 = (*row); - a_5 = abs((_e278 - vec4(_e279))); - let _e285 = light_list_info.slot_rows[1i]; - let _e286 = (*row); - b_3 = abs((_e285 - vec4(_e286))); - let _e291 = a_5[0u]; - let _e293 = a_5[1u]; - let _e296 = a_5[2u]; - let _e298 = a_5[3u]; - let _e302 = b_3[0u]; - let _e304 = b_3[1u]; - let _e307 = b_3[2u]; - let _e309 = b_3[3u]; - return (min(min(min(_e291, _e293), min(_e296, _e298)), min(min(_e302, _e304), min(_e307, _e309))) < 0.5f); + let _e279 = light_list_info.slot_rows[0i]; + let _e280 = (*row); + a_5 = abs((_e279 - vec4(_e280))); + let _e286 = light_list_info.slot_rows[1i]; + let _e287 = (*row); + b_3 = abs((_e286 - vec4(_e287))); + let _e292 = a_5[0u]; + let _e294 = a_5[1u]; + let _e297 = a_5[2u]; + let _e299 = a_5[3u]; + let _e303 = b_3[0u]; + let _e305 = b_3[1u]; + let _e308 = b_3[2u]; + let _e310 = b_3[3u]; + return (min(min(min(_e292, _e294), min(_e297, _e299)), min(min(_e303, _e305), min(_e308, _e310))) < 0.5f); } fn LightListRow_u0028_i1_u003b(slot_4: ptr) -> f32 { var param_154: vec4; var param_155: i32; - let _e276 = (*slot_4); - let _e280 = light_list_info.indices[(_e276 / 4i)]; - param_154 = _e280; - let _e281 = (*slot_4); - param_155 = _e281; - let _e282 = LightListLane_u0028_vf4_u003b_i1_u003b((¶m_154), (¶m_155)); - return _e282; + let _e277 = (*slot_4); + let _e281 = light_list_info.indices[(_e277 / 4i)]; + param_154 = _e281; + let _e282 = (*slot_4); + param_155 = _e282; + let _e283 = LightListLane_u0028_vf4_u003b_i1_u003b((¶m_154), (¶m_155)); + return _e283; } fn LightListTexel_u0028_f1_u003b_f1_u003b(texel_2: ptr, row_1: ptr) -> vec4 { - let _e275 = (*texel_2); - let _e279 = light_list_info.list[1u]; - let _e281 = (*row_1); - let _e285 = light_list_info.list[2u]; - let _e288 = textureSampleLevel(light_list_texture_tex, light_list_texture_smp, vec2(((_e275 + 0.5f) * _e279), ((_e281 + 0.5f) * _e285)), 0f); - return _e288; + let _e276 = (*texel_2); + let _e280 = light_list_info.list[1u]; + let _e282 = (*row_1); + let _e286 = light_list_info.list[2u]; + let _e289 = textureSampleLevel(light_list_texture_tex, light_list_texture_smp, vec2(((_e276 + 0.5f) * _e280), ((_e282 + 0.5f) * _e286)), 0f); + return _e289; } fn ClusterRow_u0028_i1_u003b(slot_5: ptr) -> f32 { @@ -20616,35 +20756,35 @@ fn ClusterRow_u0028_i1_u003b(slot_5: ptr) -> f32 { var param_158: vec4; var param_159: i32; - let _e283 = g_cluster_offset; - let _e284 = (*slot_5); - entry_1 = (_e283 + f32(_e284)); - let _e287 = entry_1; - row_2 = floor((_e287 / 16f)); - let _e290 = entry_1; - let _e291 = row_2; - within = (_e290 - (_e291 * 16f)); - let _e294 = within; - texel_3 = floor((_e294 / 4f)); - let _e299 = light_list_info.cluster_depth[3u]; - let _e300 = row_2; - let _e302 = texel_3; - param_156 = _e302; - param_157 = (_e299 + _e300); - let _e303 = LightListTexel_u0028_f1_u003b_f1_u003b((¶m_156), (¶m_157)); - four_1 = _e303; - let _e304 = within; - let _e305 = texel_3; - let _e310 = four_1; - param_158 = _e310; - param_159 = i32(((_e304 - (_e305 * 4f)) + 0.5f)); - let _e311 = LightListLane_u0028_vf4_u003b_i1_u003b((¶m_158), (¶m_159)); - return _e311; + let _e284 = g_cluster_offset; + let _e285 = (*slot_5); + entry_1 = (_e284 + f32(_e285)); + let _e288 = entry_1; + row_2 = floor((_e288 / 16f)); + let _e291 = entry_1; + let _e292 = row_2; + within = (_e291 - (_e292 * 16f)); + let _e295 = within; + texel_3 = floor((_e295 / 4f)); + let _e300 = light_list_info.cluster_depth[3u]; + let _e301 = row_2; + let _e303 = texel_3; + param_156 = _e303; + param_157 = (_e300 + _e301); + let _e304 = LightListTexel_u0028_f1_u003b_f1_u003b((¶m_156), (¶m_157)); + four_1 = _e304; + let _e305 = within; + let _e306 = texel_3; + let _e311 = four_1; + param_158 = _e311; + param_159 = i32(((_e305 - (_e306 * 4f)) + 0.5f)); + let _e312 = LightListLane_u0028_vf4_u003b_i1_u003b((¶m_158), (¶m_159)); + return _e312; } fn Clustered_u0028_() -> bool { - let _e275 = light_list_info.cluster_grid[3u]; - return (_e275 > 0.5f); + let _e276 = light_list_info.cluster_grid[3u]; + return (_e276 > 0.5f); } fn SampleLight_u0028_i1_u003b_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b(index_2: ptr, s_7: ptr) -> LightSample { @@ -20704,277 +20844,277 @@ fn SampleLight_u0028_i1_u003b_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_ light_4.integrated = 0f; light_4.ltc = vec3(0f, 0f, 0f); - let _e330 = (*index_2); - if (_e330 < 8i) { - let _e332 = (*index_2); - let _e335 = frag_info.light_position[_e332]; - position = _e335; - let _e336 = (*index_2); - let _e339 = frag_info.light_color[_e336]; - color_1 = _e339; - let _e340 = (*index_2); - let _e343 = frag_info.light_direction[_e340]; - direction = _e343; - let _e344 = (*index_2); - let _e347 = frag_info.light_cone[_e344]; - cone = _e347; - } else { - let _e348 = (*index_2); - slot_6 = (_e348 - 8i); - let _e350 = Clustered_u0028_(); - clustered = _e350; - let _e351 = clustered; - if _e351 { - let _e352 = slot_6; - param_160 = _e352; - let _e353 = ClusterRow_u0028_i1_u003b((¶m_160)); - local_24 = _e353; + let _e331 = (*index_2); + if (_e331 < 8i) { + let _e333 = (*index_2); + let _e336 = frag_info.light_position[_e333]; + position = _e336; + let _e337 = (*index_2); + let _e340 = frag_info.light_color[_e337]; + color_1 = _e340; + let _e341 = (*index_2); + let _e344 = frag_info.light_direction[_e341]; + direction = _e344; + let _e345 = (*index_2); + let _e348 = frag_info.light_cone[_e345]; + cone = _e348; + } else { + let _e349 = (*index_2); + slot_6 = (_e349 - 8i); + let _e351 = Clustered_u0028_(); + clustered = _e351; + let _e352 = clustered; + if _e352 { + let _e353 = slot_6; + param_160 = _e353; + let _e354 = ClusterRow_u0028_i1_u003b((¶m_160)); + local_24 = _e354; } else { - let _e354 = slot_6; - param_161 = _e354; - let _e355 = LightListRow_u0028_i1_u003b((¶m_161)); - local_24 = _e355; - } - let _e356 = local_24; - listRow = _e356; - let _e357 = listRow; - let _e361 = light_list_info.list[2u]; - v_2 = ((_e357 + 0.5f) * _e361); - let _e365 = light_list_info.list[1u]; - u_1 = _e365; - let _e366 = u_1; - let _e368 = v_2; - let _e370 = textureSampleLevel(light_list_texture_tex, light_list_texture_smp, vec2((0.5f * _e366), _e368), 0f); - position = _e370; - let _e371 = u_1; - let _e373 = v_2; - let _e375 = textureSampleLevel(light_list_texture_tex, light_list_texture_smp, vec2((1.5f * _e371), _e373), 0f); - color_1 = _e375; - let _e376 = u_1; - let _e378 = v_2; - let _e380 = textureSampleLevel(light_list_texture_tex, light_list_texture_smp, vec2((2.5f * _e376), _e378), 0f); - direction = _e380; - let _e381 = u_1; - let _e383 = v_2; - let _e385 = textureSampleLevel(light_list_texture_tex, light_list_texture_smp, vec2((3.5f * _e381), _e383), 0f); - cone = _e385; - let _e386 = clustered; - if _e386 { - let _e387 = listRow; - param_162 = _e387; - let _e388 = InSlots_u0028_f1_u003b((¶m_162)); - local_25 = select(1f, 0f, _e388); + let _e355 = slot_6; + param_161 = _e355; + let _e356 = LightListRow_u0028_i1_u003b((¶m_161)); + local_24 = _e356; + } + let _e357 = local_24; + listRow = _e357; + let _e358 = listRow; + let _e362 = light_list_info.list[2u]; + v_2 = ((_e358 + 0.5f) * _e362); + let _e366 = light_list_info.list[1u]; + u_1 = _e366; + let _e367 = u_1; + let _e369 = v_2; + let _e371 = textureSampleLevel(light_list_texture_tex, light_list_texture_smp, vec2((0.5f * _e367), _e369), 0f); + position = _e371; + let _e372 = u_1; + let _e374 = v_2; + let _e376 = textureSampleLevel(light_list_texture_tex, light_list_texture_smp, vec2((1.5f * _e372), _e374), 0f); + color_1 = _e376; + let _e377 = u_1; + let _e379 = v_2; + let _e381 = textureSampleLevel(light_list_texture_tex, light_list_texture_smp, vec2((2.5f * _e377), _e379), 0f); + direction = _e381; + let _e382 = u_1; + let _e384 = v_2; + let _e386 = textureSampleLevel(light_list_texture_tex, light_list_texture_smp, vec2((3.5f * _e382), _e384), 0f); + cone = _e386; + let _e387 = clustered; + if _e387 { + let _e388 = listRow; + param_162 = _e388; + let _e389 = InSlots_u0028_f1_u003b((¶m_162)); + local_25 = select(1f, 0f, _e389); } else { - let _e390 = slot_6; - param_163 = _e390; - let _e391 = LightListScale_u0028_i1_u003b((¶m_163)); - local_25 = _e391; - } - let _e392 = local_25; - let _e394 = color_1[3u]; - color_1[3u] = (_e394 * _e392); - } - let _e398 = position[3u]; - type_45 = _e398; - let _e399 = type_45; - if (_e399 > 2.5f) { - let _e401 = direction; - halfWidth_1 = _e401.xyz; - let _e403 = cone; - halfHeight_1 = _e403.xyz; - let _e405 = position; - let _e407 = v_world_position_1; - toCentre = (_e405.xyz - _e407); - let _e409 = toCentre; - let _e410 = halfWidth_1; - let _e412 = halfHeight_1; - corners_2[0i] = ((_e409 - _e410) - _e412); - let _e415 = toCentre; - let _e416 = halfWidth_1; - let _e418 = halfHeight_1; - corners_2[1i] = ((_e415 + _e416) - _e418); - let _e421 = toCentre; - let _e422 = halfWidth_1; - let _e424 = halfHeight_1; - corners_2[2i] = ((_e421 + _e422) + _e424); - let _e427 = toCentre; - let _e428 = halfWidth_1; - let _e430 = halfHeight_1; - corners_2[3i] = ((_e427 - _e428) + _e430); - let _e433 = toCentre; - let _e434 = halfWidth_1; - let _e435 = halfHeight_1; - behind = (dot(_e433, cross(_e434, _e435)) >= 0f); - let _e439 = behind; - if _e439 { + let _e391 = slot_6; + param_163 = _e391; + let _e392 = LightListScale_u0028_i1_u003b((¶m_163)); + local_25 = _e392; + } + let _e393 = local_25; + let _e395 = color_1[3u]; + color_1[3u] = (_e395 * _e393); + } + let _e399 = position[3u]; + type_45 = _e399; + let _e400 = type_45; + if (_e400 > 2.5f) { + let _e402 = direction; + halfWidth_1 = _e402.xyz; + let _e404 = cone; + halfHeight_1 = _e404.xyz; + let _e406 = position; + let _e408 = v_world_position_1; + toCentre = (_e406.xyz - _e408); + let _e410 = toCentre; + let _e411 = halfWidth_1; + let _e413 = halfHeight_1; + corners_2[0i] = ((_e410 - _e411) - _e413); + let _e416 = toCentre; + let _e417 = halfWidth_1; + let _e419 = halfHeight_1; + corners_2[1i] = ((_e416 + _e417) - _e419); + let _e422 = toCentre; + let _e423 = halfWidth_1; + let _e425 = halfHeight_1; + corners_2[2i] = ((_e422 + _e423) + _e425); + let _e428 = toCentre; + let _e429 = halfWidth_1; + let _e431 = halfHeight_1; + corners_2[3i] = ((_e428 - _e429) + _e431); + let _e434 = toCentre; + let _e435 = halfWidth_1; + let _e436 = halfHeight_1; + behind = (dot(_e434, cross(_e435, _e436)) >= 0f); + let _e440 = behind; + if _e440 { local_26 = 0f; } else { - let _e440 = corners_2; - param_164 = _e440; - let _e442 = (*s_7).n; - param_165 = _e442; - let _e443 = RectangleFormFactor_u0028_vf3_u005b_4_u005d_u003b_vf3_u003b((¶m_164), (¶m_165)); - local_26 = _e443; - } - let _e444 = local_26; - formFactor = _e444; - let _e445 = halfWidth_1; - let _e446 = halfHeight_1; - area = (length(cross(_e445, _e446)) * 4f); - let _e450 = area; - if (_e450 > 0.000000001f) { - let _e452 = area; - local_27 = (1f / _e452); + let _e441 = corners_2; + param_164 = _e441; + let _e443 = (*s_7).n; + param_165 = _e443; + let _e444 = RectangleFormFactor_u0028_vf3_u005b_4_u005d_u003b_vf3_u003b((¶m_164), (¶m_165)); + local_26 = _e444; + } + let _e445 = local_26; + formFactor = _e445; + let _e446 = halfWidth_1; + let _e447 = halfHeight_1; + area = (length(cross(_e446, _e447)) * 4f); + let _e451 = area; + if (_e451 > 0.000000001f) { + let _e453 = area; + local_27 = (1f / _e453); } else { local_27 = 0f; } - let _e454 = local_27; - radiance = _e454; - let _e455 = toCentre; - distance_2 = length(_e455); - let _e458 = direction[3u]; - if (_e458 > 0f) { - let _e460 = distance_2; - let _e462 = direction[3u]; - ratio_1 = (_e460 / _e462); - let _e464 = ratio_1; + let _e455 = local_27; + radiance = _e455; + let _e456 = toCentre; + distance_2 = length(_e456); + let _e459 = direction[3u]; + if (_e459 > 0f) { + let _e461 = distance_2; + let _e463 = direction[3u]; + ratio_1 = (_e461 / _e463); let _e465 = ratio_1; - let _e467 = ratio_1; - let _e469 = ratio_1; - window_1 = clamp((1f - (((_e464 * _e465) * _e467) * _e469)), 0f, 1f); - let _e473 = window_1; + let _e466 = ratio_1; + let _e468 = ratio_1; + let _e470 = ratio_1; + window_1 = clamp((1f - (((_e465 * _e466) * _e468) * _e470)), 0f, 1f); let _e474 = window_1; - let _e476 = radiance; - radiance = (_e476 * (_e473 * _e474)); - } - let _e479 = (*s_7).v; - let _e482 = (*s_7).n; - mirror_1 = reflect(-(_e479), _e482); - let _e484 = position; - param_166 = _e484.xyz; - let _e486 = halfWidth_1; - param_167 = _e486; - let _e487 = halfHeight_1; - param_168 = _e487; - let _e488 = v_world_position_1; - param_169 = _e488; - let _e489 = mirror_1; - param_170 = _e489; - let _e490 = RectangleClosestPoint_u0028_vf3_u003b_vf3_u003b_vf3_u003b_vf3_u003b_vf3_u003b((¶m_166), (¶m_167), (¶m_168), (¶m_169), (¶m_170)); - representative = _e490; - let _e491 = representative; - let _e492 = v_world_position_1; - toPoint = (_e491 - _e492); - let _e494 = toPoint; - pointDistance = length(_e494); - let _e496 = pointDistance; - if (_e496 > 0.000001f) { - let _e498 = toPoint; - let _e499 = pointDistance; - local_28 = (_e498 / vec3(_e499)); + let _e475 = window_1; + let _e477 = radiance; + radiance = (_e477 * (_e474 * _e475)); + } + let _e480 = (*s_7).v; + let _e483 = (*s_7).n; + mirror_1 = reflect(-(_e480), _e483); + let _e485 = position; + param_166 = _e485.xyz; + let _e487 = halfWidth_1; + param_167 = _e487; + let _e488 = halfHeight_1; + param_168 = _e488; + let _e489 = v_world_position_1; + param_169 = _e489; + let _e490 = mirror_1; + param_170 = _e490; + let _e491 = RectangleClosestPoint_u0028_vf3_u003b_vf3_u003b_vf3_u003b_vf3_u003b_vf3_u003b((¶m_166), (¶m_167), (¶m_168), (¶m_169), (¶m_170)); + representative = _e491; + let _e492 = representative; + let _e493 = v_world_position_1; + toPoint = (_e492 - _e493); + let _e495 = toPoint; + pointDistance = length(_e495); + let _e497 = pointDistance; + if (_e497 > 0.000001f) { + let _e499 = toPoint; + let _e500 = pointDistance; + local_28 = (_e499 / vec3(_e500)); } else { - let _e503 = (*s_7).n; - local_28 = _e503; - } - let _e504 = local_28; - light_4.l = _e504; - let _e507 = light_4.l; - let _e509 = (*s_7).v; - light_4.h = normalize((_e507 + _e509)); - let _e513 = formFactor; - light_4.n_dot_l = _e513; - let _e516 = (*s_7).n; - let _e518 = light_4.h; - light_4.n_dot_h = max(dot(_e516, _e518), 0f); - let _e523 = (*s_7).v; - let _e525 = light_4.h; - light_4.v_dot_h = max(dot(_e523, _e525), 0f); - let _e529 = color_1; - let _e532 = color_1[3u]; - let _e534 = radiance; - light_4.radiance = ((_e529.xyz * _e532) * _e534); + let _e504 = (*s_7).n; + local_28 = _e504; + } + let _e505 = local_28; + light_4.l = _e505; + let _e508 = light_4.l; + let _e510 = (*s_7).v; + light_4.h = normalize((_e508 + _e510)); + let _e514 = formFactor; + light_4.n_dot_l = _e514; + let _e517 = (*s_7).n; + let _e519 = light_4.h; + light_4.n_dot_h = max(dot(_e517, _e519), 0f); + let _e524 = (*s_7).v; + let _e526 = light_4.h; + light_4.v_dot_h = max(dot(_e524, _e526), 0f); + let _e530 = color_1; + let _e533 = color_1[3u]; + let _e535 = radiance; + light_4.radiance = ((_e530.xyz * _e533) * _e535); light_4.integrated = 1f; - let _e539 = (*s_7).n; - param_171 = _e539; - let _e541 = (*s_7).v; - param_172 = _e541; - let _e543 = (*s_7).roughness; - param_173 = _e543; - let _e544 = corners_2; - param_174 = _e544; - let _e545 = LtcRectangle_u0028_vf3_u003b_vf3_u003b_f1_u003b_vf3_u005b_4_u005d_u003b((¶m_171), (¶m_172), (¶m_173), (¶m_174)); - light_4.ltc = _e545; - let _e547 = corners_2; - g_rect_corners = _e547; - let _e548 = light_4; - return _e548; - } - let _e549 = direction; - aim = normalize(_e549.xyz); + let _e540 = (*s_7).n; + param_171 = _e540; + let _e542 = (*s_7).v; + param_172 = _e542; + let _e544 = (*s_7).roughness; + param_173 = _e544; + let _e545 = corners_2; + param_174 = _e545; + let _e546 = LtcRectangle_u0028_vf3_u003b_vf3_u003b_f1_u003b_vf3_u005b_4_u005d_u003b((¶m_171), (¶m_172), (¶m_173), (¶m_174)); + light_4.ltc = _e546; + let _e548 = corners_2; + g_rect_corners = _e548; + let _e549 = light_4; + return _e549; + } + let _e550 = direction; + aim = normalize(_e550.xyz); attenuation_1 = 1f; - let _e552 = type_45; - if (_e552 < 0.5f) { - let _e554 = aim; - light_4.l = -(_e554); - } else { - let _e557 = position; - let _e559 = v_world_position_1; - toLight_1 = (_e557.xyz - _e559); - let _e561 = toLight_1; - distance_3 = length(_e561); - let _e563 = distance_3; - if (_e563 < 0.000001f) { - let _e566 = (*s_7).n; - light_4.l = _e566; - let _e569 = (*s_7).n; - light_4.h = _e569; + let _e553 = type_45; + if (_e553 < 0.5f) { + let _e555 = aim; + light_4.l = -(_e555); + } else { + let _e558 = position; + let _e560 = v_world_position_1; + toLight_1 = (_e558.xyz - _e560); + let _e562 = toLight_1; + distance_3 = length(_e562); + let _e564 = distance_3; + if (_e564 < 0.000001f) { + let _e567 = (*s_7).n; + light_4.l = _e567; + let _e570 = (*s_7).n; + light_4.h = _e570; light_4.radiance = vec3(0f, 0f, 0f); light_4.n_dot_l = 0f; light_4.n_dot_h = 0f; light_4.v_dot_h = 0f; - let _e575 = light_4; - return _e575; - } - let _e576 = toLight_1; - let _e577 = distance_3; - light_4.l = (_e576 / vec3(_e577)); - let _e581 = distance_3; - param_175 = _e581; - let _e583 = direction[3u]; - param_176 = _e583; - let _e584 = PunctualAttenuation_u0028_f1_u003b_f1_u003b((¶m_175), (¶m_176)); - attenuation_1 = _e584; - let _e585 = type_45; - if (_e585 > 1.5f) { - let _e587 = aim; - let _e589 = light_4.l; - cosAngle = dot(_e587, -(_e589)); - let _e592 = cosAngle; - let _e594 = cone[1u]; - let _e597 = cone[0u]; - let _e599 = cone[1u]; - let _e603 = attenuation_1; - attenuation_1 = (_e603 * clamp(((_e592 - _e594) / (_e597 - _e599)), 0f, 1f)); - } - } - let _e606 = light_4.l; - let _e608 = (*s_7).v; - light_4.h = normalize((_e606 + _e608)); - let _e613 = (*s_7).n; - let _e615 = light_4.l; - light_4.n_dot_l = max(dot(_e613, _e615), 0f); - let _e620 = (*s_7).n; - let _e622 = light_4.h; - light_4.n_dot_h = max(dot(_e620, _e622), 0f); - let _e627 = (*s_7).v; - let _e629 = light_4.h; - light_4.v_dot_h = max(dot(_e627, _e629), 0f); - let _e633 = color_1; - let _e636 = color_1[3u]; - let _e638 = attenuation_1; - light_4.radiance = ((_e633.xyz * _e636) * _e638); - let _e641 = light_4; - return _e641; + let _e576 = light_4; + return _e576; + } + let _e577 = toLight_1; + let _e578 = distance_3; + light_4.l = (_e577 / vec3(_e578)); + let _e582 = distance_3; + param_175 = _e582; + let _e584 = direction[3u]; + param_176 = _e584; + let _e585 = PunctualAttenuation_u0028_f1_u003b_f1_u003b((¶m_175), (¶m_176)); + attenuation_1 = _e585; + let _e586 = type_45; + if (_e586 > 1.5f) { + let _e588 = aim; + let _e590 = light_4.l; + cosAngle = dot(_e588, -(_e590)); + let _e593 = cosAngle; + let _e595 = cone[1u]; + let _e598 = cone[0u]; + let _e600 = cone[1u]; + let _e604 = attenuation_1; + attenuation_1 = (_e604 * clamp(((_e593 - _e595) / (_e598 - _e600)), 0f, 1f)); + } + } + let _e607 = light_4.l; + let _e609 = (*s_7).v; + light_4.h = normalize((_e607 + _e609)); + let _e614 = (*s_7).n; + let _e616 = light_4.l; + light_4.n_dot_l = max(dot(_e614, _e616), 0f); + let _e621 = (*s_7).n; + let _e623 = light_4.h; + light_4.n_dot_h = max(dot(_e621, _e623), 0f); + let _e628 = (*s_7).v; + let _e630 = light_4.h; + light_4.v_dot_h = max(dot(_e628, _e630), 0f); + let _e634 = color_1; + let _e637 = color_1[3u]; + let _e639 = attenuation_1; + light_4.radiance = ((_e634.xyz * _e637) * _e639); + let _e642 = light_4; + return _e642; } fn FindCluster_u0028_vf3_u003b(world_3: ptr>) { @@ -20992,58 +21132,58 @@ fn FindCluster_u0028_vf3_u003b(world_3: ptr>) { var param_177: f32; var param_178: f32; - let _e288 = light_list_info.cluster_view_projection; - let _e289 = (*world_3); - clip_1 = (_e288 * vec4(_e289.x, _e289.y, _e289.z, 1f)); - let _e295 = clip_1; - let _e298 = clip_1[3u]; - ndc_1 = (_e295.xy / vec2(max(_e298, 0.000001f))); - let _e303 = light_list_info.cluster_grid; - grid = _e303.xyz; - let _e307 = light_list_info.cluster_depth[0u]; - near_1 = _e307; - let _e309 = ndc_1[0u]; - let _e313 = grid[0u]; - let _e317 = grid[0u]; - tx = clamp(floor((((_e309 * 0.5f) + 0.5f) * _e313)), 0f, (_e317 - 1f)); - let _e321 = ndc_1[1u]; - let _e325 = grid[1u]; - let _e329 = grid[1u]; - ty = clamp(floor((((_e321 * 0.5f) + 0.5f) * _e325)), 0f, (_e329 - 1f)); - let _e333 = clip_1[3u]; - let _e334 = near_1; - if (_e333 <= _e334) { + let _e289 = light_list_info.cluster_view_projection; + let _e290 = (*world_3); + clip_1 = (_e289 * vec4(_e290.x, _e290.y, _e290.z, 1f)); + let _e296 = clip_1; + let _e299 = clip_1[3u]; + ndc_1 = (_e296.xy / vec2(max(_e299, 0.000001f))); + let _e304 = light_list_info.cluster_grid; + grid = _e304.xyz; + let _e308 = light_list_info.cluster_depth[0u]; + near_1 = _e308; + let _e310 = ndc_1[0u]; + let _e314 = grid[0u]; + let _e318 = grid[0u]; + tx = clamp(floor((((_e310 * 0.5f) + 0.5f) * _e314)), 0f, (_e318 - 1f)); + let _e322 = ndc_1[1u]; + let _e326 = grid[1u]; + let _e330 = grid[1u]; + ty = clamp(floor((((_e322 * 0.5f) + 0.5f) * _e326)), 0f, (_e330 - 1f)); + let _e334 = clip_1[3u]; + let _e335 = near_1; + if (_e334 <= _e335) { local_29 = 0f; } else { - let _e337 = clip_1[3u]; - let _e338 = near_1; - let _e343 = light_list_info.cluster_depth[1u]; - let _e347 = grid[2u]; - local_29 = clamp(floor((log((_e337 / _e338)) * _e343)), 0f, (_e347 - 1f)); - } - let _e350 = local_29; - tz = _e350; - let _e351 = tx; - let _e352 = ty; - let _e354 = grid[0u]; - let _e357 = tz; - let _e359 = grid[0u]; - let _e362 = grid[1u]; - cell = ((_e351 + (_e352 * _e354)) + ((_e357 * _e359) * _e362)); - let _e365 = cell; - row_3 = floor((_e365 / 4f)); - let _e368 = cell; - let _e369 = row_3; - let _e374 = light_list_info.cluster_depth[2u]; - let _e375 = row_3; - param_177 = (_e368 - (_e369 * 4f)); - param_178 = (_e374 + _e375); - let _e377 = LightListTexel_u0028_f1_u003b_f1_u003b((¶m_177), (¶m_178)); - header = _e377; - let _e379 = header[0u]; - g_cluster_offset = _e379; - let _e381 = header[1u]; - g_cluster_count = _e381; + let _e338 = clip_1[3u]; + let _e339 = near_1; + let _e344 = light_list_info.cluster_depth[1u]; + let _e348 = grid[2u]; + local_29 = clamp(floor((log((_e338 / _e339)) * _e344)), 0f, (_e348 - 1f)); + } + let _e351 = local_29; + tz = _e351; + let _e352 = tx; + let _e353 = ty; + let _e355 = grid[0u]; + let _e358 = tz; + let _e360 = grid[0u]; + let _e363 = grid[1u]; + cell = ((_e352 + (_e353 * _e355)) + ((_e358 * _e360) * _e363)); + let _e366 = cell; + row_3 = floor((_e366 / 4f)); + let _e369 = cell; + let _e370 = row_3; + let _e375 = light_list_info.cluster_depth[2u]; + let _e376 = row_3; + param_177 = (_e369 - (_e370 * 4f)); + param_178 = (_e375 + _e376); + let _e378 = LightListTexel_u0028_f1_u003b_f1_u003b((¶m_177), (¶m_178)); + header = _e378; + let _e380 = header[0u]; + g_cluster_offset = _e380; + let _e382 = header[1u]; + g_cluster_count = _e382; return; } @@ -21051,19 +21191,19 @@ fn LightCount_u0028_() -> i32 { var tail: f32; var param_179: vec3; - let _e277 = light_list_info.list[0u]; - tail = _e277; - let _e278 = Clustered_u0028_(); - if _e278 { - let _e279 = v_world_position_1; - param_179 = _e279; + let _e278 = light_list_info.list[0u]; + tail = _e278; + let _e279 = Clustered_u0028_(); + if _e279 { + let _e280 = v_world_position_1; + param_179 = _e280; FindCluster_u0028_vf3_u003b((¶m_179)); - let _e280 = g_cluster_count; - tail = _e280; + let _e281 = g_cluster_count; + tail = _e281; } - let _e283 = frag_info.frame_params[1u]; - let _e287 = tail; - return (clamp(i32((_e283 + 0.5f)), 0i, 8i) + clamp(i32((_e287 + 0.5f)), 0i, 24i)); + let _e284 = frag_info.frame_params[1u]; + let _e288 = tail; + return (clamp(i32((_e284 + 0.5f)), 0i, 8i) + clamp(i32((_e288 + 0.5f)), 0i, 24i)); } fn AccumulateLights_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b(s_8: ptr) -> vec3 { @@ -21086,89 +21226,89 @@ fn AccumulateLights_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002 var param_190: LightSample; total_1 = vec3(0f, 0f, 0f); - let _e291 = LightCount_u0028_(); - count_1 = _e291; + let _e292 = LightCount_u0028_(); + count_1 = _e292; i_9 = 0i; loop { - let _e292 = i_9; - if (_e292 < 32i) { - let _e294 = i_9; - let _e295 = count_1; - if (_e294 >= _e295) { + let _e293 = i_9; + if (_e293 < 32i) { + let _e295 = i_9; + let _e296 = count_1; + if (_e295 >= _e296) { break; } - let _e297 = i_9; - param_180 = _e297; - let _e298 = (*s_8); - param_181 = _e298; - let _e299 = SampleLight_u0028_i1_u003b_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b((¶m_180), (¶m_181)); - light_5 = _e299; - let _e301 = light_5.n_dot_l; - if (_e301 <= 0f) { + let _e298 = i_9; + param_180 = _e298; + let _e299 = (*s_8); + param_181 = _e299; + let _e300 = SampleLight_u0028_i1_u003b_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b((¶m_180), (¶m_181)); + light_5 = _e300; + let _e302 = light_5.n_dot_l; + if (_e302 <= 0f) { continue; } light_transmittance = vec3(1f, 1f, 1f); - let _e303 = i_9; - param_182 = _e303; - let _e304 = LightHasShadow_u0028_i1_u003b((¶m_182)); - if _e304 { - let _e305 = (*s_8); - param_183 = _e305; - let _e306 = light_5; - param_184 = _e306; - let _e307 = i_9; - param_185 = _e307; - let _e308 = LightVisibility_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_struct_u002d_LightSample_u002d_vf3_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf31_u003b_i1_u003b((¶m_183), (¶m_184), (¶m_185)); - let _e309 = v_world_position_1; - param_186 = _e309; - let _e311 = (*s_8).n; - param_187 = _e311; - let _e312 = i_9; - param_188 = _e312; - let _e313 = PointShadowFactor_u0028_vf3_u003b_vf3_u003b_i1_u003b((¶m_186), (¶m_187), (¶m_188)); - local_30 = (_e308 * _e313); + let _e304 = i_9; + param_182 = _e304; + let _e305 = LightHasShadow_u0028_i1_u003b((¶m_182)); + if _e305 { + let _e306 = (*s_8); + param_183 = _e306; + let _e307 = light_5; + param_184 = _e307; + let _e308 = i_9; + param_185 = _e308; + let _e309 = LightVisibility_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_struct_u002d_LightSample_u002d_vf3_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf31_u003b_i1_u003b((¶m_183), (¶m_184), (¶m_185)); + let _e310 = v_world_position_1; + param_186 = _e310; + let _e312 = (*s_8).n; + param_187 = _e312; + let _e313 = i_9; + param_188 = _e313; + let _e314 = PointShadowFactor_u0028_vf3_u003b_vf3_u003b_i1_u003b((¶m_186), (¶m_187), (¶m_188)); + local_30 = (_e309 * _e314); } else { local_30 = 1f; } - let _e315 = local_30; - visibility = _e315; - let _e316 = visibility; - if (_e316 <= 0f) { + let _e316 = local_30; + visibility = _e316; + let _e317 = visibility; + if (_e317 <= 0f) { continue; } - let _e318 = (*s_8); - param_189 = _e318; - let _e319 = light_5; - param_190 = _e319; - let _e320 = ShadeLight_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_struct_u002d_LightSample_u002d_vf3_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf31_u003b((¶m_189), (¶m_190)); - let _e322 = light_5.radiance; - let _e325 = light_5.n_dot_l; - let _e327 = visibility; - let _e329 = light_transmittance; - let _e331 = total_1; - total_1 = (_e331 + ((((_e320 * _e322) * _e325) * _e327) * _e329)); + let _e319 = (*s_8); + param_189 = _e319; + let _e320 = light_5; + param_190 = _e320; + let _e321 = ShadeLight_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_struct_u002d_LightSample_u002d_vf3_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf31_u003b((¶m_189), (¶m_190)); + let _e323 = light_5.radiance; + let _e326 = light_5.n_dot_l; + let _e328 = visibility; + let _e330 = light_transmittance; + let _e332 = total_1; + total_1 = (_e332 + ((((_e321 * _e323) * _e326) * _e328) * _e330)); continue; } else { break; } continuing { - let _e333 = i_9; - i_9 = (_e333 + 1i); + let _e334 = i_9; + i_9 = (_e334 + 1i); } } - let _e335 = total_1; - return _e335; + let _e336 = total_1; + return _e336; } fn SampleLightmap_u0028_() -> vec3 { var texel_4: vec4; - let _e274 = v_lightmap_uv_1; - let _e275 = textureSample(lightmap_texture_tex, lightmap_texture_smp, _e274); - texel_4 = _e275; - let _e276 = texel_4; - let _e279 = texel_4[3u]; - return ((_e276.xyz * _e279) * 8f); + let _e275 = v_lightmap_uv_1; + let _e276 = textureSample(lightmap_texture_tex, lightmap_texture_smp, _e275); + texel_4 = _e276; + let _e277 = texel_4; + let _e280 = texel_4[3u]; + return ((_e277.xyz * _e280) * 8f); } fn SceneColourLevel_u0028_vf2_u003b_i1_u003b(uv_6: ptr>, level: ptr) -> vec3 { @@ -21176,22 +21316,22 @@ fn SceneColourLevel_u0028_vf2_u003b_i1_u003b(uv_6: ptr>, lev var inset_1: vec2; var at_4: vec2; - let _e278 = (*level); - let _e281 = layer_info.scene_levels[_e278]; - rect = _e281; - let _e283 = layer_info.scene_colour; - inset_1 = (_e283.yz * 0.5f); - let _e286 = rect; - let _e288 = (*uv_6); - let _e289 = rect; - let _e292 = inset_1; - let _e293 = rect; - let _e295 = inset_1; - let _e297 = inset_1; - at_4 = (_e286.xy + clamp((_e288 * _e289.zw), _e292, max((_e293.zw - _e295), _e297))); - let _e301 = at_4; - let _e302 = textureSampleLevel(scene_colour_texture_tex, scene_colour_texture_smp, _e301, 0f); - return _e302.xyz; + let _e279 = (*level); + let _e282 = layer_info.scene_levels[_e279]; + rect = _e282; + let _e284 = layer_info.scene_colour; + inset_1 = (_e284.yz * 0.5f); + let _e287 = rect; + let _e289 = (*uv_6); + let _e290 = rect; + let _e293 = inset_1; + let _e294 = rect; + let _e296 = inset_1; + let _e298 = inset_1; + at_4 = (_e287.xy + clamp((_e289 * _e290.zw), _e293, max((_e294.zw - _e296), _e298))); + let _e302 = at_4; + let _e303 = textureSampleLevel(scene_colour_texture_tex, scene_colour_texture_smp, _e302, 0f); + return _e303.xyz; } fn SceneColourAt_u0028_vf3_u003b_f1_u003b(world_4: ptr>, lod: ptr) -> vec3 { @@ -21209,78 +21349,78 @@ fn SceneColourAt_u0028_vf3_u003b_f1_u003b(world_4: ptr>, lod var param_193: vec2; var param_194: i32; - let _e289 = layer_info.scene_view_projection; - let _e290 = (*world_4); - clip_2 = (_e289 * vec4(_e290.x, _e290.y, _e290.z, 1f)); - let _e296 = clip_2; - let _e299 = clip_2[3u]; - ndc_2 = (_e296.xy / vec2(max(_e299, 0.000001f))); - let _e304 = ndc_2[0u]; - let _e308 = ndc_2[1u]; - view_1 = clamp(vec2(((_e304 * 0.5f) + 0.5f), (0.5f - (_e308 * 0.5f))), vec2(0f, 0f), vec2(1f, 1f)); - let _e314 = layer_info.scene_viewport; - let _e316 = view_1; - let _e318 = layer_info.scene_viewport; - uv_7 = (_e314.xy + (_e316 * _e318.zw)); - let _e324 = layer_info.scene_colour[0u]; - top = (_e324 - 1f); - let _e326 = (*lod); - let _e327 = top; - level_1 = clamp(_e326, 0f, _e327); - let _e329 = level_1; - lower = floor(_e329); - let _e331 = lower; - let _e333 = uv_7; - param_191 = _e333; - param_192 = i32(_e331); - let _e334 = SceneColourLevel_u0028_vf2_u003b_i1_u003b((¶m_191), (¶m_192)); - near_2 = _e334; - let _e335 = lower; - let _e337 = top; - let _e340 = uv_7; - param_193 = _e340; - param_194 = i32(min((_e335 + 1f), _e337)); - let _e341 = SceneColourLevel_u0028_vf2_u003b_i1_u003b((¶m_193), (¶m_194)); - far_1 = _e341; - let _e342 = near_2; - let _e343 = far_1; - let _e344 = level_1; - let _e345 = lower; - return mix(_e342, _e343, vec3((_e344 - _e345))); + let _e290 = layer_info.scene_view_projection; + let _e291 = (*world_4); + clip_2 = (_e290 * vec4(_e291.x, _e291.y, _e291.z, 1f)); + let _e297 = clip_2; + let _e300 = clip_2[3u]; + ndc_2 = (_e297.xy / vec2(max(_e300, 0.000001f))); + let _e305 = ndc_2[0u]; + let _e309 = ndc_2[1u]; + view_1 = clamp(vec2(((_e305 * 0.5f) + 0.5f), (0.5f - (_e309 * 0.5f))), vec2(0f, 0f), vec2(1f, 1f)); + let _e315 = layer_info.scene_viewport; + let _e317 = view_1; + let _e319 = layer_info.scene_viewport; + uv_7 = (_e315.xy + (_e317 * _e319.zw)); + let _e325 = layer_info.scene_colour[0u]; + top = (_e325 - 1f); + let _e327 = (*lod); + let _e328 = top; + level_1 = clamp(_e327, 0f, _e328); + let _e330 = level_1; + lower = floor(_e330); + let _e332 = lower; + let _e334 = uv_7; + param_191 = _e334; + param_192 = i32(_e332); + let _e335 = SceneColourLevel_u0028_vf2_u003b_i1_u003b((¶m_191), (¶m_192)); + near_2 = _e335; + let _e336 = lower; + let _e338 = top; + let _e341 = uv_7; + param_193 = _e341; + param_194 = i32(min((_e336 + 1f), _e338)); + let _e342 = SceneColourLevel_u0028_vf2_u003b_i1_u003b((¶m_193), (¶m_194)); + far_1 = _e342; + let _e343 = near_2; + let _e344 = far_1; + let _e345 = level_1; + let _e346 = lower; + return mix(_e343, _e344, vec3((_e345 - _e346))); } fn IorInfinite_u0028_() -> bool { - let _e275 = layer_info.coat[2u]; - return (_e275 == 0f); + let _e276 = layer_info.coat[2u]; + return (_e276 == 0f); } fn DispersionSpread_u0028_f1_u003b(ior: ptr) -> f32 { var local_31: f32; - let _e275 = IorInfinite_u0028_(); - if _e275 { + let _e276 = IorInfinite_u0028_(); + if _e276 { local_31 = 0f; } else { - let _e276 = (*ior); - let _e281 = layer_info.transmission[3u]; - local_31 = (((_e276 - 1f) * 0.025f) * _e281); + let _e277 = (*ior); + let _e282 = layer_info.transmission[3u]; + local_31 = (((_e277 - 1f) * 0.025f) * _e282); } - let _e283 = local_31; - return _e283; + let _e284 = local_31; + return _e284; } fn RefractionIor_u0028_() -> f32 { var local_32: f32; - let _e274 = IorInfinite_u0028_(); - if _e274 { + let _e275 = IorInfinite_u0028_(); + if _e275 { local_32 = 10000f; } else { - let _e277 = layer_info.coat[2u]; - local_32 = max(_e277, 1f); + let _e278 = layer_info.coat[2u]; + local_32 = max(_e278, 1f); } - let _e279 = local_32; - return _e279; + let _e280 = local_32; + return _e280; } fn SceneBehind_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b(s_9: ptr) -> vec3 { @@ -21303,81 +21443,81 @@ fn SceneBehind_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3 var param_200: vec3; var param_201: f32; - let _e292 = RefractionIor_u0028_(); - ior_1 = _e292; - let _e293 = ior_1; - param_195 = _e293; - let _e294 = DispersionSpread_u0028_f1_u003b((¶m_195)); - spread_1 = _e294; - let _e298 = layer_info.scene_levels[0i][2u]; - let _e301 = layer_info.scene_colour[1u]; - width = (_e298 / max(_e301, 0.000000001f)); - let _e304 = width; - let _e308 = (*s_9).roughness; - let _e310 = ior_1; - lod_1 = ((log2(max(_e304, 1f)) * _e308) * clamp(((_e310 * 2f) - 2f), 0f, 1f)); - let _e315 = g_thickness; - thin = (_e315 <= 0f); - let _e317 = thin; - if _e317 { - let _e319 = (*s_9).v; - local_33 = -(_e319); - } else { - let _e322 = (*s_9).v; - let _e325 = (*s_9).n; - let _e326 = ior_1; - let _e327 = spread_1; - local_33 = refract(-(_e322), _e325, (1f / max((_e326 - _e327), 1f))); - } - let _e332 = local_33; - red = _e332; - let _e333 = thin; - if _e333 { - let _e335 = (*s_9).v; - local_34 = -(_e335); - } else { - let _e338 = (*s_9).v; - let _e341 = (*s_9).n; - let _e342 = ior_1; - local_34 = refract(-(_e338), _e341, (1f / _e342)); - } - let _e345 = local_34; - green = _e345; - let _e346 = thin; - if _e346 { - let _e348 = (*s_9).v; - local_35 = -(_e348); - } else { - let _e351 = (*s_9).v; - let _e354 = (*s_9).n; - let _e355 = ior_1; - let _e356 = spread_1; - local_35 = refract(-(_e351), _e354, (1f / (_e355 + _e356))); - } - let _e360 = local_35; - blue = _e360; - let _e361 = v_world_position_1; - let _e362 = red; - let _e363 = g_thickness; - param_196 = (_e361 + (_e362 * _e363)); - let _e366 = lod_1; - param_197 = _e366; - let _e367 = SceneColourAt_u0028_vf3_u003b_f1_u003b((¶m_196), (¶m_197)); - let _e369 = v_world_position_1; - let _e370 = green; - let _e371 = g_thickness; - param_198 = (_e369 + (_e370 * _e371)); - let _e374 = lod_1; - param_199 = _e374; - let _e375 = SceneColourAt_u0028_vf3_u003b_f1_u003b((¶m_198), (¶m_199)); - let _e377 = v_world_position_1; - let _e378 = blue; - let _e379 = g_thickness; - param_200 = (_e377 + (_e378 * _e379)); - let _e382 = lod_1; - param_201 = _e382; - let _e383 = SceneColourAt_u0028_vf3_u003b_f1_u003b((¶m_200), (¶m_201)); - return vec3(_e367.x, _e375.y, _e383.z); + let _e293 = RefractionIor_u0028_(); + ior_1 = _e293; + let _e294 = ior_1; + param_195 = _e294; + let _e295 = DispersionSpread_u0028_f1_u003b((¶m_195)); + spread_1 = _e295; + let _e299 = layer_info.scene_levels[0i][2u]; + let _e302 = layer_info.scene_colour[1u]; + width = (_e299 / max(_e302, 0.000000001f)); + let _e305 = width; + let _e309 = (*s_9).roughness; + let _e311 = ior_1; + lod_1 = ((log2(max(_e305, 1f)) * _e309) * clamp(((_e311 * 2f) - 2f), 0f, 1f)); + let _e316 = g_thickness; + thin = (_e316 <= 0f); + let _e318 = thin; + if _e318 { + let _e320 = (*s_9).v; + local_33 = -(_e320); + } else { + let _e323 = (*s_9).v; + let _e326 = (*s_9).n; + let _e327 = ior_1; + let _e328 = spread_1; + local_33 = refract(-(_e323), _e326, (1f / max((_e327 - _e328), 1f))); + } + let _e333 = local_33; + red = _e333; + let _e334 = thin; + if _e334 { + let _e336 = (*s_9).v; + local_34 = -(_e336); + } else { + let _e339 = (*s_9).v; + let _e342 = (*s_9).n; + let _e343 = ior_1; + local_34 = refract(-(_e339), _e342, (1f / _e343)); + } + let _e346 = local_34; + green = _e346; + let _e347 = thin; + if _e347 { + let _e349 = (*s_9).v; + local_35 = -(_e349); + } else { + let _e352 = (*s_9).v; + let _e355 = (*s_9).n; + let _e356 = ior_1; + let _e357 = spread_1; + local_35 = refract(-(_e352), _e355, (1f / (_e356 + _e357))); + } + let _e361 = local_35; + blue = _e361; + let _e362 = v_world_position_1; + let _e363 = red; + let _e364 = g_thickness; + param_196 = (_e362 + (_e363 * _e364)); + let _e367 = lod_1; + param_197 = _e367; + let _e368 = SceneColourAt_u0028_vf3_u003b_f1_u003b((¶m_196), (¶m_197)); + let _e370 = v_world_position_1; + let _e371 = green; + let _e372 = g_thickness; + param_198 = (_e370 + (_e371 * _e372)); + let _e375 = lod_1; + param_199 = _e375; + let _e376 = SceneColourAt_u0028_vf3_u003b_f1_u003b((¶m_198), (¶m_199)); + let _e378 = v_world_position_1; + let _e379 = blue; + let _e380 = g_thickness; + param_200 = (_e378 + (_e379 * _e380)); + let _e383 = lod_1; + param_201 = _e383; + let _e384 = SceneColourAt_u0028_vf3_u003b_f1_u003b((¶m_200), (¶m_201)); + return vec3(_e368.x, _e376.y, _e384.z); } fn TransmittedRadiance_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_f1_u003b(s_10: ptr, levels: ptr) -> vec3 { @@ -21393,71 +21533,71 @@ fn TransmittedRadiance_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u var blue_1: vec3; var local_38: vec3; - let _e286 = RefractionIor_u0028_(); - ior_2 = _e286; - let _e287 = ior_2; - param_202 = _e287; - let _e288 = DispersionSpread_u0028_f1_u003b((¶m_202)); - spread_2 = _e288; - let _e290 = (*s_10).roughness; - let _e291 = ior_2; - let _e296 = (*levels); - lod_2 = ((_e290 * clamp(((_e291 * 2f) - 2f), 0f, 1f)) * _e296); - let _e298 = g_thickness; - thin_1 = (_e298 <= 0f); - let _e300 = thin_1; - if _e300 { - let _e302 = (*s_10).v; - local_36 = -(_e302); - } else { - let _e305 = (*s_10).v; - let _e308 = (*s_10).n; - let _e309 = ior_2; - let _e310 = spread_2; - local_36 = refract(-(_e305), _e308, (1f / max((_e309 - _e310), 1f))); - } - let _e315 = local_36; - red_1 = _e315; - let _e316 = thin_1; - if _e316 { - let _e318 = (*s_10).v; - local_37 = -(_e318); - } else { - let _e321 = (*s_10).v; - let _e324 = (*s_10).n; - let _e325 = ior_2; - local_37 = refract(-(_e321), _e324, (1f / _e325)); - } - let _e328 = local_37; - green_1 = _e328; - let _e329 = thin_1; - if _e329 { - let _e331 = (*s_10).v; - local_38 = -(_e331); - } else { - let _e334 = (*s_10).v; - let _e337 = (*s_10).n; - let _e338 = ior_2; - let _e339 = spread_2; - local_38 = refract(-(_e334), _e337, (1f / (_e338 + _e339))); - } - let _e343 = local_38; - blue_1 = _e343; - let _e344 = red_1; - let _e345 = lod_2; - let _e346 = textureSampleLevel(environment_texture_tex, environment_texture_smp, _e344, _e345); - let _e348 = green_1; - let _e349 = lod_2; - let _e350 = textureSampleLevel(environment_texture_tex, environment_texture_smp, _e348, _e349); - let _e352 = blue_1; - let _e353 = lod_2; - let _e354 = textureSampleLevel(environment_texture_tex, environment_texture_smp, _e352, _e353); - return vec3(_e346.x, _e350.y, _e354.z); + let _e287 = RefractionIor_u0028_(); + ior_2 = _e287; + let _e288 = ior_2; + param_202 = _e288; + let _e289 = DispersionSpread_u0028_f1_u003b((¶m_202)); + spread_2 = _e289; + let _e291 = (*s_10).roughness; + let _e292 = ior_2; + let _e297 = (*levels); + lod_2 = ((_e291 * clamp(((_e292 * 2f) - 2f), 0f, 1f)) * _e297); + let _e299 = g_thickness; + thin_1 = (_e299 <= 0f); + let _e301 = thin_1; + if _e301 { + let _e303 = (*s_10).v; + local_36 = -(_e303); + } else { + let _e306 = (*s_10).v; + let _e309 = (*s_10).n; + let _e310 = ior_2; + let _e311 = spread_2; + local_36 = refract(-(_e306), _e309, (1f / max((_e310 - _e311), 1f))); + } + let _e316 = local_36; + red_1 = _e316; + let _e317 = thin_1; + if _e317 { + let _e319 = (*s_10).v; + local_37 = -(_e319); + } else { + let _e322 = (*s_10).v; + let _e325 = (*s_10).n; + let _e326 = ior_2; + local_37 = refract(-(_e322), _e325, (1f / _e326)); + } + let _e329 = local_37; + green_1 = _e329; + let _e330 = thin_1; + if _e330 { + let _e332 = (*s_10).v; + local_38 = -(_e332); + } else { + let _e335 = (*s_10).v; + let _e338 = (*s_10).n; + let _e339 = ior_2; + let _e340 = spread_2; + local_38 = refract(-(_e335), _e338, (1f / (_e339 + _e340))); + } + let _e344 = local_38; + blue_1 = _e344; + let _e345 = red_1; + let _e346 = lod_2; + let _e347 = textureSampleLevel(environment_texture_tex, environment_texture_smp, _e345, _e346); + let _e349 = green_1; + let _e350 = lod_2; + let _e351 = textureSampleLevel(environment_texture_tex, environment_texture_smp, _e349, _e350); + let _e353 = blue_1; + let _e354 = lod_2; + let _e355 = textureSampleLevel(environment_texture_tex, environment_texture_smp, _e353, _e354); + return vec3(_e347.x, _e351.y, _e355.z); } fn SceneColourBound_u0028_() -> bool { - let _e275 = layer_info.scene_colour[0u]; - return (_e275 > 0f); + let _e276 = layer_info.scene_colour[0u]; + return (_e276 > 0f); } fn EonAlbedo_u0028_vf3_u003b_f1_u003b_f1_u003b(rho_2: ptr>, r_4: ptr, mu_1: ptr) -> vec3 { @@ -21468,23 +21608,23 @@ fn EonAlbedo_u0028_vf3_u003b_f1_u003b_f1_u003b(rho_2: ptr>, var param_206: vec3; var param_207: f32; - let _e282 = (*mu_1); - param_203 = _e282; - let _e283 = (*r_4); - param_204 = _e283; - let _e284 = FonAlbedo_u0028_f1_u003b_f1_u003b((¶m_203), (¶m_204)); - e_1 = _e284; - let _e285 = (*rho_2); - let _e286 = e_1; - let _e288 = (*r_4); - param_205 = _e288; - let _e289 = FonAverage_u0028_f1_u003b((¶m_205)); - let _e290 = (*rho_2); - param_206 = _e290; - param_207 = _e289; - let _e291 = EonMultiAlbedo_u0028_vf3_u003b_f1_u003b((¶m_206), (¶m_207)); - let _e292 = e_1; - return ((_e285 * _e286) + (_e291 * (1f - _e292))); + let _e283 = (*mu_1); + param_203 = _e283; + let _e284 = (*r_4); + param_204 = _e284; + let _e285 = FonAlbedo_u0028_f1_u003b_f1_u003b((¶m_203), (¶m_204)); + e_1 = _e285; + let _e286 = (*rho_2); + let _e287 = e_1; + let _e289 = (*r_4); + param_205 = _e289; + let _e290 = FonAverage_u0028_f1_u003b((¶m_205)); + let _e291 = (*rho_2); + param_206 = _e291; + param_207 = _e290; + let _e292 = EonMultiAlbedo_u0028_vf3_u003b_f1_u003b((¶m_206), (¶m_207)); + let _e293 = e_1; + return ((_e286 * _e287) + (_e292 * (1f - _e293))); } fn IridescenceSensitivity_u0028_f1_u003b_vf3_u003b(opd: ptr, shift: ptr>) -> vec3 { @@ -21494,30 +21634,30 @@ fn IridescenceSensitivity_u0028_f1_u003b_vf3_u003b(opd: ptr, shif var variance_1: vec3; var xyz: vec3; - let _e280 = (*opd); - phase = ((6.2831855f * _e280) * 0.000000001f); + let _e281 = (*opd); + phase = ((6.2831855f * _e281) * 0.000000001f); val = vec3(0.00000000000054856f, 0.00000000000044201f, 0.00000000000052481f); pos = vec3(1681000f, 1795300f, 2208400f); variance_1 = vec3(4327800000f, 9304600000f, 6612100000f); - let _e283 = val; - let _e284 = variance_1; - let _e288 = pos; - let _e289 = phase; - let _e291 = (*shift); - let _e295 = phase; + let _e284 = val; + let _e285 = variance_1; + let _e289 = pos; + let _e290 = phase; + let _e292 = (*shift); let _e296 = phase; - let _e299 = variance_1; - xyz = (((_e283 * sqrt((_e284 * 6.2831855f))) * cos(((_e288 * _e289) + _e291))) * exp((_e299 * -((_e295 * _e296))))); - let _e303 = phase; - let _e306 = (*shift)[0u]; - let _e310 = phase; - let _e312 = phase; - let _e317 = xyz[0u]; - xyz[0u] = (_e317 + ((0.00000001644083f * cos(((2239900f * _e303) + _e306))) * exp(((-4528200000f * _e310) * _e312)))); - let _e320 = xyz; - xyz = (_e320 / vec3(0.00000010685f)); - let _e323 = xyz; - return (mat3x3(vec3(3.2404542f, -0.969266f, 0.0556434f), vec3(-1.5371385f, 1.8760108f, -0.2040259f), vec3(-0.4985314f, 0.041556f, 1.0572252f)) * _e323); + let _e297 = phase; + let _e300 = variance_1; + xyz = (((_e284 * sqrt((_e285 * 6.2831855f))) * cos(((_e289 * _e290) + _e292))) * exp((_e300 * -((_e296 * _e297))))); + let _e304 = phase; + let _e307 = (*shift)[0u]; + let _e311 = phase; + let _e313 = phase; + let _e318 = xyz[0u]; + xyz[0u] = (_e318 + ((0.00000001644083f * cos(((2239900f * _e304) + _e307))) * exp(((-4528200000f * _e311) * _e313)))); + let _e321 = xyz; + xyz = (_e321 / vec3(0.00000010685f)); + let _e324 = xyz; + return (mat3x3(vec3(3.2404542f, -0.969266f, 0.0556434f), vec3(-1.5371385f, 1.8760108f, -0.2040259f), vec3(-0.4985314f, 0.041556f, 1.0572252f)) * _e324); } fn FresnelIridescence_u0028_f1_u003b_f1_u003b_f1_u003b_vf3_u003b(film: ptr, cos1_: ptr, thickness: ptr, base: ptr>) -> vec3 { @@ -21547,115 +21687,115 @@ fn FresnelIridescence_u0028_f1_u003b_f1_u003b_f1_u003b_vf3_u003b(film: ptr; var local_39: vec3; - let _e302 = (*film); - let _e303 = (*thickness); - eta2_ = mix(1f, _e302, smoothstep(0f, 0.03f, _e303)); - let _e306 = (*cos1_); + let _e303 = (*film); + let _e304 = (*thickness); + eta2_ = mix(1f, _e303, smoothstep(0f, 0.03f, _e304)); let _e307 = (*cos1_); - let _e310 = eta2_; + let _e308 = (*cos1_); let _e311 = eta2_; - sin2Sq = ((1f - (_e306 * _e307)) / (_e310 * _e311)); - let _e314 = sin2Sq; - cos2Sq = (1f - _e314); - let _e316 = cos2Sq; - cos2_ = sqrt(max(_e316, 0f)); - let _e319 = eta2_; - let _e321 = eta2_; - r0_ = ((_e319 - 1f) / (_e321 + 1f)); - let _e324 = r0_; + let _e312 = eta2_; + sin2Sq = ((1f - (_e307 * _e308)) / (_e311 * _e312)); + let _e315 = sin2Sq; + cos2Sq = (1f - _e315); + let _e317 = cos2Sq; + cos2_ = sqrt(max(_e317, 0f)); + let _e320 = eta2_; + let _e322 = eta2_; + r0_ = ((_e320 - 1f) / (_e322 + 1f)); let _e325 = r0_; - let _e327 = r0_; + let _e326 = r0_; let _e328 = r0_; - let _e331 = (*cos1_); - r12_ = ((_e324 * _e325) + ((1f - (_e327 * _e328)) * pow((1f - _e331), 5f))); - let _e336 = r12_; - t121_ = (1f - _e336); - let _e338 = eta2_; - phi12_ = select(0f, 3.1415927f, (_e338 < 1f)); - let _e341 = phi12_; - phi21_ = (3.1415927f - _e341); - let _e343 = (*base); - sqrtBase = sqrt(clamp(_e343, vec3(0f, 0f, 0f), vec3(0.9999f, 0.9999f, 0.9999f))); - let _e346 = sqrtBase; - let _e348 = sqrtBase; - baseIor = ((vec3(1f, 1f, 1f) + _e346) / (vec3(1f, 1f, 1f) - _e348)); - let _e351 = baseIor; - let _e352 = eta2_; - let _e355 = baseIor; - let _e356 = eta2_; - r1_ = ((_e351 - vec3(_e352)) / (_e355 + vec3(_e356))); - let _e360 = r1_; + let _e329 = r0_; + let _e332 = (*cos1_); + r12_ = ((_e325 * _e326) + ((1f - (_e328 * _e329)) * pow((1f - _e332), 5f))); + let _e337 = r12_; + t121_ = (1f - _e337); + let _e339 = eta2_; + phi12_ = select(0f, 3.1415927f, (_e339 < 1f)); + let _e342 = phi12_; + phi21_ = (3.1415927f - _e342); + let _e344 = (*base); + sqrtBase = sqrt(clamp(_e344, vec3(0f, 0f, 0f), vec3(0.9999f, 0.9999f, 0.9999f))); + let _e347 = sqrtBase; + let _e349 = sqrtBase; + baseIor = ((vec3(1f, 1f, 1f) + _e347) / (vec3(1f, 1f, 1f) - _e349)); + let _e352 = baseIor; + let _e353 = eta2_; + let _e356 = baseIor; + let _e357 = eta2_; + r1_ = ((_e352 - vec3(_e353)) / (_e356 + vec3(_e357))); let _e361 = r1_; - r1_ = (_e361 * _e360); - let _e363 = r1_; + let _e362 = r1_; + r1_ = (_e362 * _e361); let _e364 = r1_; - let _e366 = cos2_; - r23_ = (_e363 + ((vec3(1f, 1f, 1f) - _e364) * pow((1f - _e366), 5f))); - let _e372 = baseIor[0u]; - let _e373 = eta2_; - let _e377 = baseIor[1u]; - let _e378 = eta2_; - let _e382 = baseIor[2u]; - let _e383 = eta2_; - phi23_ = vec3(select(0f, 3.1415927f, (_e372 < _e373)), select(0f, 3.1415927f, (_e377 < _e378)), select(0f, 3.1415927f, (_e382 < _e383))); - let _e387 = eta2_; - let _e389 = (*thickness); - let _e391 = cos2_; - opd_1 = (((2f * _e387) * _e389) * _e391); - let _e393 = phi21_; - let _e395 = phi23_; - phi = (vec3(_e393) + _e395); - let _e397 = r12_; - let _e398 = r23_; - r123_ = clamp((_e398 * _e397), vec3(0.00001f, 0.00001f, 0.00001f), vec3(0.9999f, 0.9999f, 0.9999f)); - let _e401 = r123_; - rootR123_ = sqrt(_e401); - let _e403 = t121_; + let _e365 = r1_; + let _e367 = cos2_; + r23_ = (_e364 + ((vec3(1f, 1f, 1f) - _e365) * pow((1f - _e367), 5f))); + let _e373 = baseIor[0u]; + let _e374 = eta2_; + let _e378 = baseIor[1u]; + let _e379 = eta2_; + let _e383 = baseIor[2u]; + let _e384 = eta2_; + phi23_ = vec3(select(0f, 3.1415927f, (_e373 < _e374)), select(0f, 3.1415927f, (_e378 < _e379)), select(0f, 3.1415927f, (_e383 < _e384))); + let _e388 = eta2_; + let _e390 = (*thickness); + let _e392 = cos2_; + opd_1 = (((2f * _e388) * _e390) * _e392); + let _e394 = phi21_; + let _e396 = phi23_; + phi = (vec3(_e394) + _e396); + let _e398 = r12_; + let _e399 = r23_; + r123_ = clamp((_e399 * _e398), vec3(0.00001f, 0.00001f, 0.00001f), vec3(0.9999f, 0.9999f, 0.9999f)); + let _e402 = r123_; + rootR123_ = sqrt(_e402); let _e404 = t121_; - let _e406 = r23_; - let _e408 = r123_; - rs = ((_e406 * (_e403 * _e404)) / (vec3(1f, 1f, 1f) - _e408)); - let _e411 = r12_; - let _e413 = rs; - total_2 = (vec3(_e411) + _e413); - let _e415 = rs; - let _e416 = t121_; - cm = (_e415 - vec3(_e416)); + let _e405 = t121_; + let _e407 = r23_; + let _e409 = r123_; + rs = ((_e407 * (_e404 * _e405)) / (vec3(1f, 1f, 1f) - _e409)); + let _e412 = r12_; + let _e414 = rs; + total_2 = (vec3(_e412) + _e414); + let _e416 = rs; + let _e417 = t121_; + cm = (_e416 - vec3(_e417)); m_1 = 1i; loop { - let _e419 = m_1; - if (_e419 <= 2i) { - let _e421 = rootR123_; - let _e422 = cm; - cm = (_e422 * _e421); - let _e424 = cm; - let _e426 = m_1; - let _e428 = opd_1; - let _e430 = m_1; - let _e432 = phi; - param_208 = (f32(_e426) * _e428); - param_209 = (_e432 * f32(_e430)); - let _e434 = IridescenceSensitivity_u0028_f1_u003b_vf3_u003b((¶m_208), (¶m_209)); - let _e436 = total_2; - total_2 = (_e436 + ((_e424 * 2f) * _e434)); + let _e420 = m_1; + if (_e420 <= 2i) { + let _e422 = rootR123_; + let _e423 = cm; + cm = (_e423 * _e422); + let _e425 = cm; + let _e427 = m_1; + let _e429 = opd_1; + let _e431 = m_1; + let _e433 = phi; + param_208 = (f32(_e427) * _e429); + param_209 = (_e433 * f32(_e431)); + let _e435 = IridescenceSensitivity_u0028_f1_u003b_vf3_u003b((¶m_208), (¶m_209)); + let _e437 = total_2; + total_2 = (_e437 + ((_e425 * 2f) * _e435)); continue; } else { break; } continuing { - let _e438 = m_1; - m_1 = (_e438 + 1i); + let _e439 = m_1; + m_1 = (_e439 + 1i); } } - let _e440 = cos2Sq; - if (_e440 < 0f) { + let _e441 = cos2Sq; + if (_e441 < 0f) { local_39 = vec3(1f, 1f, 1f); } else { - let _e442 = total_2; - local_39 = max(_e442, vec3(0f, 0f, 0f)); + let _e443 = total_2; + local_39 = max(_e443, vec3(0f, 0f, 0f)); } - let _e444 = local_39; - return _e444; + let _e445 = local_39; + return _e445; } fn ReadIridescence_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b(s_11: ptr) { @@ -21665,20 +21805,20 @@ fn ReadIridescence_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d var param_212: f32; var param_213: vec3; - let _e279 = g_f0_dielectric; - let _e281 = (*s_11).albedo; - let _e283 = (*s_11).metallic; - f0_3 = mix(_e279, _e281, vec3(clamp(_e283, 0f, 1f))); - let _e289 = layer_info.iridescence[1u]; - param_210 = _e289; - let _e291 = (*s_11).n_dot_v; - param_211 = _e291; - let _e294 = layer_info.iridescence[2u]; - param_212 = _e294; - let _e295 = f0_3; - param_213 = _e295; - let _e296 = FresnelIridescence_u0028_f1_u003b_f1_u003b_f1_u003b_vf3_u003b((¶m_210), (¶m_211), (¶m_212), (¶m_213)); - g_irid_fresnel = _e296; + let _e280 = g_f0_dielectric; + let _e282 = (*s_11).albedo; + let _e284 = (*s_11).metallic; + f0_3 = mix(_e280, _e282, vec3(clamp(_e284, 0f, 1f))); + let _e290 = layer_info.iridescence[1u]; + param_210 = _e290; + let _e292 = (*s_11).n_dot_v; + param_211 = _e292; + let _e295 = layer_info.iridescence[2u]; + param_212 = _e295; + let _e296 = f0_3; + param_213 = _e296; + let _e297 = FresnelIridescence_u0028_f1_u003b_f1_u003b_f1_u003b_vf3_u003b((¶m_210), (¶m_211), (¶m_212), (¶m_213)); + g_irid_fresnel = _e297; return; } @@ -21694,89 +21834,89 @@ fn ReadLayersOnMaps_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002 var along_1: vec3; var local_41: f32; var local_42: vec3; - var phi_5007_: bool; + var phi_5040_: bool; - let _e286 = (*s_12).n_dot_v; - let _e290 = g_sheen_roughness; - param_214 = _e290; - param_215 = sqrt(clamp((1f - _e286), 0f, 1f)); + let _e287 = (*s_12).n_dot_v; + let _e291 = g_sheen_roughness; + param_214 = _e291; + param_215 = sqrt(clamp((1f - _e287), 0f, 1f)); param_216 = 1f; - let _e291 = LtcUv_u0028_f1_u003b_f1_u003b_f1_u003b((¶m_214), (¶m_215), (¶m_216)); - let _e292 = textureSampleLevel(ltc_texture_tex, ltc_texture_smp, _e291, 0f); - g_sheen_albedo = _e292.z; - let _e295 = g_sheen[0u]; - let _e297 = g_sheen[1u]; - let _e300 = g_sheen[2u]; - let _e302 = g_sheen_albedo; - g_sheen_scale = (1f - (max(max(_e295, _e297), _e300) * _e302)); - let _e305 = v_tangent_1; - let _e308 = (*s_12).n; - let _e310 = (*s_12).n; - let _e311 = v_tangent_1; - t_2 = (_e305.xyz - (_e308 * dot(_e310, _e311.xyz))); - let _e316 = t_2; + let _e292 = LtcUv_u0028_f1_u003b_f1_u003b_f1_u003b((¶m_214), (¶m_215), (¶m_216)); + let _e293 = textureSampleLevel(ltc_texture_tex, ltc_texture_smp, _e292, 0f); + g_sheen_albedo = _e293.z; + let _e296 = g_sheen[0u]; + let _e298 = g_sheen[1u]; + let _e301 = g_sheen[2u]; + let _e303 = g_sheen_albedo; + g_sheen_scale = (1f - (max(max(_e296, _e298), _e301) * _e303)); + let _e306 = v_tangent_1; + let _e309 = (*s_12).n; + let _e311 = (*s_12).n; + let _e312 = v_tangent_1; + t_2 = (_e306.xyz - (_e309 * dot(_e311, _e312.xyz))); let _e317 = t_2; - usable = (dot(_e316, _e317) > 0.000000000001f); - let _e320 = usable; - if _e320 { - let _e321 = t_2; - local_40 = normalize(_e321); + let _e318 = t_2; + usable = (dot(_e317, _e318) > 0.000000000001f); + let _e321 = usable; + if _e321 { + let _e322 = t_2; + local_40 = normalize(_e322); } else { local_40 = vec3(1f, 0f, 0f); } - let _e323 = local_40; - t_2 = _e323; - let _e325 = (*s_12).n; - let _e326 = t_2; - let _e329 = v_tangent_1[3u]; - b_4 = (cross(_e325, _e326) * _e329); - let _e331 = gl_FrontFacing_1; - if !(_e331) { - let _e333 = t_2; - t_2 = -(_e333); - } - let _e336 = layer_info.anisotropy; - turn_2 = _e336.yz; - let _e338 = t_2; - let _e340 = turn_2[0u]; - let _e342 = b_4; - let _e344 = turn_2[1u]; - along_1 = ((_e338 * _e340) + (_e342 * _e344)); - let _e347 = usable; - phi_5007_ = _e347; - if _e347 { - let _e348 = along_1; + let _e324 = local_40; + t_2 = _e324; + let _e326 = (*s_12).n; + let _e327 = t_2; + let _e330 = v_tangent_1[3u]; + b_4 = (cross(_e326, _e327) * _e330); + let _e332 = gl_FrontFacing_1; + if !(_e332) { + let _e334 = t_2; + t_2 = -(_e334); + } + let _e337 = layer_info.anisotropy; + turn_2 = _e337.yz; + let _e339 = t_2; + let _e341 = turn_2[0u]; + let _e343 = b_4; + let _e345 = turn_2[1u]; + along_1 = ((_e339 * _e341) + (_e343 * _e345)); + let _e348 = usable; + phi_5040_ = _e348; + if _e348 { let _e349 = along_1; - phi_5007_ = (dot(_e348, _e349) > 0.000000000001f); + let _e350 = along_1; + phi_5040_ = (dot(_e349, _e350) > 0.000000000001f); } - let _e353 = phi_5007_; - if _e353 { - let _e356 = layer_info.anisotropy[0u]; - local_41 = clamp(_e356, 0f, 1f); + let _e354 = phi_5040_; + if _e354 { + let _e357 = layer_info.anisotropy[0u]; + local_41 = clamp(_e357, 0f, 1f); } else { local_41 = 0f; } - let _e358 = local_41; - g_aniso = _e358; - let _e359 = g_aniso; - if (_e359 > 0f) { - let _e361 = along_1; - local_42 = normalize(_e361); - } else { - let _e363 = t_2; - local_42 = _e363; - } - let _e364 = local_42; - g_aniso_t = _e364; - let _e366 = (*s_12).n; - let _e367 = g_aniso_t; - g_aniso_b = cross(_e366, _e367); + let _e359 = local_41; + g_aniso = _e359; + let _e360 = g_aniso; + if (_e360 > 0f) { + let _e362 = along_1; + local_42 = normalize(_e362); + } else { + let _e364 = t_2; + local_42 = _e364; + } + let _e365 = local_42; + g_aniso_t = _e365; + let _e367 = (*s_12).n; + let _e368 = g_aniso_t; + g_aniso_b = cross(_e367, _e368); return; } fn MaterialLodBias_u0028_() -> f32 { - let _e275 = frag_info.target_origin[1u]; - return _e275; + let _e276 = frag_info.target_origin[1u]; + return _e276; } fn ApplyMetallicRoughnessMap_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b(s_13: ptr) { @@ -21784,16 +21924,16 @@ fn ApplyMetallicRoughnessMap_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d var param_217: i32; param_217 = 1i; - let _e276 = MapUv_u0028_i1_u003b((¶m_217)); - let _e277 = MaterialLodBias_u0028_(); - let _e278 = textureSampleBias(metallic_roughness_texture_tex, metallic_roughness_texture_smp, _e276, _e277); - orm = _e278.xyz; - let _e281 = (*s_13).metallic; - let _e283 = orm[2u]; - (*s_13).metallic = clamp((_e281 * _e283), 0f, 1f); - let _e288 = (*s_13).roughness; - let _e290 = orm[1u]; - (*s_13).roughness = clamp((_e288 * _e290), 0.02f, 1f); + let _e277 = MapUv_u0028_i1_u003b((¶m_217)); + let _e278 = MaterialLodBias_u0028_(); + let _e279 = textureSampleBias(metallic_roughness_texture_tex, metallic_roughness_texture_smp, _e277, _e278); + orm = _e279.xyz; + let _e282 = (*s_13).metallic; + let _e284 = orm[2u]; + (*s_13).metallic = clamp((_e282 * _e284), 0f, 1f); + let _e289 = (*s_13).roughness; + let _e291 = orm[1u]; + (*s_13).roughness = clamp((_e289 * _e291), 0.02f, 1f); return; } @@ -21803,16 +21943,16 @@ fn ApplyEmissiveMap_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002 var param_219: vec3; param_218 = 4i; - let _e277 = MapUv_u0028_i1_u003b((¶m_218)); - let _e278 = MaterialLodBias_u0028_(); - let _e279 = textureSampleBias(emissive_texture_tex, emissive_texture_smp, _e277, _e278); - param_219 = _e279.xyz; - let _e281 = SrgbToLinear_u0028_vf3_u003b((¶m_219)); - emissive = _e281; - let _e282 = emissive; - let _e284 = frag_info.emissive; - let _e289 = frag_info.material2_[3u]; - (*s_14).emissive = ((_e282 * _e284.xyz) * _e289); + let _e278 = MapUv_u0028_i1_u003b((¶m_218)); + let _e279 = MaterialLodBias_u0028_(); + let _e280 = textureSampleBias(emissive_texture_tex, emissive_texture_smp, _e278, _e279); + param_219 = _e280.xyz; + let _e282 = SrgbToLinear_u0028_vf3_u003b((¶m_219)); + emissive = _e282; + let _e283 = emissive; + let _e285 = frag_info.emissive; + let _e290 = frag_info.material2_[3u]; + (*s_14).emissive = ((_e283 * _e285.xyz) * _e290); return; } @@ -21821,13 +21961,13 @@ fn ApplyOcclusionMap_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u00 var param_220: i32; param_220 = 3i; - let _e276 = MapUv_u0028_i1_u003b((¶m_220)); - let _e277 = MaterialLodBias_u0028_(); - let _e278 = textureSampleBias(occlusion_texture_tex, occlusion_texture_smp, _e276, _e277); - occlusion = _e278.x; - let _e280 = occlusion; - let _e283 = frag_info.material2_[2u]; - (*s_15).occlusion = mix(1f, _e280, clamp(_e283, 0f, 1f)); + let _e277 = MapUv_u0028_i1_u003b((¶m_220)); + let _e278 = MaterialLodBias_u0028_(); + let _e279 = textureSampleBias(occlusion_texture_tex, occlusion_texture_smp, _e277, _e278); + occlusion = _e279.x; + let _e281 = occlusion; + let _e284 = frag_info.material2_[2u]; + (*s_15).occlusion = mix(1f, _e281, clamp(_e284, 0f, 1f)); return; } @@ -21835,17 +21975,17 @@ fn MapMatrix_u0028_i1_u003b(slot_7: ptr) -> vec4 { var u_2: vec4; var v_3: vec4; - let _e276 = (*slot_7); - let _e280 = layer_info.uv_transform[(_e276 * 2i)]; - u_2 = _e280; - let _e281 = (*slot_7); - let _e286 = layer_info.uv_transform[((_e281 * 2i) + 1i)]; - v_3 = _e286; - let _e288 = u_2[0u]; - let _e290 = u_2[1u]; - let _e292 = v_3[0u]; - let _e294 = v_3[1u]; - return vec4(_e288, _e290, _e292, _e294); + let _e277 = (*slot_7); + let _e281 = layer_info.uv_transform[(_e277 * 2i)]; + u_2 = _e281; + let _e282 = (*slot_7); + let _e287 = layer_info.uv_transform[((_e282 * 2i) + 1i)]; + v_3 = _e287; + let _e289 = u_2[0u]; + let _e291 = u_2[1u]; + let _e293 = v_3[0u]; + let _e295 = v_3[1u]; + return vec4(_e289, _e291, _e293, _e295); } fn ApplyNormalMap_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b(s_16: ptr) { @@ -21870,141 +22010,141 @@ fn ApplyNormalMap_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_ var phi_3787_: bool; param_221 = 2i; - let _e289 = MapUv_u0028_i1_u003b((¶m_221)); - let _e290 = MaterialLodBias_u0028_(); - let _e291 = textureSampleBias(normal_texture_tex, normal_texture_smp, _e289, _e290); - sampledTexel = _e291; - let _e292 = v_tangent_1; - t_3 = _e292.xyz; - let _e294 = t_3; - let _e296 = (*s_16).n; - let _e298 = (*s_16).n; - let _e299 = t_3; - t_3 = (_e294 - (_e296 * dot(_e298, _e299))); - let _e303 = t_3; + let _e290 = MapUv_u0028_i1_u003b((¶m_221)); + let _e291 = MaterialLodBias_u0028_(); + let _e292 = textureSampleBias(normal_texture_tex, normal_texture_smp, _e290, _e291); + sampledTexel = _e292; + let _e293 = v_tangent_1; + t_3 = _e293.xyz; + let _e295 = t_3; + let _e297 = (*s_16).n; + let _e299 = (*s_16).n; + let _e300 = t_3; + t_3 = (_e295 - (_e297 * dot(_e299, _e300))); let _e304 = t_3; - if (dot(_e303, _e304) < 0.000000000001f) { + let _e305 = t_3; + if (dot(_e304, _e305) < 0.000000000001f) { return; } - let _e307 = t_3; - t_3 = normalize(_e307); - let _e310 = (*s_16).n; - let _e311 = t_3; - let _e314 = v_tangent_1[3u]; - b_5 = (cross(_e310, _e311) * _e314); + let _e308 = t_3; + t_3 = normalize(_e308); + let _e311 = (*s_16).n; + let _e312 = t_3; + let _e315 = v_tangent_1[3u]; + b_5 = (cross(_e311, _e312) * _e315); param_222 = 2i; - let _e316 = MapMatrix_u0028_i1_u003b((¶m_222)); - m_2 = _e316; - let _e318 = m_2[0u]; - let _e320 = m_2[3u]; - let _e323 = m_2[1u]; - let _e325 = m_2[2u]; - det = ((_e318 * _e320) - (_e323 * _e325)); - let _e328 = det; - flip = select(1f, -1f, (_e328 < 0f)); - let _e331 = gl_FrontFacing_1; - if _e331 { - let _e332 = b_5; - local_43 = _e332; - } else { + let _e317 = MapMatrix_u0028_i1_u003b((¶m_222)); + m_2 = _e317; + let _e319 = m_2[0u]; + let _e321 = m_2[3u]; + let _e324 = m_2[1u]; + let _e326 = m_2[2u]; + det = ((_e319 * _e321) - (_e324 * _e326)); + let _e329 = det; + flip = select(1f, -1f, (_e329 < 0f)); + let _e332 = gl_FrontFacing_1; + if _e332 { let _e333 = b_5; - local_43 = -(_e333); - } - let _e335 = local_43; - front = _e335; - let _e336 = t_3; - let _e338 = m_2[3u]; - let _e340 = front; - let _e342 = m_2[2u]; - let _e345 = flip; - turned = (((_e336 * _e338) + (_e340 * _e342)) * _e345); - let _e348 = m_2[1u]; - let _e349 = (_e348 != 0f); - phi_3766_ = _e349; - if !(_e349) { - let _e352 = m_2[2u]; - phi_3766_ = (_e352 != 0f); - } - let _e355 = phi_3766_; - phi_3773_ = _e355; - if !(_e355) { - let _e358 = m_2[0u]; - phi_3773_ = (_e358 < 0f); - } - let _e361 = phi_3773_; - phi_3780_ = _e361; - if !(_e361) { - let _e364 = m_2[3u]; - phi_3780_ = (_e364 < 0f); - } - let _e367 = phi_3780_; - phi_3787_ = _e367; - if _e367 { - let _e368 = turned; + local_43 = _e333; + } else { + let _e334 = b_5; + local_43 = -(_e334); + } + let _e336 = local_43; + front = _e336; + let _e337 = t_3; + let _e339 = m_2[3u]; + let _e341 = front; + let _e343 = m_2[2u]; + let _e346 = flip; + turned = (((_e337 * _e339) + (_e341 * _e343)) * _e346); + let _e349 = m_2[1u]; + let _e350 = (_e349 != 0f); + phi_3766_ = _e350; + if !(_e350) { + let _e353 = m_2[2u]; + phi_3766_ = (_e353 != 0f); + } + let _e356 = phi_3766_; + phi_3773_ = _e356; + if !(_e356) { + let _e359 = m_2[0u]; + phi_3773_ = (_e359 < 0f); + } + let _e362 = phi_3773_; + phi_3780_ = _e362; + if !(_e362) { + let _e365 = m_2[3u]; + phi_3780_ = (_e365 < 0f); + } + let _e368 = phi_3780_; + phi_3787_ = _e368; + if _e368 { let _e369 = turned; - phi_3787_ = (dot(_e368, _e369) > 0.000000000001f); - } - let _e373 = phi_3787_; - turns = _e373; - let _e374 = turns; - if _e374 { - let _e375 = turned; - local_44 = normalize(_e375); - } else { - let _e377 = t_3; - local_44 = _e377; - } - let _e378 = local_44; - t_3 = _e378; - let _e379 = turns; - if _e379 { - let _e381 = (*s_16).n; - let _e382 = t_3; - let _e385 = v_tangent_1[3u]; - let _e387 = flip; - local_45 = ((cross(_e381, _e382) * _e385) * _e387); - } else { - let _e389 = b_5; - local_45 = _e389; - } - let _e390 = local_45; - b_5 = _e390; - let _e391 = gl_FrontFacing_1; - if !(_e391) { - let _e393 = t_3; - t_3 = -(_e393); - } - let _e395 = sampledTexel; - sampled = ((_e395.xyz * 2f) - vec3(1f)); - let _e402 = frag_info.emissive[3u]; - if (_e402 > 0.5f) { - let _e404 = sampled; - let _e406 = sampled; - sampled[2u] = sqrt(max((1f - dot(_e404.xy, _e406.xy)), 0f)); - } - let _e415 = frag_info.material2_[1u]; - let _e416 = sampled; - let _e418 = (_e416.xy * _e415); - sampled[0u] = _e418.x; - sampled[1u] = _e418.y; - let _e423 = t_3; - let _e425 = sampled[0u]; - let _e427 = b_5; - let _e429 = sampled[1u]; - let _e433 = (*s_16).n; - let _e435 = sampled[2u]; - (*s_16).n = normalize((((_e423 * _e425) + (_e427 * _e429)) + (_e433 * _e435))); - let _e441 = (*s_16).n; - let _e443 = (*s_16).v; - (*s_16).n_dot_v = max(dot(_e441, _e443), 0.0001f); + let _e370 = turned; + phi_3787_ = (dot(_e369, _e370) > 0.000000000001f); + } + let _e374 = phi_3787_; + turns = _e374; + let _e375 = turns; + if _e375 { + let _e376 = turned; + local_44 = normalize(_e376); + } else { + let _e378 = t_3; + local_44 = _e378; + } + let _e379 = local_44; + t_3 = _e379; + let _e380 = turns; + if _e380 { + let _e382 = (*s_16).n; + let _e383 = t_3; + let _e386 = v_tangent_1[3u]; + let _e388 = flip; + local_45 = ((cross(_e382, _e383) * _e386) * _e388); + } else { + let _e390 = b_5; + local_45 = _e390; + } + let _e391 = local_45; + b_5 = _e391; + let _e392 = gl_FrontFacing_1; + if !(_e392) { + let _e394 = t_3; + t_3 = -(_e394); + } + let _e396 = sampledTexel; + sampled = ((_e396.xyz * 2f) - vec3(1f)); + let _e403 = frag_info.emissive[3u]; + if (_e403 > 0.5f) { + let _e405 = sampled; + let _e407 = sampled; + sampled[2u] = sqrt(max((1f - dot(_e405.xy, _e407.xy)), 0f)); + } + let _e416 = frag_info.material2_[1u]; + let _e417 = sampled; + let _e419 = (_e417.xy * _e416); + sampled[0u] = _e419.x; + sampled[1u] = _e419.y; + let _e424 = t_3; + let _e426 = sampled[0u]; + let _e428 = b_5; + let _e430 = sampled[1u]; + let _e434 = (*s_16).n; + let _e436 = sampled[2u]; + (*s_16).n = normalize((((_e424 * _e426) + (_e428 * _e430)) + (_e434 * _e436))); + let _e442 = (*s_16).n; + let _e444 = (*s_16).v; + (*s_16).n_dot_v = max(dot(_e442, _e444), 0.0001f); return; } fn AtlasTexel_u0028_vf2_u003b(texel_5: ptr>) -> vec4 { - let _e274 = (*texel_5); - let _e278 = irradiance_info.atlas; - let _e281 = textureSampleLevel(irradiance_texture_tex, irradiance_texture_smp, ((_e274 + vec2(0.5f)) * _e278.xy), 0f); - return _e281; + let _e275 = (*texel_5); + let _e279 = irradiance_info.atlas; + let _e282 = textureSampleLevel(irradiance_texture_tex, irradiance_texture_smp, ((_e275 + vec2(0.5f)) * _e279.xy), 0f); + return _e282; } fn TileBilinear_u0028_vf2_u003b_f1_u003b_vf2_u003b(corner: ptr>, interior: ptr, uv_8: ptr>) -> vec4 { @@ -22020,42 +22160,42 @@ fn TileBilinear_u0028_vf2_u003b_f1_u003b_vf2_u003b(corner: ptr; var param_226: vec2; - let _e287 = (*uv_8); - let _e288 = (*interior); - at_5 = ((vec2(1f) + (_e287 * _e288)) - vec2(0.5f)); - let _e294 = at_5; - low = floor(_e294); - let _e296 = at_5; - let _e297 = low; - f_5 = (_e296 - _e297); - let _e299 = (*corner); - let _e300 = low; - param_223 = (_e299 + _e300); - let _e302 = AtlasTexel_u0028_vf2_u003b((¶m_223)); - a_6 = _e302; - let _e303 = (*corner); - let _e304 = low; - param_224 = ((_e303 + _e304) + vec2(1f, 0f)); - let _e307 = AtlasTexel_u0028_vf2_u003b((¶m_224)); - b_6 = _e307; - let _e308 = (*corner); - let _e309 = low; - param_225 = ((_e308 + _e309) + vec2(0f, 1f)); - let _e312 = AtlasTexel_u0028_vf2_u003b((¶m_225)); - c_1 = _e312; - let _e313 = (*corner); - let _e314 = low; - param_226 = ((_e313 + _e314) + vec2(1f, 1f)); - let _e317 = AtlasTexel_u0028_vf2_u003b((¶m_226)); - d_6 = _e317; - let _e318 = a_6; - let _e319 = b_6; - let _e321 = f_5[0u]; - let _e324 = c_1; - let _e325 = d_6; - let _e327 = f_5[0u]; - let _e331 = f_5[1u]; - return mix(mix(_e318, _e319, vec4(_e321)), mix(_e324, _e325, vec4(_e327)), vec4(_e331)); + let _e288 = (*uv_8); + let _e289 = (*interior); + at_5 = ((vec2(1f) + (_e288 * _e289)) - vec2(0.5f)); + let _e295 = at_5; + low = floor(_e295); + let _e297 = at_5; + let _e298 = low; + f_5 = (_e297 - _e298); + let _e300 = (*corner); + let _e301 = low; + param_223 = (_e300 + _e301); + let _e303 = AtlasTexel_u0028_vf2_u003b((¶m_223)); + a_6 = _e303; + let _e304 = (*corner); + let _e305 = low; + param_224 = ((_e304 + _e305) + vec2(1f, 0f)); + let _e308 = AtlasTexel_u0028_vf2_u003b((¶m_224)); + b_6 = _e308; + let _e309 = (*corner); + let _e310 = low; + param_225 = ((_e309 + _e310) + vec2(0f, 1f)); + let _e313 = AtlasTexel_u0028_vf2_u003b((¶m_225)); + c_1 = _e313; + let _e314 = (*corner); + let _e315 = low; + param_226 = ((_e314 + _e315) + vec2(1f, 1f)); + let _e318 = AtlasTexel_u0028_vf2_u003b((¶m_226)); + d_6 = _e318; + let _e319 = a_6; + let _e320 = b_6; + let _e322 = f_5[0u]; + let _e325 = c_1; + let _e326 = d_6; + let _e328 = f_5[0u]; + let _e332 = f_5[1u]; + return mix(mix(_e319, _e320, vec4(_e322)), mix(_e325, _e326, vec4(_e328)), vec4(_e332)); } fn ProbeOctahedral_u0028_vf3_u003b(direction_1: ptr>) -> vec2 { @@ -22063,29 +22203,29 @@ fn ProbeOctahedral_u0028_vf3_u003b(direction_1: ptr>) -> vec var n_6: vec3; var xy: vec2; - let _e278 = (*direction_1)[0u]; - let _e281 = (*direction_1)[1u]; - let _e285 = (*direction_1)[2u]; - sum_1 = ((abs(_e278) + abs(_e281)) + abs(_e285)); - let _e288 = sum_1; - if (_e288 <= 0f) { + let _e279 = (*direction_1)[0u]; + let _e282 = (*direction_1)[1u]; + let _e286 = (*direction_1)[2u]; + sum_1 = ((abs(_e279) + abs(_e282)) + abs(_e286)); + let _e289 = sum_1; + if (_e289 <= 0f) { return vec2(0.5f, 0.5f); } - let _e290 = (*direction_1); - let _e291 = sum_1; - n_6 = (_e290 / vec3(_e291)); - let _e294 = n_6; - xy = _e294.xy; - let _e297 = n_6[2u]; - if (_e297 < 0f) { - let _e300 = n_6[1u]; - let _e304 = n_6[0u]; - let _e309 = n_6[0u]; - let _e313 = n_6[1u]; - xy = vec2(((1f - abs(_e300)) * select(-1f, 1f, (_e304 >= 0f))), ((1f - abs(_e309)) * select(-1f, 1f, (_e313 >= 0f)))); + let _e291 = (*direction_1); + let _e292 = sum_1; + n_6 = (_e291 / vec3(_e292)); + let _e295 = n_6; + xy = _e295.xy; + let _e298 = n_6[2u]; + if (_e298 < 0f) { + let _e301 = n_6[1u]; + let _e305 = n_6[0u]; + let _e310 = n_6[0u]; + let _e314 = n_6[1u]; + xy = vec2(((1f - abs(_e301)) * select(-1f, 1f, (_e305 >= 0f))), ((1f - abs(_e310)) * select(-1f, 1f, (_e314 >= 0f)))); } - let _e318 = xy; - return ((_e318 * 0.5f) + vec2(0.5f)); + let _e319 = xy; + return ((_e319 * 0.5f) + vec2(0.5f)); } fn SampleIrradiance_u0028_vf3_u003b_vf3_u003b_vf3_u003b(world_5: ptr>, normal_1: ptr>, view_2: ptr>) -> vec3 { @@ -22133,190 +22273,190 @@ fn SampleIrradiance_u0028_vf3_u003b_vf3_u003b_vf3_u003b(world_5: ptr; var local_46: vec3; - let _e320 = irradiance_info.origin; - origin_2 = _e320.xyz; - let _e323 = irradiance_info.spacing; - spacing = _e323.xyz; - let _e326 = irradiance_info.counts; - counts = _e326.xyz; - let _e330 = irradiance_info.tiles[0u]; - irradianceTile = _e330; - let _e333 = irradiance_info.tiles[1u]; - depthTile = _e333; - let _e336 = irradiance_info.tiles[2u]; - columns = _e336; - let _e339 = irradiance_info.tiles[3u]; - momentsTop = _e339; - let _e340 = (*normal_1); - unit = normalize(_e340); - let _e342 = (*world_5); - let _e343 = unit; - let _e346 = irradiance_info.spacing[3u]; - let _e349 = (*view_2); - let _e352 = irradiance_info.counts[3u]; - biased = ((_e342 + (_e343 * _e346)) + (_e349 * _e352)); - let _e355 = biased; - let _e356 = origin_2; - let _e358 = spacing; - grid_1 = ((_e355 - _e356) / _e358); - let _e360 = grid_1; - let _e362 = counts; - base_1 = clamp(floor(_e360), vec3(0f, 0f, 0f), (_e362 - vec3(2f))); - let _e366 = grid_1; - let _e367 = base_1; - f_6 = clamp((_e366 - _e367), vec3(0f, 0f, 0f), vec3(1f, 1f, 1f)); + let _e321 = irradiance_info.origin; + origin_2 = _e321.xyz; + let _e324 = irradiance_info.spacing; + spacing = _e324.xyz; + let _e327 = irradiance_info.counts; + counts = _e327.xyz; + let _e331 = irradiance_info.tiles[0u]; + irradianceTile = _e331; + let _e334 = irradiance_info.tiles[1u]; + depthTile = _e334; + let _e337 = irradiance_info.tiles[2u]; + columns = _e337; + let _e340 = irradiance_info.tiles[3u]; + momentsTop = _e340; + let _e341 = (*normal_1); + unit = normalize(_e341); + let _e343 = (*world_5); + let _e344 = unit; + let _e347 = irradiance_info.spacing[3u]; + let _e350 = (*view_2); + let _e353 = irradiance_info.counts[3u]; + biased = ((_e343 + (_e344 * _e347)) + (_e350 * _e353)); + let _e356 = biased; + let _e357 = origin_2; + let _e359 = spacing; + grid_1 = ((_e356 - _e357) / _e359); + let _e361 = grid_1; + let _e363 = counts; + base_1 = clamp(floor(_e361), vec3(0f, 0f, 0f), (_e363 - vec3(2f))); + let _e367 = grid_1; + let _e368 = base_1; + f_6 = clamp((_e367 - _e368), vec3(0f, 0f, 0f), vec3(1f, 1f, 1f)); total_3 = vec3(0f, 0f, 0f); weights = 0f; corner_1 = 0i; loop { - let _e370 = corner_1; - if (_e370 < 8i) { - let _e372 = corner_1; - let _e375 = corner_1; - let _e380 = corner_1; - offset_3 = vec3(f32((_e372 & 1i)), f32(((_e375 >> bitcast(1i)) & 1i)), f32(((_e380 >> bitcast(2i)) & 1i))); - let _e386 = base_1; - let _e387 = offset_3; - cell_1 = (_e386 + _e387); - let _e390 = cell_1[2u]; - let _e392 = counts[1u]; - let _e395 = cell_1[1u]; - let _e398 = counts[0u]; - let _e401 = cell_1[0u]; - probe = ((((_e390 * _e392) + _e395) * _e398) + _e401); - let _e403 = probe; - let _e404 = columns; - let _e409 = probe; - let _e410 = columns; - tile_4 = vec2((_e403 - (floor((_e403 / _e404)) * _e404)), floor((_e409 / _e410))); - let _e414 = tile_4; - let _e415 = irradianceTile; - irradianceCorner = (_e414 * (_e415 + 2f)); - let _e419 = tile_4[0u]; - let _e420 = depthTile; - let _e423 = momentsTop; - let _e425 = tile_4[1u]; - let _e426 = depthTile; - momentCorner = vec2((_e419 * (_e420 + 2f)), (_e423 + (_e425 * (_e426 + 2f)))); - let _e431 = irradianceCorner; - param_227 = (_e431 + vec2(1f)); - let _e434 = AtlasTexel_u0028_vf2_u003b((¶m_227)); - if (_e434.w < 0.5f) { + let _e371 = corner_1; + if (_e371 < 8i) { + let _e373 = corner_1; + let _e376 = corner_1; + let _e381 = corner_1; + offset_3 = vec3(f32((_e373 & 1i)), f32(((_e376 >> bitcast(1i)) & 1i)), f32(((_e381 >> bitcast(2i)) & 1i))); + let _e387 = base_1; + let _e388 = offset_3; + cell_1 = (_e387 + _e388); + let _e391 = cell_1[2u]; + let _e393 = counts[1u]; + let _e396 = cell_1[1u]; + let _e399 = counts[0u]; + let _e402 = cell_1[0u]; + probe = ((((_e391 * _e393) + _e396) * _e399) + _e402); + let _e404 = probe; + let _e405 = columns; + let _e410 = probe; + let _e411 = columns; + tile_4 = vec2((_e404 - (floor((_e404 / _e405)) * _e405)), floor((_e410 / _e411))); + let _e415 = tile_4; + let _e416 = irradianceTile; + irradianceCorner = (_e415 * (_e416 + 2f)); + let _e420 = tile_4[0u]; + let _e421 = depthTile; + let _e424 = momentsTop; + let _e426 = tile_4[1u]; + let _e427 = depthTile; + momentCorner = vec2((_e420 * (_e421 + 2f)), (_e424 + (_e426 * (_e427 + 2f)))); + let _e432 = irradianceCorner; + param_227 = (_e432 + vec2(1f)); + let _e435 = AtlasTexel_u0028_vf2_u003b((¶m_227)); + if (_e435.w < 0.5f) { continue; } - let _e437 = f_6; - let _e439 = f_6; - let _e440 = offset_3; - trilinear = mix((vec3(1f, 1f, 1f) - _e437), _e439, _e440); - let _e443 = trilinear[0u]; - let _e445 = trilinear[1u]; - let _e448 = trilinear[2u]; - weight_3 = max(((_e443 * _e445) * _e448), 0.001f); - let _e451 = origin_2; - let _e452 = spacing; - let _e453 = cell_1; - probePosition = (_e451 + (_e452 * _e453)); - let _e456 = probePosition; - let _e457 = biased; - toProbe = (_e456 - _e457); - let _e459 = toProbe; - distance_4 = length(_e459); - let _e461 = distance_4; - if (_e461 > 0.000001f) { - let _e463 = toProbe; - let _e464 = distance_4; - direction_2 = (_e463 / vec3(_e464)); - let _e467 = unit; - let _e468 = probePosition; - let _e469 = (*world_5); - facing = ((dot(_e467, normalize((_e468 - _e469))) * 0.5f) + 0.5f); - let _e475 = facing; + let _e438 = f_6; + let _e440 = f_6; + let _e441 = offset_3; + trilinear = mix((vec3(1f, 1f, 1f) - _e438), _e440, _e441); + let _e444 = trilinear[0u]; + let _e446 = trilinear[1u]; + let _e449 = trilinear[2u]; + weight_3 = max(((_e444 * _e446) * _e449), 0.001f); + let _e452 = origin_2; + let _e453 = spacing; + let _e454 = cell_1; + probePosition = (_e452 + (_e453 * _e454)); + let _e457 = probePosition; + let _e458 = biased; + toProbe = (_e457 - _e458); + let _e460 = toProbe; + distance_4 = length(_e460); + let _e462 = distance_4; + if (_e462 > 0.000001f) { + let _e464 = toProbe; + let _e465 = distance_4; + direction_2 = (_e464 / vec3(_e465)); + let _e468 = unit; + let _e469 = probePosition; + let _e470 = (*world_5); + facing = ((dot(_e468, normalize((_e469 - _e470))) * 0.5f) + 0.5f); let _e476 = facing; - probeWeight = ((_e475 * _e476) + 0.2f); - let _e479 = direction_2; - param_228 = -(_e479); - let _e481 = ProbeOctahedral_u0028_vf3_u003b((¶m_228)); - let _e482 = momentCorner; - param_229 = _e482; - let _e483 = depthTile; - param_230 = _e483; - param_231 = _e481; - let _e484 = TileBilinear_u0028_vf2_u003b_f1_u003b_vf2_u003b((¶m_229), (¶m_230), (¶m_231)); - moments_3 = _e484.xy; + let _e477 = facing; + probeWeight = ((_e476 * _e477) + 0.2f); + let _e480 = direction_2; + param_228 = -(_e480); + let _e482 = ProbeOctahedral_u0028_vf3_u003b((¶m_228)); + let _e483 = momentCorner; + param_229 = _e483; + let _e484 = depthTile; + param_230 = _e484; + param_231 = _e482; + let _e485 = TileBilinear_u0028_vf2_u003b_f1_u003b_vf2_u003b((¶m_229), (¶m_230), (¶m_231)); + moments_3 = _e485.xy; chebyshev = 1f; - let _e486 = distance_4; - let _e488 = moments_3[0u]; - if (_e486 > _e488) { - let _e491 = moments_3[1u]; - let _e493 = moments_3[0u]; - let _e495 = moments_3[0u]; - variance_2 = max((_e491 - (_e493 * _e495)), 0.000001f); - let _e499 = distance_4; - let _e501 = moments_3[0u]; - difference = (_e499 - _e501); - let _e503 = variance_2; + let _e487 = distance_4; + let _e489 = moments_3[0u]; + if (_e487 > _e489) { + let _e492 = moments_3[1u]; + let _e494 = moments_3[0u]; + let _e496 = moments_3[0u]; + variance_2 = max((_e492 - (_e494 * _e496)), 0.000001f); + let _e500 = distance_4; + let _e502 = moments_3[0u]; + difference = (_e500 - _e502); let _e504 = variance_2; - let _e505 = difference; + let _e505 = variance_2; let _e506 = difference; - chebyshev = (_e503 / (_e504 + (_e505 * _e506))); - let _e510 = chebyshev; + let _e507 = difference; + chebyshev = (_e504 / (_e505 + (_e506 * _e507))); let _e511 = chebyshev; - let _e513 = chebyshev; - chebyshev = ((_e510 * _e511) * _e513); + let _e512 = chebyshev; + let _e514 = chebyshev; + chebyshev = ((_e511 * _e512) * _e514); } - let _e515 = probeWeight; - let _e516 = chebyshev; - probeWeight = max((_e515 * max(_e516, 0.05f)), 0.000001f); - let _e520 = probeWeight; - if (_e520 < 0.2f) { - let _e522 = probeWeight; + let _e516 = probeWeight; + let _e517 = chebyshev; + probeWeight = max((_e516 * max(_e517, 0.05f)), 0.000001f); + let _e521 = probeWeight; + if (_e521 < 0.2f) { let _e523 = probeWeight; - let _e526 = probeWeight; - probeWeight = (_e526 * ((_e522 * _e523) * 25f)); + let _e524 = probeWeight; + let _e527 = probeWeight; + probeWeight = (_e527 * ((_e523 * _e524) * 25f)); } - let _e528 = probeWeight; - let _e529 = weight_3; - weight_3 = (_e529 * _e528); - } - let _e531 = unit; - param_232 = _e531; - let _e532 = ProbeOctahedral_u0028_vf3_u003b((¶m_232)); - let _e533 = irradianceCorner; - param_233 = _e533; - let _e534 = irradianceTile; - param_234 = _e534; - param_235 = _e532; - let _e535 = TileBilinear_u0028_vf2_u003b_f1_u003b_vf2_u003b((¶m_233), (¶m_234), (¶m_235)); - let _e537 = weight_3; - let _e539 = total_3; - total_3 = (_e539 + (_e535.xyz * _e537)); - let _e541 = weight_3; - let _e542 = weights; - weights = (_e542 + _e541); + let _e529 = probeWeight; + let _e530 = weight_3; + weight_3 = (_e530 * _e529); + } + let _e532 = unit; + param_232 = _e532; + let _e533 = ProbeOctahedral_u0028_vf3_u003b((¶m_232)); + let _e534 = irradianceCorner; + param_233 = _e534; + let _e535 = irradianceTile; + param_234 = _e535; + param_235 = _e533; + let _e536 = TileBilinear_u0028_vf2_u003b_f1_u003b_vf2_u003b((¶m_233), (¶m_234), (¶m_235)); + let _e538 = weight_3; + let _e540 = total_3; + total_3 = (_e540 + (_e536.xyz * _e538)); + let _e542 = weight_3; + let _e543 = weights; + weights = (_e543 + _e542); continue; } else { break; } continuing { - let _e544 = corner_1; - corner_1 = (_e544 + 1i); + let _e545 = corner_1; + corner_1 = (_e545 + 1i); } } - let _e546 = weights; - if (_e546 > 0f) { - let _e548 = total_3; - let _e549 = weights; - local_46 = (_e548 / vec3(_e549)); + let _e547 = weights; + if (_e547 > 0f) { + let _e549 = total_3; + let _e550 = weights; + local_46 = (_e549 / vec3(_e550)); } else { local_46 = vec3(0f, 0f, 0f); } - let _e552 = local_46; - return _e552; + let _e553 = local_46; + return _e553; } fn IrradianceEnabled_u0028_() -> bool { - let _e275 = irradiance_info.origin[3u]; - return (_e275 > 0.5f); + let _e276 = irradiance_info.origin[3u]; + return (_e276 > 0.5f); } fn ApplyCommonMaps_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b(s_17: ptr) { @@ -22327,33 +22467,33 @@ fn ApplyCommonMaps_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d var param_240: Surface; var param_241: Surface; - let _e280 = IrradianceEnabled_u0028_(); - if _e280 { - let _e281 = v_world_position_1; - param_236 = _e281; - let _e283 = (*s_17).n; - param_237 = _e283; - let _e285 = (*s_17).v; - param_238 = _e285; - let _e286 = SampleIrradiance_u0028_vf3_u003b_vf3_u003b_vf3_u003b((¶m_236), (¶m_237), (¶m_238)); - let _e289 = frag_info.material[2u]; - (*s_17).ambient = (_e286 * _e289); - } - let _e292 = (*s_17); - param_239 = _e292; + let _e281 = IrradianceEnabled_u0028_(); + if _e281 { + let _e282 = v_world_position_1; + param_236 = _e282; + let _e284 = (*s_17).n; + param_237 = _e284; + let _e286 = (*s_17).v; + param_238 = _e286; + let _e287 = SampleIrradiance_u0028_vf3_u003b_vf3_u003b_vf3_u003b((¶m_236), (¶m_237), (¶m_238)); + let _e290 = frag_info.material[2u]; + (*s_17).ambient = (_e287 * _e290); + } + let _e293 = (*s_17); + param_239 = _e293; ApplyNormalMap_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b((¶m_239)); - let _e293 = param_239; - (*s_17) = _e293; - let _e294 = (*s_17); - param_240 = _e294; + let _e294 = param_239; + (*s_17) = _e294; + let _e295 = (*s_17); + param_240 = _e295; ApplyOcclusionMap_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b((¶m_240)); - let _e295 = param_240; - (*s_17) = _e295; - let _e296 = (*s_17); - param_241 = _e296; + let _e296 = param_240; + (*s_17) = _e296; + let _e297 = (*s_17); + param_241 = _e297; ApplyEmissiveMap_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b((¶m_241)); - let _e297 = param_241; - (*s_17) = _e297; + let _e298 = param_241; + (*s_17) = _e298; return; } @@ -22369,108 +22509,108 @@ fn ReadLayers_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_ var local_48: vec3; var fc: f32; - let _e284 = v_texcoord_1; - let _e285 = MaterialLodBias_u0028_(); - let _e286 = textureSampleBias(coat_texture_tex, coat_texture_smp, _e284, _e285); - coatTexel = _e286; - let _e287 = v_texcoord_1; - let _e288 = MaterialLodBias_u0028_(); - let _e289 = textureSampleBias(sheen_texture_tex, sheen_texture_smp, _e287, _e288); - sheenTexel = _e289; - let _e291 = layer_info.sheen; - let _e293 = sheenTexel; - param_242 = _e293.xyz; - let _e295 = SrgbToLinear_u0028_vf3_u003b((¶m_242)); - g_sheen = (_e291.xyz * _e295); - let _e299 = layer_info.sheen[3u]; - let _e301 = sheenTexel[3u]; - g_sheen_roughness = clamp((_e299 * _e301), 0.07f, 1f); - let _e306 = layer_info.coat[2u]; - ior_3 = max(_e306, 1f); - let _e308 = IorInfinite_u0028_(); - if _e308 { + let _e285 = v_texcoord_1; + let _e286 = MaterialLodBias_u0028_(); + let _e287 = textureSampleBias(coat_texture_tex, coat_texture_smp, _e285, _e286); + coatTexel = _e287; + let _e288 = v_texcoord_1; + let _e289 = MaterialLodBias_u0028_(); + let _e290 = textureSampleBias(sheen_texture_tex, sheen_texture_smp, _e288, _e289); + sheenTexel = _e290; + let _e292 = layer_info.sheen; + let _e294 = sheenTexel; + param_242 = _e294.xyz; + let _e296 = SrgbToLinear_u0028_vf3_u003b((¶m_242)); + g_sheen = (_e292.xyz * _e296); + let _e300 = layer_info.sheen[3u]; + let _e302 = sheenTexel[3u]; + g_sheen_roughness = clamp((_e300 * _e302), 0.07f, 1f); + let _e307 = layer_info.coat[2u]; + ior_3 = max(_e307, 1f); + let _e309 = IorInfinite_u0028_(); + if _e309 { local_47 = 1f; } else { - let _e309 = ior_3; - let _e311 = ior_3; - local_47 = ((_e309 - 1f) / (_e311 + 1f)); + let _e310 = ior_3; + let _e312 = ior_3; + local_47 = ((_e310 - 1f) / (_e312 + 1f)); } - let _e314 = local_47; - r_5 = _e314; - let _e315 = r_5; + let _e315 = local_47; + r_5 = _e315; let _e316 = r_5; - let _e320 = layer_info.specular; - let _e326 = layer_info.specular[3u]; - g_f0_dielectric = (min((vec3((_e315 * _e316)) * _e320.xyz), vec3(1f, 1f, 1f)) * _e326); - let _e330 = layer_info.specular[3u]; - g_f90_ = _e330; - let _e333 = layer_info.coat[0u]; - let _e335 = coatTexel[0u]; - g_coat = clamp((_e333 * _e335), 0f, 1f); - let _e340 = layer_info.coat[1u]; - let _e342 = coatTexel[1u]; - g_coat_roughness = clamp((_e340 * _e342), 0.02f, 1f); - let _e347 = layer_info.transmission[0u]; - let _e349 = coatTexel[2u]; - g_transmission = clamp((_e347 * _e349), 0f, 1f); - let _e354 = layer_info.transmission[1u]; - let _e356 = coatTexel[3u]; - g_thickness = max((_e354 * _e356), 0f); - let _e361 = layer_info.attenuation[3u]; - let _e363 = g_thickness; - if ((_e361 > 0.5f) && (_e363 > 0f)) { - let _e367 = (*s_18).v; - let _e370 = (*s_18).n; - let _e371 = RefractionIor_u0028_(); - bent = refract(-(_e367), _e370, (1f / _e371)); - let _e374 = g_thickness; - let _e376 = (*s_18).n; - let _e377 = bent; - let _e382 = g_thickness; - g_thickness = max((_e374 * max(-(dot(_e376, _e377)), 0f)), (0.0001f * _e382)); - } - let _e387 = layer_info.transmission[2u]; - distance_5 = _e387; - let _e388 = distance_5; - if (_e388 > 0f) { - let _e391 = layer_info.attenuation; - let _e394 = g_thickness; - let _e395 = distance_5; - local_48 = pow(max(_e391.xyz, vec3(0.0001f, 0.0001f, 0.0001f)), vec3((_e394 / _e395))); + let _e317 = r_5; + let _e321 = layer_info.specular; + let _e327 = layer_info.specular[3u]; + g_f0_dielectric = (min((vec3((_e316 * _e317)) * _e321.xyz), vec3(1f, 1f, 1f)) * _e327); + let _e331 = layer_info.specular[3u]; + g_f90_ = _e331; + let _e334 = layer_info.coat[0u]; + let _e336 = coatTexel[0u]; + g_coat = clamp((_e334 * _e336), 0f, 1f); + let _e341 = layer_info.coat[1u]; + let _e343 = coatTexel[1u]; + g_coat_roughness = clamp((_e341 * _e343), 0.02f, 1f); + let _e348 = layer_info.transmission[0u]; + let _e350 = coatTexel[2u]; + g_transmission = clamp((_e348 * _e350), 0f, 1f); + let _e355 = layer_info.transmission[1u]; + let _e357 = coatTexel[3u]; + g_thickness = max((_e355 * _e357), 0f); + let _e362 = layer_info.attenuation[3u]; + let _e364 = g_thickness; + if ((_e362 > 0.5f) && (_e364 > 0f)) { + let _e368 = (*s_18).v; + let _e371 = (*s_18).n; + let _e372 = RefractionIor_u0028_(); + bent = refract(-(_e368), _e371, (1f / _e372)); + let _e375 = g_thickness; + let _e377 = (*s_18).n; + let _e378 = bent; + let _e383 = g_thickness; + g_thickness = max((_e375 * max(-(dot(_e377, _e378)), 0f)), (0.0001f * _e383)); + } + let _e388 = layer_info.transmission[2u]; + distance_5 = _e388; + let _e389 = distance_5; + if (_e389 > 0f) { + let _e392 = layer_info.attenuation; + let _e395 = g_thickness; + let _e396 = distance_5; + local_48 = pow(max(_e392.xyz, vec3(0.0001f, 0.0001f, 0.0001f)), vec3((_e395 / _e396))); } else { local_48 = vec3(1f, 1f, 1f); } - let _e399 = local_48; - g_transmittance = _e399; - let _e402 = layer_info.iridescence[0u]; - g_iridescence = clamp(_e402, 0f, 1f); - let _e405 = (*s_18).n; - g_coat_n = _e405; - let _e407 = (*s_18).n; - let _e409 = (*s_18).v; - g_coat_n_dot_v = max(dot(_e407, _e409), 0.0001f); - let _e412 = g_coat_n_dot_v; - fc = (0.04f + (0.96f * pow((1f - _e412), 5f))); - let _e417 = g_coat; - let _e418 = fc; - g_coat_through = (1f - (_e417 * _e418)); + let _e400 = local_48; + g_transmittance = _e400; + let _e403 = layer_info.iridescence[0u]; + g_iridescence = clamp(_e403, 0f, 1f); + let _e406 = (*s_18).n; + g_coat_n = _e406; + let _e408 = (*s_18).n; + let _e410 = (*s_18).v; + g_coat_n_dot_v = max(dot(_e408, _e410), 0.0001f); + let _e413 = g_coat_n_dot_v; + fc = (0.04f + (0.96f * pow((1f - _e413), 5f))); + let _e418 = g_coat; + let _e419 = fc; + g_coat_through = (1f - (_e418 * _e419)); return; } fn TowardsEye_u0028_() -> vec3 { var local_49: vec3; - let _e274 = Orthographic_u0028_(); - if _e274 { - let _e276 = fog_info.forward; - local_49 = -(_e276.xyz); + let _e275 = Orthographic_u0028_(); + if _e275 { + let _e277 = fog_info.forward; + local_49 = -(_e277.xyz); } else { - let _e280 = fog_info.eye; - let _e282 = v_world_position_1; - local_49 = normalize((_e280.xyz - _e282)); + let _e281 = fog_info.eye; + let _e283 = v_world_position_1; + local_49 = normalize((_e281.xyz - _e283)); } - let _e285 = local_49; - return _e285; + let _e286 = local_49; + return _e286; } fn ReadSurface_u0028_() -> Surface { @@ -22485,89 +22625,89 @@ fn ReadSurface_u0028_() -> Surface { var noise_1: f32; param_243 = 0i; - let _e282 = MapUv_u0028_i1_u003b((¶m_243)); - let _e283 = MaterialLodBias_u0028_(); - let _e284 = textureSampleBias(base_color_texture_tex, base_color_texture_smp, _e282, _e283); - texel_6 = _e284; - let _e285 = texel_6; - param_244 = _e285.xyz; - let _e287 = SrgbToLinear_u0028_vf3_u003b((¶m_244)); - let _e289 = frag_info.base_color; - param_245 = _e289.xyz; - let _e291 = SrgbToLinear_u0028_vf3_u003b((¶m_245)); - let _e293 = v_color_1; - s_19.albedo = ((_e287 * _e291) * _e293.xyz); - let _e298 = texel_6[3u]; - let _e301 = frag_info.base_color[3u]; - let _e304 = v_color_1[3u]; - s_19.alpha = ((_e298 * _e301) * _e304); - let _e308 = s_19.albedo; - g_albedo = _e308; - let _e311 = frag_info.material2_[0u]; - cutoff = _e311; - let _e312 = cutoff; - if (_e312 > 1f) { - let _e314 = cutoff; - edge = (_e314 - 1f); - let _e317 = s_19.alpha; - let _e318 = edge; - let _e321 = s_19.alpha; - let _e322 = fwidth(_e321); - s_19.alpha = clamp((((_e317 - _e318) / max(_e322, 0.0001f)) + 0.5f), 0f, 1f); - } else { - let _e328 = cutoff; - if (_e328 >= 0f) { - let _e331 = s_19.alpha; - let _e332 = cutoff; - if (_e331 < _e332) { + let _e283 = MapUv_u0028_i1_u003b((¶m_243)); + let _e284 = MaterialLodBias_u0028_(); + let _e285 = textureSampleBias(base_color_texture_tex, base_color_texture_smp, _e283, _e284); + texel_6 = _e285; + let _e286 = texel_6; + param_244 = _e286.xyz; + let _e288 = SrgbToLinear_u0028_vf3_u003b((¶m_244)); + let _e290 = frag_info.base_color; + param_245 = _e290.xyz; + let _e292 = SrgbToLinear_u0028_vf3_u003b((¶m_245)); + let _e294 = v_color_1; + s_19.albedo = ((_e288 * _e292) * _e294.xyz); + let _e299 = texel_6[3u]; + let _e302 = frag_info.base_color[3u]; + let _e305 = v_color_1[3u]; + s_19.alpha = ((_e299 * _e302) * _e305); + let _e309 = s_19.albedo; + g_albedo = _e309; + let _e312 = frag_info.material2_[0u]; + cutoff = _e312; + let _e313 = cutoff; + if (_e313 > 1f) { + let _e315 = cutoff; + edge = (_e315 - 1f); + let _e318 = s_19.alpha; + let _e319 = edge; + let _e322 = s_19.alpha; + let _e323 = fwidth(_e322); + s_19.alpha = clamp((((_e318 - _e319) / max(_e323, 0.0001f)) + 0.5f), 0f, 1f); + } else { + let _e329 = cutoff; + if (_e329 >= 0f) { + let _e332 = s_19.alpha; + let _e333 = cutoff; + if (_e332 < _e333) { discard; } s_19.alpha = 1f; } else { - let _e335 = cutoff; - if (_e335 < -1.5f) { - let _e337 = v_world_position_1; - anchored = floor((_e337 * 16f)); - let _e340 = anchored; - noise_1 = fract((sin(dot(_e340, vec3(12.9898f, 78.233f, 37.719f))) * 43758.547f)); - let _e346 = s_19.alpha; - let _e347 = noise_1; - if (_e346 < _e347) { + let _e336 = cutoff; + if (_e336 < -1.5f) { + let _e338 = v_world_position_1; + anchored = floor((_e338 * 16f)); + let _e341 = anchored; + noise_1 = fract((sin(dot(_e341, vec3(12.9898f, 78.233f, 37.719f))) * 43758.547f)); + let _e347 = s_19.alpha; + let _e348 = noise_1; + if (_e347 < _e348) { discard; } } } } - let _e349 = cutoff; - let _e351 = cutoff; - g_premultiply = ((_e349 < 0f) && (_e351 > -0.75f)); - let _e354 = v_normal_1; - s_19.n = normalize(_e354); - let _e357 = gl_FrontFacing_1; - if !(_e357) { - let _e360 = s_19.n; - s_19.n = -(_e360); - } - let _e363 = TowardsEye_u0028_(); - s_19.v = _e363; - let _e366 = s_19.n; - let _e368 = s_19.v; - s_19.n_dot_v = max(dot(_e366, _e368), 0.0001f); - let _e374 = frag_info.material[0u]; - s_19.metallic = clamp(_e374, 0f, 1f); - let _e379 = frag_info.material[1u]; - s_19.roughness = clamp(_e379, 0.02f, 1f); - let _e383 = frag_info.ambient_ground; - let _e386 = frag_info.ambient_sky; - let _e390 = s_19.n[1u]; - let _e397 = frag_info.material[2u]; - s_19.ambient = (mix(_e383.xyz, _e386.xyz, vec3(((_e390 * 0.5f) + 0.5f))) * _e397); - let _e402 = frag_info.frame_params[0u]; - s_19.exposure = max(_e402, 0f); + let _e350 = cutoff; + let _e352 = cutoff; + g_premultiply = ((_e350 < 0f) && (_e352 > -0.75f)); + let _e355 = v_normal_1; + s_19.n = normalize(_e355); + let _e358 = gl_FrontFacing_1; + if !(_e358) { + let _e361 = s_19.n; + s_19.n = -(_e361); + } + let _e364 = TowardsEye_u0028_(); + s_19.v = _e364; + let _e367 = s_19.n; + let _e369 = s_19.v; + s_19.n_dot_v = max(dot(_e367, _e369), 0.0001f); + let _e375 = frag_info.material[0u]; + s_19.metallic = clamp(_e375, 0f, 1f); + let _e380 = frag_info.material[1u]; + s_19.roughness = clamp(_e380, 0.02f, 1f); + let _e384 = frag_info.ambient_ground; + let _e387 = frag_info.ambient_sky; + let _e391 = s_19.n[1u]; + let _e398 = frag_info.material[2u]; + s_19.ambient = (mix(_e384.xyz, _e387.xyz, vec3(((_e391 * 0.5f) + 0.5f))) * _e398); + let _e403 = frag_info.frame_params[0u]; + s_19.exposure = max(_e403, 0f); s_19.occlusion = 1f; s_19.emissive = vec3(0f, 0f, 0f); - let _e407 = s_19; - return _e407; + let _e408 = s_19; + return _e408; } fn main_1() { @@ -22656,274 +22796,274 @@ fn main_1() { g_iridescence = 0f; g_irid_fresnel = vec3(0.04f, 0.04f, 0.04f); g_pane = false; - let _e329 = ReadSurface_u0028_(); - s_20 = _e329; - let _e330 = s_20; - param_246 = _e330; - ReadLayers_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b((¶m_246)); + let _e330 = ReadSurface_u0028_(); + s_20 = _e330; let _e331 = s_20; - param_247 = _e331; + param_246 = _e331; + ReadLayers_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b((¶m_246)); + let _e332 = s_20; + param_247 = _e332; ApplyCommonMaps_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b((¶m_247)); - let _e332 = param_247; - s_20 = _e332; - let _e333 = s_20; - param_248 = _e333; + let _e333 = param_247; + s_20 = _e333; + let _e334 = s_20; + param_248 = _e334; ApplyMetallicRoughnessMap_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b((¶m_248)); - let _e334 = param_248; - s_20 = _e334; - let _e335 = s_20; - param_249 = _e335; - ReadLayersOnMaps_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b((¶m_249)); + let _e335 = param_248; + s_20 = _e335; let _e336 = s_20; - param_250 = _e336; + param_249 = _e336; + ReadLayersOnMaps_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b((¶m_249)); + let _e337 = s_20; + param_250 = _e337; ReadIridescence_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b((¶m_250)); - let _e338 = s_20.metallic; - metallic = clamp(_e338, 0f, 1f); - let _e341 = s_20.albedo; - let _e342 = metallic; - diffuseColor_1 = (_e341 * (1f - _e342)); - let _e345 = EonDiffuse_u0028_(); - if _e345 { - let _e346 = diffuseColor_1; - param_251 = _e346; - let _e348 = s_20.roughness; - param_252 = _e348; - let _e350 = s_20.n_dot_v; - param_253 = _e350; - let _e351 = EonAlbedo_u0028_vf3_u003b_f1_u003b_f1_u003b((¶m_251), (¶m_252), (¶m_253)); - diffuseColor_1 = _e351; - } - let _e352 = diffuseColor_1; - let _e354 = s_20.ambient; - let _e357 = s_20.occlusion; - ambient = ((_e352 * _e354) * _e357); - let _e359 = g_premultiply; - let _e360 = g_transmission; - let _e363 = g_thickness; - g_pane = ((_e359 && (_e360 > 0f)) && (_e363 <= 0f)); - let _e366 = SceneColourBound_u0028_(); - let _e367 = g_pane; - let _e369 = g_transmittance; - let _e372 = g_transmission; - let _e375 = ambient; - ambient = (_e375 * mix(vec3(1f, 1f, 1f), select(_e369, vec3(0f, 0f, 0f), vec3((_e366 || _e367))), vec3(_e372))); - let _e379 = frag_info.frame_params[3u]; - levels_1 = _e379; + let _e339 = s_20.metallic; + metallic = clamp(_e339, 0f, 1f); + let _e342 = s_20.albedo; + let _e343 = metallic; + diffuseColor_1 = (_e342 * (1f - _e343)); + let _e346 = EonDiffuse_u0028_(); + if _e346 { + let _e347 = diffuseColor_1; + param_251 = _e347; + let _e349 = s_20.roughness; + param_252 = _e349; + let _e351 = s_20.n_dot_v; + param_253 = _e351; + let _e352 = EonAlbedo_u0028_vf3_u003b_f1_u003b_f1_u003b((¶m_251), (¶m_252), (¶m_253)); + diffuseColor_1 = _e352; + } + let _e353 = diffuseColor_1; + let _e355 = s_20.ambient; + let _e358 = s_20.occlusion; + ambient = ((_e353 * _e355) * _e358); + let _e360 = g_premultiply; + let _e361 = g_transmission; + let _e364 = g_thickness; + g_pane = ((_e360 && (_e361 > 0f)) && (_e364 <= 0f)); + let _e367 = SceneColourBound_u0028_(); + let _e368 = g_pane; + let _e370 = g_transmittance; + let _e373 = g_transmission; + let _e376 = ambient; + ambient = (_e376 * mix(vec3(1f, 1f, 1f), select(_e370, vec3(0f, 0f, 0f), vec3((_e367 || _e368))), vec3(_e373))); + let _e380 = frag_info.frame_params[3u]; + levels_1 = _e380; coatAmbient = vec3(0f, 0f, 0f); - let _e381 = s_20.ambient; - sheenIncoming = _e381; - let _e382 = levels_1; - if (_e382 > 0f) { - let _e384 = g_f0_dielectric; - let _e386 = s_20.albedo; - let _e387 = metallic; - f0_4 = mix(_e384, _e386, vec3(_e387)); - let _e390 = g_f90_; - let _e391 = metallic; - f90_2 = mix(_e390, 1f, _e391); - let _e394 = s_20.n; - bent_1 = _e394; - let _e395 = g_aniso; - if (_e395 > 0f) { - let _e397 = g_aniso_t; - let _e399 = s_20.v; - across = cross(_e397, _e399); - let _e401 = across; - let _e402 = g_aniso_t; - anisoN = cross(_e401, _e402); - let _e404 = g_aniso; - let _e406 = s_20.roughness; - bend = (1f - (_e404 * (1f - _e406))); - let _e410 = bend; + let _e382 = s_20.ambient; + sheenIncoming = _e382; + let _e383 = levels_1; + if (_e383 > 0f) { + let _e385 = g_f0_dielectric; + let _e387 = s_20.albedo; + let _e388 = metallic; + f0_4 = mix(_e385, _e387, vec3(_e388)); + let _e391 = g_f90_; + let _e392 = metallic; + f90_2 = mix(_e391, 1f, _e392); + let _e395 = s_20.n; + bent_1 = _e395; + let _e396 = g_aniso; + if (_e396 > 0f) { + let _e398 = g_aniso_t; + let _e400 = s_20.v; + across = cross(_e398, _e400); + let _e402 = across; + let _e403 = g_aniso_t; + anisoN = cross(_e402, _e403); + let _e405 = g_aniso; + let _e407 = s_20.roughness; + bend = (1f - (_e405 * (1f - _e407))); let _e411 = bend; - let _e413 = bend; - let _e415 = bend; - bend4_ = (((_e410 * _e411) * _e413) * _e415); - let _e417 = anisoN; - let _e419 = s_20.n; - let _e420 = bend4_; - bent_1 = normalize(mix(_e417, _e419, vec3(_e420))); - } - let _e425 = s_20.v; - let _e427 = bent_1; - reflected = reflect(-(_e425), _e427); - let _e430 = s_20.n; - let _e431 = levels_1; - let _e432 = textureSampleLevel(environment_texture_tex, environment_texture_smp, _e430, _e431); - irradiance = _e432.xyz; - let _e434 = reflected; - let _e436 = s_20.roughness; - let _e437 = levels_1; - let _e439 = textureSampleLevel(environment_texture_tex, environment_texture_smp, _e434, (_e436 * _e437)); - prefiltered = _e439.xyz; - let _e442 = s_20.roughness; - param_254 = _e442; - let _e444 = s_20.n_dot_v; - param_255 = _e444; - let _e445 = EnvBrdf_u0028_f1_u003b_f1_u003b((¶m_254), (¶m_255)); - ab_4 = _e445; - let _e446 = f0_4; - let _e447 = g_irid_fresnel; - let _e448 = g_iridescence; - let _e452 = ab_4[0u]; - let _e454 = f90_2; - let _e456 = ab_4[1u]; - single_1 = ((mix(_e446, _e447, vec3(_e448)) * _e452) + vec3((_e454 * _e456))); - let _e460 = prefiltered; - let _e461 = single_1; - specular_1 = (_e460 * _e461); - let _e463 = EnergyCompensation_u0028_(); - if _e463 { - let _e465 = ab_4[0u]; - let _e467 = ab_4[1u]; - missed = (1f - (_e465 + _e467)); - let _e470 = f0_4; + let _e412 = bend; + let _e414 = bend; + let _e416 = bend; + bend4_ = (((_e411 * _e412) * _e414) * _e416); + let _e418 = anisoN; + let _e420 = s_20.n; + let _e421 = bend4_; + bent_1 = normalize(mix(_e418, _e420, vec3(_e421))); + } + let _e426 = s_20.v; + let _e428 = bent_1; + reflected = reflect(-(_e426), _e428); + let _e431 = s_20.n; + let _e432 = levels_1; + let _e433 = textureSampleLevel(environment_texture_tex, environment_texture_smp, _e431, _e432); + irradiance = _e433.xyz; + let _e435 = reflected; + let _e437 = s_20.roughness; + let _e438 = levels_1; + let _e440 = textureSampleLevel(environment_texture_tex, environment_texture_smp, _e435, (_e437 * _e438)); + prefiltered = _e440.xyz; + let _e443 = s_20.roughness; + param_254 = _e443; + let _e445 = s_20.n_dot_v; + param_255 = _e445; + let _e446 = EnvBrdf_u0028_f1_u003b_f1_u003b((¶m_254), (¶m_255)); + ab_4 = _e446; + let _e447 = f0_4; + let _e448 = g_irid_fresnel; + let _e449 = g_iridescence; + let _e453 = ab_4[0u]; + let _e455 = f90_2; + let _e457 = ab_4[1u]; + single_1 = ((mix(_e447, _e448, vec3(_e449)) * _e453) + vec3((_e455 * _e457))); + let _e461 = prefiltered; + let _e462 = single_1; + specular_1 = (_e461 * _e462); + let _e464 = EnergyCompensation_u0028_(); + if _e464 { + let _e466 = ab_4[0u]; + let _e468 = ab_4[1u]; + missed = (1f - (_e466 + _e468)); let _e471 = f0_4; - average_2 = (_e470 + ((vec3(1f, 1f, 1f) - _e471) / vec3(21f))); - let _e476 = single_1; - let _e477 = average_2; - let _e479 = missed; - let _e480 = average_2; - multiple = ((_e476 * _e477) / (vec3(1f, 1f, 1f) - (_e480 * _e479))); - let _e484 = multiple; - let _e485 = missed; - let _e487 = irradiance; - let _e489 = specular_1; - specular_1 = (_e489 + ((_e484 * _e485) * _e487)); - } - let _e491 = diffuseColor_1; - let _e492 = irradiance; - let _e494 = specular_1; - let _e498 = frag_info.material[2u]; - let _e501 = s_20.occlusion; - ambient = ((((_e491 * _e492) + _e494) * _e498) * _e501); - let _e503 = g_f0_dielectric; - let _e504 = g_irid_fresnel; - let _e505 = g_iridescence; - let _e509 = ab_4[0u]; - let _e511 = g_f90_; - let _e513 = ab_4[1u]; - reflects = ((mix(_e503, _e504, vec3(_e505)) * _e509) + vec3((_e511 * _e513))); - let _e517 = SceneColourBound_u0028_(); - let _e518 = g_pane; - if (_e517 || _e518) { + let _e472 = f0_4; + average_2 = (_e471 + ((vec3(1f, 1f, 1f) - _e472) / vec3(21f))); + let _e477 = single_1; + let _e478 = average_2; + let _e480 = missed; + let _e481 = average_2; + multiple = ((_e477 * _e478) / (vec3(1f, 1f, 1f) - (_e481 * _e480))); + let _e485 = multiple; + let _e486 = missed; + let _e488 = irradiance; + let _e490 = specular_1; + specular_1 = (_e490 + ((_e485 * _e486) * _e488)); + } + let _e492 = diffuseColor_1; + let _e493 = irradiance; + let _e495 = specular_1; + let _e499 = frag_info.material[2u]; + let _e502 = s_20.occlusion; + ambient = ((((_e492 * _e493) + _e495) * _e499) * _e502); + let _e504 = g_f0_dielectric; + let _e505 = g_irid_fresnel; + let _e506 = g_iridescence; + let _e510 = ab_4[0u]; + let _e512 = g_f90_; + let _e514 = ab_4[1u]; + reflects = ((mix(_e504, _e505, vec3(_e506)) * _e510) + vec3((_e512 * _e514))); + let _e518 = SceneColourBound_u0028_(); + let _e519 = g_pane; + if (_e518 || _e519) { local_50 = vec3(0f, 0f, 0f); } else { - let _e520 = s_20; - param_256 = _e520; - let _e521 = levels_1; - param_257 = _e521; - let _e522 = TransmittedRadiance_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_f1_u003b((¶m_256), (¶m_257)); - let _e523 = g_transmittance; - let _e525 = reflects; - local_50 = ((_e522 * _e523) * (vec3(1f, 1f, 1f) - min(_e525, vec3(1f, 1f, 1f)))); - } - let _e529 = local_50; - through_1 = _e529; - let _e530 = diffuseColor_1; - let _e531 = through_1; - let _e532 = irradiance; - let _e535 = g_transmission; - let _e539 = frag_info.material[2u]; - let _e542 = s_20.occlusion; - let _e544 = ambient; - ambient = (_e544 + ((((_e530 * (_e531 - _e532)) * _e535) * _e539) * _e542)); - let _e547 = s_20.v; - let _e549 = g_coat_n; - let _e551 = g_coat_roughness; - let _e552 = levels_1; - let _e554 = textureSampleLevel(environment_texture_tex, environment_texture_smp, reflect(-(_e547), _e549), (_e551 * _e552)); - coatPrefiltered = _e554.xyz; - let _e556 = g_coat_roughness; - param_258 = _e556; - let _e557 = g_coat_n_dot_v; - param_259 = _e557; - let _e558 = EnvBrdf_u0028_f1_u003b_f1_u003b((¶m_258), (¶m_259)); - coatAb = _e558; - let _e559 = coatPrefiltered; - let _e561 = coatAb[0u]; - let _e564 = coatAb[1u]; - let _e567 = g_coat; - let _e571 = frag_info.material[2u]; - let _e574 = s_20.occlusion; - coatAmbient = ((((_e559 * ((0.04f * _e561) + _e564)) * _e567) * _e571) * _e574); - let _e577 = s_20.n; - let _e578 = g_sheen_roughness; - let _e579 = levels_1; - let _e581 = textureSampleLevel(environment_texture_tex, environment_texture_smp, _e577, (_e578 * _e579)); - let _e585 = frag_info.material[2u]; - sheenIncoming = (_e581.xyz * _e585); - } - let _e588 = s_20.roughness; - param_260 = _e588; - let _e590 = s_20.n_dot_v; - param_261 = _e590; - let _e591 = EnvBrdf_u0028_f1_u003b_f1_u003b((¶m_260), (¶m_261)); - sceneAb = _e591; - let _e592 = g_f0_dielectric; - let _e593 = g_irid_fresnel; - let _e594 = g_iridescence; - let _e598 = sceneAb[0u]; - let _e600 = g_f90_; - let _e602 = sceneAb[1u]; - sceneReflects = ((mix(_e592, _e593, vec3(_e594)) * _e598) + vec3((_e600 * _e602))); - let _e606 = diffuseColor_1; - let _e607 = g_transmittance; - let _e609 = sceneReflects; - let _e613 = g_transmission; - passes = (((_e606 * _e607) * (vec3(1f, 1f, 1f) - min(_e609, vec3(1f, 1f, 1f)))) * _e613); - let _e615 = g_pane; - if _e615 { - let _e617 = passes[0u]; - let _e619 = passes[1u]; - let _e622 = passes[2u]; - g_pass_through = clamp((((_e617 + _e619) + _e622) / 3f), 0f, 1f); - } else { - let _e626 = SceneColourBound_u0028_(); - if _e626 { - let _e627 = s_20; - param_262 = _e627; - let _e628 = SceneBehind_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b((¶m_262)); - let _e629 = passes; - let _e631 = ambient; - ambient = (_e631 + (_e628 * _e629)); - } - } - let _e633 = diffuseColor_1; - let _e634 = SampleLightmap_u0028_(); - let _e637 = s_20.occlusion; - let _e639 = ambient; - ambient = (_e639 + ((_e633 * _e634) * _e637)); - let _e641 = g_sheen; - let _e642 = g_sheen_albedo; - let _e644 = sheenIncoming; - let _e647 = s_20.occlusion; - sheenAmbient = (((_e641 * _e642) * _e644) * _e647); - let _e649 = s_20; - param_263 = _e649; - let _e650 = AccumulateLights_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b((¶m_263)); - let _e652 = s_20.occlusion; - let _e654 = ambient; - let _e655 = g_sheen_scale; - let _e657 = sheenAmbient; - let _e660 = s_20.emissive; - let _e662 = g_coat_through; - let _e665 = coatAmbient; - lit_3 = (((_e650 * _e652) + ((((_e654 * _e655) + _e657) + _e660) * _e662)) + _e665); - let _e667 = s_20; - param_264 = _e667; - let _e668 = lit_3; - param_265 = _e668; - let _e669 = WriteDebugView_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_vf3_u003b((¶m_264), (¶m_265)); - if _e669 { + let _e521 = s_20; + param_256 = _e521; + let _e522 = levels_1; + param_257 = _e522; + let _e523 = TransmittedRadiance_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_f1_u003b((¶m_256), (¶m_257)); + let _e524 = g_transmittance; + let _e526 = reflects; + local_50 = ((_e523 * _e524) * (vec3(1f, 1f, 1f) - min(_e526, vec3(1f, 1f, 1f)))); + } + let _e530 = local_50; + through_1 = _e530; + let _e531 = diffuseColor_1; + let _e532 = through_1; + let _e533 = irradiance; + let _e536 = g_transmission; + let _e540 = frag_info.material[2u]; + let _e543 = s_20.occlusion; + let _e545 = ambient; + ambient = (_e545 + ((((_e531 * (_e532 - _e533)) * _e536) * _e540) * _e543)); + let _e548 = s_20.v; + let _e550 = g_coat_n; + let _e552 = g_coat_roughness; + let _e553 = levels_1; + let _e555 = textureSampleLevel(environment_texture_tex, environment_texture_smp, reflect(-(_e548), _e550), (_e552 * _e553)); + coatPrefiltered = _e555.xyz; + let _e557 = g_coat_roughness; + param_258 = _e557; + let _e558 = g_coat_n_dot_v; + param_259 = _e558; + let _e559 = EnvBrdf_u0028_f1_u003b_f1_u003b((¶m_258), (¶m_259)); + coatAb = _e559; + let _e560 = coatPrefiltered; + let _e562 = coatAb[0u]; + let _e565 = coatAb[1u]; + let _e568 = g_coat; + let _e572 = frag_info.material[2u]; + let _e575 = s_20.occlusion; + coatAmbient = ((((_e560 * ((0.04f * _e562) + _e565)) * _e568) * _e572) * _e575); + let _e578 = s_20.n; + let _e579 = g_sheen_roughness; + let _e580 = levels_1; + let _e582 = textureSampleLevel(environment_texture_tex, environment_texture_smp, _e578, (_e579 * _e580)); + let _e586 = frag_info.material[2u]; + sheenIncoming = (_e582.xyz * _e586); + } + let _e589 = s_20.roughness; + param_260 = _e589; + let _e591 = s_20.n_dot_v; + param_261 = _e591; + let _e592 = EnvBrdf_u0028_f1_u003b_f1_u003b((¶m_260), (¶m_261)); + sceneAb = _e592; + let _e593 = g_f0_dielectric; + let _e594 = g_irid_fresnel; + let _e595 = g_iridescence; + let _e599 = sceneAb[0u]; + let _e601 = g_f90_; + let _e603 = sceneAb[1u]; + sceneReflects = ((mix(_e593, _e594, vec3(_e595)) * _e599) + vec3((_e601 * _e603))); + let _e607 = diffuseColor_1; + let _e608 = g_transmittance; + let _e610 = sceneReflects; + let _e614 = g_transmission; + passes = (((_e607 * _e608) * (vec3(1f, 1f, 1f) - min(_e610, vec3(1f, 1f, 1f)))) * _e614); + let _e616 = g_pane; + if _e616 { + let _e618 = passes[0u]; + let _e620 = passes[1u]; + let _e623 = passes[2u]; + g_pass_through = clamp((((_e618 + _e620) + _e623) / 3f), 0f, 1f); + } else { + let _e627 = SceneColourBound_u0028_(); + if _e627 { + let _e628 = s_20; + param_262 = _e628; + let _e629 = SceneBehind_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b((¶m_262)); + let _e630 = passes; + let _e632 = ambient; + ambient = (_e632 + (_e629 * _e630)); + } + } + let _e634 = diffuseColor_1; + let _e635 = SampleLightmap_u0028_(); + let _e638 = s_20.occlusion; + let _e640 = ambient; + ambient = (_e640 + ((_e634 * _e635) * _e638)); + let _e642 = g_sheen; + let _e643 = g_sheen_albedo; + let _e645 = sheenIncoming; + let _e648 = s_20.occlusion; + sheenAmbient = (((_e642 * _e643) * _e645) * _e648); + let _e650 = s_20; + param_263 = _e650; + let _e651 = AccumulateLights_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b((¶m_263)); + let _e653 = s_20.occlusion; + let _e655 = ambient; + let _e656 = g_sheen_scale; + let _e658 = sheenAmbient; + let _e661 = s_20.emissive; + let _e663 = g_coat_through; + let _e666 = coatAmbient; + lit_3 = (((_e651 * _e653) + ((((_e655 * _e656) + _e658) + _e661) * _e663)) + _e666); + let _e668 = s_20; + param_264 = _e668; + let _e669 = lit_3; + param_265 = _e669; + let _e670 = WriteDebugView_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_vf3_u003b((¶m_264), (¶m_265)); + if _e670 { return; } - let _e670 = lit_3; - param_266 = _e670; - let _e672 = s_20.alpha; - param_267 = _e672; - let _e674 = s_20.roughness; - param_268 = _e674; + let _e671 = lit_3; + param_266 = _e671; + let _e673 = s_20.alpha; + param_267 = _e673; + let _e675 = s_20.roughness; + param_268 = _e675; WriteSurface_u0028_vf3_u003b_f1_u003b_f1_u003b((¶m_266), (¶m_267), (¶m_268)); return; } @@ -23530,10 +23670,10 @@ var shadow_texture_tex: texture_2d; var shadow_texture_smp: sampler; fn ViewDepth_u0028_() -> f32 { - let _e188 = v_world_position_1; - let _e190 = fog_info.eye; - let _e194 = fog_info.forward; - return dot((_e188 - _e190.xyz), _e194.xyz); + let _e189 = v_world_position_1; + let _e191 = fog_info.eye; + let _e195 = fog_info.forward; + return dot((_e189 - _e191.xyz), _e195.xyz); } fn WeightedBlendedWeight_u0028_f1_u003b(alpha: ptr) -> f32 { @@ -23542,22 +23682,22 @@ fn WeightedBlendedWeight_u0028_f1_u003b(alpha: ptr) -> f32 { var far: f32; var far3_: f32; - let _e193 = ViewDepth_u0028_(); - z = abs(_e193); - let _e195 = z; - near = (_e195 / 5f); - let _e197 = z; - far = (_e197 / 200f); - let _e199 = far; + let _e194 = ViewDepth_u0028_(); + z = abs(_e194); + let _e196 = z; + near = (_e196 / 5f); + let _e198 = z; + far = (_e198 / 200f); let _e200 = far; - let _e202 = far; - far3_ = ((_e199 * _e200) * _e202); - let _e204 = (*alpha); - let _e205 = near; + let _e201 = far; + let _e203 = far; + far3_ = ((_e200 * _e201) * _e203); + let _e205 = (*alpha); let _e206 = near; - let _e209 = far3_; + let _e207 = near; let _e210 = far3_; - return (_e204 * clamp((10f / ((0.00001f + (_e205 * _e206)) + (_e209 * _e210))), 0.01f, 3000f)); + let _e211 = far3_; + return (_e205 * clamp((10f / ((0.00001f + (_e206 * _e207)) + (_e210 * _e211))), 0.01f, 3000f)); } fn WriteWeightedBlended_u0028_() { @@ -23565,43 +23705,43 @@ fn WriteWeightedBlended_u0028_() { var alpha_1: f32; var weight: f32; var param: f32; - var accumulate: vec4; - var revealage: bool; - var local: vec4; - - let _e197 = fog_info.forward[3u]; - mode = _e197; - let _e198 = mode; - if (_e198 > 0.5f) { - let _e201 = frag_color[3u]; - alpha_1 = _e201; - let _e202 = alpha_1; - param = _e202; - let _e203 = WeightedBlendedWeight_u0028_f1_u003b((¶m)); - weight = _e203; - let _e204 = frag_color; - let _e206 = weight; - let _e207 = (_e204.xyz * _e206); - let _e208 = alpha_1; - let _e209 = weight; - accumulate = vec4(_e207.x, _e207.y, _e207.z, (_e208 * _e209)); - let _e215 = mode; - let _e217 = mode; - revealage = ((_e215 > 1.5f) && (_e217 < 2.5f)); - let _e220 = revealage; - if _e220 { - let _e221 = alpha_1; - local = vec4(_e221); + var accumulate: vec4; + var revealage: bool; + var local: vec4; + + let _e198 = fog_info.forward[3u]; + mode = _e198; + let _e199 = mode; + if (_e199 > 0.5f) { + let _e202 = frag_color[3u]; + alpha_1 = _e202; + let _e203 = alpha_1; + param = _e203; + let _e204 = WeightedBlendedWeight_u0028_f1_u003b((¶m)); + weight = _e204; + let _e205 = frag_color; + let _e207 = weight; + let _e208 = (_e205.xyz * _e207); + let _e209 = alpha_1; + let _e210 = weight; + accumulate = vec4(_e208.x, _e208.y, _e208.z, (_e209 * _e210)); + let _e216 = mode; + let _e218 = mode; + revealage = ((_e216 > 1.5f) && (_e218 < 2.5f)); + let _e221 = revealage; + if _e221 { + let _e222 = alpha_1; + local = vec4(_e222); } else { - let _e223 = accumulate; - local = _e223; + let _e224 = accumulate; + local = _e224; } - let _e224 = local; - frag_color = _e224; - let _e225 = mode; - if (_e225 > 2.5f) { - let _e227 = alpha_1; - frag_surface = vec4(_e227); + let _e225 = local; + frag_color = _e225; + let _e226 = mode; + if (_e226 > 2.5f) { + let _e228 = alpha_1; + frag_surface = vec4(_e228); } } return; @@ -23610,29 +23750,29 @@ fn WriteWeightedBlended_u0028_() { fn EncodeOctahedral_u0028_vf3_u003b(n: ptr>) -> vec2 { var e: vec2; - let _e191 = (*n)[0u]; - let _e194 = (*n)[1u]; - let _e198 = (*n)[2u]; - let _e201 = (*n); - (*n) = (_e201 / vec3(((abs(_e191) + abs(_e194)) + abs(_e198)))); - let _e204 = (*n); - e = _e204.xy; - let _e207 = (*n)[2u]; - if (_e207 < 0f) { - let _e209 = (*n); - let _e215 = (*n)[0u]; - let _e219 = (*n)[1u]; - e = ((vec2(1f) - abs(_e209.yx)) * vec2(select(-1f, 1f, (_e215 >= 0f)), select(-1f, 1f, (_e219 >= 0f)))); + let _e192 = (*n)[0u]; + let _e195 = (*n)[1u]; + let _e199 = (*n)[2u]; + let _e202 = (*n); + (*n) = (_e202 / vec3(((abs(_e192) + abs(_e195)) + abs(_e199)))); + let _e205 = (*n); + e = _e205.xy; + let _e208 = (*n)[2u]; + if (_e208 < 0f) { + let _e210 = (*n); + let _e216 = (*n)[0u]; + let _e220 = (*n)[1u]; + e = ((vec2(1f) - abs(_e210.yx)) * vec2(select(-1f, 1f, (_e216 >= 0f)), select(-1f, 1f, (_e220 >= 0f)))); } - let _e224 = e; - return ((_e224 * 0.5f) + vec2(0.5f)); + let _e225 = e; + return ((_e225 * 0.5f) + vec2(0.5f)); } fn LinearToSrgb_u0028_vf3_u003b(linear: ptr>) -> vec3 { - let _e189 = (*linear); - let _e191 = (*linear); - let _e195 = (*linear); - return mix((_e189 * 12.92f), ((pow(_e191, vec3(0.41666666f, 0.41666666f, 0.41666666f)) * 1.055f) - vec3(0.055f, 0.055f, 0.055f)), step(vec3(0.0031308f, 0.0031308f, 0.0031308f), _e195)); + let _e190 = (*linear); + let _e192 = (*linear); + let _e196 = (*linear); + return mix((_e190 * 12.92f), ((pow(_e192, vec3(0.41666666f, 0.41666666f, 0.41666666f)) * 1.055f) - vec3(0.055f, 0.055f, 0.055f)), step(vec3(0.0031308f, 0.0031308f, 0.0031308f), _e196)); } fn WriteSurfaceGeometry_u0028_f1_u003b(roughness: ptr) { @@ -23640,52 +23780,52 @@ fn WriteSurfaceGeometry_u0028_f1_u003b(roughness: ptr) { var geometric: vec3; var param_2: vec3; - let _e192 = g_albedo; - param_1 = clamp(_e192, vec3(0f, 0f, 0f), vec3(1f, 1f, 1f)); - let _e194 = LinearToSrgb_u0028_vf3_u003b((¶m_1)); - frag_albedo = vec4(_e194.x, _e194.y, _e194.z, 1f); - let _e199 = g_debug_surface_on; - if _e199 { - let _e200 = g_debug_surface; - let _e201 = ViewDepth_u0028_(); - frag_surface = vec4(_e200.x, _e200.y, _e200.z, _e201); + let _e193 = g_albedo; + param_1 = clamp(_e193, vec3(0f, 0f, 0f), vec3(1f, 1f, 1f)); + let _e195 = LinearToSrgb_u0028_vf3_u003b((¶m_1)); + frag_albedo = vec4(_e195.x, _e195.y, _e195.z, 1f); + let _e200 = g_debug_surface_on; + if _e200 { + let _e201 = g_debug_surface; + let _e202 = ViewDepth_u0028_(); + frag_surface = vec4(_e201.x, _e201.y, _e201.z, _e202); return; } - let _e206 = v_normal_1; - geometric = normalize(_e206); - let _e208 = gl_FrontFacing_1; - if !(_e208) { - let _e210 = geometric; - geometric = -(_e210); - } - let _e212 = geometric; - param_2 = _e212; - let _e213 = EncodeOctahedral_u0028_vf3_u003b((¶m_2)); - let _e214 = (*roughness); - let _e216 = ViewDepth_u0028_(); - frag_surface = vec4(_e213.x, _e213.y, clamp(_e214, 0f, 1f), _e216); + let _e207 = v_normal_1; + geometric = normalize(_e207); + let _e209 = gl_FrontFacing_1; + if !(_e209) { + let _e211 = geometric; + geometric = -(_e211); + } + let _e213 = geometric; + param_2 = _e213; + let _e214 = EncodeOctahedral_u0028_vf3_u003b((¶m_2)); + let _e215 = (*roughness); + let _e217 = ViewDepth_u0028_(); + frag_surface = vec4(_e214.x, _e214.y, clamp(_e215, 0f, 1f), _e217); return; } fn Orthographic_u0028_() -> bool { - let _e190 = fog_info.projection[0u]; - return (_e190 > 0.5f); + let _e191 = fog_info.projection[0u]; + return (_e191 > 0.5f); } fn EyeDistance_u0028_() -> f32 { var local_1: f32; - let _e189 = Orthographic_u0028_(); - if _e189 { - let _e190 = ViewDepth_u0028_(); - local_1 = max(_e190, 0f); + let _e190 = Orthographic_u0028_(); + if _e190 { + let _e191 = ViewDepth_u0028_(); + local_1 = max(_e191, 0f); } else { - let _e192 = v_world_position_1; - let _e194 = fog_info.eye; - local_1 = distance(_e192, _e194.xyz); + let _e193 = v_world_position_1; + let _e195 = fog_info.eye; + local_1 = distance(_e193, _e195.xyz); } - let _e197 = local_1; - return _e197; + let _e198 = local_1; + return _e198; } fn ApplyFog_u0028_vf3_u003b(color: ptr>) -> vec3 { @@ -23695,41 +23835,41 @@ fn ApplyFog_u0028_vf3_u003b(color: ptr>) -> vec3 { var k: f32; var local_2: f32; - let _e196 = fog_info.fog[3u]; - density = _e196; - let _e197 = density; - if (_e197 <= 0f) { - let _e199 = (*color); - return _e199; - } - let _e200 = EyeDistance_u0028_(); - d = _e200; - let _e203 = fog_info.eye[3u]; - falloff = _e203; - let _e204 = falloff; - if (_e204 > 0f) { - let _e206 = falloff; - let _e208 = v_world_position_1[1u]; - let _e211 = fog_info.eye[1u]; - k = (_e206 * (_e208 - _e211)); - let _e214 = k; - if (abs(_e214) > 0.001f) { - let _e217 = k; - let _e221 = k; - local_2 = ((1f - exp(-(_e217))) / _e221); + let _e197 = fog_info.fog[3u]; + density = _e197; + let _e198 = density; + if (_e198 <= 0f) { + let _e200 = (*color); + return _e200; + } + let _e201 = EyeDistance_u0028_(); + d = _e201; + let _e204 = fog_info.eye[3u]; + falloff = _e204; + let _e205 = falloff; + if (_e205 > 0f) { + let _e207 = falloff; + let _e209 = v_world_position_1[1u]; + let _e212 = fog_info.eye[1u]; + k = (_e207 * (_e209 - _e212)); + let _e215 = k; + if (abs(_e215) > 0.001f) { + let _e218 = k; + let _e222 = k; + local_2 = ((1f - exp(-(_e218))) / _e222); } else { - let _e223 = k; - local_2 = (1f - (0.5f * _e223)); + let _e224 = k; + local_2 = (1f - (0.5f * _e224)); } - let _e226 = local_2; - let _e227 = density; - density = (_e227 * _e226); + let _e227 = local_2; + let _e228 = density; + density = (_e228 * _e227); } - let _e230 = fog_info.fog; - let _e232 = (*color); - let _e233 = density; - let _e235 = d; - return mix(_e230.xyz, _e232, vec3(clamp(exp((-(_e233) * _e235)), 0f, 1f))); + let _e231 = fog_info.fog; + let _e233 = (*color); + let _e234 = density; + let _e236 = d; + return mix(_e231.xyz, _e233, vec3(clamp(exp((-(_e234) * _e236)), 0f, 1f))); } fn WriteSurface_u0028_vf3_u003b_f1_u003b_f1_u003b(linearColor: ptr>, alpha_2: ptr, roughness_1: ptr) { @@ -23737,44 +23877,44 @@ fn WriteSurface_u0028_vf3_u003b_f1_u003b_f1_u003b(linearColor: ptr; var param_4: f32; - let _e194 = g_premultiply; - let _e195 = (*alpha_2); - weight_1 = select(1f, _e195, _e194); - let _e197 = (*linearColor); - param_3 = _e197; - let _e198 = ApplyFog_u0028_vf3_u003b((¶m_3)); - let _e199 = weight_1; - let _e200 = (_e198 * _e199); - let _e201 = (*alpha_2); - let _e202 = g_pass_through; - frag_color = vec4(_e200.x, _e200.y, _e200.z, (_e201 * (1f - _e202))); - let _e209 = (*roughness_1); - param_4 = _e209; + let _e195 = g_premultiply; + let _e196 = (*alpha_2); + weight_1 = select(1f, _e196, _e195); + let _e198 = (*linearColor); + param_3 = _e198; + let _e199 = ApplyFog_u0028_vf3_u003b((¶m_3)); + let _e200 = weight_1; + let _e201 = (_e199 * _e200); + let _e202 = (*alpha_2); + let _e203 = g_pass_through; + frag_color = vec4(_e201.x, _e201.y, _e201.z, (_e202 * (1f - _e203))); + let _e210 = (*roughness_1); + param_4 = _e210; WriteSurfaceGeometry_u0028_f1_u003b((¶m_4)); WriteWeightedBlended_u0028_(); return; } fn SrgbToLinear_u0028_vf3_u003b(srgb: ptr>) -> vec3 { - let _e189 = (*srgb); - let _e192 = (*srgb); - let _e197 = (*srgb); - return mix((_e189 / vec3(12.92f)), pow(((_e192 + vec3(0.055f, 0.055f, 0.055f)) / vec3(1.055f)), vec3(2.4f, 2.4f, 2.4f)), step(vec3(0.04045f, 0.04045f, 0.04045f), _e197)); + let _e190 = (*srgb); + let _e193 = (*srgb); + let _e198 = (*srgb); + return mix((_e190 / vec3(12.92f)), pow(((_e193 + vec3(0.055f, 0.055f, 0.055f)) / vec3(1.055f)), vec3(2.4f, 2.4f, 2.4f)), step(vec3(0.04045f, 0.04045f, 0.04045f), _e198)); } fn NonFinite_u0028_vf3_u003b(c: ptr>) -> bool { var phi_2562_: bool; - let _e189 = (*c); let _e190 = (*c); - let _e192 = any((_e189 != _e190)); - phi_2562_ = _e192; - if !(_e192) { - let _e194 = (*c); - phi_2562_ = any((abs(_e194) > vec3(300000000000000000000000000000000000000f, 300000000000000000000000000000000000000f, 300000000000000000000000000000000000000f))); - } - let _e199 = phi_2562_; - return _e199; + let _e191 = (*c); + let _e193 = any((_e190 != _e191)); + phi_2562_ = _e193; + if !(_e193) { + let _e195 = (*c); + phi_2562_ = any((abs(_e195) > vec3(300000000000000000000000000000000000000f, 300000000000000000000000000000000000000f, 300000000000000000000000000000000000000f))); + } + let _e200 = phi_2562_; + return _e200; } fn WriteDebugView_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_vf3_u003b(s: ptr, lit: ptr>) -> bool { @@ -23792,78 +23932,78 @@ fn WriteDebugView_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_ var param_9: vec3; var param_10: f32; - let _e205 = frag_info.debug_view[0u]; - view = _e205; - let _e206 = view; - if (_e206 < 0.5f) { + let _e206 = frag_info.debug_view[0u]; + view = _e206; + let _e207 = view; + if (_e207 < 0.5f) { return false; } - let _e209 = gl_FragCoord_1[0u]; - let _e212 = frag_info.debug_view[1u]; - let _e215 = frag_info.debug_view[2u]; - if (_e209 < (_e212 * _e215)) { + let _e210 = gl_FragCoord_1[0u]; + let _e213 = frag_info.debug_view[1u]; + let _e216 = frag_info.debug_view[2u]; + if (_e210 < (_e213 * _e216)) { return false; } - let _e218 = view; - code = i32((_e218 + 0.5f)); + let _e219 = view; + code = i32((_e219 + 0.5f)); shown = vec3(0f, 0f, 0f); - let _e221 = code; - if (_e221 == 1i) { - let _e224 = (*s).albedo; - param_5 = clamp(_e224, vec3(0f, 0f, 0f), vec3(1f, 1f, 1f)); - let _e226 = LinearToSrgb_u0028_vf3_u003b((¶m_5)); - shown = _e226; - } else { - let _e227 = code; - if (_e227 == 2i) { - let _e230 = (*s).n; - shown = ((_e230 * 0.5f) + vec3(0.5f, 0.5f, 0.5f)); + let _e222 = code; + if (_e222 == 1i) { + let _e225 = (*s).albedo; + param_5 = clamp(_e225, vec3(0f, 0f, 0f), vec3(1f, 1f, 1f)); + let _e227 = LinearToSrgb_u0028_vf3_u003b((¶m_5)); + shown = _e227; + } else { + let _e228 = code; + if (_e228 == 2i) { + let _e231 = (*s).n; + shown = ((_e231 * 0.5f) + vec3(0.5f, 0.5f, 0.5f)); } else { - let _e233 = code; - if (_e233 == 3i) { - let _e236 = (*s).roughness; - shown = vec3(clamp(_e236, 0f, 1f)); + let _e234 = code; + if (_e234 == 3i) { + let _e237 = (*s).roughness; + shown = vec3(clamp(_e237, 0f, 1f)); } else { - let _e239 = code; - if (_e239 == 4i) { - let _e242 = (*s).metallic; - shown = vec3(clamp(_e242, 0f, 1f)); + let _e240 = code; + if (_e240 == 4i) { + let _e243 = (*s).metallic; + shown = vec3(clamp(_e243, 0f, 1f)); } else { - let _e245 = code; - if (_e245 == 5i) { - let _e248 = (*s).occlusion; - shown = vec3(clamp(_e248, 0f, 1f)); + let _e246 = code; + if (_e246 == 5i) { + let _e249 = (*s).occlusion; + shown = vec3(clamp(_e249, 0f, 1f)); } else { - let _e251 = code; - if (_e251 == 6i) { - let _e254 = (*s).emissive; - param_6 = clamp(_e254, vec3(0f, 0f, 0f), vec3(1f, 1f, 1f)); - let _e256 = LinearToSrgb_u0028_vf3_u003b((¶m_6)); - shown = _e256; + let _e252 = code; + if (_e252 == 6i) { + let _e255 = (*s).emissive; + param_6 = clamp(_e255, vec3(0f, 0f, 0f), vec3(1f, 1f, 1f)); + let _e257 = LinearToSrgb_u0028_vf3_u003b((¶m_6)); + shown = _e257; } else { - let _e257 = code; - if (_e257 == 7i) { - let _e259 = v_texcoord_1; - let _e260 = fract(_e259); - shown = vec3(_e260.x, _e260.y, 0f); + let _e258 = code; + if (_e258 == 7i) { + let _e260 = v_texcoord_1; + let _e261 = fract(_e260); + shown = vec3(_e261.x, _e261.y, 0f); } else { - let _e264 = code; - if (_e264 == 8i) { - let _e266 = (*lit); - param_7 = clamp(_e266, vec3(0f, 0f, 0f), vec3(1f, 1f, 1f)); - let _e268 = LinearToSrgb_u0028_vf3_u003b((¶m_7)); - grey = dot(_e268, vec3(0.2126f, 0.7152f, 0.0722f)); - let _e270 = (*lit); - param_8 = _e270; - let _e271 = NonFinite_u0028_vf3_u003b((¶m_8)); - if _e271 { + let _e265 = code; + if (_e265 == 8i) { + let _e267 = (*lit); + param_7 = clamp(_e267, vec3(0f, 0f, 0f), vec3(1f, 1f, 1f)); + let _e269 = LinearToSrgb_u0028_vf3_u003b((¶m_7)); + grey = dot(_e269, vec3(0.2126f, 0.7152f, 0.0722f)); + let _e271 = (*lit); + param_8 = _e271; + let _e272 = NonFinite_u0028_vf3_u003b((¶m_8)); + if _e272 { local_3 = vec3(1f, 0f, 1f); } else { - let _e272 = grey; - local_3 = vec3((_e272 * 0.5f)); + let _e273 = grey; + local_3 = vec3((_e273 * 0.5f)); } - let _e275 = local_3; - shown = _e275; + let _e276 = local_3; + shown = _e276; } } } @@ -23872,24 +24012,24 @@ fn WriteDebugView_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_ } } } - let _e276 = g_premultiply; - if _e276 { - let _e278 = (*s).alpha; - local_4 = _e278; + let _e277 = g_premultiply; + if _e277 { + let _e279 = (*s).alpha; + local_4 = _e279; } else { local_4 = 1f; } - let _e279 = local_4; - weight_2 = _e279; - let _e280 = shown; - param_9 = _e280; - let _e281 = SrgbToLinear_u0028_vf3_u003b((¶m_9)); - let _e282 = weight_2; - let _e283 = (_e281 * _e282); - let _e285 = (*s).alpha; - frag_color = vec4(_e283.x, _e283.y, _e283.z, _e285); - let _e291 = (*s).roughness; - param_10 = _e291; + let _e280 = local_4; + weight_2 = _e280; + let _e281 = shown; + param_9 = _e281; + let _e282 = SrgbToLinear_u0028_vf3_u003b((¶m_9)); + let _e283 = weight_2; + let _e284 = (_e282 * _e283); + let _e286 = (*s).alpha; + frag_color = vec4(_e284.x, _e284.y, _e284.z, _e286); + let _e292 = (*s).roughness; + param_10 = _e292; WriteSurfaceGeometry_u0028_f1_u003b((¶m_10)); WriteWeightedBlended_u0028_(); return true; @@ -23901,54 +24041,54 @@ fn ShadeLight_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_ var fraction: f32; var ramp: f32; - let _e195 = (*s_1).roughness; - bands = mix(5f, 2f, _e195); - let _e198 = (*light).n_dot_l; - let _e199 = bands; - let _e202 = bands; - quantized = (floor((_e198 * _e199)) / _e202); - let _e205 = (*light).n_dot_l; - let _e206 = bands; - fraction = fract((_e205 * _e206)); - let _e209 = fraction; - let _e211 = bands; - let _e213 = quantized; - quantized = (_e213 + (smoothstep(0.85f, 1f, _e209) / _e211)); - let _e215 = quantized; - let _e217 = (*light).n_dot_l; - ramp = (_e215 / max(_e217, 0.001f)); - let _e221 = (*s_1).albedo; - let _e222 = ramp; - return (_e221 * _e222); + let _e196 = (*s_1).roughness; + bands = mix(5f, 2f, _e196); + let _e199 = (*light).n_dot_l; + let _e200 = bands; + let _e203 = bands; + quantized = (floor((_e199 * _e200)) / _e203); + let _e206 = (*light).n_dot_l; + let _e207 = bands; + fraction = fract((_e206 * _e207)); + let _e210 = fraction; + let _e212 = bands; + let _e214 = quantized; + quantized = (_e214 + (smoothstep(0.85f, 1f, _e210) / _e212)); + let _e216 = quantized; + let _e218 = (*light).n_dot_l; + ramp = (_e216 / max(_e218, 0.001f)); + let _e222 = (*s_1).albedo; + let _e223 = ramp; + return (_e222 * _e223); } fn PointShadowDiskTap_u0028_i1_u003b(i: ptr) -> vec2 { - let _e189 = (*i); - if (_e189 == 0i) { + let _e190 = (*i); + if (_e190 == 0i) { return vec2(-0.94201624f, -0.39906216f); } - let _e191 = (*i); - if (_e191 == 1i) { + let _e192 = (*i); + if (_e192 == 1i) { return vec2(0.9455861f, -0.76890725f); } - let _e193 = (*i); - if (_e193 == 2i) { + let _e194 = (*i); + if (_e194 == 2i) { return vec2(-0.0941841f, -0.9293887f); } - let _e195 = (*i); - if (_e195 == 3i) { + let _e196 = (*i); + if (_e196 == 3i) { return vec2(0.34495938f, 0.2938776f); } - let _e197 = (*i); - if (_e197 == 4i) { + let _e198 = (*i); + if (_e198 == 4i) { return vec2(-0.9158858f, 0.45771432f); } - let _e199 = (*i); - if (_e199 == 5i) { + let _e200 = (*i); + if (_e200 == 5i) { return vec2(-0.8154423f, -0.87912464f); } - let _e201 = (*i); - if (_e201 == 6i) { + let _e202 = (*i); + if (_e202 == 6i) { return vec2(-0.38277543f, 0.27676845f); } return vec2(0.974844f, 0.7564838f); @@ -23958,20 +24098,20 @@ fn PointShadowOffset_u0028_i1_u003b_f1_u003b_f1_u003b_f1_u003b(i_1: ptr; var param_11: i32; - let _e194 = (*i_1); - param_11 = _e194; - let _e195 = PointShadowDiskTap_u0028_i1_u003b((¶m_11)); - p = _e195; - let _e197 = p[0u]; - let _e198 = (*ca); - let _e201 = p[1u]; - let _e202 = (*sa); - let _e206 = p[0u]; - let _e207 = (*sa); - let _e210 = p[1u]; - let _e211 = (*ca); - let _e215 = (*radius); - return (vec2(((_e197 * _e198) - (_e201 * _e202)), ((_e206 * _e207) + (_e210 * _e211))) * _e215); + let _e195 = (*i_1); + param_11 = _e195; + let _e196 = PointShadowDiskTap_u0028_i1_u003b((¶m_11)); + p = _e196; + let _e198 = p[0u]; + let _e199 = (*ca); + let _e202 = p[1u]; + let _e203 = (*sa); + let _e207 = p[0u]; + let _e208 = (*sa); + let _e211 = p[1u]; + let _e212 = (*ca); + let _e216 = (*radius); + return (vec2(((_e198 * _e199) - (_e202 * _e203)), ((_e207 * _e208) + (_e211 * _e212))) * _e216); } fn PointShadowDistance_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b(uv: ptr>, offset: ptr>, tile: ptr>, range: ptr) -> f32 { @@ -23979,27 +24119,27 @@ fn PointShadowDistance_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b(uv: ptr; var atlas: vec2; - let _e197 = point_shadow.params[0u]; - inset = _e197; - let _e198 = (*uv); - let _e199 = (*offset); - let _e201 = inset; - let _e202 = inset; - local_5 = clamp((_e198 + _e199), vec2(_e201), vec2((1f - _e202))); - let _e207 = local_5; - let _e208 = (*tile); - atlas = ((_e207 + _e208) * vec2(0.16666667f, 0.16666667f)); - let _e213 = point_shadow.params3_[0u]; - if (_e213 > 0.5f) { - let _e216 = atlas[1u]; - atlas[1u] = (1f - _e216); + let _e198 = point_shadow.params[0u]; + inset = _e198; + let _e199 = (*uv); + let _e200 = (*offset); + let _e202 = inset; + let _e203 = inset; + local_5 = clamp((_e199 + _e200), vec2(_e202), vec2((1f - _e203))); + let _e208 = local_5; + let _e209 = (*tile); + atlas = ((_e208 + _e209) * vec2(0.16666667f, 0.16666667f)); + let _e214 = point_shadow.params3_[0u]; + if (_e214 > 0.5f) { + let _e217 = atlas[1u]; + atlas[1u] = (1f - _e217); } - let _e219 = atlas; - let _e220 = textureSampleLevel(point_shadow_texture_tex, point_shadow_texture_smp, _e219, 0f); - let _e222 = atlas; - let _e223 = textureSampleLevel(point_shadow_static_texture_tex, point_shadow_static_texture_smp, _e222, 0f); - let _e226 = (*range); - return (min(_e220.x, _e223.x) * _e226); + let _e220 = atlas; + let _e221 = textureSampleLevel(point_shadow_texture_tex, point_shadow_texture_smp, _e220, 0f); + let _e223 = atlas; + let _e224 = textureSampleLevel(point_shadow_static_texture_tex, point_shadow_static_texture_smp, _e223, 0f); + let _e227 = (*range); + return (min(_e221.x, _e224.x) * _e227); } fn PointShadowTap_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b_f1_u003b(uv_1: ptr>, offset_1: ptr>, tile_1: ptr>, range_1: ptr, receiver: ptr) -> f32 { @@ -24009,24 +24149,24 @@ fn PointShadowTap_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b_f1_u003b(uv_1: pt var param_14: vec2; var param_15: f32; - let _e198 = (*uv_1); - param_12 = _e198; - let _e199 = (*offset_1); - param_13 = _e199; - let _e200 = (*tile_1); - param_14 = _e200; - let _e201 = (*range_1); - param_15 = _e201; - let _e202 = PointShadowDistance_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b((¶m_12), (¶m_13), (¶m_14), (¶m_15)); - stored = _e202; - let _e203 = stored; - let _e204 = (*range_1); - if (_e203 >= (_e204 * 0.999f)) { + let _e199 = (*uv_1); + param_12 = _e199; + let _e200 = (*offset_1); + param_13 = _e200; + let _e201 = (*tile_1); + param_14 = _e201; + let _e202 = (*range_1); + param_15 = _e202; + let _e203 = PointShadowDistance_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b((¶m_12), (¶m_13), (¶m_14), (¶m_15)); + stored = _e203; + let _e204 = stored; + let _e205 = (*range_1); + if (_e204 >= (_e205 * 0.999f)) { return 1f; } - let _e207 = (*receiver); - let _e208 = stored; - return select(1f, 0f, (_e207 > _e208)); + let _e208 = (*receiver); + let _e209 = stored; + return select(1f, 0f, (_e208 > _e209)); } fn PointShadowPenumbra_u0028_vf2_u003b_vf2_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b(uv_2: ptr>, tile_2: ptr>, range_2: ptr, receiver_1: ptr, ca_1: ptr, sa_1: ptr, tanHalf: ptr, blockerOut: ptr) -> f32 { @@ -24053,111 +24193,111 @@ fn PointShadowPenumbra_u0028_vf2_u003b_vf2_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u var world: f32; (*blockerOut) = -1f; - let _e219 = point_shadow.params2_[1u]; - lightRadius = _e219; - let _e222 = point_shadow.params2_[0u]; - minRadius = _e222; - let _e225 = point_shadow.params2_[2u]; - maxRadius = _e225; - let _e226 = lightRadius; - if (_e226 <= 0f) { - let _e228 = (*uv_2); - param_16 = _e228; + let _e220 = point_shadow.params2_[1u]; + lightRadius = _e220; + let _e223 = point_shadow.params2_[0u]; + minRadius = _e223; + let _e226 = point_shadow.params2_[2u]; + maxRadius = _e226; + let _e227 = lightRadius; + if (_e227 <= 0f) { + let _e229 = (*uv_2); + param_16 = _e229; param_17 = vec2(0f, 0f); - let _e229 = (*tile_2); - param_18 = _e229; - let _e230 = (*range_2); - param_19 = _e230; - let _e231 = PointShadowDistance_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b((¶m_16), (¶m_17), (¶m_18), (¶m_19)); - (*blockerOut) = _e231; - let _e232 = minRadius; - return _e232; + let _e230 = (*tile_2); + param_18 = _e230; + let _e231 = (*range_2); + param_19 = _e231; + let _e232 = PointShadowDistance_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b((¶m_16), (¶m_17), (¶m_18), (¶m_19)); + (*blockerOut) = _e232; + let _e233 = minRadius; + return _e233; } sum = 0f; count = 0f; i_2 = 0i; loop { - let _e233 = i_2; - if (_e233 < 8i) { - let _e235 = i_2; - param_20 = _e235; - let _e236 = (*ca_1); - param_21 = _e236; - let _e237 = (*sa_1); - param_22 = _e237; - let _e238 = maxRadius; - param_23 = _e238; - let _e239 = PointShadowOffset_u0028_i1_u003b_f1_u003b_f1_u003b_f1_u003b((¶m_20), (¶m_21), (¶m_22), (¶m_23)); - let _e240 = (*uv_2); - param_24 = _e240; - param_25 = _e239; - let _e241 = (*tile_2); - param_26 = _e241; - let _e242 = (*range_2); - param_27 = _e242; - let _e243 = PointShadowDistance_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b((¶m_24), (¶m_25), (¶m_26), (¶m_27)); - stored_1 = _e243; - let _e244 = stored_1; - let _e245 = (*range_2); - if (_e244 >= (_e245 * 0.999f)) { + let _e234 = i_2; + if (_e234 < 8i) { + let _e236 = i_2; + param_20 = _e236; + let _e237 = (*ca_1); + param_21 = _e237; + let _e238 = (*sa_1); + param_22 = _e238; + let _e239 = maxRadius; + param_23 = _e239; + let _e240 = PointShadowOffset_u0028_i1_u003b_f1_u003b_f1_u003b_f1_u003b((¶m_20), (¶m_21), (¶m_22), (¶m_23)); + let _e241 = (*uv_2); + param_24 = _e241; + param_25 = _e240; + let _e242 = (*tile_2); + param_26 = _e242; + let _e243 = (*range_2); + param_27 = _e243; + let _e244 = PointShadowDistance_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b((¶m_24), (¶m_25), (¶m_26), (¶m_27)); + stored_1 = _e244; + let _e245 = stored_1; + let _e246 = (*range_2); + if (_e245 >= (_e246 * 0.999f)) { continue; } - let _e248 = stored_1; - let _e249 = (*receiver_1); - if (_e248 >= _e249) { + let _e249 = stored_1; + let _e250 = (*receiver_1); + if (_e249 >= _e250) { continue; } - let _e251 = stored_1; - let _e252 = sum; - sum = (_e252 + _e251); - let _e254 = count; - count = (_e254 + 1f); + let _e252 = stored_1; + let _e253 = sum; + sum = (_e253 + _e252); + let _e255 = count; + count = (_e255 + 1f); continue; } else { break; } continuing { - let _e256 = i_2; - i_2 = (_e256 + 1i); + let _e257 = i_2; + i_2 = (_e257 + 1i); } } - let _e258 = count; - if (_e258 < 0.5f) { + let _e259 = count; + if (_e259 < 0.5f) { return -1f; } - let _e260 = sum; - let _e261 = count; - blocker = max((_e260 / _e261), 0.0001f); - let _e264 = blocker; - (*blockerOut) = _e264; - let _e265 = lightRadius; - let _e266 = (*receiver_1); - let _e267 = blocker; - let _e271 = blocker; - world = ((_e265 * max((_e266 - _e267), 0f)) / _e271); - let _e273 = world; - let _e274 = (*receiver_1); - let _e276 = (*tanHalf); - let _e279 = minRadius; - let _e280 = maxRadius; - return clamp((_e273 / ((2f * _e274) * _e276)), _e279, _e280); + let _e261 = sum; + let _e262 = count; + blocker = max((_e261 / _e262), 0.0001f); + let _e265 = blocker; + (*blockerOut) = _e265; + let _e266 = lightRadius; + let _e267 = (*receiver_1); + let _e268 = blocker; + let _e272 = blocker; + world = ((_e266 * max((_e267 - _e268), 0f)) / _e272); + let _e274 = world; + let _e275 = (*receiver_1); + let _e277 = (*tanHalf); + let _e280 = minRadius; + let _e281 = maxRadius; + return clamp((_e274 / ((2f * _e275) * _e277)), _e280, _e281); } fn FragCoordFromTop_u0028_f1_u003b(rows: ptr) -> vec2 { var local_6: vec2; - let _e190 = (*rows); - if (_e190 > 0f) { - let _e193 = gl_FragCoord_1[0u]; - let _e194 = (*rows); - let _e196 = gl_FragCoord_1[1u]; - local_6 = vec2(_e193, (_e194 - _e196)); + let _e191 = (*rows); + if (_e191 > 0f) { + let _e194 = gl_FragCoord_1[0u]; + let _e195 = (*rows); + let _e197 = gl_FragCoord_1[1u]; + local_6 = vec2(_e194, (_e195 - _e197)); } else { - let _e199 = gl_FragCoord_1; - local_6 = _e199.xy; + let _e200 = gl_FragCoord_1; + local_6 = _e200.xy; } - let _e201 = local_6; - return _e201; + let _e202 = local_6; + return _e202; } fn PointShadowFactor_u0028_vf3_u003b_vf3_u003b_i1_u003b(world_1: ptr>, normal: ptr>, lightIndex: ptr) -> f32 { @@ -24215,257 +24355,257 @@ fn PointShadowFactor_u0028_vf3_u003b_vf3_u003b_i1_u003b(world_1: ptr= _e329) { + let _e285 = nDotL; + slope = min((sqrt(max((1f - (_e278 * _e279)), 0f)) / (_e284 * _e285)), 8f); + let _e289 = toLightLength; + let _e291 = (*lightIndex); + let _e295 = point_shadow.slots[_e291][2u]; + let _e300 = point_shadow.params3_[1u]; + texel = (((2f * _e289) * max(_e295, 0.0001f)) * _e300); + let _e302 = (*world_1); + let _e303 = (*normal); + let _e304 = texel; + let _e308 = point_shadow.params[3u]; + let _e310 = slope; + origin = (_e302 + (((_e303 * _e304) * _e308) * (1f + _e310))); + let _e314 = origin; + let _e315 = slot; + let _e318 = point_shadow.lights[_e315]; + toFragment = (_e314 - _e318.xyz); + let _e321 = toFragment; + distance_ = length(_e321); + let _e323 = slot; + let _e327 = point_shadow.lights[_e323][3u]; + range_3 = max(_e327, 0.0001f); + let _e329 = distance_; + let _e330 = range_3; + if (_e329 >= _e330) { return 1f; } face = 0i; - let _e331 = (*lightIndex); - let _e335 = point_shadow.slots[_e331][1u]; - if (_e335 < 0.5f) { - let _e337 = toFragment; - a = abs(_e337); - let _e340 = a[0u]; - let _e342 = a[1u]; - let _e343 = (_e340 >= _e342); - phi_2249_ = _e343; - if _e343 { - let _e345 = a[0u]; - let _e347 = a[2u]; - phi_2249_ = (_e345 >= _e347); + let _e332 = (*lightIndex); + let _e336 = point_shadow.slots[_e332][1u]; + if (_e336 < 0.5f) { + let _e338 = toFragment; + a = abs(_e338); + let _e341 = a[0u]; + let _e343 = a[1u]; + let _e344 = (_e341 >= _e343); + phi_2249_ = _e344; + if _e344 { + let _e346 = a[0u]; + let _e348 = a[2u]; + phi_2249_ = (_e346 >= _e348); } - let _e350 = phi_2249_; - if _e350 { - let _e352 = toFragment[0u]; - face = select(1i, 0i, (_e352 > 0f)); + let _e351 = phi_2249_; + if _e351 { + let _e353 = toFragment[0u]; + face = select(1i, 0i, (_e353 > 0f)); } else { - let _e356 = a[1u]; - let _e358 = a[2u]; - if (_e356 >= _e358) { - let _e361 = toFragment[1u]; - face = select(3i, 2i, (_e361 > 0f)); + let _e357 = a[1u]; + let _e359 = a[2u]; + if (_e357 >= _e359) { + let _e362 = toFragment[1u]; + face = select(3i, 2i, (_e362 > 0f)); } else { - let _e365 = toFragment[2u]; - face = select(5i, 4i, (_e365 > 0f)); + let _e366 = toFragment[2u]; + face = select(5i, 4i, (_e366 > 0f)); } } } - let _e368 = slot; - let _e370 = face; - let _e374 = point_shadow.faces[((_e368 * 6i) + _e370)]; - let _e375 = origin; - clip = (_e374 * vec4(_e375.x, _e375.y, _e375.z, 1f)); - let _e382 = clip[3u]; - if (_e382 <= 0f) { + let _e369 = slot; + let _e371 = face; + let _e375 = point_shadow.faces[((_e369 * 6i) + _e371)]; + let _e376 = origin; + clip = (_e375 * vec4(_e376.x, _e376.y, _e376.z, 1f)); + let _e383 = clip[3u]; + if (_e383 <= 0f) { return 1f; } - let _e384 = clip; - let _e387 = clip[3u]; - ndc = (_e384.xy / vec2(_e387)); - let _e391 = ndc[0u]; - let _e393 = (abs(_e391) > 1f); - phi_2310_ = _e393; - if !(_e393) { - let _e396 = ndc[1u]; - phi_2310_ = (abs(_e396) > 1f); - } - let _e400 = phi_2310_; - if _e400 { + let _e385 = clip; + let _e388 = clip[3u]; + ndc = (_e385.xy / vec2(_e388)); + let _e392 = ndc[0u]; + let _e394 = (abs(_e392) > 1f); + phi_2310_ = _e394; + if !(_e394) { + let _e397 = ndc[1u]; + phi_2310_ = (abs(_e397) > 1f); + } + let _e401 = phi_2310_; + if _e401 { return 1f; } - let _e402 = ndc[0u]; - let _e406 = ndc[1u]; - uv_3 = vec2(((_e402 * 0.5f) + 0.5f), (0.5f - (_e406 * 0.5f))); - let _e410 = face; - let _e412 = slot; - tile_3 = vec2(f32(_e410), f32(_e412)); - let _e415 = distance_; - let _e418 = point_shadow.params[1u]; - receiver_2 = (_e415 - _e418); - let _e422 = frag_info.target_origin[0u]; - param_28 = _e422; - let _e423 = FragCoordFromTop_u0028_f1_u003b((¶m_28)); - noise = fract((52.982918f * fract(dot(_e423, vec2(0.06711056f, 0.00583715f))))); - let _e428 = noise; - angle = (_e428 * 6.2831855f); - let _e430 = angle; - ca_2 = cos(_e430); - let _e432 = angle; - sa_2 = sin(_e432); - let _e434 = (*lightIndex); - let _e438 = point_shadow.slots[_e434][2u]; - tanHalf_1 = max(_e438, 0.0001f); - blocker_1 = -1f; - let _e440 = uv_3; - param_29 = _e440; - let _e441 = tile_3; - param_30 = _e441; - let _e442 = range_3; - param_31 = _e442; - let _e443 = receiver_2; - param_32 = _e443; - let _e444 = ca_2; - param_33 = _e444; - let _e445 = sa_2; - param_34 = _e445; - let _e446 = tanHalf_1; - param_35 = _e446; - let _e447 = PointShadowPenumbra_u0028_vf2_u003b_vf2_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b((¶m_29), (¶m_30), (¶m_31), (¶m_32), (¶m_33), (¶m_34), (¶m_35), (¶m_36)); - let _e448 = param_36; - blocker_1 = _e448; - radius_1 = _e447; - let _e451 = point_shadow.params2_[3u]; - if (_e451 > 0.5f) { - g_debug_surface_on = true; - let _e453 = radius_1; - if (_e453 < 0f) { - local_7 = vec3(0f, 0f, 1f); - } else { - let _e455 = radius_1; - let _e458 = point_shadow.params2_[2u]; - let _e462 = blocker_1; - let _e463 = range_3; - local_7 = vec3(clamp((_e455 / max(_e458, 0.000001f)), 0f, 1f), clamp((_e462 / _e463), 0f, 1f), 0f); + let _e403 = ndc[0u]; + let _e407 = ndc[1u]; + uv_3 = vec2(((_e403 * 0.5f) + 0.5f), (0.5f - (_e407 * 0.5f))); + let _e411 = face; + let _e413 = slot; + tile_3 = vec2(f32(_e411), f32(_e413)); + let _e416 = distance_; + let _e419 = point_shadow.params[1u]; + receiver_2 = (_e416 - _e419); + let _e423 = frag_info.target_origin[0u]; + param_28 = _e423; + let _e424 = FragCoordFromTop_u0028_f1_u003b((¶m_28)); + noise = fract((52.982918f * fract(dot(_e424, vec2(0.06711056f, 0.00583715f))))); + let _e429 = noise; + angle = (_e429 * 6.2831855f); + let _e431 = angle; + ca_2 = cos(_e431); + let _e433 = angle; + sa_2 = sin(_e433); + let _e435 = (*lightIndex); + let _e439 = point_shadow.slots[_e435][2u]; + tanHalf_1 = max(_e439, 0.0001f); + blocker_1 = -1f; + let _e441 = uv_3; + param_29 = _e441; + let _e442 = tile_3; + param_30 = _e442; + let _e443 = range_3; + param_31 = _e443; + let _e444 = receiver_2; + param_32 = _e444; + let _e445 = ca_2; + param_33 = _e445; + let _e446 = sa_2; + param_34 = _e446; + let _e447 = tanHalf_1; + param_35 = _e447; + let _e448 = PointShadowPenumbra_u0028_vf2_u003b_vf2_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b((¶m_29), (¶m_30), (¶m_31), (¶m_32), (¶m_33), (¶m_34), (¶m_35), (¶m_36)); + let _e449 = param_36; + blocker_1 = _e449; + radius_1 = _e448; + let _e452 = point_shadow.params2_[3u]; + if (_e452 > 0.5f) { + g_debug_surface_on = true; + let _e454 = radius_1; + if (_e454 < 0f) { + local_7 = vec3(0f, 0f, 1f); + } else { + let _e456 = radius_1; + let _e459 = point_shadow.params2_[2u]; + let _e463 = blocker_1; + let _e464 = range_3; + local_7 = vec3(clamp((_e456 / max(_e459, 0.000001f)), 0f, 1f), clamp((_e463 / _e464), 0f, 1f), 0f); } - let _e467 = local_7; - g_debug_surface = _e467; + let _e468 = local_7; + g_debug_surface = _e468; } - let _e468 = radius_1; - if (_e468 < 0f) { + let _e469 = radius_1; + if (_e469 < 0f) { return 1f; } - let _e470 = uv_3; - param_37 = _e470; + let _e471 = uv_3; + param_37 = _e471; param_38 = vec2(0f, 0f); - let _e471 = tile_3; - param_39 = _e471; - let _e472 = range_3; - param_40 = _e472; - let _e473 = receiver_2; - param_41 = _e473; - let _e474 = PointShadowTap_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b_f1_u003b((¶m_37), (¶m_38), (¶m_39), (¶m_40), (¶m_41)); - lit_1 = _e474; - let _e475 = radius_1; - if (_e475 > 0f) { + let _e472 = tile_3; + param_39 = _e472; + let _e473 = range_3; + param_40 = _e473; + let _e474 = receiver_2; + param_41 = _e474; + let _e475 = PointShadowTap_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b_f1_u003b((¶m_37), (¶m_38), (¶m_39), (¶m_40), (¶m_41)); + lit_1 = _e475; + let _e476 = radius_1; + if (_e476 > 0f) { i_3 = 0i; loop { - let _e477 = i_3; - if (_e477 < 8i) { - let _e479 = i_3; - param_42 = _e479; - let _e480 = ca_2; - param_43 = _e480; - let _e481 = sa_2; - param_44 = _e481; - let _e482 = radius_1; - param_45 = _e482; - let _e483 = PointShadowOffset_u0028_i1_u003b_f1_u003b_f1_u003b_f1_u003b((¶m_42), (¶m_43), (¶m_44), (¶m_45)); - let _e484 = uv_3; - param_46 = _e484; - param_47 = _e483; - let _e485 = tile_3; - param_48 = _e485; - let _e486 = range_3; - param_49 = _e486; - let _e487 = receiver_2; - param_50 = _e487; - let _e488 = PointShadowTap_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b_f1_u003b((¶m_46), (¶m_47), (¶m_48), (¶m_49), (¶m_50)); - let _e489 = lit_1; - lit_1 = (_e489 + _e488); + let _e478 = i_3; + if (_e478 < 8i) { + let _e480 = i_3; + param_42 = _e480; + let _e481 = ca_2; + param_43 = _e481; + let _e482 = sa_2; + param_44 = _e482; + let _e483 = radius_1; + param_45 = _e483; + let _e484 = PointShadowOffset_u0028_i1_u003b_f1_u003b_f1_u003b_f1_u003b((¶m_42), (¶m_43), (¶m_44), (¶m_45)); + let _e485 = uv_3; + param_46 = _e485; + param_47 = _e484; + let _e486 = tile_3; + param_48 = _e486; + let _e487 = range_3; + param_49 = _e487; + let _e488 = receiver_2; + param_50 = _e488; + let _e489 = PointShadowTap_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b_f1_u003b((¶m_46), (¶m_47), (¶m_48), (¶m_49), (¶m_50)); + let _e490 = lit_1; + lit_1 = (_e490 + _e489); continue; } else { break; } continuing { - let _e491 = i_3; - i_3 = (_e491 + 1i); + let _e492 = i_3; + i_3 = (_e492 + 1i); } } - let _e493 = lit_1; - lit_1 = (_e493 * 0.11111111f); + let _e494 = lit_1; + lit_1 = (_e494 * 0.11111111f); } - let _e495 = lit_1; - let _e496 = strength; - return mix(1f, _e495, clamp(_e496, 0f, 1f)); + let _e496 = lit_1; + let _e497 = strength; + return mix(1f, _e496, clamp(_e497, 0f, 1f)); } fn VogelDisc_u0028_i1_u003b_i1_u003b_f1_u003b(i_4: ptr, n_1: ptr, turn: ptr) -> vec2 { var r: f32; var theta: f32; - let _e193 = (*i_4); - let _e196 = (*n_1); - r = sqrt(((f32(_e193) + 0.5f) / f32(_e196))); - let _e200 = (*i_4); - let _e203 = (*turn); - theta = ((f32(_e200) * 2.3999631f) + _e203); - let _e205 = r; - let _e206 = theta; - let _e208 = theta; - return (vec2(cos(_e206), sin(_e208)) * _e205); + let _e194 = (*i_4); + let _e197 = (*n_1); + r = sqrt(((f32(_e194) + 0.5f) / f32(_e197))); + let _e201 = (*i_4); + let _e204 = (*turn); + theta = ((f32(_e201) * 2.3999631f) + _e204); + let _e206 = r; + let _e207 = theta; + let _e209 = theta; + return (vec2(cos(_e207), sin(_e209)) * _e206); } fn ShadowNoise_u0028_() -> f32 { var at: vec2; var param_51: f32; - let _e192 = frag_info.target_origin[0u]; - param_51 = _e192; - let _e193 = FragCoordFromTop_u0028_f1_u003b((¶m_51)); - let _e196 = frag_info.target_origin[3u]; - at = (_e193 + vec2((5.588238f * max(_e196, 0f)))); - let _e201 = at; - return fract((52.982918f * fract(dot(_e201, vec2(0.06711056f, 0.00583715f))))); + let _e193 = frag_info.target_origin[0u]; + param_51 = _e193; + let _e194 = FragCoordFromTop_u0028_f1_u003b((¶m_51)); + let _e197 = frag_info.target_origin[3u]; + at = (_e194 + vec2((5.588238f * max(_e197, 0f)))); + let _e202 = at; + return fract((52.982918f * fract(dot(_e202, vec2(0.06711056f, 0.00583715f))))); } fn EvsmChebyshev_u0028_vf2_u003b_f1_u003b_f1_u003b_f1_u003b(moments: ptr>, t: ptr, minVariance: ptr, bleed: ptr) -> f32 { @@ -24474,37 +24614,37 @@ fn EvsmChebyshev_u0028_vf2_u003b_f1_u003b_f1_u003b_f1_u003b(moments: ptr) -> vec2 { var d_2: f32; - let _e190 = (*depth); - d_2 = ((2f * clamp(_e190, 0f, 1f)) - 1f); - let _e194 = d_2; - let _e197 = d_2; - return vec2(exp((40f * _e194)), -(exp((-5f * _e197)))); + let _e191 = (*depth); + d_2 = ((2f * clamp(_e191, 0f, 1f)) - 1f); + let _e195 = d_2; + let _e198 = d_2; + return vec2(exp((40f * _e195)), -(exp((-5f * _e198)))); } fn EvsmVisibility_u0028_vf4_u003b_f1_u003b_f1_u003b(moments_1: ptr>, depth_1: ptr, bleed_1: ptr) -> f32 { @@ -24522,37 +24662,37 @@ fn EvsmVisibility_u0028_vf4_u003b_f1_u003b_f1_u003b(moments_1: ptr(0.004f, 0.0005f) * _e206); - let _e209 = scale[0u]; - let _e211 = scale[0u]; - let _e213 = (*moments_1); - param_53 = _e213.xy; - let _e216 = warped[0u]; - param_54 = _e216; - param_55 = (_e209 * _e211); - let _e217 = (*bleed_1); - param_56 = _e217; - let _e218 = EvsmChebyshev_u0028_vf2_u003b_f1_u003b_f1_u003b_f1_u003b((¶m_53), (¶m_54), (¶m_55), (¶m_56)); - positive = _e218; - let _e220 = scale[1u]; - let _e222 = scale[1u]; - let _e224 = (*moments_1); - param_57 = _e224.zw; - let _e227 = warped[1u]; - param_58 = _e227; - param_59 = (_e220 * _e222); - let _e228 = (*bleed_1); - param_60 = _e228; - let _e229 = EvsmChebyshev_u0028_vf2_u003b_f1_u003b_f1_u003b_f1_u003b((¶m_57), (¶m_58), (¶m_59), (¶m_60)); - negative = _e229; - let _e230 = positive; - let _e231 = negative; - return min(_e230, _e231); + let _e205 = (*depth_1); + param_52 = _e205; + let _e206 = EvsmWarp_u0028_f1_u003b((¶m_52)); + warped = _e206; + let _e207 = warped; + scale = (vec2(0.004f, 0.0005f) * _e207); + let _e210 = scale[0u]; + let _e212 = scale[0u]; + let _e214 = (*moments_1); + param_53 = _e214.xy; + let _e217 = warped[0u]; + param_54 = _e217; + param_55 = (_e210 * _e212); + let _e218 = (*bleed_1); + param_56 = _e218; + let _e219 = EvsmChebyshev_u0028_vf2_u003b_f1_u003b_f1_u003b_f1_u003b((¶m_53), (¶m_54), (¶m_55), (¶m_56)); + positive = _e219; + let _e221 = scale[1u]; + let _e223 = scale[1u]; + let _e225 = (*moments_1); + param_57 = _e225.zw; + let _e228 = warped[1u]; + param_58 = _e228; + param_59 = (_e221 * _e223); + let _e229 = (*bleed_1); + param_60 = _e229; + let _e230 = EvsmChebyshev_u0028_vf2_u003b_f1_u003b_f1_u003b_f1_u003b((¶m_57), (¶m_58), (¶m_59), (¶m_60)); + negative = _e230; + let _e231 = positive; + let _e232 = negative; + return min(_e231, _e232); } fn ShadowFactor_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_struct_u002d_LightSample_u002d_vf3_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf31_u003b_i1_u003b(s_2: ptr, light_1: ptr, lightIndex_1: ptr) -> f32 { @@ -24590,6 +24730,8 @@ fn ShadowFactor_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf var tileLo: vec2; var tileHi: vec2; var stored_2: vec4; + var y: i32; + var x: i32; var through: vec3; var softness: f32; var lit_2: f32; @@ -24597,8 +24739,8 @@ fn ShadowFactor_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf var param_61: vec4; var param_62: f32; var param_63: f32; - var y: i32; - var x: i32; + var y_1: i32; + var x_1: i32; var occluder: f32; var spread: f32; var turn_1: f32; @@ -24627,45 +24769,45 @@ fn ShadowFactor_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf var phi_3710_: bool; var phi_3717_: bool; - let _e258 = frag_info.shadow_params[3u]; - strength_1 = _e258; - let _e259 = strength_1; - if (_e259 <= 0f) { + let _e261 = frag_info.shadow_params[3u]; + strength_1 = _e261; + let _e262 = strength_1; + if (_e262 <= 0f) { return 1f; } - let _e261 = (*lightIndex_1); - let _e264 = frag_info.frame_params[2u]; - if (_e261 != i32((_e264 + 0.5f))) { + let _e264 = (*lightIndex_1); + let _e267 = frag_info.frame_params[2u]; + if (_e264 != i32((_e267 + 0.5f))) { return 1f; } - let _e270 = frag_info.shadow_cascades[2u]; - cascadeCount = i32((_e270 + 0.5f)); - let _e273 = v_world_position_1; - let _e275 = frag_info.camera_position; - viewDistance = length((_e273 - _e275.xyz)); + let _e273 = frag_info.shadow_cascades[2u]; + cascadeCount = i32((_e273 + 0.5f)); + let _e276 = v_world_position_1; + let _e278 = frag_info.camera_position; + viewDistance = length((_e276 - _e278.xyz)); cascade = 0i; - let _e279 = cascadeCount; - let _e280 = (_e279 > 1i); - phi_3531_ = _e280; - if _e280 { - let _e281 = viewDistance; - let _e284 = frag_info.shadow_cascades[0u]; - phi_3531_ = (_e281 > _e284); - } - let _e287 = phi_3531_; - if _e287 { + let _e282 = cascadeCount; + let _e283 = (_e282 > 1i); + phi_3531_ = _e283; + if _e283 { + let _e284 = viewDistance; + let _e287 = frag_info.shadow_cascades[0u]; + phi_3531_ = (_e284 > _e287); + } + let _e290 = phi_3531_; + if _e290 { cascade = 1i; } - let _e288 = cascadeCount; - let _e289 = (_e288 > 2i); - phi_3542_ = _e289; - if _e289 { - let _e290 = viewDistance; - let _e293 = frag_info.shadow_cascades[1u]; - phi_3542_ = (_e290 > _e293); + let _e291 = cascadeCount; + let _e292 = (_e291 > 2i); + phi_3542_ = _e292; + if _e292 { + let _e293 = viewDistance; + let _e296 = frag_info.shadow_cascades[1u]; + phi_3542_ = (_e293 > _e296); } - let _e296 = phi_3542_; - if _e296 { + let _e299 = phi_3542_; + if _e299 { cascade = 2i; } uv_4 = vec2(0f, 0f); @@ -24676,247 +24818,280 @@ fn ShadowFactor_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf receiverSlope = 0f; attempt = 0i; loop { - let _e297 = attempt; - if (_e297 < 3i) { - let _e299 = cascade; - let _e300 = attempt; - which = (_e299 + _e300); - let _e302 = which; - let _e303 = cascadeCount; - if (_e302 >= _e303) { + let _e300 = attempt; + if (_e300 < 3i) { + let _e302 = cascade; + let _e303 = attempt; + which = (_e302 + _e303); + let _e305 = which; + let _e306 = cascadeCount; + if (_e305 >= _e306) { break; } - let _e305 = which; - if (_e305 == 0i) { - let _e308 = frag_info.shadow_matrix; - local_8 = _e308; + let _e308 = which; + if (_e308 == 0i) { + let _e311 = frag_info.shadow_matrix; + local_8 = _e311; } else { - let _e309 = which; - if (_e309 == 1i) { - let _e312 = frag_info.shadow_matrix_far; - local_9 = _e312; + let _e312 = which; + if (_e312 == 1i) { + let _e315 = frag_info.shadow_matrix_far; + local_9 = _e315; } else { - let _e314 = frag_info.shadow_matrix_farthest; - local_9 = _e314; + let _e317 = frag_info.shadow_matrix_farthest; + local_9 = _e317; } - let _e315 = local_9; - local_8 = _e315; - } - let _e316 = local_8; - matrix = _e316; - let _e319 = matrix[0][0u]; - let _e322 = matrix[1][0u]; - let _e325 = matrix[2][0u]; - axisX = vec3(_e319, _e322, _e325); - let _e329 = matrix[0][1u]; - let _e332 = matrix[1][1u]; - let _e335 = matrix[2][1u]; - axisY = vec3(_e329, _e332, _e335); - let _e337 = axisX; - rowX = max(length(_e337), 0.000001f); - let _e340 = axisY; - rowY = max(length(_e340), 0.000001f); - let _e345 = frag_info.shadow_cascades[3u]; - let _e347 = rowX; - texelMetres = ((2f * _e345) / _e347); - let _e351 = frag_info.shadow_cascades[3u]; - let _e354 = (*s_2).n; - let _e355 = axisX; - let _e358 = rowX; - let _e359 = rowX; - let _e363 = (*s_2).n; - let _e364 = axisY; - let _e367 = rowY; - let _e368 = rowY; - reach = ((3f * _e351) * ((abs(dot(_e354, _e355)) / (_e358 * _e359)) + (abs(dot(_e363, _e364)) / (_e367 * _e368)))); - let _e375 = frag_info.shadow_params[2u]; - let _e376 = texelMetres; - flatOffset = min(_e375, _e376); - let _e378 = v_world_position_1; - let _e380 = (*s_2).n; - let _e381 = flatOffset; - let _e382 = reach; - origin_1 = (_e378 + (_e380 * (_e381 + _e382))); - let _e386 = matrix; - let _e387 = origin_1; - lightSpace = (_e386 * vec4(_e387.x, _e387.y, _e387.z, 1f)); - let _e394 = lightSpace[3u]; - if (_e394 <= 0f) { + let _e318 = local_9; + local_8 = _e318; + } + let _e319 = local_8; + matrix = _e319; + let _e322 = matrix[0][0u]; + let _e325 = matrix[1][0u]; + let _e328 = matrix[2][0u]; + axisX = vec3(_e322, _e325, _e328); + let _e332 = matrix[0][1u]; + let _e335 = matrix[1][1u]; + let _e338 = matrix[2][1u]; + axisY = vec3(_e332, _e335, _e338); + let _e340 = axisX; + rowX = max(length(_e340), 0.000001f); + let _e343 = axisY; + rowY = max(length(_e343), 0.000001f); + let _e348 = frag_info.shadow_cascades[3u]; + let _e350 = rowX; + texelMetres = ((2f * _e348) / _e350); + let _e354 = frag_info.shadow_cascades[3u]; + let _e357 = (*s_2).n; + let _e358 = axisX; + let _e361 = rowX; + let _e362 = rowX; + let _e366 = (*s_2).n; + let _e367 = axisY; + let _e370 = rowY; + let _e371 = rowY; + reach = ((3f * _e354) * ((abs(dot(_e357, _e358)) / (_e361 * _e362)) + (abs(dot(_e366, _e367)) / (_e370 * _e371)))); + let _e378 = frag_info.shadow_params[2u]; + let _e379 = texelMetres; + flatOffset = min(_e378, _e379); + let _e381 = v_world_position_1; + let _e383 = (*s_2).n; + let _e384 = flatOffset; + let _e385 = reach; + origin_1 = (_e381 + (_e383 * (_e384 + _e385))); + let _e389 = matrix; + let _e390 = origin_1; + lightSpace = (_e389 * vec4(_e390.x, _e390.y, _e390.z, 1f)); + let _e397 = lightSpace[3u]; + if (_e397 <= 0f) { continue; } - let _e396 = lightSpace; - let _e399 = lightSpace[3u]; - candidate = (_e396.xyz / vec3(_e399)); - let _e403 = candidate[0u]; - let _e407 = candidate[1u]; - inTile = vec2(((_e403 * 0.5f) + 0.5f), (0.5f - (_e407 * 0.5f))); - let _e412 = inTile[0u]; - let _e413 = (_e412 < 0f); - phi_3703_ = _e413; - if !(_e413) { - let _e416 = inTile[0u]; - phi_3703_ = (_e416 > 1f); - } - let _e419 = phi_3703_; - phi_3710_ = _e419; - if !(_e419) { - let _e422 = inTile[1u]; - phi_3710_ = (_e422 < 0f); - } - let _e425 = phi_3710_; - phi_3717_ = _e425; - if !(_e425) { - let _e428 = inTile[1u]; - phi_3717_ = (_e428 > 1f); - } - let _e431 = phi_3717_; - if _e431 { + let _e399 = lightSpace; + let _e402 = lightSpace[3u]; + candidate = (_e399.xyz / vec3(_e402)); + let _e406 = candidate[0u]; + let _e410 = candidate[1u]; + inTile = vec2(((_e406 * 0.5f) + 0.5f), (0.5f - (_e410 * 0.5f))); + let _e415 = inTile[0u]; + let _e416 = (_e415 < 0f); + phi_3703_ = _e416; + if !(_e416) { + let _e419 = inTile[0u]; + phi_3703_ = (_e419 > 1f); + } + let _e422 = phi_3703_; + phi_3710_ = _e422; + if !(_e422) { + let _e425 = inTile[1u]; + phi_3710_ = (_e425 < 0f); + } + let _e428 = phi_3710_; + phi_3717_ = _e428; + if !(_e428) { + let _e431 = inTile[1u]; + phi_3717_ = (_e431 > 1f); + } + let _e434 = phi_3717_; + if _e434 { continue; } - let _e433 = candidate[2u]; - if (_e433 > 1f) { - let _e435 = which; - let _e436 = cascadeCount; - if (_e435 < (_e436 - 1i)) { + let _e436 = candidate[2u]; + if (_e436 > 1f) { + let _e438 = which; + let _e439 = cascadeCount; + if (_e438 < (_e439 - 1i)) { continue; } candidate[2u] = 1f; } - let _e441 = inTile[0u]; - let _e442 = which; - let _e445 = cascadeCount; - let _e449 = inTile[1u]; - uv_4 = vec2(((_e441 + f32(_e442)) / f32(_e445)), _e449); - let _e451 = candidate; - projected = _e451; - let _e452 = which; - cascade = _e452; - let _e453 = texelMetres; - cascadeTexel = _e453; - let _e456 = matrix[0][2u]; - let _e459 = matrix[1][2u]; - let _e462 = matrix[2][2u]; - cascadeDepth = (1f / max(length(vec3(_e456, _e459, _e462)), 0.000001f)); - let _e468 = (*s_2).n; - let _e471 = matrix[0][2u]; - let _e474 = matrix[1][2u]; - let _e477 = matrix[2][2u]; - let _e481 = cascadeDepth; - cosSlope = clamp((abs(dot(_e468, vec3(_e471, _e474, _e477))) * _e481), 0.1f, 1f); - let _e484 = texelMetres; - let _e485 = cosSlope; - let _e486 = cosSlope; - let _e492 = cosSlope; - let _e494 = cascadeDepth; - receiverSlope = (((_e484 * sqrt(max((1f - (_e485 * _e486)), 0f))) / _e492) / _e494); + let _e444 = inTile[0u]; + let _e445 = which; + let _e448 = cascadeCount; + let _e452 = inTile[1u]; + uv_4 = vec2(((_e444 + f32(_e445)) / f32(_e448)), _e452); + let _e454 = candidate; + projected = _e454; + let _e455 = which; + cascade = _e455; + let _e456 = texelMetres; + cascadeTexel = _e456; + let _e459 = matrix[0][2u]; + let _e462 = matrix[1][2u]; + let _e465 = matrix[2][2u]; + cascadeDepth = (1f / max(length(vec3(_e459, _e462, _e465)), 0.000001f)); + let _e471 = (*s_2).n; + let _e474 = matrix[0][2u]; + let _e477 = matrix[1][2u]; + let _e480 = matrix[2][2u]; + let _e484 = cascadeDepth; + cosSlope = clamp((abs(dot(_e471, vec3(_e474, _e477, _e480))) * _e484), 0.1f, 1f); + let _e487 = texelMetres; + let _e488 = cosSlope; + let _e489 = cosSlope; + let _e495 = cosSlope; + let _e497 = cascadeDepth; + receiverSlope = (((_e487 * sqrt(max((1f - (_e488 * _e489)), 0f))) / _e495) / _e497); found = true; break; } else { break; } continuing { - let _e496 = attempt; - attempt = (_e496 + 1i); + let _e499 = attempt; + attempt = (_e499 + 1i); } } - let _e498 = found; - if !(_e498) { + let _e501 = found; + if !(_e501) { return 1f; } - let _e500 = cascade; - if (_e500 == 0i) { - let _e504 = frag_info.shadow_bias[0u]; - local_10 = _e504; + let _e503 = cascade; + if (_e503 == 0i) { + let _e507 = frag_info.shadow_bias[0u]; + local_10 = _e507; } else { - let _e505 = cascade; - if (_e505 == 1i) { - let _e509 = frag_info.shadow_bias[1u]; - local_11 = _e509; - } else { - let _e512 = frag_info.shadow_bias[2u]; + let _e508 = cascade; + if (_e508 == 1i) { + let _e512 = frag_info.shadow_bias[1u]; local_11 = _e512; - } - let _e513 = local_11; - local_10 = _e513; - } - let _e514 = local_10; - bias = _e514; - let _e517 = frag_info.shadow_params[0u]; - let _e520 = frag_info.shadow_cascades[3u]; - texel_1 = vec2(_e517, _e520); - let _e522 = cascade; - let _e524 = cascadeCount; - let _e528 = texel_1; - tileLo = (vec2((f32(_e522) / f32(_e524)), 0f) + (_e528 * 0.5f)); - let _e531 = cascade; - let _e534 = cascadeCount; - let _e538 = texel_1; - tileHi = (vec2((f32((_e531 + 1i)) / f32(_e534)), 1f) - (_e538 * 0.5f)); - let _e543 = frag_info.shadow_bias[3u]; - if (_e543 > 0.5f) { - let _e545 = uv_4; - let _e546 = tileLo; - let _e547 = tileHi; - let _e549 = textureSampleLevel(shadow_texture_tex, shadow_texture_smp, clamp(_e545, _e546, _e547), 0f); - stored_2 = _e549; - let _e551 = stored_2[1u]; - let _e554 = stored_2[2u]; - let _e557 = stored_2[3u]; - through = clamp(vec3((1f - _e551), (1f - _e554), _e557), vec3(0f), vec3(4f)); - let _e562 = through; - let _e563 = strength_1; - light_transmittance = mix(vec3(1f, 1f, 1f), _e562, vec3(clamp(_e563, 0f, 1f))); - } - let _e569 = frag_info.ambient_ground[3u]; - softness = _e569; + } else { + let _e515 = frag_info.shadow_bias[2u]; + local_11 = _e515; + } + let _e516 = local_11; + local_10 = _e516; + } + let _e517 = local_10; + bias = _e517; + let _e520 = frag_info.shadow_params[0u]; + let _e523 = frag_info.shadow_cascades[3u]; + texel_1 = vec2(_e520, _e523); + let _e525 = cascade; + let _e527 = cascadeCount; + let _e531 = texel_1; + tileLo = (vec2((f32(_e525) / f32(_e527)), 0f) + (_e531 * 0.5f)); + let _e534 = cascade; + let _e537 = cascadeCount; + let _e541 = texel_1; + tileHi = (vec2((f32((_e534 + 1i)) / f32(_e537)), 1f) - (_e541 * 0.5f)); + let _e546 = frag_info.shadow_bias[3u]; + if (_e546 > 0.5f) { + stored_2 = vec4(0f, 0f, 0f, 0f); + y = -1i; + loop { + let _e548 = y; + if (_e548 <= 1i) { + x = -1i; + loop { + let _e550 = x; + if (_e550 <= 1i) { + let _e552 = uv_4; + let _e553 = x; + let _e555 = y; + let _e558 = texel_1; + let _e561 = tileLo; + let _e562 = tileHi; + let _e564 = textureSampleLevel(shadow_texture_tex, shadow_texture_smp, clamp((_e552 + (vec2(f32(_e553), f32(_e555)) * _e558)), _e561, _e562), 0f); + let _e565 = stored_2; + stored_2 = (_e565 + _e564); + continue; + } else { + break; + } + continuing { + let _e567 = x; + x = (_e567 + 1i); + } + } + continue; + } else { + break; + } + continuing { + let _e569 = y; + y = (_e569 + 1i); + } + } + let _e571 = stored_2; + stored_2 = (_e571 * 0.11111111f); + let _e574 = stored_2[1u]; + let _e577 = stored_2[2u]; + let _e580 = stored_2[3u]; + through = clamp(vec3((1f - _e574), (1f - _e577), _e580), vec3(0f), vec3(4f)); + let _e585 = through; + let _e586 = strength_1; + light_transmittance = mix(vec3(1f, 1f, 1f), _e585, vec3(clamp(_e586, 0f, 1f))); + } + let _e592 = frag_info.ambient_ground[3u]; + softness = _e592; lit_2 = 0f; - let _e570 = softness; - if (_e570 < 0f) { - let _e572 = uv_4; - let _e573 = tileLo; - let _e574 = tileHi; - let _e576 = textureSampleLevel(shadow_texture_tex, shadow_texture_smp, clamp(_e572, _e573, _e574), 0f); - moments_2 = _e576; - let _e578 = projected[2u]; - let _e579 = bias; - let _e581 = softness; - let _e585 = moments_2; - param_61 = _e585; - param_62 = (_e578 - _e579); - param_63 = clamp((-(_e581) - 1f), 0f, 0.95f); - let _e586 = EvsmVisibility_u0028_vf4_u003b_f1_u003b_f1_u003b((¶m_61), (¶m_62), (¶m_63)); - lit_2 = _e586; - } else { - let _e587 = softness; - if (_e587 <= 0f) { - y = -1i; + let _e593 = softness; + if (_e593 < 0f) { + let _e595 = uv_4; + let _e596 = tileLo; + let _e597 = tileHi; + let _e599 = textureSampleLevel(shadow_texture_tex, shadow_texture_smp, clamp(_e595, _e596, _e597), 0f); + moments_2 = _e599; + let _e601 = projected[2u]; + let _e602 = bias; + let _e604 = softness; + let _e608 = moments_2; + param_61 = _e608; + param_62 = (_e601 - _e602); + param_63 = clamp((-(_e604) - 1f), 0f, 0.95f); + let _e609 = EvsmVisibility_u0028_vf4_u003b_f1_u003b_f1_u003b((¶m_61), (¶m_62), (¶m_63)); + lit_2 = _e609; + } else { + let _e610 = softness; + if (_e610 <= 0f) { + y_1 = -1i; loop { - let _e589 = y; - if (_e589 <= 1i) { - x = -1i; + let _e612 = y_1; + if (_e612 <= 1i) { + x_1 = -1i; loop { - let _e591 = x; - if (_e591 <= 1i) { - let _e593 = uv_4; - let _e594 = x; - let _e596 = y; - let _e599 = texel_1; - let _e602 = tileLo; - let _e603 = tileHi; - let _e605 = textureSampleLevel(shadow_texture_tex, shadow_texture_smp, clamp((_e593 + (vec2(f32(_e594), f32(_e596)) * _e599)), _e602, _e603), 0f); - occluder = _e605.x; - let _e608 = projected[2u]; - let _e609 = bias; - let _e611 = occluder; - let _e614 = lit_2; - lit_2 = (_e614 + select(1f, 0f, ((_e608 - _e609) > _e611))); + let _e614 = x_1; + if (_e614 <= 1i) { + let _e616 = uv_4; + let _e617 = x_1; + let _e619 = y_1; + let _e622 = texel_1; + let _e625 = tileLo; + let _e626 = tileHi; + let _e628 = textureSampleLevel(shadow_texture_tex, shadow_texture_smp, clamp((_e616 + (vec2(f32(_e617), f32(_e619)) * _e622)), _e625, _e626), 0f); + occluder = _e628.x; + let _e631 = projected[2u]; + let _e632 = bias; + let _e634 = occluder; + let _e637 = lit_2; + lit_2 = (_e637 + select(1f, 0f, ((_e631 - _e632) > _e634))); continue; } else { break; } continuing { - let _e616 = x; - x = (_e616 + 1i); + let _e639 = x_1; + x_1 = (_e639 + 1i); } } continue; @@ -24924,125 +25099,125 @@ fn ShadowFactor_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf break; } continuing { - let _e618 = y; - y = (_e618 + 1i); + let _e641 = y_1; + y_1 = (_e641 + 1i); } } - let _e620 = lit_2; - lit_2 = (_e620 * 0.11111111f); + let _e643 = lit_2; + lit_2 = (_e643 * 0.11111111f); } else { - let _e622 = softness; - spread = tan(min(_e622, 0.5f)); - let _e625 = ShadowNoise_u0028_(); - turn_1 = (_e625 * 6.2831855f); - let _e627 = spread; - let _e629 = projected[2u]; - let _e631 = cascadeDepth; - let _e633 = cascadeTexel; - searchRadius = clamp((((_e627 * _e629) * _e631) / _e633), 1f, 16f); + let _e645 = softness; + spread = tan(min(_e645, 0.5f)); + let _e648 = ShadowNoise_u0028_(); + turn_1 = (_e648 * 6.2831855f); + let _e650 = spread; + let _e652 = projected[2u]; + let _e654 = cascadeDepth; + let _e656 = cascadeTexel; + searchRadius = clamp((((_e650 * _e652) * _e654) / _e656), 1f, 16f); blockerSum = 0f; blockerCount = 0f; i_5 = 0i; loop { - let _e636 = i_5; - if (_e636 < 16i) { - let _e638 = i_5; - param_64 = _e638; + let _e659 = i_5; + if (_e659 < 16i) { + let _e661 = i_5; + param_64 = _e661; param_65 = 16i; - let _e639 = turn_1; - param_66 = _e639; - let _e640 = VogelDisc_u0028_i1_u003b_i1_u003b_f1_u003b((¶m_64), (¶m_65), (¶m_66)); - disc = _e640; - let _e641 = bias; - let _e642 = disc; - let _e644 = searchRadius; - let _e648 = receiverSlope; - tapBias = (_e641 + (max(((length(_e642) * _e644) - 1.5f), 0f) * _e648)); - let _e651 = uv_4; - let _e652 = disc; - let _e653 = texel_1; - let _e655 = searchRadius; - let _e658 = tileLo; - let _e659 = tileHi; - let _e661 = textureSampleLevel(shadow_texture_tex, shadow_texture_smp, clamp((_e651 + ((_e652 * _e653) * _e655)), _e658, _e659), 0f); - occluder_1 = _e661.x; - let _e664 = projected[2u]; - let _e665 = tapBias; - let _e667 = occluder_1; - if ((_e664 - _e665) > _e667) { - let _e669 = occluder_1; - let _e670 = blockerSum; - blockerSum = (_e670 + _e669); - let _e672 = blockerCount; - blockerCount = (_e672 + 1f); + let _e662 = turn_1; + param_66 = _e662; + let _e663 = VogelDisc_u0028_i1_u003b_i1_u003b_f1_u003b((¶m_64), (¶m_65), (¶m_66)); + disc = _e663; + let _e664 = bias; + let _e665 = disc; + let _e667 = searchRadius; + let _e671 = receiverSlope; + tapBias = (_e664 + (max(((length(_e665) * _e667) - 1.5f), 0f) * _e671)); + let _e674 = uv_4; + let _e675 = disc; + let _e676 = texel_1; + let _e678 = searchRadius; + let _e681 = tileLo; + let _e682 = tileHi; + let _e684 = textureSampleLevel(shadow_texture_tex, shadow_texture_smp, clamp((_e674 + ((_e675 * _e676) * _e678)), _e681, _e682), 0f); + occluder_1 = _e684.x; + let _e687 = projected[2u]; + let _e688 = tapBias; + let _e690 = occluder_1; + if ((_e687 - _e688) > _e690) { + let _e692 = occluder_1; + let _e693 = blockerSum; + blockerSum = (_e693 + _e692); + let _e695 = blockerCount; + blockerCount = (_e695 + 1f); } continue; } else { break; } continuing { - let _e674 = i_5; - i_5 = (_e674 + 1i); + let _e697 = i_5; + i_5 = (_e697 + 1i); } } - let _e676 = blockerCount; - if (_e676 <= 0f) { + let _e699 = blockerCount; + if (_e699 <= 0f) { return 1f; } - let _e679 = projected[2u]; - let _e680 = blockerSum; - let _e681 = blockerCount; - let _e685 = cascadeDepth; - gap = (max((_e679 - (_e680 / _e681)), 0f) * _e685); - let _e687 = spread; - let _e688 = gap; - let _e690 = cascadeTexel; - radius_2 = clamp(((_e687 * _e688) / _e690), 1f, 16f); + let _e702 = projected[2u]; + let _e703 = blockerSum; + let _e704 = blockerCount; + let _e708 = cascadeDepth; + gap = (max((_e702 - (_e703 / _e704)), 0f) * _e708); + let _e710 = spread; + let _e711 = gap; + let _e713 = cascadeTexel; + radius_2 = clamp(((_e710 * _e711) / _e713), 1f, 16f); i_6 = 0i; loop { - let _e693 = i_6; - if (_e693 < 16i) { - let _e695 = turn_1; - let _e697 = i_6; - param_67 = _e697; + let _e716 = i_6; + if (_e716 < 16i) { + let _e718 = turn_1; + let _e720 = i_6; + param_67 = _e720; param_68 = 16i; - param_69 = (_e695 + 1f); - let _e698 = VogelDisc_u0028_i1_u003b_i1_u003b_f1_u003b((¶m_67), (¶m_68), (¶m_69)); - disc_1 = _e698; - let _e699 = bias; - let _e700 = disc_1; - let _e702 = radius_2; - let _e706 = receiverSlope; - tapBias_1 = (_e699 + (max(((length(_e700) * _e702) - 1.5f), 0f) * _e706)); - let _e709 = uv_4; - let _e710 = disc_1; - let _e711 = texel_1; - let _e713 = radius_2; - let _e716 = tileLo; - let _e717 = tileHi; - let _e719 = textureSampleLevel(shadow_texture_tex, shadow_texture_smp, clamp((_e709 + ((_e710 * _e711) * _e713)), _e716, _e717), 0f); - occluder_2 = _e719.x; - let _e722 = projected[2u]; - let _e723 = tapBias_1; - let _e725 = occluder_2; - let _e728 = lit_2; - lit_2 = (_e728 + select(1f, 0f, ((_e722 - _e723) > _e725))); + param_69 = (_e718 + 1f); + let _e721 = VogelDisc_u0028_i1_u003b_i1_u003b_f1_u003b((¶m_67), (¶m_68), (¶m_69)); + disc_1 = _e721; + let _e722 = bias; + let _e723 = disc_1; + let _e725 = radius_2; + let _e729 = receiverSlope; + tapBias_1 = (_e722 + (max(((length(_e723) * _e725) - 1.5f), 0f) * _e729)); + let _e732 = uv_4; + let _e733 = disc_1; + let _e734 = texel_1; + let _e736 = radius_2; + let _e739 = tileLo; + let _e740 = tileHi; + let _e742 = textureSampleLevel(shadow_texture_tex, shadow_texture_smp, clamp((_e732 + ((_e733 * _e734) * _e736)), _e739, _e740), 0f); + occluder_2 = _e742.x; + let _e745 = projected[2u]; + let _e746 = tapBias_1; + let _e748 = occluder_2; + let _e751 = lit_2; + lit_2 = (_e751 + select(1f, 0f, ((_e745 - _e746) > _e748))); continue; } else { break; } continuing { - let _e730 = i_6; - i_6 = (_e730 + 1i); + let _e753 = i_6; + i_6 = (_e753 + 1i); } } - let _e732 = lit_2; - lit_2 = (_e732 * 0.0625f); + let _e755 = lit_2; + lit_2 = (_e755 * 0.0625f); } } - let _e734 = lit_2; - let _e735 = strength_1; - return mix(1f, _e734, clamp(_e735, 0f, 1f)); + let _e757 = lit_2; + let _e758 = strength_1; + return mix(1f, _e757, clamp(_e758, 0f, 1f)); } fn LightVisibility_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_struct_u002d_LightSample_u002d_vf3_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf31_u003b_i1_u003b(s_3: ptr, light_2: ptr, index: ptr) -> f32 { @@ -25050,19 +25225,19 @@ fn LightVisibility_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d var param_71: LightSample; var param_72: i32; - let _e194 = (*s_3); - param_70 = _e194; - let _e195 = (*light_2); - param_71 = _e195; - let _e196 = (*index); - param_72 = _e196; - let _e197 = ShadowFactor_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_struct_u002d_LightSample_u002d_vf3_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf31_u003b_i1_u003b((¶m_70), (¶m_71), (¶m_72)); - return _e197; + let _e195 = (*s_3); + param_70 = _e195; + let _e196 = (*light_2); + param_71 = _e196; + let _e197 = (*index); + param_72 = _e197; + let _e198 = ShadowFactor_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_struct_u002d_LightSample_u002d_vf3_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf31_u003b_i1_u003b((¶m_70), (¶m_71), (¶m_72)); + return _e198; } fn LightHasShadow_u0028_i1_u003b(index_1: ptr) -> bool { - let _e189 = (*index_1); - return (_e189 < 8i); + let _e190 = (*index_1); + return (_e190 < 8i); } fn PunctualAttenuation_u0028_f1_u003b_f1_u003b(distance_1: ptr, range_4: ptr) -> f32 { @@ -25070,111 +25245,111 @@ fn PunctualAttenuation_u0028_f1_u003b_f1_u003b(distance_1: ptr, r var ratio: f32; var window: f32; - let _e193 = (*distance_1); let _e194 = (*distance_1); - attenuation = (1f / max((_e193 * _e194), 0.0001f)); - let _e198 = (*range_4); - if (_e198 > 0f) { - let _e200 = (*distance_1); - let _e201 = (*range_4); - ratio = (_e200 / _e201); - let _e203 = ratio; + let _e195 = (*distance_1); + attenuation = (1f / max((_e194 * _e195), 0.0001f)); + let _e199 = (*range_4); + if (_e199 > 0f) { + let _e201 = (*distance_1); + let _e202 = (*range_4); + ratio = (_e201 / _e202); let _e204 = ratio; - let _e206 = ratio; - let _e208 = ratio; - window = clamp((1f - (((_e203 * _e204) * _e206) * _e208)), 0f, 1f); - let _e212 = window; - let _e213 = window; - let _e215 = attenuation; - attenuation = (_e215 * (_e212 * _e213)); - } - let _e217 = attenuation; - return _e217; -} - -fn RectangleClosestPoint_u0028_vf3_u003b_vf3_u003b_vf3_u003b_vf3_u003b_vf3_u003b(centre: ptr>, halfWidth: ptr>, halfHeight: ptr>, world_2: ptr>, mirror: ptr>) -> vec3 { - var n_2: vec3; - var nLen: f32; - var toPlane: vec3; - var denom: f32; - var onPlane: vec3; - var t_1: f32; - var local_12: vec3; - var offset_2: vec3; - var wLen2_: f32; - var hLen2_: f32; - var u: f32; - var v: f32; - - let _e205 = (*halfWidth); - let _e206 = (*halfHeight); - n_2 = cross(_e205, _e206); - let _e208 = n_2; - nLen = length(_e208); - let _e210 = nLen; - if (_e210 < 0.000000000001f) { - let _e212 = (*centre); - return _e212; - } - let _e213 = nLen; - let _e214 = n_2; - n_2 = (_e214 / vec3(_e213)); - let _e217 = (*centre); - let _e218 = (*world_2); - toPlane = (_e217 - _e218); - let _e220 = (*mirror); - let _e221 = n_2; - denom = dot(_e220, _e221); - let _e223 = denom; - if (abs(_e223) < 0.00001f) { - let _e226 = toPlane; - let _e227 = n_2; - let _e228 = toPlane; - let _e229 = n_2; - onPlane = (_e226 - (_e227 * dot(_e228, _e229))); - } else { - let _e233 = toPlane; - let _e234 = n_2; - let _e236 = denom; - t_1 = (dot(_e233, _e234) / _e236); - let _e238 = t_1; - if (_e238 > 0f) { - let _e240 = (*mirror); - let _e241 = t_1; - local_12 = (_e240 * _e241); + let _e205 = ratio; + let _e207 = ratio; + let _e209 = ratio; + window = clamp((1f - (((_e204 * _e205) * _e207) * _e209)), 0f, 1f); + let _e213 = window; + let _e214 = window; + let _e216 = attenuation; + attenuation = (_e216 * (_e213 * _e214)); + } + let _e218 = attenuation; + return _e218; +} + +fn RectangleClosestPoint_u0028_vf3_u003b_vf3_u003b_vf3_u003b_vf3_u003b_vf3_u003b(centre: ptr>, halfWidth: ptr>, halfHeight: ptr>, world_2: ptr>, mirror: ptr>) -> vec3 { + var n_2: vec3; + var nLen: f32; + var toPlane: vec3; + var denom: f32; + var onPlane: vec3; + var t_1: f32; + var local_12: vec3; + var offset_2: vec3; + var wLen2_: f32; + var hLen2_: f32; + var u: f32; + var v: f32; + + let _e206 = (*halfWidth); + let _e207 = (*halfHeight); + n_2 = cross(_e206, _e207); + let _e209 = n_2; + nLen = length(_e209); + let _e211 = nLen; + if (_e211 < 0.000000000001f) { + let _e213 = (*centre); + return _e213; + } + let _e214 = nLen; + let _e215 = n_2; + n_2 = (_e215 / vec3(_e214)); + let _e218 = (*centre); + let _e219 = (*world_2); + toPlane = (_e218 - _e219); + let _e221 = (*mirror); + let _e222 = n_2; + denom = dot(_e221, _e222); + let _e224 = denom; + if (abs(_e224) < 0.00001f) { + let _e227 = toPlane; + let _e228 = n_2; + let _e229 = toPlane; + let _e230 = n_2; + onPlane = (_e227 - (_e228 * dot(_e229, _e230))); + } else { + let _e234 = toPlane; + let _e235 = n_2; + let _e237 = denom; + t_1 = (dot(_e234, _e235) / _e237); + let _e239 = t_1; + if (_e239 > 0f) { + let _e241 = (*mirror); + let _e242 = t_1; + local_12 = (_e241 * _e242); } else { - let _e243 = toPlane; - let _e244 = n_2; - let _e245 = toPlane; - let _e246 = n_2; - local_12 = (_e243 - (_e244 * dot(_e245, _e246))); + let _e244 = toPlane; + let _e245 = n_2; + let _e246 = toPlane; + let _e247 = n_2; + local_12 = (_e244 - (_e245 * dot(_e246, _e247))); } - let _e250 = local_12; - onPlane = _e250; + let _e251 = local_12; + onPlane = _e251; } - let _e251 = onPlane; - let _e252 = toPlane; - offset_2 = (_e251 - _e252); - let _e254 = (*halfWidth); + let _e252 = onPlane; + let _e253 = toPlane; + offset_2 = (_e252 - _e253); let _e255 = (*halfWidth); - wLen2_ = max(dot(_e254, _e255), 0.000000000001f); - let _e258 = (*halfHeight); + let _e256 = (*halfWidth); + wLen2_ = max(dot(_e255, _e256), 0.000000000001f); let _e259 = (*halfHeight); - hLen2_ = max(dot(_e258, _e259), 0.000000000001f); - let _e262 = offset_2; - let _e263 = (*halfWidth); - let _e265 = wLen2_; - u = clamp((dot(_e262, _e263) / _e265), -1f, 1f); - let _e268 = offset_2; - let _e269 = (*halfHeight); - let _e271 = hLen2_; - v = clamp((dot(_e268, _e269) / _e271), -1f, 1f); - let _e274 = (*centre); - let _e275 = (*halfWidth); - let _e276 = u; - let _e279 = (*halfHeight); - let _e280 = v; - return ((_e274 + (_e275 * _e276)) + (_e279 * _e280)); + let _e260 = (*halfHeight); + hLen2_ = max(dot(_e259, _e260), 0.000000000001f); + let _e263 = offset_2; + let _e264 = (*halfWidth); + let _e266 = wLen2_; + u = clamp((dot(_e263, _e264) / _e266), -1f, 1f); + let _e269 = offset_2; + let _e270 = (*halfHeight); + let _e272 = hLen2_; + v = clamp((dot(_e269, _e270) / _e272), -1f, 1f); + let _e275 = (*centre); + let _e276 = (*halfWidth); + let _e277 = u; + let _e280 = (*halfHeight); + let _e281 = v; + return ((_e275 + (_e276 * _e277)) + (_e280 * _e281)); } fn LambertEdge_u0028_vf3_u003b_vf3_u003b_vf3_u003b(a_1: ptr>, b: ptr>, n_3: ptr>) -> f32 { @@ -25185,32 +25360,32 @@ fn LambertEdge_u0028_vf3_u003b_vf3_u003b_vf3_u003b(a_1: ptr> var len: f32; var local_13: f32; - let _e197 = (*a_1); let _e198 = (*a_1); - ua = (_e197 / vec3(max(length(_e198), 0.000000000001f))); - let _e203 = (*b); + let _e199 = (*a_1); + ua = (_e198 / vec3(max(length(_e199), 0.000000000001f))); let _e204 = (*b); - ub = (_e203 / vec3(max(length(_e204), 0.000000000001f))); - let _e209 = ua; - let _e210 = ub; - angle_1 = acos(clamp(dot(_e209, _e210), -1f, 1f)); - let _e214 = ua; - let _e215 = ub; - axis = cross(_e214, _e215); - let _e217 = axis; - len = length(_e217); - let _e219 = len; - if (_e219 > 0.000001f) { - let _e221 = angle_1; - let _e222 = axis; - let _e223 = (*n_3); - let _e226 = len; - local_13 = ((_e221 * dot(_e222, _e223)) / _e226); + let _e205 = (*b); + ub = (_e204 / vec3(max(length(_e205), 0.000000000001f))); + let _e210 = ua; + let _e211 = ub; + angle_1 = acos(clamp(dot(_e210, _e211), -1f, 1f)); + let _e215 = ua; + let _e216 = ub; + axis = cross(_e215, _e216); + let _e218 = axis; + len = length(_e218); + let _e220 = len; + if (_e220 > 0.000001f) { + let _e222 = angle_1; + let _e223 = axis; + let _e224 = (*n_3); + let _e227 = len; + local_13 = ((_e222 * dot(_e223, _e224)) / _e227); } else { local_13 = 0f; } - let _e228 = local_13; - return _e228; + let _e229 = local_13; + return _e229; } fn RectangleFormFactor_u0028_vf3_u005b_4_u005d_u003b_vf3_u003b(corners: ptr, 4>>, n_4: ptr>) -> f32 { @@ -25241,98 +25416,98 @@ fn RectangleFormFactor_u0028_vf3_u005b_4_u005d_u003b_vf3_u003b(corners: ptr(0f, 0f, 0f); i_7 = 0i; loop { - let _e211 = i_7; - if (_e211 < 4i) { - let _e213 = i_7; - let _e215 = (*corners)[_e213]; - a_2 = _e215; - let _e216 = i_7; - if (_e216 == 3i) { + let _e212 = i_7; + if (_e212 < 4i) { + let _e214 = i_7; + let _e216 = (*corners)[_e214]; + a_2 = _e216; + let _e217 = i_7; + if (_e217 == 3i) { local_14 = 0i; } else { - let _e218 = i_7; - local_14 = (_e218 + 1i); + let _e219 = i_7; + local_14 = (_e219 + 1i); } - let _e220 = local_14; - let _e222 = (*corners)[_e220]; - b_1 = _e222; - let _e223 = a_2; - let _e224 = (*n_4); - ha = dot(_e223, _e224); - let _e226 = b_1; - let _e227 = (*n_4); - hb = dot(_e226, _e227); - let _e229 = ha; - let _e230 = hb; - d_3 = (_e229 - _e230); - let _e232 = a_2; - let _e233 = b_1; - let _e234 = a_2; - let _e236 = d_3; - if (abs(_e236) > 0.000000000001f) { - let _e239 = ha; - let _e240 = d_3; - local_15 = (_e239 / _e240); + let _e221 = local_14; + let _e223 = (*corners)[_e221]; + b_1 = _e223; + let _e224 = a_2; + let _e225 = (*n_4); + ha = dot(_e224, _e225); + let _e227 = b_1; + let _e228 = (*n_4); + hb = dot(_e227, _e228); + let _e230 = ha; + let _e231 = hb; + d_3 = (_e230 - _e231); + let _e233 = a_2; + let _e234 = b_1; + let _e235 = a_2; + let _e237 = d_3; + if (abs(_e237) > 0.000000000001f) { + let _e240 = ha; + let _e241 = d_3; + local_15 = (_e240 / _e241); } else { local_15 = 0f; } - let _e242 = local_15; - q = (_e232 + ((_e233 - _e234) * _e242)); - let _e245 = ha; - aAbove = (_e245 > 0f); - let _e247 = hb; - bAbove = (_e247 > 0f); - let _e249 = aAbove; - let _e250 = bAbove; - if (_e249 || _e250) { - let _e252 = aAbove; - let _e253 = a_2; - let _e254 = q; - let _e257 = bAbove; - let _e258 = b_1; - let _e259 = q; - param_73 = select(_e254, _e253, vec3(_e252)); - param_74 = select(_e259, _e258, vec3(_e257)); - let _e262 = (*n_4); - param_75 = _e262; - let _e263 = LambertEdge_u0028_vf3_u003b_vf3_u003b_vf3_u003b((¶m_73), (¶m_74), (¶m_75)); - local_16 = _e263; + let _e243 = local_15; + q = (_e233 + ((_e234 - _e235) * _e243)); + let _e246 = ha; + aAbove = (_e246 > 0f); + let _e248 = hb; + bAbove = (_e248 > 0f); + let _e250 = aAbove; + let _e251 = bAbove; + if (_e250 || _e251) { + let _e253 = aAbove; + let _e254 = a_2; + let _e255 = q; + let _e258 = bAbove; + let _e259 = b_1; + let _e260 = q; + param_73 = select(_e255, _e254, vec3(_e253)); + param_74 = select(_e260, _e259, vec3(_e258)); + let _e263 = (*n_4); + param_75 = _e263; + let _e264 = LambertEdge_u0028_vf3_u003b_vf3_u003b_vf3_u003b((¶m_73), (¶m_74), (¶m_75)); + local_16 = _e264; } else { local_16 = 0f; } - let _e264 = local_16; - let _e265 = total; - total = (_e265 + _e264); - let _e267 = aAbove; - let _e268 = bAbove; - let _e271 = q; - let _e272 = exit; - exit = select(_e272, _e271, vec3((_e267 && !(_e268)))); - let _e275 = aAbove; - let _e277 = bAbove; - let _e279 = q; - let _e280 = entry; - entry = select(_e280, _e279, vec3((!(_e275) && _e277))); + let _e265 = local_16; + let _e266 = total; + total = (_e266 + _e265); + let _e268 = aAbove; + let _e269 = bAbove; + let _e272 = q; + let _e273 = exit; + exit = select(_e273, _e272, vec3((_e268 && !(_e269)))); + let _e276 = aAbove; + let _e278 = bAbove; + let _e280 = q; + let _e281 = entry; + entry = select(_e281, _e280, vec3((!(_e276) && _e278))); continue; } else { break; } continuing { - let _e283 = i_7; - i_7 = (_e283 + 1i); + let _e284 = i_7; + i_7 = (_e284 + 1i); } } - let _e285 = exit; - param_76 = _e285; - let _e286 = entry; - param_77 = _e286; - let _e287 = (*n_4); - param_78 = _e287; - let _e288 = LambertEdge_u0028_vf3_u003b_vf3_u003b_vf3_u003b((¶m_76), (¶m_77), (¶m_78)); - let _e289 = total; - total = (_e289 + _e288); - let _e291 = total; - return max((-(_e291) * 0.5f), 0f); + let _e286 = exit; + param_76 = _e286; + let _e287 = entry; + param_77 = _e287; + let _e288 = (*n_4); + param_78 = _e288; + let _e289 = LambertEdge_u0028_vf3_u003b_vf3_u003b_vf3_u003b((¶m_76), (¶m_77), (¶m_78)); + let _e290 = total; + total = (_e290 + _e289); + let _e292 = total; + return max((-(_e292) * 0.5f), 0f); } fn LightListLane_u0028_vf4_u003b_i1_u003b(four: ptr>, slot_1: ptr) -> f32 { @@ -25341,133 +25516,133 @@ fn LightListLane_u0028_vf4_u003b_i1_u003b(four: ptr>, slot_1 var local_18: f32; var local_19: f32; - let _e194 = (*slot_1); let _e195 = (*slot_1); - lane = (_e194 - ((_e195 / 4i) * 4i)); - let _e199 = lane; - if (_e199 == 0i) { - let _e202 = (*four)[0u]; - local_17 = _e202; - } else { - let _e203 = lane; - if (_e203 == 1i) { - let _e206 = (*four)[1u]; - local_18 = _e206; + let _e196 = (*slot_1); + lane = (_e195 - ((_e196 / 4i) * 4i)); + let _e200 = lane; + if (_e200 == 0i) { + let _e203 = (*four)[0u]; + local_17 = _e203; + } else { + let _e204 = lane; + if (_e204 == 1i) { + let _e207 = (*four)[1u]; + local_18 = _e207; } else { - let _e207 = lane; - if (_e207 == 2i) { - let _e210 = (*four)[2u]; - local_19 = _e210; + let _e208 = lane; + if (_e208 == 2i) { + let _e211 = (*four)[2u]; + local_19 = _e211; } else { - let _e212 = (*four)[3u]; - local_19 = _e212; + let _e213 = (*four)[3u]; + local_19 = _e213; } - let _e213 = local_19; - local_18 = _e213; + let _e214 = local_19; + local_18 = _e214; } - let _e214 = local_18; - local_17 = _e214; + let _e215 = local_18; + local_17 = _e215; } - let _e215 = local_17; - return _e215; + let _e216 = local_17; + return _e216; } fn LightListScale_u0028_i1_u003b(slot_2: ptr) -> f32 { var param_79: vec4; var param_80: i32; - let _e191 = (*slot_2); - let _e195 = light_list_info.scales[(_e191 / 4i)]; - param_79 = _e195; - let _e196 = (*slot_2); - param_80 = _e196; - let _e197 = LightListLane_u0028_vf4_u003b_i1_u003b((¶m_79), (¶m_80)); - return _e197; + let _e192 = (*slot_2); + let _e196 = light_list_info.scales[(_e192 / 4i)]; + param_79 = _e196; + let _e197 = (*slot_2); + param_80 = _e197; + let _e198 = LightListLane_u0028_vf4_u003b_i1_u003b((¶m_79), (¶m_80)); + return _e198; } fn InSlots_u0028_f1_u003b(row: ptr) -> bool { var a_3: vec4; var b_2: vec4; - let _e193 = light_list_info.slot_rows[0i]; - let _e194 = (*row); - a_3 = abs((_e193 - vec4(_e194))); - let _e200 = light_list_info.slot_rows[1i]; - let _e201 = (*row); - b_2 = abs((_e200 - vec4(_e201))); - let _e206 = a_3[0u]; - let _e208 = a_3[1u]; - let _e211 = a_3[2u]; - let _e213 = a_3[3u]; - let _e217 = b_2[0u]; - let _e219 = b_2[1u]; - let _e222 = b_2[2u]; - let _e224 = b_2[3u]; - return (min(min(min(_e206, _e208), min(_e211, _e213)), min(min(_e217, _e219), min(_e222, _e224))) < 0.5f); + let _e194 = light_list_info.slot_rows[0i]; + let _e195 = (*row); + a_3 = abs((_e194 - vec4(_e195))); + let _e201 = light_list_info.slot_rows[1i]; + let _e202 = (*row); + b_2 = abs((_e201 - vec4(_e202))); + let _e207 = a_3[0u]; + let _e209 = a_3[1u]; + let _e212 = a_3[2u]; + let _e214 = a_3[3u]; + let _e218 = b_2[0u]; + let _e220 = b_2[1u]; + let _e223 = b_2[2u]; + let _e225 = b_2[3u]; + return (min(min(min(_e207, _e209), min(_e212, _e214)), min(min(_e218, _e220), min(_e223, _e225))) < 0.5f); } fn LightListRow_u0028_i1_u003b(slot_3: ptr) -> f32 { var param_81: vec4; var param_82: i32; - let _e191 = (*slot_3); - let _e195 = light_list_info.indices[(_e191 / 4i)]; - param_81 = _e195; - let _e196 = (*slot_3); - param_82 = _e196; - let _e197 = LightListLane_u0028_vf4_u003b_i1_u003b((¶m_81), (¶m_82)); - return _e197; + let _e192 = (*slot_3); + let _e196 = light_list_info.indices[(_e192 / 4i)]; + param_81 = _e196; + let _e197 = (*slot_3); + param_82 = _e197; + let _e198 = LightListLane_u0028_vf4_u003b_i1_u003b((¶m_81), (¶m_82)); + return _e198; } fn LightListTexel_u0028_f1_u003b_f1_u003b(texel_2: ptr, row_1: ptr) -> vec4 { - let _e190 = (*texel_2); - let _e194 = light_list_info.list[1u]; - let _e196 = (*row_1); - let _e200 = light_list_info.list[2u]; - let _e203 = textureSampleLevel(light_list_texture_tex, light_list_texture_smp, vec2(((_e190 + 0.5f) * _e194), ((_e196 + 0.5f) * _e200)), 0f); - return _e203; -} - -fn ClusterRow_u0028_i1_u003b(slot_4: ptr) -> f32 { - var entry_1: f32; - var row_2: f32; - var within: f32; - var texel_3: f32; - var four_1: vec4; - var param_83: f32; - var param_84: f32; - var param_85: vec4; - var param_86: i32; - - let _e198 = g_cluster_offset; - let _e199 = (*slot_4); - entry_1 = (_e198 + f32(_e199)); - let _e202 = entry_1; - row_2 = floor((_e202 / 16f)); - let _e205 = entry_1; - let _e206 = row_2; - within = (_e205 - (_e206 * 16f)); - let _e209 = within; - texel_3 = floor((_e209 / 4f)); - let _e214 = light_list_info.cluster_depth[3u]; - let _e215 = row_2; - let _e217 = texel_3; - param_83 = _e217; - param_84 = (_e214 + _e215); - let _e218 = LightListTexel_u0028_f1_u003b_f1_u003b((¶m_83), (¶m_84)); - four_1 = _e218; - let _e219 = within; - let _e220 = texel_3; - let _e225 = four_1; - param_85 = _e225; - param_86 = i32(((_e219 - (_e220 * 4f)) + 0.5f)); - let _e226 = LightListLane_u0028_vf4_u003b_i1_u003b((¶m_85), (¶m_86)); - return _e226; + let _e191 = (*texel_2); + let _e195 = light_list_info.list[1u]; + let _e197 = (*row_1); + let _e201 = light_list_info.list[2u]; + let _e204 = textureSampleLevel(light_list_texture_tex, light_list_texture_smp, vec2(((_e191 + 0.5f) * _e195), ((_e197 + 0.5f) * _e201)), 0f); + return _e204; +} + +fn ClusterRow_u0028_i1_u003b(slot_4: ptr) -> f32 { + var entry_1: f32; + var row_2: f32; + var within: f32; + var texel_3: f32; + var four_1: vec4; + var param_83: f32; + var param_84: f32; + var param_85: vec4; + var param_86: i32; + + let _e199 = g_cluster_offset; + let _e200 = (*slot_4); + entry_1 = (_e199 + f32(_e200)); + let _e203 = entry_1; + row_2 = floor((_e203 / 16f)); + let _e206 = entry_1; + let _e207 = row_2; + within = (_e206 - (_e207 * 16f)); + let _e210 = within; + texel_3 = floor((_e210 / 4f)); + let _e215 = light_list_info.cluster_depth[3u]; + let _e216 = row_2; + let _e218 = texel_3; + param_83 = _e218; + param_84 = (_e215 + _e216); + let _e219 = LightListTexel_u0028_f1_u003b_f1_u003b((¶m_83), (¶m_84)); + four_1 = _e219; + let _e220 = within; + let _e221 = texel_3; + let _e226 = four_1; + param_85 = _e226; + param_86 = i32(((_e220 - (_e221 * 4f)) + 0.5f)); + let _e227 = LightListLane_u0028_vf4_u003b_i1_u003b((¶m_85), (¶m_86)); + return _e227; } fn Clustered_u0028_() -> bool { - let _e190 = light_list_info.cluster_grid[3u]; - return (_e190 > 0.5f); + let _e191 = light_list_info.cluster_grid[3u]; + return (_e191 > 0.5f); } fn SampleLight_u0028_i1_u003b_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b(index_2: ptr, s_4: ptr) -> LightSample { @@ -25523,264 +25698,264 @@ fn SampleLight_u0028_i1_u003b_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_ light_3.integrated = 0f; light_3.ltc = vec3(0f, 0f, 0f); - let _e241 = (*index_2); - if (_e241 < 8i) { - let _e243 = (*index_2); - let _e246 = frag_info.light_position[_e243]; - position = _e246; - let _e247 = (*index_2); - let _e250 = frag_info.light_color[_e247]; - color_1 = _e250; - let _e251 = (*index_2); - let _e254 = frag_info.light_direction[_e251]; - direction = _e254; - let _e255 = (*index_2); - let _e258 = frag_info.light_cone[_e255]; - cone = _e258; - } else { - let _e259 = (*index_2); - slot_5 = (_e259 - 8i); - let _e261 = Clustered_u0028_(); - clustered = _e261; - let _e262 = clustered; - if _e262 { - let _e263 = slot_5; - param_87 = _e263; - let _e264 = ClusterRow_u0028_i1_u003b((¶m_87)); - local_20 = _e264; - } else { - let _e265 = slot_5; - param_88 = _e265; - let _e266 = LightListRow_u0028_i1_u003b((¶m_88)); - local_20 = _e266; - } - let _e267 = local_20; - listRow = _e267; - let _e268 = listRow; - let _e272 = light_list_info.list[2u]; - v_1 = ((_e268 + 0.5f) * _e272); - let _e276 = light_list_info.list[1u]; - u_1 = _e276; - let _e277 = u_1; - let _e279 = v_1; - let _e281 = textureSampleLevel(light_list_texture_tex, light_list_texture_smp, vec2((0.5f * _e277), _e279), 0f); - position = _e281; - let _e282 = u_1; - let _e284 = v_1; - let _e286 = textureSampleLevel(light_list_texture_tex, light_list_texture_smp, vec2((1.5f * _e282), _e284), 0f); - color_1 = _e286; - let _e287 = u_1; - let _e289 = v_1; - let _e291 = textureSampleLevel(light_list_texture_tex, light_list_texture_smp, vec2((2.5f * _e287), _e289), 0f); - direction = _e291; - let _e292 = u_1; - let _e294 = v_1; - let _e296 = textureSampleLevel(light_list_texture_tex, light_list_texture_smp, vec2((3.5f * _e292), _e294), 0f); - cone = _e296; - let _e297 = clustered; - if _e297 { - let _e298 = listRow; - param_89 = _e298; - let _e299 = InSlots_u0028_f1_u003b((¶m_89)); - local_21 = select(1f, 0f, _e299); - } else { - let _e301 = slot_5; - param_90 = _e301; - let _e302 = LightListScale_u0028_i1_u003b((¶m_90)); - local_21 = _e302; - } - let _e303 = local_21; - let _e305 = color_1[3u]; - color_1[3u] = (_e305 * _e303); - } - let _e309 = position[3u]; - type_39 = _e309; - let _e310 = type_39; - if (_e310 > 2.5f) { - let _e312 = direction; - halfWidth_1 = _e312.xyz; - let _e314 = cone; - halfHeight_1 = _e314.xyz; - let _e316 = position; - let _e318 = v_world_position_1; - toCentre = (_e316.xyz - _e318); - let _e320 = toCentre; - let _e321 = halfWidth_1; - let _e323 = halfHeight_1; - corners_1[0i] = ((_e320 - _e321) - _e323); - let _e326 = toCentre; - let _e327 = halfWidth_1; - let _e329 = halfHeight_1; - corners_1[1i] = ((_e326 + _e327) - _e329); - let _e332 = toCentre; - let _e333 = halfWidth_1; - let _e335 = halfHeight_1; - corners_1[2i] = ((_e332 + _e333) + _e335); - let _e338 = toCentre; - let _e339 = halfWidth_1; - let _e341 = halfHeight_1; - corners_1[3i] = ((_e338 - _e339) + _e341); - let _e344 = toCentre; - let _e345 = halfWidth_1; - let _e346 = halfHeight_1; - behind = (dot(_e344, cross(_e345, _e346)) >= 0f); - let _e350 = behind; - if _e350 { - local_22 = 0f; - } else { - let _e351 = corners_1; - param_91 = _e351; - let _e353 = (*s_4).n; - param_92 = _e353; - let _e354 = RectangleFormFactor_u0028_vf3_u005b_4_u005d_u003b_vf3_u003b((¶m_91), (¶m_92)); - local_22 = _e354; - } - let _e355 = local_22; - formFactor = _e355; - let _e356 = halfWidth_1; - let _e357 = halfHeight_1; - area = (length(cross(_e356, _e357)) * 4f); - let _e361 = area; - if (_e361 > 0.000000001f) { - let _e363 = area; - local_23 = (1f / _e363); - } else { - local_23 = 0f; - } - let _e365 = local_23; - radiance = _e365; - let _e366 = toCentre; - distance_2 = length(_e366); - let _e369 = direction[3u]; - if (_e369 > 0f) { - let _e371 = distance_2; - let _e373 = direction[3u]; - ratio_1 = (_e371 / _e373); - let _e375 = ratio_1; - let _e376 = ratio_1; - let _e378 = ratio_1; - let _e380 = ratio_1; - window_1 = clamp((1f - (((_e375 * _e376) * _e378) * _e380)), 0f, 1f); - let _e384 = window_1; - let _e385 = window_1; - let _e387 = radiance; - radiance = (_e387 * (_e384 * _e385)); - } - let _e390 = (*s_4).v; - let _e393 = (*s_4).n; - mirror_1 = reflect(-(_e390), _e393); - let _e395 = position; - param_93 = _e395.xyz; - let _e397 = halfWidth_1; - param_94 = _e397; - let _e398 = halfHeight_1; - param_95 = _e398; - let _e399 = v_world_position_1; - param_96 = _e399; - let _e400 = mirror_1; - param_97 = _e400; - let _e401 = RectangleClosestPoint_u0028_vf3_u003b_vf3_u003b_vf3_u003b_vf3_u003b_vf3_u003b((¶m_93), (¶m_94), (¶m_95), (¶m_96), (¶m_97)); - representative = _e401; - let _e402 = representative; - let _e403 = v_world_position_1; - toPoint = (_e402 - _e403); - let _e405 = toPoint; - pointDistance = length(_e405); - let _e407 = pointDistance; - if (_e407 > 0.000001f) { - let _e409 = toPoint; - let _e410 = pointDistance; - local_24 = (_e409 / vec3(_e410)); - } else { - let _e414 = (*s_4).n; - local_24 = _e414; - } - let _e415 = local_24; - light_3.l = _e415; - let _e418 = light_3.l; - let _e420 = (*s_4).v; - light_3.h = normalize((_e418 + _e420)); - let _e424 = formFactor; - light_3.n_dot_l = _e424; - let _e427 = (*s_4).n; - let _e429 = light_3.h; - light_3.n_dot_h = max(dot(_e427, _e429), 0f); - let _e434 = (*s_4).v; - let _e436 = light_3.h; - light_3.v_dot_h = max(dot(_e434, _e436), 0f); - let _e440 = color_1; - let _e443 = color_1[3u]; - let _e445 = radiance; - light_3.radiance = ((_e440.xyz * _e443) * _e445); - let _e448 = light_3; - return _e448; - } - let _e449 = direction; - aim = normalize(_e449.xyz); - attenuation_1 = 1f; - let _e452 = type_39; - if (_e452 < 0.5f) { - let _e454 = aim; - light_3.l = -(_e454); - } else { - let _e457 = position; - let _e459 = v_world_position_1; - toLight_1 = (_e457.xyz - _e459); - let _e461 = toLight_1; - distance_3 = length(_e461); - let _e463 = distance_3; - if (_e463 < 0.000001f) { - let _e466 = (*s_4).n; - light_3.l = _e466; - let _e469 = (*s_4).n; - light_3.h = _e469; - light_3.radiance = vec3(0f, 0f, 0f); - light_3.n_dot_l = 0f; - light_3.n_dot_h = 0f; - light_3.v_dot_h = 0f; - let _e475 = light_3; - return _e475; - } - let _e476 = toLight_1; - let _e477 = distance_3; - light_3.l = (_e476 / vec3(_e477)); - let _e481 = distance_3; - param_98 = _e481; - let _e483 = direction[3u]; - param_99 = _e483; - let _e484 = PunctualAttenuation_u0028_f1_u003b_f1_u003b((¶m_98), (¶m_99)); - attenuation_1 = _e484; - let _e485 = type_39; - if (_e485 > 1.5f) { - let _e487 = aim; - let _e489 = light_3.l; - cosAngle = dot(_e487, -(_e489)); - let _e492 = cosAngle; - let _e494 = cone[1u]; - let _e497 = cone[0u]; - let _e499 = cone[1u]; - let _e503 = attenuation_1; - attenuation_1 = (_e503 * clamp(((_e492 - _e494) / (_e497 - _e499)), 0f, 1f)); + let _e242 = (*index_2); + if (_e242 < 8i) { + let _e244 = (*index_2); + let _e247 = frag_info.light_position[_e244]; + position = _e247; + let _e248 = (*index_2); + let _e251 = frag_info.light_color[_e248]; + color_1 = _e251; + let _e252 = (*index_2); + let _e255 = frag_info.light_direction[_e252]; + direction = _e255; + let _e256 = (*index_2); + let _e259 = frag_info.light_cone[_e256]; + cone = _e259; + } else { + let _e260 = (*index_2); + slot_5 = (_e260 - 8i); + let _e262 = Clustered_u0028_(); + clustered = _e262; + let _e263 = clustered; + if _e263 { + let _e264 = slot_5; + param_87 = _e264; + let _e265 = ClusterRow_u0028_i1_u003b((¶m_87)); + local_20 = _e265; + } else { + let _e266 = slot_5; + param_88 = _e266; + let _e267 = LightListRow_u0028_i1_u003b((¶m_88)); + local_20 = _e267; + } + let _e268 = local_20; + listRow = _e268; + let _e269 = listRow; + let _e273 = light_list_info.list[2u]; + v_1 = ((_e269 + 0.5f) * _e273); + let _e277 = light_list_info.list[1u]; + u_1 = _e277; + let _e278 = u_1; + let _e280 = v_1; + let _e282 = textureSampleLevel(light_list_texture_tex, light_list_texture_smp, vec2((0.5f * _e278), _e280), 0f); + position = _e282; + let _e283 = u_1; + let _e285 = v_1; + let _e287 = textureSampleLevel(light_list_texture_tex, light_list_texture_smp, vec2((1.5f * _e283), _e285), 0f); + color_1 = _e287; + let _e288 = u_1; + let _e290 = v_1; + let _e292 = textureSampleLevel(light_list_texture_tex, light_list_texture_smp, vec2((2.5f * _e288), _e290), 0f); + direction = _e292; + let _e293 = u_1; + let _e295 = v_1; + let _e297 = textureSampleLevel(light_list_texture_tex, light_list_texture_smp, vec2((3.5f * _e293), _e295), 0f); + cone = _e297; + let _e298 = clustered; + if _e298 { + let _e299 = listRow; + param_89 = _e299; + let _e300 = InSlots_u0028_f1_u003b((¶m_89)); + local_21 = select(1f, 0f, _e300); + } else { + let _e302 = slot_5; + param_90 = _e302; + let _e303 = LightListScale_u0028_i1_u003b((¶m_90)); + local_21 = _e303; + } + let _e304 = local_21; + let _e306 = color_1[3u]; + color_1[3u] = (_e306 * _e304); + } + let _e310 = position[3u]; + type_39 = _e310; + let _e311 = type_39; + if (_e311 > 2.5f) { + let _e313 = direction; + halfWidth_1 = _e313.xyz; + let _e315 = cone; + halfHeight_1 = _e315.xyz; + let _e317 = position; + let _e319 = v_world_position_1; + toCentre = (_e317.xyz - _e319); + let _e321 = toCentre; + let _e322 = halfWidth_1; + let _e324 = halfHeight_1; + corners_1[0i] = ((_e321 - _e322) - _e324); + let _e327 = toCentre; + let _e328 = halfWidth_1; + let _e330 = halfHeight_1; + corners_1[1i] = ((_e327 + _e328) - _e330); + let _e333 = toCentre; + let _e334 = halfWidth_1; + let _e336 = halfHeight_1; + corners_1[2i] = ((_e333 + _e334) + _e336); + let _e339 = toCentre; + let _e340 = halfWidth_1; + let _e342 = halfHeight_1; + corners_1[3i] = ((_e339 - _e340) + _e342); + let _e345 = toCentre; + let _e346 = halfWidth_1; + let _e347 = halfHeight_1; + behind = (dot(_e345, cross(_e346, _e347)) >= 0f); + let _e351 = behind; + if _e351 { + local_22 = 0f; + } else { + let _e352 = corners_1; + param_91 = _e352; + let _e354 = (*s_4).n; + param_92 = _e354; + let _e355 = RectangleFormFactor_u0028_vf3_u005b_4_u005d_u003b_vf3_u003b((¶m_91), (¶m_92)); + local_22 = _e355; + } + let _e356 = local_22; + formFactor = _e356; + let _e357 = halfWidth_1; + let _e358 = halfHeight_1; + area = (length(cross(_e357, _e358)) * 4f); + let _e362 = area; + if (_e362 > 0.000000001f) { + let _e364 = area; + local_23 = (1f / _e364); + } else { + local_23 = 0f; } - } - let _e506 = light_3.l; - let _e508 = (*s_4).v; - light_3.h = normalize((_e506 + _e508)); - let _e513 = (*s_4).n; - let _e515 = light_3.l; - light_3.n_dot_l = max(dot(_e513, _e515), 0f); - let _e520 = (*s_4).n; - let _e522 = light_3.h; - light_3.n_dot_h = max(dot(_e520, _e522), 0f); - let _e527 = (*s_4).v; - let _e529 = light_3.h; - light_3.v_dot_h = max(dot(_e527, _e529), 0f); - let _e533 = color_1; - let _e536 = color_1[3u]; - let _e538 = attenuation_1; - light_3.radiance = ((_e533.xyz * _e536) * _e538); - let _e541 = light_3; - return _e541; + let _e366 = local_23; + radiance = _e366; + let _e367 = toCentre; + distance_2 = length(_e367); + let _e370 = direction[3u]; + if (_e370 > 0f) { + let _e372 = distance_2; + let _e374 = direction[3u]; + ratio_1 = (_e372 / _e374); + let _e376 = ratio_1; + let _e377 = ratio_1; + let _e379 = ratio_1; + let _e381 = ratio_1; + window_1 = clamp((1f - (((_e376 * _e377) * _e379) * _e381)), 0f, 1f); + let _e385 = window_1; + let _e386 = window_1; + let _e388 = radiance; + radiance = (_e388 * (_e385 * _e386)); + } + let _e391 = (*s_4).v; + let _e394 = (*s_4).n; + mirror_1 = reflect(-(_e391), _e394); + let _e396 = position; + param_93 = _e396.xyz; + let _e398 = halfWidth_1; + param_94 = _e398; + let _e399 = halfHeight_1; + param_95 = _e399; + let _e400 = v_world_position_1; + param_96 = _e400; + let _e401 = mirror_1; + param_97 = _e401; + let _e402 = RectangleClosestPoint_u0028_vf3_u003b_vf3_u003b_vf3_u003b_vf3_u003b_vf3_u003b((¶m_93), (¶m_94), (¶m_95), (¶m_96), (¶m_97)); + representative = _e402; + let _e403 = representative; + let _e404 = v_world_position_1; + toPoint = (_e403 - _e404); + let _e406 = toPoint; + pointDistance = length(_e406); + let _e408 = pointDistance; + if (_e408 > 0.000001f) { + let _e410 = toPoint; + let _e411 = pointDistance; + local_24 = (_e410 / vec3(_e411)); + } else { + let _e415 = (*s_4).n; + local_24 = _e415; + } + let _e416 = local_24; + light_3.l = _e416; + let _e419 = light_3.l; + let _e421 = (*s_4).v; + light_3.h = normalize((_e419 + _e421)); + let _e425 = formFactor; + light_3.n_dot_l = _e425; + let _e428 = (*s_4).n; + let _e430 = light_3.h; + light_3.n_dot_h = max(dot(_e428, _e430), 0f); + let _e435 = (*s_4).v; + let _e437 = light_3.h; + light_3.v_dot_h = max(dot(_e435, _e437), 0f); + let _e441 = color_1; + let _e444 = color_1[3u]; + let _e446 = radiance; + light_3.radiance = ((_e441.xyz * _e444) * _e446); + let _e449 = light_3; + return _e449; + } + let _e450 = direction; + aim = normalize(_e450.xyz); + attenuation_1 = 1f; + let _e453 = type_39; + if (_e453 < 0.5f) { + let _e455 = aim; + light_3.l = -(_e455); + } else { + let _e458 = position; + let _e460 = v_world_position_1; + toLight_1 = (_e458.xyz - _e460); + let _e462 = toLight_1; + distance_3 = length(_e462); + let _e464 = distance_3; + if (_e464 < 0.000001f) { + let _e467 = (*s_4).n; + light_3.l = _e467; + let _e470 = (*s_4).n; + light_3.h = _e470; + light_3.radiance = vec3(0f, 0f, 0f); + light_3.n_dot_l = 0f; + light_3.n_dot_h = 0f; + light_3.v_dot_h = 0f; + let _e476 = light_3; + return _e476; + } + let _e477 = toLight_1; + let _e478 = distance_3; + light_3.l = (_e477 / vec3(_e478)); + let _e482 = distance_3; + param_98 = _e482; + let _e484 = direction[3u]; + param_99 = _e484; + let _e485 = PunctualAttenuation_u0028_f1_u003b_f1_u003b((¶m_98), (¶m_99)); + attenuation_1 = _e485; + let _e486 = type_39; + if (_e486 > 1.5f) { + let _e488 = aim; + let _e490 = light_3.l; + cosAngle = dot(_e488, -(_e490)); + let _e493 = cosAngle; + let _e495 = cone[1u]; + let _e498 = cone[0u]; + let _e500 = cone[1u]; + let _e504 = attenuation_1; + attenuation_1 = (_e504 * clamp(((_e493 - _e495) / (_e498 - _e500)), 0f, 1f)); + } + } + let _e507 = light_3.l; + let _e509 = (*s_4).v; + light_3.h = normalize((_e507 + _e509)); + let _e514 = (*s_4).n; + let _e516 = light_3.l; + light_3.n_dot_l = max(dot(_e514, _e516), 0f); + let _e521 = (*s_4).n; + let _e523 = light_3.h; + light_3.n_dot_h = max(dot(_e521, _e523), 0f); + let _e528 = (*s_4).v; + let _e530 = light_3.h; + light_3.v_dot_h = max(dot(_e528, _e530), 0f); + let _e534 = color_1; + let _e537 = color_1[3u]; + let _e539 = attenuation_1; + light_3.radiance = ((_e534.xyz * _e537) * _e539); + let _e542 = light_3; + return _e542; } fn FindCluster_u0028_vf3_u003b(world_3: ptr>) { @@ -25798,58 +25973,58 @@ fn FindCluster_u0028_vf3_u003b(world_3: ptr>) { var param_100: f32; var param_101: f32; - let _e203 = light_list_info.cluster_view_projection; - let _e204 = (*world_3); - clip_1 = (_e203 * vec4(_e204.x, _e204.y, _e204.z, 1f)); - let _e210 = clip_1; - let _e213 = clip_1[3u]; - ndc_1 = (_e210.xy / vec2(max(_e213, 0.000001f))); - let _e218 = light_list_info.cluster_grid; - grid = _e218.xyz; - let _e222 = light_list_info.cluster_depth[0u]; - near_1 = _e222; - let _e224 = ndc_1[0u]; - let _e228 = grid[0u]; - let _e232 = grid[0u]; - tx = clamp(floor((((_e224 * 0.5f) + 0.5f) * _e228)), 0f, (_e232 - 1f)); - let _e236 = ndc_1[1u]; - let _e240 = grid[1u]; - let _e244 = grid[1u]; - ty = clamp(floor((((_e236 * 0.5f) + 0.5f) * _e240)), 0f, (_e244 - 1f)); - let _e248 = clip_1[3u]; - let _e249 = near_1; - if (_e248 <= _e249) { + let _e204 = light_list_info.cluster_view_projection; + let _e205 = (*world_3); + clip_1 = (_e204 * vec4(_e205.x, _e205.y, _e205.z, 1f)); + let _e211 = clip_1; + let _e214 = clip_1[3u]; + ndc_1 = (_e211.xy / vec2(max(_e214, 0.000001f))); + let _e219 = light_list_info.cluster_grid; + grid = _e219.xyz; + let _e223 = light_list_info.cluster_depth[0u]; + near_1 = _e223; + let _e225 = ndc_1[0u]; + let _e229 = grid[0u]; + let _e233 = grid[0u]; + tx = clamp(floor((((_e225 * 0.5f) + 0.5f) * _e229)), 0f, (_e233 - 1f)); + let _e237 = ndc_1[1u]; + let _e241 = grid[1u]; + let _e245 = grid[1u]; + ty = clamp(floor((((_e237 * 0.5f) + 0.5f) * _e241)), 0f, (_e245 - 1f)); + let _e249 = clip_1[3u]; + let _e250 = near_1; + if (_e249 <= _e250) { local_25 = 0f; } else { - let _e252 = clip_1[3u]; - let _e253 = near_1; - let _e258 = light_list_info.cluster_depth[1u]; - let _e262 = grid[2u]; - local_25 = clamp(floor((log((_e252 / _e253)) * _e258)), 0f, (_e262 - 1f)); - } - let _e265 = local_25; - tz = _e265; - let _e266 = tx; - let _e267 = ty; - let _e269 = grid[0u]; - let _e272 = tz; - let _e274 = grid[0u]; - let _e277 = grid[1u]; - cell = ((_e266 + (_e267 * _e269)) + ((_e272 * _e274) * _e277)); - let _e280 = cell; - row_3 = floor((_e280 / 4f)); - let _e283 = cell; - let _e284 = row_3; - let _e289 = light_list_info.cluster_depth[2u]; - let _e290 = row_3; - param_100 = (_e283 - (_e284 * 4f)); - param_101 = (_e289 + _e290); - let _e292 = LightListTexel_u0028_f1_u003b_f1_u003b((¶m_100), (¶m_101)); - header = _e292; - let _e294 = header[0u]; - g_cluster_offset = _e294; - let _e296 = header[1u]; - g_cluster_count = _e296; + let _e253 = clip_1[3u]; + let _e254 = near_1; + let _e259 = light_list_info.cluster_depth[1u]; + let _e263 = grid[2u]; + local_25 = clamp(floor((log((_e253 / _e254)) * _e259)), 0f, (_e263 - 1f)); + } + let _e266 = local_25; + tz = _e266; + let _e267 = tx; + let _e268 = ty; + let _e270 = grid[0u]; + let _e273 = tz; + let _e275 = grid[0u]; + let _e278 = grid[1u]; + cell = ((_e267 + (_e268 * _e270)) + ((_e273 * _e275) * _e278)); + let _e281 = cell; + row_3 = floor((_e281 / 4f)); + let _e284 = cell; + let _e285 = row_3; + let _e290 = light_list_info.cluster_depth[2u]; + let _e291 = row_3; + param_100 = (_e284 - (_e285 * 4f)); + param_101 = (_e290 + _e291); + let _e293 = LightListTexel_u0028_f1_u003b_f1_u003b((¶m_100), (¶m_101)); + header = _e293; + let _e295 = header[0u]; + g_cluster_offset = _e295; + let _e297 = header[1u]; + g_cluster_count = _e297; return; } @@ -25857,19 +26032,19 @@ fn LightCount_u0028_() -> i32 { var tail: f32; var param_102: vec3; - let _e192 = light_list_info.list[0u]; - tail = _e192; - let _e193 = Clustered_u0028_(); - if _e193 { - let _e194 = v_world_position_1; - param_102 = _e194; + let _e193 = light_list_info.list[0u]; + tail = _e193; + let _e194 = Clustered_u0028_(); + if _e194 { + let _e195 = v_world_position_1; + param_102 = _e195; FindCluster_u0028_vf3_u003b((¶m_102)); - let _e195 = g_cluster_count; - tail = _e195; + let _e196 = g_cluster_count; + tail = _e196; } - let _e198 = frag_info.frame_params[1u]; - let _e202 = tail; - return (clamp(i32((_e198 + 0.5f)), 0i, 8i) + clamp(i32((_e202 + 0.5f)), 0i, 24i)); + let _e199 = frag_info.frame_params[1u]; + let _e203 = tail; + return (clamp(i32((_e199 + 0.5f)), 0i, 8i) + clamp(i32((_e203 + 0.5f)), 0i, 24i)); } fn AccumulateLights_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b(s_5: ptr) -> vec3 { @@ -25892,109 +26067,109 @@ fn AccumulateLights_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002 var param_113: LightSample; total_1 = vec3(0f, 0f, 0f); - let _e206 = LightCount_u0028_(); - count_1 = _e206; + let _e207 = LightCount_u0028_(); + count_1 = _e207; i_8 = 0i; loop { - let _e207 = i_8; - if (_e207 < 32i) { - let _e209 = i_8; - let _e210 = count_1; - if (_e209 >= _e210) { + let _e208 = i_8; + if (_e208 < 32i) { + let _e210 = i_8; + let _e211 = count_1; + if (_e210 >= _e211) { break; } - let _e212 = i_8; - param_103 = _e212; - let _e213 = (*s_5); - param_104 = _e213; - let _e214 = SampleLight_u0028_i1_u003b_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b((¶m_103), (¶m_104)); - light_4 = _e214; - let _e216 = light_4.n_dot_l; - if (_e216 <= 0f) { + let _e213 = i_8; + param_103 = _e213; + let _e214 = (*s_5); + param_104 = _e214; + let _e215 = SampleLight_u0028_i1_u003b_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b((¶m_103), (¶m_104)); + light_4 = _e215; + let _e217 = light_4.n_dot_l; + if (_e217 <= 0f) { continue; } light_transmittance = vec3(1f, 1f, 1f); - let _e218 = i_8; - param_105 = _e218; - let _e219 = LightHasShadow_u0028_i1_u003b((¶m_105)); - if _e219 { - let _e220 = (*s_5); - param_106 = _e220; - let _e221 = light_4; - param_107 = _e221; - let _e222 = i_8; - param_108 = _e222; - let _e223 = LightVisibility_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_struct_u002d_LightSample_u002d_vf3_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf31_u003b_i1_u003b((¶m_106), (¶m_107), (¶m_108)); - let _e224 = v_world_position_1; - param_109 = _e224; - let _e226 = (*s_5).n; - param_110 = _e226; - let _e227 = i_8; - param_111 = _e227; - let _e228 = PointShadowFactor_u0028_vf3_u003b_vf3_u003b_i1_u003b((¶m_109), (¶m_110), (¶m_111)); - local_26 = (_e223 * _e228); + let _e219 = i_8; + param_105 = _e219; + let _e220 = LightHasShadow_u0028_i1_u003b((¶m_105)); + if _e220 { + let _e221 = (*s_5); + param_106 = _e221; + let _e222 = light_4; + param_107 = _e222; + let _e223 = i_8; + param_108 = _e223; + let _e224 = LightVisibility_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_struct_u002d_LightSample_u002d_vf3_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf31_u003b_i1_u003b((¶m_106), (¶m_107), (¶m_108)); + let _e225 = v_world_position_1; + param_109 = _e225; + let _e227 = (*s_5).n; + param_110 = _e227; + let _e228 = i_8; + param_111 = _e228; + let _e229 = PointShadowFactor_u0028_vf3_u003b_vf3_u003b_i1_u003b((¶m_109), (¶m_110), (¶m_111)); + local_26 = (_e224 * _e229); } else { local_26 = 1f; } - let _e230 = local_26; - visibility = _e230; - let _e231 = visibility; - if (_e231 <= 0f) { + let _e231 = local_26; + visibility = _e231; + let _e232 = visibility; + if (_e232 <= 0f) { continue; } - let _e233 = (*s_5); - param_112 = _e233; - let _e234 = light_4; - param_113 = _e234; - let _e235 = ShadeLight_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_struct_u002d_LightSample_u002d_vf3_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf31_u003b((¶m_112), (¶m_113)); - let _e237 = light_4.radiance; - let _e240 = light_4.n_dot_l; - let _e242 = visibility; - let _e244 = light_transmittance; - let _e246 = total_1; - total_1 = (_e246 + ((((_e235 * _e237) * _e240) * _e242) * _e244)); + let _e234 = (*s_5); + param_112 = _e234; + let _e235 = light_4; + param_113 = _e235; + let _e236 = ShadeLight_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_struct_u002d_LightSample_u002d_vf3_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf31_u003b((¶m_112), (¶m_113)); + let _e238 = light_4.radiance; + let _e241 = light_4.n_dot_l; + let _e243 = visibility; + let _e245 = light_transmittance; + let _e247 = total_1; + total_1 = (_e247 + ((((_e236 * _e238) * _e241) * _e243) * _e245)); continue; } else { break; } continuing { - let _e248 = i_8; - i_8 = (_e248 + 1i); + let _e249 = i_8; + i_8 = (_e249 + 1i); } } - let _e250 = total_1; - return _e250; + let _e251 = total_1; + return _e251; } fn SampleLightmap_u0028_() -> vec3 { var texel_4: vec4; - let _e189 = v_lightmap_uv_1; - let _e190 = textureSample(lightmap_texture_tex, lightmap_texture_smp, _e189); - texel_4 = _e190; - let _e191 = texel_4; - let _e194 = texel_4[3u]; - return ((_e191.xyz * _e194) * 8f); + let _e190 = v_lightmap_uv_1; + let _e191 = textureSample(lightmap_texture_tex, lightmap_texture_smp, _e190); + texel_4 = _e191; + let _e192 = texel_4; + let _e195 = texel_4[3u]; + return ((_e192.xyz * _e195) * 8f); } fn MaterialLodBias_u0028_() -> f32 { - let _e190 = frag_info.target_origin[1u]; - return _e190; + let _e191 = frag_info.target_origin[1u]; + return _e191; } fn ApplyMetallicRoughnessMap_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b(s_6: ptr) { var orm: vec3; - let _e190 = v_texcoord_1; - let _e191 = MaterialLodBias_u0028_(); - let _e192 = textureSampleBias(metallic_roughness_texture_tex, metallic_roughness_texture_smp, _e190, _e191); - orm = _e192.xyz; - let _e195 = (*s_6).metallic; - let _e197 = orm[2u]; - (*s_6).metallic = clamp((_e195 * _e197), 0f, 1f); - let _e202 = (*s_6).roughness; - let _e204 = orm[1u]; - (*s_6).roughness = clamp((_e202 * _e204), 0.02f, 1f); + let _e191 = v_texcoord_1; + let _e192 = MaterialLodBias_u0028_(); + let _e193 = textureSampleBias(metallic_roughness_texture_tex, metallic_roughness_texture_smp, _e191, _e192); + orm = _e193.xyz; + let _e196 = (*s_6).metallic; + let _e198 = orm[2u]; + (*s_6).metallic = clamp((_e196 * _e198), 0f, 1f); + let _e203 = (*s_6).roughness; + let _e205 = orm[1u]; + (*s_6).roughness = clamp((_e203 * _e205), 0.02f, 1f); return; } @@ -26002,29 +26177,29 @@ fn ApplyEmissiveMap_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002 var emissive: vec3; var param_114: vec3; - let _e191 = v_texcoord_1; - let _e192 = MaterialLodBias_u0028_(); - let _e193 = textureSampleBias(emissive_texture_tex, emissive_texture_smp, _e191, _e192); - param_114 = _e193.xyz; - let _e195 = SrgbToLinear_u0028_vf3_u003b((¶m_114)); - emissive = _e195; - let _e196 = emissive; - let _e198 = frag_info.emissive; - let _e203 = frag_info.material2_[3u]; - (*s_7).emissive = ((_e196 * _e198.xyz) * _e203); + let _e192 = v_texcoord_1; + let _e193 = MaterialLodBias_u0028_(); + let _e194 = textureSampleBias(emissive_texture_tex, emissive_texture_smp, _e192, _e193); + param_114 = _e194.xyz; + let _e196 = SrgbToLinear_u0028_vf3_u003b((¶m_114)); + emissive = _e196; + let _e197 = emissive; + let _e199 = frag_info.emissive; + let _e204 = frag_info.material2_[3u]; + (*s_7).emissive = ((_e197 * _e199.xyz) * _e204); return; } fn ApplyOcclusionMap_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b(s_8: ptr) { var occlusion: f32; - let _e190 = v_texcoord_1; - let _e191 = MaterialLodBias_u0028_(); - let _e192 = textureSampleBias(occlusion_texture_tex, occlusion_texture_smp, _e190, _e191); - occlusion = _e192.x; - let _e194 = occlusion; - let _e197 = frag_info.material2_[2u]; - (*s_8).occlusion = mix(1f, _e194, clamp(_e197, 0f, 1f)); + let _e191 = v_texcoord_1; + let _e192 = MaterialLodBias_u0028_(); + let _e193 = textureSampleBias(occlusion_texture_tex, occlusion_texture_smp, _e191, _e192); + occlusion = _e193.x; + let _e195 = occlusion; + let _e198 = frag_info.material2_[2u]; + (*s_8).occlusion = mix(1f, _e195, clamp(_e198, 0f, 1f)); return; } @@ -26034,64 +26209,64 @@ fn ApplyNormalMap_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_ var b_3: vec3; var sampled: vec3; - let _e193 = v_texcoord_1; - let _e194 = MaterialLodBias_u0028_(); - let _e195 = textureSampleBias(normal_texture_tex, normal_texture_smp, _e193, _e194); - sampledTexel = _e195; - let _e196 = v_tangent_1; - t_2 = _e196.xyz; - let _e198 = t_2; - let _e200 = (*s_9).n; - let _e202 = (*s_9).n; - let _e203 = t_2; - t_2 = (_e198 - (_e200 * dot(_e202, _e203))); - let _e207 = t_2; + let _e194 = v_texcoord_1; + let _e195 = MaterialLodBias_u0028_(); + let _e196 = textureSampleBias(normal_texture_tex, normal_texture_smp, _e194, _e195); + sampledTexel = _e196; + let _e197 = v_tangent_1; + t_2 = _e197.xyz; + let _e199 = t_2; + let _e201 = (*s_9).n; + let _e203 = (*s_9).n; + let _e204 = t_2; + t_2 = (_e199 - (_e201 * dot(_e203, _e204))); let _e208 = t_2; - if (dot(_e207, _e208) < 0.000000000001f) { - return; - } - let _e211 = t_2; - t_2 = normalize(_e211); - let _e214 = (*s_9).n; - let _e215 = t_2; - let _e218 = v_tangent_1[3u]; - b_3 = (cross(_e214, _e215) * _e218); - let _e220 = gl_FrontFacing_1; - if !(_e220) { - let _e222 = t_2; - t_2 = -(_e222); - } - let _e224 = sampledTexel; - sampled = ((_e224.xyz * 2f) - vec3(1f)); - let _e231 = frag_info.emissive[3u]; - if (_e231 > 0.5f) { - let _e233 = sampled; - let _e235 = sampled; - sampled[2u] = sqrt(max((1f - dot(_e233.xy, _e235.xy)), 0f)); - } - let _e244 = frag_info.material2_[1u]; - let _e245 = sampled; - let _e247 = (_e245.xy * _e244); - sampled[0u] = _e247.x; - sampled[1u] = _e247.y; - let _e252 = t_2; - let _e254 = sampled[0u]; - let _e256 = b_3; - let _e258 = sampled[1u]; - let _e262 = (*s_9).n; - let _e264 = sampled[2u]; - (*s_9).n = normalize((((_e252 * _e254) + (_e256 * _e258)) + (_e262 * _e264))); - let _e270 = (*s_9).n; - let _e272 = (*s_9).v; - (*s_9).n_dot_v = max(dot(_e270, _e272), 0.0001f); + let _e209 = t_2; + if (dot(_e208, _e209) < 0.000000000001f) { + return; + } + let _e212 = t_2; + t_2 = normalize(_e212); + let _e215 = (*s_9).n; + let _e216 = t_2; + let _e219 = v_tangent_1[3u]; + b_3 = (cross(_e215, _e216) * _e219); + let _e221 = gl_FrontFacing_1; + if !(_e221) { + let _e223 = t_2; + t_2 = -(_e223); + } + let _e225 = sampledTexel; + sampled = ((_e225.xyz * 2f) - vec3(1f)); + let _e232 = frag_info.emissive[3u]; + if (_e232 > 0.5f) { + let _e234 = sampled; + let _e236 = sampled; + sampled[2u] = sqrt(max((1f - dot(_e234.xy, _e236.xy)), 0f)); + } + let _e245 = frag_info.material2_[1u]; + let _e246 = sampled; + let _e248 = (_e246.xy * _e245); + sampled[0u] = _e248.x; + sampled[1u] = _e248.y; + let _e253 = t_2; + let _e255 = sampled[0u]; + let _e257 = b_3; + let _e259 = sampled[1u]; + let _e263 = (*s_9).n; + let _e265 = sampled[2u]; + (*s_9).n = normalize((((_e253 * _e255) + (_e257 * _e259)) + (_e263 * _e265))); + let _e271 = (*s_9).n; + let _e273 = (*s_9).v; + (*s_9).n_dot_v = max(dot(_e271, _e273), 0.0001f); return; } fn AtlasTexel_u0028_vf2_u003b(texel_5: ptr>) -> vec4 { - let _e189 = (*texel_5); - let _e193 = irradiance_info.atlas; - let _e196 = textureSampleLevel(irradiance_texture_tex, irradiance_texture_smp, ((_e189 + vec2(0.5f)) * _e193.xy), 0f); - return _e196; + let _e190 = (*texel_5); + let _e194 = irradiance_info.atlas; + let _e197 = textureSampleLevel(irradiance_texture_tex, irradiance_texture_smp, ((_e190 + vec2(0.5f)) * _e194.xy), 0f); + return _e197; } fn TileBilinear_u0028_vf2_u003b_f1_u003b_vf2_u003b(corner: ptr>, interior: ptr, uv_5: ptr>) -> vec4 { @@ -26107,42 +26282,42 @@ fn TileBilinear_u0028_vf2_u003b_f1_u003b_vf2_u003b(corner: ptr; var param_118: vec2; - let _e202 = (*uv_5); - let _e203 = (*interior); - at_1 = ((vec2(1f) + (_e202 * _e203)) - vec2(0.5f)); - let _e209 = at_1; - low = floor(_e209); - let _e211 = at_1; - let _e212 = low; - f = (_e211 - _e212); - let _e214 = (*corner); - let _e215 = low; - param_115 = (_e214 + _e215); - let _e217 = AtlasTexel_u0028_vf2_u003b((¶m_115)); - a_4 = _e217; - let _e218 = (*corner); - let _e219 = low; - param_116 = ((_e218 + _e219) + vec2(1f, 0f)); - let _e222 = AtlasTexel_u0028_vf2_u003b((¶m_116)); - b_4 = _e222; - let _e223 = (*corner); - let _e224 = low; - param_117 = ((_e223 + _e224) + vec2(0f, 1f)); - let _e227 = AtlasTexel_u0028_vf2_u003b((¶m_117)); - c_1 = _e227; - let _e228 = (*corner); - let _e229 = low; - param_118 = ((_e228 + _e229) + vec2(1f, 1f)); - let _e232 = AtlasTexel_u0028_vf2_u003b((¶m_118)); - d_4 = _e232; - let _e233 = a_4; - let _e234 = b_4; - let _e236 = f[0u]; - let _e239 = c_1; - let _e240 = d_4; - let _e242 = f[0u]; - let _e246 = f[1u]; - return mix(mix(_e233, _e234, vec4(_e236)), mix(_e239, _e240, vec4(_e242)), vec4(_e246)); + let _e203 = (*uv_5); + let _e204 = (*interior); + at_1 = ((vec2(1f) + (_e203 * _e204)) - vec2(0.5f)); + let _e210 = at_1; + low = floor(_e210); + let _e212 = at_1; + let _e213 = low; + f = (_e212 - _e213); + let _e215 = (*corner); + let _e216 = low; + param_115 = (_e215 + _e216); + let _e218 = AtlasTexel_u0028_vf2_u003b((¶m_115)); + a_4 = _e218; + let _e219 = (*corner); + let _e220 = low; + param_116 = ((_e219 + _e220) + vec2(1f, 0f)); + let _e223 = AtlasTexel_u0028_vf2_u003b((¶m_116)); + b_4 = _e223; + let _e224 = (*corner); + let _e225 = low; + param_117 = ((_e224 + _e225) + vec2(0f, 1f)); + let _e228 = AtlasTexel_u0028_vf2_u003b((¶m_117)); + c_1 = _e228; + let _e229 = (*corner); + let _e230 = low; + param_118 = ((_e229 + _e230) + vec2(1f, 1f)); + let _e233 = AtlasTexel_u0028_vf2_u003b((¶m_118)); + d_4 = _e233; + let _e234 = a_4; + let _e235 = b_4; + let _e237 = f[0u]; + let _e240 = c_1; + let _e241 = d_4; + let _e243 = f[0u]; + let _e247 = f[1u]; + return mix(mix(_e234, _e235, vec4(_e237)), mix(_e240, _e241, vec4(_e243)), vec4(_e247)); } fn ProbeOctahedral_u0028_vf3_u003b(direction_1: ptr>) -> vec2 { @@ -26150,29 +26325,29 @@ fn ProbeOctahedral_u0028_vf3_u003b(direction_1: ptr>) -> vec var n_5: vec3; var xy: vec2; - let _e193 = (*direction_1)[0u]; - let _e196 = (*direction_1)[1u]; - let _e200 = (*direction_1)[2u]; - sum_1 = ((abs(_e193) + abs(_e196)) + abs(_e200)); - let _e203 = sum_1; - if (_e203 <= 0f) { + let _e194 = (*direction_1)[0u]; + let _e197 = (*direction_1)[1u]; + let _e201 = (*direction_1)[2u]; + sum_1 = ((abs(_e194) + abs(_e197)) + abs(_e201)); + let _e204 = sum_1; + if (_e204 <= 0f) { return vec2(0.5f, 0.5f); } - let _e205 = (*direction_1); - let _e206 = sum_1; - n_5 = (_e205 / vec3(_e206)); - let _e209 = n_5; - xy = _e209.xy; - let _e212 = n_5[2u]; - if (_e212 < 0f) { - let _e215 = n_5[1u]; - let _e219 = n_5[0u]; - let _e224 = n_5[0u]; - let _e228 = n_5[1u]; - xy = vec2(((1f - abs(_e215)) * select(-1f, 1f, (_e219 >= 0f))), ((1f - abs(_e224)) * select(-1f, 1f, (_e228 >= 0f)))); + let _e206 = (*direction_1); + let _e207 = sum_1; + n_5 = (_e206 / vec3(_e207)); + let _e210 = n_5; + xy = _e210.xy; + let _e213 = n_5[2u]; + if (_e213 < 0f) { + let _e216 = n_5[1u]; + let _e220 = n_5[0u]; + let _e225 = n_5[0u]; + let _e229 = n_5[1u]; + xy = vec2(((1f - abs(_e216)) * select(-1f, 1f, (_e220 >= 0f))), ((1f - abs(_e225)) * select(-1f, 1f, (_e229 >= 0f)))); } - let _e233 = xy; - return ((_e233 * 0.5f) + vec2(0.5f)); + let _e234 = xy; + return ((_e234 * 0.5f) + vec2(0.5f)); } fn SampleIrradiance_u0028_vf3_u003b_vf3_u003b_vf3_u003b(world_4: ptr>, normal_1: ptr>, view_1: ptr>) -> vec3 { @@ -26220,190 +26395,190 @@ fn SampleIrradiance_u0028_vf3_u003b_vf3_u003b_vf3_u003b(world_4: ptr; var local_27: vec3; - let _e235 = irradiance_info.origin; - origin_2 = _e235.xyz; - let _e238 = irradiance_info.spacing; - spacing = _e238.xyz; - let _e241 = irradiance_info.counts; - counts = _e241.xyz; - let _e245 = irradiance_info.tiles[0u]; - irradianceTile = _e245; - let _e248 = irradiance_info.tiles[1u]; - depthTile = _e248; - let _e251 = irradiance_info.tiles[2u]; - columns = _e251; - let _e254 = irradiance_info.tiles[3u]; - momentsTop = _e254; - let _e255 = (*normal_1); - unit = normalize(_e255); - let _e257 = (*world_4); - let _e258 = unit; - let _e261 = irradiance_info.spacing[3u]; - let _e264 = (*view_1); - let _e267 = irradiance_info.counts[3u]; - biased = ((_e257 + (_e258 * _e261)) + (_e264 * _e267)); - let _e270 = biased; - let _e271 = origin_2; - let _e273 = spacing; - grid_1 = ((_e270 - _e271) / _e273); - let _e275 = grid_1; - let _e277 = counts; - base = clamp(floor(_e275), vec3(0f, 0f, 0f), (_e277 - vec3(2f))); - let _e281 = grid_1; - let _e282 = base; - f_1 = clamp((_e281 - _e282), vec3(0f, 0f, 0f), vec3(1f, 1f, 1f)); + let _e236 = irradiance_info.origin; + origin_2 = _e236.xyz; + let _e239 = irradiance_info.spacing; + spacing = _e239.xyz; + let _e242 = irradiance_info.counts; + counts = _e242.xyz; + let _e246 = irradiance_info.tiles[0u]; + irradianceTile = _e246; + let _e249 = irradiance_info.tiles[1u]; + depthTile = _e249; + let _e252 = irradiance_info.tiles[2u]; + columns = _e252; + let _e255 = irradiance_info.tiles[3u]; + momentsTop = _e255; + let _e256 = (*normal_1); + unit = normalize(_e256); + let _e258 = (*world_4); + let _e259 = unit; + let _e262 = irradiance_info.spacing[3u]; + let _e265 = (*view_1); + let _e268 = irradiance_info.counts[3u]; + biased = ((_e258 + (_e259 * _e262)) + (_e265 * _e268)); + let _e271 = biased; + let _e272 = origin_2; + let _e274 = spacing; + grid_1 = ((_e271 - _e272) / _e274); + let _e276 = grid_1; + let _e278 = counts; + base = clamp(floor(_e276), vec3(0f, 0f, 0f), (_e278 - vec3(2f))); + let _e282 = grid_1; + let _e283 = base; + f_1 = clamp((_e282 - _e283), vec3(0f, 0f, 0f), vec3(1f, 1f, 1f)); total_2 = vec3(0f, 0f, 0f); weights = 0f; corner_1 = 0i; loop { - let _e285 = corner_1; - if (_e285 < 8i) { - let _e287 = corner_1; - let _e290 = corner_1; - let _e295 = corner_1; - offset_3 = vec3(f32((_e287 & 1i)), f32(((_e290 >> bitcast(1i)) & 1i)), f32(((_e295 >> bitcast(2i)) & 1i))); - let _e301 = base; - let _e302 = offset_3; - cell_1 = (_e301 + _e302); - let _e305 = cell_1[2u]; - let _e307 = counts[1u]; - let _e310 = cell_1[1u]; - let _e313 = counts[0u]; - let _e316 = cell_1[0u]; - probe = ((((_e305 * _e307) + _e310) * _e313) + _e316); - let _e318 = probe; - let _e319 = columns; - let _e324 = probe; - let _e325 = columns; - tile_4 = vec2((_e318 - (floor((_e318 / _e319)) * _e319)), floor((_e324 / _e325))); - let _e329 = tile_4; - let _e330 = irradianceTile; - irradianceCorner = (_e329 * (_e330 + 2f)); - let _e334 = tile_4[0u]; - let _e335 = depthTile; - let _e338 = momentsTop; - let _e340 = tile_4[1u]; - let _e341 = depthTile; - momentCorner = vec2((_e334 * (_e335 + 2f)), (_e338 + (_e340 * (_e341 + 2f)))); - let _e346 = irradianceCorner; - param_119 = (_e346 + vec2(1f)); - let _e349 = AtlasTexel_u0028_vf2_u003b((¶m_119)); - if (_e349.w < 0.5f) { + let _e286 = corner_1; + if (_e286 < 8i) { + let _e288 = corner_1; + let _e291 = corner_1; + let _e296 = corner_1; + offset_3 = vec3(f32((_e288 & 1i)), f32(((_e291 >> bitcast(1i)) & 1i)), f32(((_e296 >> bitcast(2i)) & 1i))); + let _e302 = base; + let _e303 = offset_3; + cell_1 = (_e302 + _e303); + let _e306 = cell_1[2u]; + let _e308 = counts[1u]; + let _e311 = cell_1[1u]; + let _e314 = counts[0u]; + let _e317 = cell_1[0u]; + probe = ((((_e306 * _e308) + _e311) * _e314) + _e317); + let _e319 = probe; + let _e320 = columns; + let _e325 = probe; + let _e326 = columns; + tile_4 = vec2((_e319 - (floor((_e319 / _e320)) * _e320)), floor((_e325 / _e326))); + let _e330 = tile_4; + let _e331 = irradianceTile; + irradianceCorner = (_e330 * (_e331 + 2f)); + let _e335 = tile_4[0u]; + let _e336 = depthTile; + let _e339 = momentsTop; + let _e341 = tile_4[1u]; + let _e342 = depthTile; + momentCorner = vec2((_e335 * (_e336 + 2f)), (_e339 + (_e341 * (_e342 + 2f)))); + let _e347 = irradianceCorner; + param_119 = (_e347 + vec2(1f)); + let _e350 = AtlasTexel_u0028_vf2_u003b((¶m_119)); + if (_e350.w < 0.5f) { continue; } - let _e352 = f_1; - let _e354 = f_1; - let _e355 = offset_3; - trilinear = mix((vec3(1f, 1f, 1f) - _e352), _e354, _e355); - let _e358 = trilinear[0u]; - let _e360 = trilinear[1u]; - let _e363 = trilinear[2u]; - weight_3 = max(((_e358 * _e360) * _e363), 0.001f); - let _e366 = origin_2; - let _e367 = spacing; - let _e368 = cell_1; - probePosition = (_e366 + (_e367 * _e368)); - let _e371 = probePosition; - let _e372 = biased; - toProbe = (_e371 - _e372); - let _e374 = toProbe; - distance_4 = length(_e374); - let _e376 = distance_4; - if (_e376 > 0.000001f) { - let _e378 = toProbe; - let _e379 = distance_4; - direction_2 = (_e378 / vec3(_e379)); - let _e382 = unit; - let _e383 = probePosition; - let _e384 = (*world_4); - facing = ((dot(_e382, normalize((_e383 - _e384))) * 0.5f) + 0.5f); - let _e390 = facing; + let _e353 = f_1; + let _e355 = f_1; + let _e356 = offset_3; + trilinear = mix((vec3(1f, 1f, 1f) - _e353), _e355, _e356); + let _e359 = trilinear[0u]; + let _e361 = trilinear[1u]; + let _e364 = trilinear[2u]; + weight_3 = max(((_e359 * _e361) * _e364), 0.001f); + let _e367 = origin_2; + let _e368 = spacing; + let _e369 = cell_1; + probePosition = (_e367 + (_e368 * _e369)); + let _e372 = probePosition; + let _e373 = biased; + toProbe = (_e372 - _e373); + let _e375 = toProbe; + distance_4 = length(_e375); + let _e377 = distance_4; + if (_e377 > 0.000001f) { + let _e379 = toProbe; + let _e380 = distance_4; + direction_2 = (_e379 / vec3(_e380)); + let _e383 = unit; + let _e384 = probePosition; + let _e385 = (*world_4); + facing = ((dot(_e383, normalize((_e384 - _e385))) * 0.5f) + 0.5f); let _e391 = facing; - probeWeight = ((_e390 * _e391) + 0.2f); - let _e394 = direction_2; - param_120 = -(_e394); - let _e396 = ProbeOctahedral_u0028_vf3_u003b((¶m_120)); - let _e397 = momentCorner; - param_121 = _e397; - let _e398 = depthTile; - param_122 = _e398; - param_123 = _e396; - let _e399 = TileBilinear_u0028_vf2_u003b_f1_u003b_vf2_u003b((¶m_121), (¶m_122), (¶m_123)); - moments_3 = _e399.xy; + let _e392 = facing; + probeWeight = ((_e391 * _e392) + 0.2f); + let _e395 = direction_2; + param_120 = -(_e395); + let _e397 = ProbeOctahedral_u0028_vf3_u003b((¶m_120)); + let _e398 = momentCorner; + param_121 = _e398; + let _e399 = depthTile; + param_122 = _e399; + param_123 = _e397; + let _e400 = TileBilinear_u0028_vf2_u003b_f1_u003b_vf2_u003b((¶m_121), (¶m_122), (¶m_123)); + moments_3 = _e400.xy; chebyshev = 1f; - let _e401 = distance_4; - let _e403 = moments_3[0u]; - if (_e401 > _e403) { - let _e406 = moments_3[1u]; - let _e408 = moments_3[0u]; - let _e410 = moments_3[0u]; - variance_1 = max((_e406 - (_e408 * _e410)), 0.000001f); - let _e414 = distance_4; - let _e416 = moments_3[0u]; - difference = (_e414 - _e416); - let _e418 = variance_1; + let _e402 = distance_4; + let _e404 = moments_3[0u]; + if (_e402 > _e404) { + let _e407 = moments_3[1u]; + let _e409 = moments_3[0u]; + let _e411 = moments_3[0u]; + variance_1 = max((_e407 - (_e409 * _e411)), 0.000001f); + let _e415 = distance_4; + let _e417 = moments_3[0u]; + difference = (_e415 - _e417); let _e419 = variance_1; - let _e420 = difference; + let _e420 = variance_1; let _e421 = difference; - chebyshev = (_e418 / (_e419 + (_e420 * _e421))); - let _e425 = chebyshev; + let _e422 = difference; + chebyshev = (_e419 / (_e420 + (_e421 * _e422))); let _e426 = chebyshev; - let _e428 = chebyshev; - chebyshev = ((_e425 * _e426) * _e428); + let _e427 = chebyshev; + let _e429 = chebyshev; + chebyshev = ((_e426 * _e427) * _e429); } - let _e430 = probeWeight; - let _e431 = chebyshev; - probeWeight = max((_e430 * max(_e431, 0.05f)), 0.000001f); - let _e435 = probeWeight; - if (_e435 < 0.2f) { - let _e437 = probeWeight; + let _e431 = probeWeight; + let _e432 = chebyshev; + probeWeight = max((_e431 * max(_e432, 0.05f)), 0.000001f); + let _e436 = probeWeight; + if (_e436 < 0.2f) { let _e438 = probeWeight; - let _e441 = probeWeight; - probeWeight = (_e441 * ((_e437 * _e438) * 25f)); + let _e439 = probeWeight; + let _e442 = probeWeight; + probeWeight = (_e442 * ((_e438 * _e439) * 25f)); } - let _e443 = probeWeight; - let _e444 = weight_3; - weight_3 = (_e444 * _e443); - } - let _e446 = unit; - param_124 = _e446; - let _e447 = ProbeOctahedral_u0028_vf3_u003b((¶m_124)); - let _e448 = irradianceCorner; - param_125 = _e448; - let _e449 = irradianceTile; - param_126 = _e449; - param_127 = _e447; - let _e450 = TileBilinear_u0028_vf2_u003b_f1_u003b_vf2_u003b((¶m_125), (¶m_126), (¶m_127)); - let _e452 = weight_3; - let _e454 = total_2; - total_2 = (_e454 + (_e450.xyz * _e452)); - let _e456 = weight_3; - let _e457 = weights; - weights = (_e457 + _e456); + let _e444 = probeWeight; + let _e445 = weight_3; + weight_3 = (_e445 * _e444); + } + let _e447 = unit; + param_124 = _e447; + let _e448 = ProbeOctahedral_u0028_vf3_u003b((¶m_124)); + let _e449 = irradianceCorner; + param_125 = _e449; + let _e450 = irradianceTile; + param_126 = _e450; + param_127 = _e448; + let _e451 = TileBilinear_u0028_vf2_u003b_f1_u003b_vf2_u003b((¶m_125), (¶m_126), (¶m_127)); + let _e453 = weight_3; + let _e455 = total_2; + total_2 = (_e455 + (_e451.xyz * _e453)); + let _e457 = weight_3; + let _e458 = weights; + weights = (_e458 + _e457); continue; } else { break; } continuing { - let _e459 = corner_1; - corner_1 = (_e459 + 1i); + let _e460 = corner_1; + corner_1 = (_e460 + 1i); } } - let _e461 = weights; - if (_e461 > 0f) { - let _e463 = total_2; - let _e464 = weights; - local_27 = (_e463 / vec3(_e464)); + let _e462 = weights; + if (_e462 > 0f) { + let _e464 = total_2; + let _e465 = weights; + local_27 = (_e464 / vec3(_e465)); } else { local_27 = vec3(0f, 0f, 0f); } - let _e467 = local_27; - return _e467; + let _e468 = local_27; + return _e468; } fn IrradianceEnabled_u0028_() -> bool { - let _e190 = irradiance_info.origin[3u]; - return (_e190 > 0.5f); + let _e191 = irradiance_info.origin[3u]; + return (_e191 > 0.5f); } fn ApplyCommonMaps_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b(s_10: ptr) { @@ -26414,50 +26589,50 @@ fn ApplyCommonMaps_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d var param_132: Surface; var param_133: Surface; - let _e195 = IrradianceEnabled_u0028_(); - if _e195 { - let _e196 = v_world_position_1; - param_128 = _e196; - let _e198 = (*s_10).n; - param_129 = _e198; - let _e200 = (*s_10).v; - param_130 = _e200; - let _e201 = SampleIrradiance_u0028_vf3_u003b_vf3_u003b_vf3_u003b((¶m_128), (¶m_129), (¶m_130)); - let _e204 = frag_info.material[2u]; - (*s_10).ambient = (_e201 * _e204); + let _e196 = IrradianceEnabled_u0028_(); + if _e196 { + let _e197 = v_world_position_1; + param_128 = _e197; + let _e199 = (*s_10).n; + param_129 = _e199; + let _e201 = (*s_10).v; + param_130 = _e201; + let _e202 = SampleIrradiance_u0028_vf3_u003b_vf3_u003b_vf3_u003b((¶m_128), (¶m_129), (¶m_130)); + let _e205 = frag_info.material[2u]; + (*s_10).ambient = (_e202 * _e205); } - let _e207 = (*s_10); - param_131 = _e207; + let _e208 = (*s_10); + param_131 = _e208; ApplyNormalMap_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b((¶m_131)); - let _e208 = param_131; - (*s_10) = _e208; - let _e209 = (*s_10); - param_132 = _e209; - ApplyOcclusionMap_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b((¶m_132)); - let _e210 = param_132; - (*s_10) = _e210; - let _e211 = (*s_10); - param_133 = _e211; + let _e209 = param_131; + (*s_10) = _e209; + let _e210 = (*s_10); + param_132 = _e210; + ApplyOcclusionMap_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b((¶m_132)); + let _e211 = param_132; + (*s_10) = _e211; + let _e212 = (*s_10); + param_133 = _e212; ApplyEmissiveMap_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b((¶m_133)); - let _e212 = param_133; - (*s_10) = _e212; + let _e213 = param_133; + (*s_10) = _e213; return; } fn TowardsEye_u0028_() -> vec3 { var local_28: vec3; - let _e189 = Orthographic_u0028_(); - if _e189 { - let _e191 = fog_info.forward; - local_28 = -(_e191.xyz); + let _e190 = Orthographic_u0028_(); + if _e190 { + let _e192 = fog_info.forward; + local_28 = -(_e192.xyz); } else { - let _e195 = fog_info.eye; - let _e197 = v_world_position_1; - local_28 = normalize((_e195.xyz - _e197)); + let _e196 = fog_info.eye; + let _e198 = v_world_position_1; + local_28 = normalize((_e196.xyz - _e198)); } - let _e200 = local_28; - return _e200; + let _e201 = local_28; + return _e201; } fn ReadSurface_u0028_() -> Surface { @@ -26470,89 +26645,89 @@ fn ReadSurface_u0028_() -> Surface { var anchored: vec3; var noise_1: f32; - let _e196 = v_texcoord_1; - let _e197 = MaterialLodBias_u0028_(); - let _e198 = textureSampleBias(base_color_texture_tex, base_color_texture_smp, _e196, _e197); - texel_6 = _e198; - let _e199 = texel_6; - param_134 = _e199.xyz; - let _e201 = SrgbToLinear_u0028_vf3_u003b((¶m_134)); - let _e203 = frag_info.base_color; - param_135 = _e203.xyz; - let _e205 = SrgbToLinear_u0028_vf3_u003b((¶m_135)); - let _e207 = v_color_1; - s_11.albedo = ((_e201 * _e205) * _e207.xyz); - let _e212 = texel_6[3u]; - let _e215 = frag_info.base_color[3u]; - let _e218 = v_color_1[3u]; - s_11.alpha = ((_e212 * _e215) * _e218); - let _e222 = s_11.albedo; - g_albedo = _e222; - let _e225 = frag_info.material2_[0u]; - cutoff = _e225; - let _e226 = cutoff; - if (_e226 > 1f) { - let _e228 = cutoff; - edge = (_e228 - 1f); - let _e231 = s_11.alpha; - let _e232 = edge; - let _e235 = s_11.alpha; - let _e236 = fwidth(_e235); - s_11.alpha = clamp((((_e231 - _e232) / max(_e236, 0.0001f)) + 0.5f), 0f, 1f); - } else { - let _e242 = cutoff; - if (_e242 >= 0f) { - let _e245 = s_11.alpha; - let _e246 = cutoff; - if (_e245 < _e246) { + let _e197 = v_texcoord_1; + let _e198 = MaterialLodBias_u0028_(); + let _e199 = textureSampleBias(base_color_texture_tex, base_color_texture_smp, _e197, _e198); + texel_6 = _e199; + let _e200 = texel_6; + param_134 = _e200.xyz; + let _e202 = SrgbToLinear_u0028_vf3_u003b((¶m_134)); + let _e204 = frag_info.base_color; + param_135 = _e204.xyz; + let _e206 = SrgbToLinear_u0028_vf3_u003b((¶m_135)); + let _e208 = v_color_1; + s_11.albedo = ((_e202 * _e206) * _e208.xyz); + let _e213 = texel_6[3u]; + let _e216 = frag_info.base_color[3u]; + let _e219 = v_color_1[3u]; + s_11.alpha = ((_e213 * _e216) * _e219); + let _e223 = s_11.albedo; + g_albedo = _e223; + let _e226 = frag_info.material2_[0u]; + cutoff = _e226; + let _e227 = cutoff; + if (_e227 > 1f) { + let _e229 = cutoff; + edge = (_e229 - 1f); + let _e232 = s_11.alpha; + let _e233 = edge; + let _e236 = s_11.alpha; + let _e237 = fwidth(_e236); + s_11.alpha = clamp((((_e232 - _e233) / max(_e237, 0.0001f)) + 0.5f), 0f, 1f); + } else { + let _e243 = cutoff; + if (_e243 >= 0f) { + let _e246 = s_11.alpha; + let _e247 = cutoff; + if (_e246 < _e247) { discard; } s_11.alpha = 1f; } else { - let _e249 = cutoff; - if (_e249 < -1.5f) { - let _e251 = v_world_position_1; - anchored = floor((_e251 * 16f)); - let _e254 = anchored; - noise_1 = fract((sin(dot(_e254, vec3(12.9898f, 78.233f, 37.719f))) * 43758.547f)); - let _e260 = s_11.alpha; - let _e261 = noise_1; - if (_e260 < _e261) { + let _e250 = cutoff; + if (_e250 < -1.5f) { + let _e252 = v_world_position_1; + anchored = floor((_e252 * 16f)); + let _e255 = anchored; + noise_1 = fract((sin(dot(_e255, vec3(12.9898f, 78.233f, 37.719f))) * 43758.547f)); + let _e261 = s_11.alpha; + let _e262 = noise_1; + if (_e261 < _e262) { discard; } } } } - let _e263 = cutoff; - let _e265 = cutoff; - g_premultiply = ((_e263 < 0f) && (_e265 > -0.75f)); - let _e268 = v_normal_1; - s_11.n = normalize(_e268); - let _e271 = gl_FrontFacing_1; - if !(_e271) { - let _e274 = s_11.n; - s_11.n = -(_e274); - } - let _e277 = TowardsEye_u0028_(); - s_11.v = _e277; - let _e280 = s_11.n; - let _e282 = s_11.v; - s_11.n_dot_v = max(dot(_e280, _e282), 0.0001f); - let _e288 = frag_info.material[0u]; - s_11.metallic = clamp(_e288, 0f, 1f); - let _e293 = frag_info.material[1u]; - s_11.roughness = clamp(_e293, 0.02f, 1f); - let _e297 = frag_info.ambient_ground; - let _e300 = frag_info.ambient_sky; - let _e304 = s_11.n[1u]; - let _e311 = frag_info.material[2u]; - s_11.ambient = (mix(_e297.xyz, _e300.xyz, vec3(((_e304 * 0.5f) + 0.5f))) * _e311); - let _e316 = frag_info.frame_params[0u]; - s_11.exposure = max(_e316, 0f); + let _e264 = cutoff; + let _e266 = cutoff; + g_premultiply = ((_e264 < 0f) && (_e266 > -0.75f)); + let _e269 = v_normal_1; + s_11.n = normalize(_e269); + let _e272 = gl_FrontFacing_1; + if !(_e272) { + let _e275 = s_11.n; + s_11.n = -(_e275); + } + let _e278 = TowardsEye_u0028_(); + s_11.v = _e278; + let _e281 = s_11.n; + let _e283 = s_11.v; + s_11.n_dot_v = max(dot(_e281, _e283), 0.0001f); + let _e289 = frag_info.material[0u]; + s_11.metallic = clamp(_e289, 0f, 1f); + let _e294 = frag_info.material[1u]; + s_11.roughness = clamp(_e294, 0.02f, 1f); + let _e298 = frag_info.ambient_ground; + let _e301 = frag_info.ambient_sky; + let _e305 = s_11.n[1u]; + let _e312 = frag_info.material[2u]; + s_11.ambient = (mix(_e298.xyz, _e301.xyz, vec3(((_e305 * 0.5f) + 0.5f))) * _e312); + let _e317 = frag_info.frame_params[0u]; + s_11.exposure = max(_e317, 0f); s_11.occlusion = 1f; s_11.emissive = vec3(0f, 0f, 0f); - let _e321 = s_11; - return _e321; + let _e322 = s_11; + return _e322; } fn main_1() { @@ -26577,48 +26752,48 @@ fn main_1() { g_cluster_offset = 0f; g_cluster_count = 0f; light_transmittance = vec3(1f, 1f, 1f); - let _e200 = ReadSurface_u0028_(); - s_12 = _e200; - let _e201 = s_12; - param_136 = _e201; + let _e201 = ReadSurface_u0028_(); + s_12 = _e201; + let _e202 = s_12; + param_136 = _e202; ApplyCommonMaps_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b((¶m_136)); - let _e202 = param_136; - s_12 = _e202; - let _e203 = s_12; - param_137 = _e203; + let _e203 = param_136; + s_12 = _e203; + let _e204 = s_12; + param_137 = _e204; ApplyMetallicRoughnessMap_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b((¶m_137)); - let _e204 = param_137; - s_12 = _e204; - let _e206 = s_12.n_dot_v; - let _e211 = frag_info.material[3u]; - rim = (pow((1f - _e206), 3f) * _e211); - let _e214 = s_12.albedo; - let _e216 = s_12.ambient; - let _e217 = SampleLightmap_u0028_(); - let _e221 = s_12.occlusion; - ambient = ((_e214 * (_e216 + _e217)) * _e221); - let _e223 = s_12; - param_138 = _e223; - let _e224 = AccumulateLights_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b((¶m_138)); - let _e226 = s_12.occlusion; - let _e228 = ambient; - let _e230 = rim; - let _e235 = s_12.emissive; - lit_3 = ((((_e224 * _e226) + _e228) + vec3((_e230 * 0.35f))) + _e235); - let _e237 = s_12; - param_139 = _e237; - let _e238 = lit_3; - param_140 = _e238; - let _e239 = WriteDebugView_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_vf3_u003b((¶m_139), (¶m_140)); - if _e239 { + let _e205 = param_137; + s_12 = _e205; + let _e207 = s_12.n_dot_v; + let _e212 = frag_info.material[3u]; + rim = (pow((1f - _e207), 3f) * _e212); + let _e215 = s_12.albedo; + let _e217 = s_12.ambient; + let _e218 = SampleLightmap_u0028_(); + let _e222 = s_12.occlusion; + ambient = ((_e215 * (_e217 + _e218)) * _e222); + let _e224 = s_12; + param_138 = _e224; + let _e225 = AccumulateLights_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b((¶m_138)); + let _e227 = s_12.occlusion; + let _e229 = ambient; + let _e231 = rim; + let _e236 = s_12.emissive; + lit_3 = ((((_e225 * _e227) + _e229) + vec3((_e231 * 0.35f))) + _e236); + let _e238 = s_12; + param_139 = _e238; + let _e239 = lit_3; + param_140 = _e239; + let _e240 = WriteDebugView_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_vf3_u003b((¶m_139), (¶m_140)); + if _e240 { return; } - let _e240 = lit_3; - param_141 = _e240; - let _e242 = s_12.alpha; - param_142 = _e242; - let _e244 = s_12.roughness; - param_143 = _e244; + let _e241 = lit_3; + param_141 = _e241; + let _e243 = s_12.alpha; + param_142 = _e243; + let _e245 = s_12.roughness; + param_143 = _e245; WriteSurface_u0028_vf3_u003b_f1_u003b_f1_u003b((¶m_141), (¶m_142), (¶m_143)); return; } @@ -46207,10 +46382,10 @@ var v_tangent_1: vec4; var v_lightmap_uv_1: vec2; fn ViewDepth_u0028_() -> f32 { - let _e178 = v_world_position_1; - let _e180 = fog_info.eye; - let _e184 = fog_info.forward; - return dot((_e178 - _e180.xyz), _e184.xyz); + let _e179 = v_world_position_1; + let _e181 = fog_info.eye; + let _e185 = fog_info.forward; + return dot((_e179 - _e181.xyz), _e185.xyz); } fn WeightedBlendedWeight_u0028_f1_u003b(alpha: ptr) -> f32 { @@ -46219,22 +46394,22 @@ fn WeightedBlendedWeight_u0028_f1_u003b(alpha: ptr) -> f32 { var far: f32; var far3_: f32; - let _e183 = ViewDepth_u0028_(); - z = abs(_e183); - let _e185 = z; - near = (_e185 / 5f); - let _e187 = z; - far = (_e187 / 200f); - let _e189 = far; + let _e184 = ViewDepth_u0028_(); + z = abs(_e184); + let _e186 = z; + near = (_e186 / 5f); + let _e188 = z; + far = (_e188 / 200f); let _e190 = far; - let _e192 = far; - far3_ = ((_e189 * _e190) * _e192); - let _e194 = (*alpha); - let _e195 = near; + let _e191 = far; + let _e193 = far; + far3_ = ((_e190 * _e191) * _e193); + let _e195 = (*alpha); let _e196 = near; - let _e199 = far3_; + let _e197 = near; let _e200 = far3_; - return (_e194 * clamp((10f / ((0.00001f + (_e195 * _e196)) + (_e199 * _e200))), 0.01f, 3000f)); + let _e201 = far3_; + return (_e195 * clamp((10f / ((0.00001f + (_e196 * _e197)) + (_e200 * _e201))), 0.01f, 3000f)); } fn WriteWeightedBlended_u0028_() { @@ -46246,39 +46421,39 @@ fn WriteWeightedBlended_u0028_() { var revealage: bool; var local: vec4; - let _e187 = fog_info.forward[3u]; - mode = _e187; - let _e188 = mode; - if (_e188 > 0.5f) { - let _e191 = frag_color[3u]; - alpha_1 = _e191; - let _e192 = alpha_1; - param = _e192; - let _e193 = WeightedBlendedWeight_u0028_f1_u003b((¶m)); - weight = _e193; - let _e194 = frag_color; - let _e196 = weight; - let _e197 = (_e194.xyz * _e196); - let _e198 = alpha_1; - let _e199 = weight; - accumulate = vec4(_e197.x, _e197.y, _e197.z, (_e198 * _e199)); - let _e205 = mode; - let _e207 = mode; - revealage = ((_e205 > 1.5f) && (_e207 < 2.5f)); - let _e210 = revealage; - if _e210 { - let _e211 = alpha_1; - local = vec4(_e211); + let _e188 = fog_info.forward[3u]; + mode = _e188; + let _e189 = mode; + if (_e189 > 0.5f) { + let _e192 = frag_color[3u]; + alpha_1 = _e192; + let _e193 = alpha_1; + param = _e193; + let _e194 = WeightedBlendedWeight_u0028_f1_u003b((¶m)); + weight = _e194; + let _e195 = frag_color; + let _e197 = weight; + let _e198 = (_e195.xyz * _e197); + let _e199 = alpha_1; + let _e200 = weight; + accumulate = vec4(_e198.x, _e198.y, _e198.z, (_e199 * _e200)); + let _e206 = mode; + let _e208 = mode; + revealage = ((_e206 > 1.5f) && (_e208 < 2.5f)); + let _e211 = revealage; + if _e211 { + let _e212 = alpha_1; + local = vec4(_e212); } else { - let _e213 = accumulate; - local = _e213; + let _e214 = accumulate; + local = _e214; } - let _e214 = local; - frag_color = _e214; - let _e215 = mode; - if (_e215 > 2.5f) { - let _e217 = alpha_1; - frag_surface = vec4(_e217); + let _e215 = local; + frag_color = _e215; + let _e216 = mode; + if (_e216 > 2.5f) { + let _e218 = alpha_1; + frag_surface = vec4(_e218); } } return; @@ -46287,29 +46462,29 @@ fn WriteWeightedBlended_u0028_() { fn EncodeOctahedral_u0028_vf3_u003b(n: ptr>) -> vec2 { var e: vec2; - let _e181 = (*n)[0u]; - let _e184 = (*n)[1u]; - let _e188 = (*n)[2u]; - let _e191 = (*n); - (*n) = (_e191 / vec3(((abs(_e181) + abs(_e184)) + abs(_e188)))); - let _e194 = (*n); - e = _e194.xy; - let _e197 = (*n)[2u]; - if (_e197 < 0f) { - let _e199 = (*n); - let _e205 = (*n)[0u]; - let _e209 = (*n)[1u]; - e = ((vec2(1f) - abs(_e199.yx)) * vec2(select(-1f, 1f, (_e205 >= 0f)), select(-1f, 1f, (_e209 >= 0f)))); + let _e182 = (*n)[0u]; + let _e185 = (*n)[1u]; + let _e189 = (*n)[2u]; + let _e192 = (*n); + (*n) = (_e192 / vec3(((abs(_e182) + abs(_e185)) + abs(_e189)))); + let _e195 = (*n); + e = _e195.xy; + let _e198 = (*n)[2u]; + if (_e198 < 0f) { + let _e200 = (*n); + let _e206 = (*n)[0u]; + let _e210 = (*n)[1u]; + e = ((vec2(1f) - abs(_e200.yx)) * vec2(select(-1f, 1f, (_e206 >= 0f)), select(-1f, 1f, (_e210 >= 0f)))); } - let _e214 = e; - return ((_e214 * 0.5f) + vec2(0.5f)); + let _e215 = e; + return ((_e215 * 0.5f) + vec2(0.5f)); } fn LinearToSrgb_u0028_vf3_u003b(linear: ptr>) -> vec3 { - let _e179 = (*linear); - let _e181 = (*linear); - let _e185 = (*linear); - return mix((_e179 * 12.92f), ((pow(_e181, vec3(0.41666666f, 0.41666666f, 0.41666666f)) * 1.055f) - vec3(0.055f, 0.055f, 0.055f)), step(vec3(0.0031308f, 0.0031308f, 0.0031308f), _e185)); + let _e180 = (*linear); + let _e182 = (*linear); + let _e186 = (*linear); + return mix((_e180 * 12.92f), ((pow(_e182, vec3(0.41666666f, 0.41666666f, 0.41666666f)) * 1.055f) - vec3(0.055f, 0.055f, 0.055f)), step(vec3(0.0031308f, 0.0031308f, 0.0031308f), _e186)); } fn WriteSurfaceGeometry_u0028_f1_u003b(roughness: ptr) { @@ -46317,52 +46492,52 @@ fn WriteSurfaceGeometry_u0028_f1_u003b(roughness: ptr) { var geometric: vec3; var param_2: vec3; - let _e182 = g_albedo; - param_1 = clamp(_e182, vec3(0f, 0f, 0f), vec3(1f, 1f, 1f)); - let _e184 = LinearToSrgb_u0028_vf3_u003b((¶m_1)); - frag_albedo = vec4(_e184.x, _e184.y, _e184.z, 1f); - let _e189 = g_debug_surface_on; - if _e189 { - let _e190 = g_debug_surface; - let _e191 = ViewDepth_u0028_(); - frag_surface = vec4(_e190.x, _e190.y, _e190.z, _e191); + let _e183 = g_albedo; + param_1 = clamp(_e183, vec3(0f, 0f, 0f), vec3(1f, 1f, 1f)); + let _e185 = LinearToSrgb_u0028_vf3_u003b((¶m_1)); + frag_albedo = vec4(_e185.x, _e185.y, _e185.z, 1f); + let _e190 = g_debug_surface_on; + if _e190 { + let _e191 = g_debug_surface; + let _e192 = ViewDepth_u0028_(); + frag_surface = vec4(_e191.x, _e191.y, _e191.z, _e192); return; } - let _e196 = v_normal_1; - geometric = normalize(_e196); - let _e198 = gl_FrontFacing_1; - if !(_e198) { - let _e200 = geometric; - geometric = -(_e200); - } - let _e202 = geometric; - param_2 = _e202; - let _e203 = EncodeOctahedral_u0028_vf3_u003b((¶m_2)); - let _e204 = (*roughness); - let _e206 = ViewDepth_u0028_(); - frag_surface = vec4(_e203.x, _e203.y, clamp(_e204, 0f, 1f), _e206); + let _e197 = v_normal_1; + geometric = normalize(_e197); + let _e199 = gl_FrontFacing_1; + if !(_e199) { + let _e201 = geometric; + geometric = -(_e201); + } + let _e203 = geometric; + param_2 = _e203; + let _e204 = EncodeOctahedral_u0028_vf3_u003b((¶m_2)); + let _e205 = (*roughness); + let _e207 = ViewDepth_u0028_(); + frag_surface = vec4(_e204.x, _e204.y, clamp(_e205, 0f, 1f), _e207); return; } fn Orthographic_u0028_() -> bool { - let _e180 = fog_info.projection[0u]; - return (_e180 > 0.5f); + let _e181 = fog_info.projection[0u]; + return (_e181 > 0.5f); } fn EyeDistance_u0028_() -> f32 { var local_1: f32; - let _e179 = Orthographic_u0028_(); - if _e179 { - let _e180 = ViewDepth_u0028_(); - local_1 = max(_e180, 0f); + let _e180 = Orthographic_u0028_(); + if _e180 { + let _e181 = ViewDepth_u0028_(); + local_1 = max(_e181, 0f); } else { - let _e182 = v_world_position_1; - let _e184 = fog_info.eye; - local_1 = distance(_e182, _e184.xyz); + let _e183 = v_world_position_1; + let _e185 = fog_info.eye; + local_1 = distance(_e183, _e185.xyz); } - let _e187 = local_1; - return _e187; + let _e188 = local_1; + return _e188; } fn ApplyFog_u0028_vf3_u003b(color: ptr>) -> vec3 { @@ -46372,41 +46547,41 @@ fn ApplyFog_u0028_vf3_u003b(color: ptr>) -> vec3 { var k: f32; var local_2: f32; - let _e186 = fog_info.fog[3u]; - density = _e186; - let _e187 = density; - if (_e187 <= 0f) { - let _e189 = (*color); - return _e189; - } - let _e190 = EyeDistance_u0028_(); - d = _e190; - let _e193 = fog_info.eye[3u]; - falloff = _e193; - let _e194 = falloff; - if (_e194 > 0f) { - let _e196 = falloff; - let _e198 = v_world_position_1[1u]; - let _e201 = fog_info.eye[1u]; - k = (_e196 * (_e198 - _e201)); - let _e204 = k; - if (abs(_e204) > 0.001f) { - let _e207 = k; - let _e211 = k; - local_2 = ((1f - exp(-(_e207))) / _e211); + let _e187 = fog_info.fog[3u]; + density = _e187; + let _e188 = density; + if (_e188 <= 0f) { + let _e190 = (*color); + return _e190; + } + let _e191 = EyeDistance_u0028_(); + d = _e191; + let _e194 = fog_info.eye[3u]; + falloff = _e194; + let _e195 = falloff; + if (_e195 > 0f) { + let _e197 = falloff; + let _e199 = v_world_position_1[1u]; + let _e202 = fog_info.eye[1u]; + k = (_e197 * (_e199 - _e202)); + let _e205 = k; + if (abs(_e205) > 0.001f) { + let _e208 = k; + let _e212 = k; + local_2 = ((1f - exp(-(_e208))) / _e212); } else { - let _e213 = k; - local_2 = (1f - (0.5f * _e213)); + let _e214 = k; + local_2 = (1f - (0.5f * _e214)); } - let _e216 = local_2; - let _e217 = density; - density = (_e217 * _e216); + let _e217 = local_2; + let _e218 = density; + density = (_e218 * _e217); } - let _e220 = fog_info.fog; - let _e222 = (*color); - let _e223 = density; - let _e225 = d; - return mix(_e220.xyz, _e222, vec3(clamp(exp((-(_e223) * _e225)), 0f, 1f))); + let _e221 = fog_info.fog; + let _e223 = (*color); + let _e224 = density; + let _e226 = d; + return mix(_e221.xyz, _e223, vec3(clamp(exp((-(_e224) * _e226)), 0f, 1f))); } fn WriteSurface_u0028_vf3_u003b_f1_u003b_f1_u003b(linearColor: ptr>, alpha_2: ptr, roughness_1: ptr) { @@ -46414,44 +46589,44 @@ fn WriteSurface_u0028_vf3_u003b_f1_u003b_f1_u003b(linearColor: ptr; var param_4: f32; - let _e184 = g_premultiply; - let _e185 = (*alpha_2); - weight_1 = select(1f, _e185, _e184); - let _e187 = (*linearColor); - param_3 = _e187; - let _e188 = ApplyFog_u0028_vf3_u003b((¶m_3)); - let _e189 = weight_1; - let _e190 = (_e188 * _e189); - let _e191 = (*alpha_2); - let _e192 = g_pass_through; - frag_color = vec4(_e190.x, _e190.y, _e190.z, (_e191 * (1f - _e192))); - let _e199 = (*roughness_1); - param_4 = _e199; + let _e185 = g_premultiply; + let _e186 = (*alpha_2); + weight_1 = select(1f, _e186, _e185); + let _e188 = (*linearColor); + param_3 = _e188; + let _e189 = ApplyFog_u0028_vf3_u003b((¶m_3)); + let _e190 = weight_1; + let _e191 = (_e189 * _e190); + let _e192 = (*alpha_2); + let _e193 = g_pass_through; + frag_color = vec4(_e191.x, _e191.y, _e191.z, (_e192 * (1f - _e193))); + let _e200 = (*roughness_1); + param_4 = _e200; WriteSurfaceGeometry_u0028_f1_u003b((¶m_4)); WriteWeightedBlended_u0028_(); return; } fn SrgbToLinear_u0028_vf3_u003b(srgb: ptr>) -> vec3 { - let _e179 = (*srgb); - let _e182 = (*srgb); - let _e187 = (*srgb); - return mix((_e179 / vec3(12.92f)), pow(((_e182 + vec3(0.055f, 0.055f, 0.055f)) / vec3(1.055f)), vec3(2.4f, 2.4f, 2.4f)), step(vec3(0.04045f, 0.04045f, 0.04045f), _e187)); + let _e180 = (*srgb); + let _e183 = (*srgb); + let _e188 = (*srgb); + return mix((_e180 / vec3(12.92f)), pow(((_e183 + vec3(0.055f, 0.055f, 0.055f)) / vec3(1.055f)), vec3(2.4f, 2.4f, 2.4f)), step(vec3(0.04045f, 0.04045f, 0.04045f), _e188)); } fn NonFinite_u0028_vf3_u003b(c: ptr>) -> bool { var phi_2753_: bool; - let _e179 = (*c); let _e180 = (*c); - let _e182 = any((_e179 != _e180)); - phi_2753_ = _e182; - if !(_e182) { - let _e184 = (*c); - phi_2753_ = any((abs(_e184) > vec3(300000000000000000000000000000000000000f, 300000000000000000000000000000000000000f, 300000000000000000000000000000000000000f))); - } - let _e189 = phi_2753_; - return _e189; + let _e181 = (*c); + let _e183 = any((_e180 != _e181)); + phi_2753_ = _e183; + if !(_e183) { + let _e185 = (*c); + phi_2753_ = any((abs(_e185) > vec3(300000000000000000000000000000000000000f, 300000000000000000000000000000000000000f, 300000000000000000000000000000000000000f))); + } + let _e190 = phi_2753_; + return _e190; } fn WriteDebugView_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_vf3_u003b(s: ptr, lit: ptr>) -> bool { @@ -46469,78 +46644,78 @@ fn WriteDebugView_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_ var param_9: vec3; var param_10: f32; - let _e195 = frag_info.debug_view[0u]; - view = _e195; - let _e196 = view; - if (_e196 < 0.5f) { + let _e196 = frag_info.debug_view[0u]; + view = _e196; + let _e197 = view; + if (_e197 < 0.5f) { return false; } - let _e199 = gl_FragCoord_1[0u]; - let _e202 = frag_info.debug_view[1u]; - let _e205 = frag_info.debug_view[2u]; - if (_e199 < (_e202 * _e205)) { + let _e200 = gl_FragCoord_1[0u]; + let _e203 = frag_info.debug_view[1u]; + let _e206 = frag_info.debug_view[2u]; + if (_e200 < (_e203 * _e206)) { return false; } - let _e208 = view; - code = i32((_e208 + 0.5f)); + let _e209 = view; + code = i32((_e209 + 0.5f)); shown = vec3(0f, 0f, 0f); - let _e211 = code; - if (_e211 == 1i) { - let _e214 = (*s).albedo; - param_5 = clamp(_e214, vec3(0f, 0f, 0f), vec3(1f, 1f, 1f)); - let _e216 = LinearToSrgb_u0028_vf3_u003b((¶m_5)); - shown = _e216; - } else { - let _e217 = code; - if (_e217 == 2i) { - let _e220 = (*s).n; - shown = ((_e220 * 0.5f) + vec3(0.5f, 0.5f, 0.5f)); + let _e212 = code; + if (_e212 == 1i) { + let _e215 = (*s).albedo; + param_5 = clamp(_e215, vec3(0f, 0f, 0f), vec3(1f, 1f, 1f)); + let _e217 = LinearToSrgb_u0028_vf3_u003b((¶m_5)); + shown = _e217; + } else { + let _e218 = code; + if (_e218 == 2i) { + let _e221 = (*s).n; + shown = ((_e221 * 0.5f) + vec3(0.5f, 0.5f, 0.5f)); } else { - let _e223 = code; - if (_e223 == 3i) { - let _e226 = (*s).roughness; - shown = vec3(clamp(_e226, 0f, 1f)); + let _e224 = code; + if (_e224 == 3i) { + let _e227 = (*s).roughness; + shown = vec3(clamp(_e227, 0f, 1f)); } else { - let _e229 = code; - if (_e229 == 4i) { - let _e232 = (*s).metallic; - shown = vec3(clamp(_e232, 0f, 1f)); + let _e230 = code; + if (_e230 == 4i) { + let _e233 = (*s).metallic; + shown = vec3(clamp(_e233, 0f, 1f)); } else { - let _e235 = code; - if (_e235 == 5i) { - let _e238 = (*s).occlusion; - shown = vec3(clamp(_e238, 0f, 1f)); + let _e236 = code; + if (_e236 == 5i) { + let _e239 = (*s).occlusion; + shown = vec3(clamp(_e239, 0f, 1f)); } else { - let _e241 = code; - if (_e241 == 6i) { - let _e244 = (*s).emissive; - param_6 = clamp(_e244, vec3(0f, 0f, 0f), vec3(1f, 1f, 1f)); - let _e246 = LinearToSrgb_u0028_vf3_u003b((¶m_6)); - shown = _e246; + let _e242 = code; + if (_e242 == 6i) { + let _e245 = (*s).emissive; + param_6 = clamp(_e245, vec3(0f, 0f, 0f), vec3(1f, 1f, 1f)); + let _e247 = LinearToSrgb_u0028_vf3_u003b((¶m_6)); + shown = _e247; } else { - let _e247 = code; - if (_e247 == 7i) { - let _e249 = v_texcoord_1; - let _e250 = fract(_e249); - shown = vec3(_e250.x, _e250.y, 0f); + let _e248 = code; + if (_e248 == 7i) { + let _e250 = v_texcoord_1; + let _e251 = fract(_e250); + shown = vec3(_e251.x, _e251.y, 0f); } else { - let _e254 = code; - if (_e254 == 8i) { - let _e256 = (*lit); - param_7 = clamp(_e256, vec3(0f, 0f, 0f), vec3(1f, 1f, 1f)); - let _e258 = LinearToSrgb_u0028_vf3_u003b((¶m_7)); - grey = dot(_e258, vec3(0.2126f, 0.7152f, 0.0722f)); - let _e260 = (*lit); - param_8 = _e260; - let _e261 = NonFinite_u0028_vf3_u003b((¶m_8)); - if _e261 { + let _e255 = code; + if (_e255 == 8i) { + let _e257 = (*lit); + param_7 = clamp(_e257, vec3(0f, 0f, 0f), vec3(1f, 1f, 1f)); + let _e259 = LinearToSrgb_u0028_vf3_u003b((¶m_7)); + grey = dot(_e259, vec3(0.2126f, 0.7152f, 0.0722f)); + let _e261 = (*lit); + param_8 = _e261; + let _e262 = NonFinite_u0028_vf3_u003b((¶m_8)); + if _e262 { local_3 = vec3(1f, 0f, 1f); } else { - let _e262 = grey; - local_3 = vec3((_e262 * 0.5f)); + let _e263 = grey; + local_3 = vec3((_e263 * 0.5f)); } - let _e265 = local_3; - shown = _e265; + let _e266 = local_3; + shown = _e266; } } } @@ -46549,61 +46724,61 @@ fn WriteDebugView_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_ } } } - let _e266 = g_premultiply; - if _e266 { - let _e268 = (*s).alpha; - local_4 = _e268; + let _e267 = g_premultiply; + if _e267 { + let _e269 = (*s).alpha; + local_4 = _e269; } else { local_4 = 1f; } - let _e269 = local_4; - weight_2 = _e269; - let _e270 = shown; - param_9 = _e270; - let _e271 = SrgbToLinear_u0028_vf3_u003b((¶m_9)); - let _e272 = weight_2; - let _e273 = (_e271 * _e272); - let _e275 = (*s).alpha; - frag_color = vec4(_e273.x, _e273.y, _e273.z, _e275); - let _e281 = (*s).roughness; - param_10 = _e281; + let _e270 = local_4; + weight_2 = _e270; + let _e271 = shown; + param_9 = _e271; + let _e272 = SrgbToLinear_u0028_vf3_u003b((¶m_9)); + let _e273 = weight_2; + let _e274 = (_e272 * _e273); + let _e276 = (*s).alpha; + frag_color = vec4(_e274.x, _e274.y, _e274.z, _e276); + let _e282 = (*s).roughness; + param_10 = _e282; WriteSurfaceGeometry_u0028_f1_u003b((¶m_10)); WriteWeightedBlended_u0028_(); return true; } fn ShadeLight_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_struct_u002d_LightSample_u002d_vf3_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf31_u003b(s_1: ptr, light: ptr) -> vec3 { - let _e181 = (*s_1).albedo; - return _e181; + let _e182 = (*s_1).albedo; + return _e182; } fn PointShadowDiskTap_u0028_i1_u003b(i: ptr) -> vec2 { - let _e179 = (*i); - if (_e179 == 0i) { + let _e180 = (*i); + if (_e180 == 0i) { return vec2(-0.94201624f, -0.39906216f); } - let _e181 = (*i); - if (_e181 == 1i) { + let _e182 = (*i); + if (_e182 == 1i) { return vec2(0.9455861f, -0.76890725f); } - let _e183 = (*i); - if (_e183 == 2i) { + let _e184 = (*i); + if (_e184 == 2i) { return vec2(-0.0941841f, -0.9293887f); } - let _e185 = (*i); - if (_e185 == 3i) { + let _e186 = (*i); + if (_e186 == 3i) { return vec2(0.34495938f, 0.2938776f); } - let _e187 = (*i); - if (_e187 == 4i) { + let _e188 = (*i); + if (_e188 == 4i) { return vec2(-0.9158858f, 0.45771432f); } - let _e189 = (*i); - if (_e189 == 5i) { + let _e190 = (*i); + if (_e190 == 5i) { return vec2(-0.8154423f, -0.87912464f); } - let _e191 = (*i); - if (_e191 == 6i) { + let _e192 = (*i); + if (_e192 == 6i) { return vec2(-0.38277543f, 0.27676845f); } return vec2(0.974844f, 0.7564838f); @@ -46613,20 +46788,20 @@ fn PointShadowOffset_u0028_i1_u003b_f1_u003b_f1_u003b_f1_u003b(i_1: ptr; var param_11: i32; - let _e184 = (*i_1); - param_11 = _e184; - let _e185 = PointShadowDiskTap_u0028_i1_u003b((¶m_11)); - p = _e185; - let _e187 = p[0u]; - let _e188 = (*ca); - let _e191 = p[1u]; - let _e192 = (*sa); - let _e196 = p[0u]; - let _e197 = (*sa); - let _e200 = p[1u]; - let _e201 = (*ca); - let _e205 = (*radius); - return (vec2(((_e187 * _e188) - (_e191 * _e192)), ((_e196 * _e197) + (_e200 * _e201))) * _e205); + let _e185 = (*i_1); + param_11 = _e185; + let _e186 = PointShadowDiskTap_u0028_i1_u003b((¶m_11)); + p = _e186; + let _e188 = p[0u]; + let _e189 = (*ca); + let _e192 = p[1u]; + let _e193 = (*sa); + let _e197 = p[0u]; + let _e198 = (*sa); + let _e201 = p[1u]; + let _e202 = (*ca); + let _e206 = (*radius); + return (vec2(((_e188 * _e189) - (_e192 * _e193)), ((_e197 * _e198) + (_e201 * _e202))) * _e206); } fn PointShadowDistance_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b(uv: ptr>, offset: ptr>, tile: ptr>, range: ptr) -> f32 { @@ -46634,27 +46809,27 @@ fn PointShadowDistance_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b(uv: ptr; var atlas: vec2; - let _e187 = point_shadow.params[0u]; - inset = _e187; - let _e188 = (*uv); - let _e189 = (*offset); - let _e191 = inset; + let _e188 = point_shadow.params[0u]; + inset = _e188; + let _e189 = (*uv); + let _e190 = (*offset); let _e192 = inset; - local_5 = clamp((_e188 + _e189), vec2(_e191), vec2((1f - _e192))); - let _e197 = local_5; - let _e198 = (*tile); - atlas = ((_e197 + _e198) * vec2(0.16666667f, 0.16666667f)); - let _e203 = point_shadow.params3_[0u]; - if (_e203 > 0.5f) { - let _e206 = atlas[1u]; - atlas[1u] = (1f - _e206); - } - let _e209 = atlas; - let _e210 = textureSampleLevel(point_shadow_texture_tex, point_shadow_texture_smp, _e209, 0f); - let _e212 = atlas; - let _e213 = textureSampleLevel(point_shadow_static_texture_tex, point_shadow_static_texture_smp, _e212, 0f); - let _e216 = (*range); - return (min(_e210.x, _e213.x) * _e216); + let _e193 = inset; + local_5 = clamp((_e189 + _e190), vec2(_e192), vec2((1f - _e193))); + let _e198 = local_5; + let _e199 = (*tile); + atlas = ((_e198 + _e199) * vec2(0.16666667f, 0.16666667f)); + let _e204 = point_shadow.params3_[0u]; + if (_e204 > 0.5f) { + let _e207 = atlas[1u]; + atlas[1u] = (1f - _e207); + } + let _e210 = atlas; + let _e211 = textureSampleLevel(point_shadow_texture_tex, point_shadow_texture_smp, _e210, 0f); + let _e213 = atlas; + let _e214 = textureSampleLevel(point_shadow_static_texture_tex, point_shadow_static_texture_smp, _e213, 0f); + let _e217 = (*range); + return (min(_e211.x, _e214.x) * _e217); } fn PointShadowTap_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b_f1_u003b(uv_1: ptr>, offset_1: ptr>, tile_1: ptr>, range_1: ptr, receiver: ptr) -> f32 { @@ -46664,24 +46839,24 @@ fn PointShadowTap_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b_f1_u003b(uv_1: pt var param_14: vec2; var param_15: f32; - let _e188 = (*uv_1); - param_12 = _e188; - let _e189 = (*offset_1); - param_13 = _e189; - let _e190 = (*tile_1); - param_14 = _e190; - let _e191 = (*range_1); - param_15 = _e191; - let _e192 = PointShadowDistance_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b((¶m_12), (¶m_13), (¶m_14), (¶m_15)); - stored = _e192; - let _e193 = stored; - let _e194 = (*range_1); - if (_e193 >= (_e194 * 0.999f)) { + let _e189 = (*uv_1); + param_12 = _e189; + let _e190 = (*offset_1); + param_13 = _e190; + let _e191 = (*tile_1); + param_14 = _e191; + let _e192 = (*range_1); + param_15 = _e192; + let _e193 = PointShadowDistance_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b((¶m_12), (¶m_13), (¶m_14), (¶m_15)); + stored = _e193; + let _e194 = stored; + let _e195 = (*range_1); + if (_e194 >= (_e195 * 0.999f)) { return 1f; } - let _e197 = (*receiver); - let _e198 = stored; - return select(1f, 0f, (_e197 > _e198)); + let _e198 = (*receiver); + let _e199 = stored; + return select(1f, 0f, (_e198 > _e199)); } fn PointShadowPenumbra_u0028_vf2_u003b_vf2_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b(uv_2: ptr>, tile_2: ptr>, range_2: ptr, receiver_1: ptr, ca_1: ptr, sa_1: ptr, tanHalf: ptr, blockerOut: ptr) -> f32 { @@ -46708,111 +46883,111 @@ fn PointShadowPenumbra_u0028_vf2_u003b_vf2_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u var world: f32; (*blockerOut) = -1f; - let _e209 = point_shadow.params2_[1u]; - lightRadius = _e209; - let _e212 = point_shadow.params2_[0u]; - minRadius = _e212; - let _e215 = point_shadow.params2_[2u]; - maxRadius = _e215; - let _e216 = lightRadius; - if (_e216 <= 0f) { - let _e218 = (*uv_2); - param_16 = _e218; + let _e210 = point_shadow.params2_[1u]; + lightRadius = _e210; + let _e213 = point_shadow.params2_[0u]; + minRadius = _e213; + let _e216 = point_shadow.params2_[2u]; + maxRadius = _e216; + let _e217 = lightRadius; + if (_e217 <= 0f) { + let _e219 = (*uv_2); + param_16 = _e219; param_17 = vec2(0f, 0f); - let _e219 = (*tile_2); - param_18 = _e219; - let _e220 = (*range_2); - param_19 = _e220; - let _e221 = PointShadowDistance_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b((¶m_16), (¶m_17), (¶m_18), (¶m_19)); - (*blockerOut) = _e221; - let _e222 = minRadius; - return _e222; + let _e220 = (*tile_2); + param_18 = _e220; + let _e221 = (*range_2); + param_19 = _e221; + let _e222 = PointShadowDistance_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b((¶m_16), (¶m_17), (¶m_18), (¶m_19)); + (*blockerOut) = _e222; + let _e223 = minRadius; + return _e223; } sum = 0f; count = 0f; i_2 = 0i; loop { - let _e223 = i_2; - if (_e223 < 8i) { - let _e225 = i_2; - param_20 = _e225; - let _e226 = (*ca_1); - param_21 = _e226; - let _e227 = (*sa_1); - param_22 = _e227; - let _e228 = maxRadius; - param_23 = _e228; - let _e229 = PointShadowOffset_u0028_i1_u003b_f1_u003b_f1_u003b_f1_u003b((¶m_20), (¶m_21), (¶m_22), (¶m_23)); - let _e230 = (*uv_2); - param_24 = _e230; - param_25 = _e229; - let _e231 = (*tile_2); - param_26 = _e231; - let _e232 = (*range_2); - param_27 = _e232; - let _e233 = PointShadowDistance_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b((¶m_24), (¶m_25), (¶m_26), (¶m_27)); - stored_1 = _e233; - let _e234 = stored_1; - let _e235 = (*range_2); - if (_e234 >= (_e235 * 0.999f)) { + let _e224 = i_2; + if (_e224 < 8i) { + let _e226 = i_2; + param_20 = _e226; + let _e227 = (*ca_1); + param_21 = _e227; + let _e228 = (*sa_1); + param_22 = _e228; + let _e229 = maxRadius; + param_23 = _e229; + let _e230 = PointShadowOffset_u0028_i1_u003b_f1_u003b_f1_u003b_f1_u003b((¶m_20), (¶m_21), (¶m_22), (¶m_23)); + let _e231 = (*uv_2); + param_24 = _e231; + param_25 = _e230; + let _e232 = (*tile_2); + param_26 = _e232; + let _e233 = (*range_2); + param_27 = _e233; + let _e234 = PointShadowDistance_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b((¶m_24), (¶m_25), (¶m_26), (¶m_27)); + stored_1 = _e234; + let _e235 = stored_1; + let _e236 = (*range_2); + if (_e235 >= (_e236 * 0.999f)) { continue; } - let _e238 = stored_1; - let _e239 = (*receiver_1); - if (_e238 >= _e239) { + let _e239 = stored_1; + let _e240 = (*receiver_1); + if (_e239 >= _e240) { continue; } - let _e241 = stored_1; - let _e242 = sum; - sum = (_e242 + _e241); - let _e244 = count; - count = (_e244 + 1f); + let _e242 = stored_1; + let _e243 = sum; + sum = (_e243 + _e242); + let _e245 = count; + count = (_e245 + 1f); continue; } else { break; } continuing { - let _e246 = i_2; - i_2 = (_e246 + 1i); + let _e247 = i_2; + i_2 = (_e247 + 1i); } } - let _e248 = count; - if (_e248 < 0.5f) { + let _e249 = count; + if (_e249 < 0.5f) { return -1f; } - let _e250 = sum; - let _e251 = count; - blocker = max((_e250 / _e251), 0.0001f); - let _e254 = blocker; - (*blockerOut) = _e254; - let _e255 = lightRadius; - let _e256 = (*receiver_1); - let _e257 = blocker; - let _e261 = blocker; - world = ((_e255 * max((_e256 - _e257), 0f)) / _e261); - let _e263 = world; - let _e264 = (*receiver_1); - let _e266 = (*tanHalf); - let _e269 = minRadius; - let _e270 = maxRadius; - return clamp((_e263 / ((2f * _e264) * _e266)), _e269, _e270); + let _e251 = sum; + let _e252 = count; + blocker = max((_e251 / _e252), 0.0001f); + let _e255 = blocker; + (*blockerOut) = _e255; + let _e256 = lightRadius; + let _e257 = (*receiver_1); + let _e258 = blocker; + let _e262 = blocker; + world = ((_e256 * max((_e257 - _e258), 0f)) / _e262); + let _e264 = world; + let _e265 = (*receiver_1); + let _e267 = (*tanHalf); + let _e270 = minRadius; + let _e271 = maxRadius; + return clamp((_e264 / ((2f * _e265) * _e267)), _e270, _e271); } fn FragCoordFromTop_u0028_f1_u003b(rows: ptr) -> vec2 { var local_6: vec2; - let _e180 = (*rows); - if (_e180 > 0f) { - let _e183 = gl_FragCoord_1[0u]; - let _e184 = (*rows); - let _e186 = gl_FragCoord_1[1u]; - local_6 = vec2(_e183, (_e184 - _e186)); + let _e181 = (*rows); + if (_e181 > 0f) { + let _e184 = gl_FragCoord_1[0u]; + let _e185 = (*rows); + let _e187 = gl_FragCoord_1[1u]; + local_6 = vec2(_e184, (_e185 - _e187)); } else { - let _e189 = gl_FragCoord_1; - local_6 = _e189.xy; + let _e190 = gl_FragCoord_1; + local_6 = _e190.xy; } - let _e191 = local_6; - return _e191; + let _e192 = local_6; + return _e192; } fn PointShadowFactor_u0028_vf3_u003b_vf3_u003b_i1_u003b(world_1: ptr>, normal: ptr>, lightIndex: ptr) -> f32 { @@ -46870,257 +47045,257 @@ fn PointShadowFactor_u0028_vf3_u003b_vf3_u003b_i1_u003b(world_1: ptr= _e319) { + let _e275 = nDotL; + slope = min((sqrt(max((1f - (_e268 * _e269)), 0f)) / (_e274 * _e275)), 8f); + let _e279 = toLightLength; + let _e281 = (*lightIndex); + let _e285 = point_shadow.slots[_e281][2u]; + let _e290 = point_shadow.params3_[1u]; + texel = (((2f * _e279) * max(_e285, 0.0001f)) * _e290); + let _e292 = (*world_1); + let _e293 = (*normal); + let _e294 = texel; + let _e298 = point_shadow.params[3u]; + let _e300 = slope; + origin = (_e292 + (((_e293 * _e294) * _e298) * (1f + _e300))); + let _e304 = origin; + let _e305 = slot; + let _e308 = point_shadow.lights[_e305]; + toFragment = (_e304 - _e308.xyz); + let _e311 = toFragment; + distance_ = length(_e311); + let _e313 = slot; + let _e317 = point_shadow.lights[_e313][3u]; + range_3 = max(_e317, 0.0001f); + let _e319 = distance_; + let _e320 = range_3; + if (_e319 >= _e320) { return 1f; } face = 0i; - let _e321 = (*lightIndex); - let _e325 = point_shadow.slots[_e321][1u]; - if (_e325 < 0.5f) { - let _e327 = toFragment; - a = abs(_e327); - let _e330 = a[0u]; - let _e332 = a[1u]; - let _e333 = (_e330 >= _e332); - phi_2440_ = _e333; - if _e333 { - let _e335 = a[0u]; - let _e337 = a[2u]; - phi_2440_ = (_e335 >= _e337); - } - let _e340 = phi_2440_; - if _e340 { - let _e342 = toFragment[0u]; - face = select(1i, 0i, (_e342 > 0f)); + let _e322 = (*lightIndex); + let _e326 = point_shadow.slots[_e322][1u]; + if (_e326 < 0.5f) { + let _e328 = toFragment; + a = abs(_e328); + let _e331 = a[0u]; + let _e333 = a[1u]; + let _e334 = (_e331 >= _e333); + phi_2440_ = _e334; + if _e334 { + let _e336 = a[0u]; + let _e338 = a[2u]; + phi_2440_ = (_e336 >= _e338); + } + let _e341 = phi_2440_; + if _e341 { + let _e343 = toFragment[0u]; + face = select(1i, 0i, (_e343 > 0f)); } else { - let _e346 = a[1u]; - let _e348 = a[2u]; - if (_e346 >= _e348) { - let _e351 = toFragment[1u]; - face = select(3i, 2i, (_e351 > 0f)); + let _e347 = a[1u]; + let _e349 = a[2u]; + if (_e347 >= _e349) { + let _e352 = toFragment[1u]; + face = select(3i, 2i, (_e352 > 0f)); } else { - let _e355 = toFragment[2u]; - face = select(5i, 4i, (_e355 > 0f)); + let _e356 = toFragment[2u]; + face = select(5i, 4i, (_e356 > 0f)); } } } - let _e358 = slot; - let _e360 = face; - let _e364 = point_shadow.faces[((_e358 * 6i) + _e360)]; - let _e365 = origin; - clip = (_e364 * vec4(_e365.x, _e365.y, _e365.z, 1f)); - let _e372 = clip[3u]; - if (_e372 <= 0f) { + let _e359 = slot; + let _e361 = face; + let _e365 = point_shadow.faces[((_e359 * 6i) + _e361)]; + let _e366 = origin; + clip = (_e365 * vec4(_e366.x, _e366.y, _e366.z, 1f)); + let _e373 = clip[3u]; + if (_e373 <= 0f) { return 1f; } - let _e374 = clip; - let _e377 = clip[3u]; - ndc = (_e374.xy / vec2(_e377)); - let _e381 = ndc[0u]; - let _e383 = (abs(_e381) > 1f); - phi_2501_ = _e383; - if !(_e383) { - let _e386 = ndc[1u]; - phi_2501_ = (abs(_e386) > 1f); - } - let _e390 = phi_2501_; - if _e390 { + let _e375 = clip; + let _e378 = clip[3u]; + ndc = (_e375.xy / vec2(_e378)); + let _e382 = ndc[0u]; + let _e384 = (abs(_e382) > 1f); + phi_2501_ = _e384; + if !(_e384) { + let _e387 = ndc[1u]; + phi_2501_ = (abs(_e387) > 1f); + } + let _e391 = phi_2501_; + if _e391 { return 1f; } - let _e392 = ndc[0u]; - let _e396 = ndc[1u]; - uv_3 = vec2(((_e392 * 0.5f) + 0.5f), (0.5f - (_e396 * 0.5f))); - let _e400 = face; - let _e402 = slot; - tile_3 = vec2(f32(_e400), f32(_e402)); - let _e405 = distance_; - let _e408 = point_shadow.params[1u]; - receiver_2 = (_e405 - _e408); - let _e412 = frag_info.target_origin[0u]; - param_28 = _e412; - let _e413 = FragCoordFromTop_u0028_f1_u003b((¶m_28)); - noise = fract((52.982918f * fract(dot(_e413, vec2(0.06711056f, 0.00583715f))))); - let _e418 = noise; - angle = (_e418 * 6.2831855f); - let _e420 = angle; - ca_2 = cos(_e420); - let _e422 = angle; - sa_2 = sin(_e422); - let _e424 = (*lightIndex); - let _e428 = point_shadow.slots[_e424][2u]; - tanHalf_1 = max(_e428, 0.0001f); + let _e393 = ndc[0u]; + let _e397 = ndc[1u]; + uv_3 = vec2(((_e393 * 0.5f) + 0.5f), (0.5f - (_e397 * 0.5f))); + let _e401 = face; + let _e403 = slot; + tile_3 = vec2(f32(_e401), f32(_e403)); + let _e406 = distance_; + let _e409 = point_shadow.params[1u]; + receiver_2 = (_e406 - _e409); + let _e413 = frag_info.target_origin[0u]; + param_28 = _e413; + let _e414 = FragCoordFromTop_u0028_f1_u003b((¶m_28)); + noise = fract((52.982918f * fract(dot(_e414, vec2(0.06711056f, 0.00583715f))))); + let _e419 = noise; + angle = (_e419 * 6.2831855f); + let _e421 = angle; + ca_2 = cos(_e421); + let _e423 = angle; + sa_2 = sin(_e423); + let _e425 = (*lightIndex); + let _e429 = point_shadow.slots[_e425][2u]; + tanHalf_1 = max(_e429, 0.0001f); blocker_1 = -1f; - let _e430 = uv_3; - param_29 = _e430; - let _e431 = tile_3; - param_30 = _e431; - let _e432 = range_3; - param_31 = _e432; - let _e433 = receiver_2; - param_32 = _e433; - let _e434 = ca_2; - param_33 = _e434; - let _e435 = sa_2; - param_34 = _e435; - let _e436 = tanHalf_1; - param_35 = _e436; - let _e437 = PointShadowPenumbra_u0028_vf2_u003b_vf2_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b((¶m_29), (¶m_30), (¶m_31), (¶m_32), (¶m_33), (¶m_34), (¶m_35), (¶m_36)); - let _e438 = param_36; - blocker_1 = _e438; - radius_1 = _e437; - let _e441 = point_shadow.params2_[3u]; - if (_e441 > 0.5f) { + let _e431 = uv_3; + param_29 = _e431; + let _e432 = tile_3; + param_30 = _e432; + let _e433 = range_3; + param_31 = _e433; + let _e434 = receiver_2; + param_32 = _e434; + let _e435 = ca_2; + param_33 = _e435; + let _e436 = sa_2; + param_34 = _e436; + let _e437 = tanHalf_1; + param_35 = _e437; + let _e438 = PointShadowPenumbra_u0028_vf2_u003b_vf2_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b_f1_u003b((¶m_29), (¶m_30), (¶m_31), (¶m_32), (¶m_33), (¶m_34), (¶m_35), (¶m_36)); + let _e439 = param_36; + blocker_1 = _e439; + radius_1 = _e438; + let _e442 = point_shadow.params2_[3u]; + if (_e442 > 0.5f) { g_debug_surface_on = true; - let _e443 = radius_1; - if (_e443 < 0f) { + let _e444 = radius_1; + if (_e444 < 0f) { local_7 = vec3(0f, 0f, 1f); } else { - let _e445 = radius_1; - let _e448 = point_shadow.params2_[2u]; - let _e452 = blocker_1; - let _e453 = range_3; - local_7 = vec3(clamp((_e445 / max(_e448, 0.000001f)), 0f, 1f), clamp((_e452 / _e453), 0f, 1f), 0f); + let _e446 = radius_1; + let _e449 = point_shadow.params2_[2u]; + let _e453 = blocker_1; + let _e454 = range_3; + local_7 = vec3(clamp((_e446 / max(_e449, 0.000001f)), 0f, 1f), clamp((_e453 / _e454), 0f, 1f), 0f); } - let _e457 = local_7; - g_debug_surface = _e457; + let _e458 = local_7; + g_debug_surface = _e458; } - let _e458 = radius_1; - if (_e458 < 0f) { + let _e459 = radius_1; + if (_e459 < 0f) { return 1f; } - let _e460 = uv_3; - param_37 = _e460; + let _e461 = uv_3; + param_37 = _e461; param_38 = vec2(0f, 0f); - let _e461 = tile_3; - param_39 = _e461; - let _e462 = range_3; - param_40 = _e462; - let _e463 = receiver_2; - param_41 = _e463; - let _e464 = PointShadowTap_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b_f1_u003b((¶m_37), (¶m_38), (¶m_39), (¶m_40), (¶m_41)); - lit_1 = _e464; - let _e465 = radius_1; - if (_e465 > 0f) { + let _e462 = tile_3; + param_39 = _e462; + let _e463 = range_3; + param_40 = _e463; + let _e464 = receiver_2; + param_41 = _e464; + let _e465 = PointShadowTap_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b_f1_u003b((¶m_37), (¶m_38), (¶m_39), (¶m_40), (¶m_41)); + lit_1 = _e465; + let _e466 = radius_1; + if (_e466 > 0f) { i_3 = 0i; loop { - let _e467 = i_3; - if (_e467 < 8i) { - let _e469 = i_3; - param_42 = _e469; - let _e470 = ca_2; - param_43 = _e470; - let _e471 = sa_2; - param_44 = _e471; - let _e472 = radius_1; - param_45 = _e472; - let _e473 = PointShadowOffset_u0028_i1_u003b_f1_u003b_f1_u003b_f1_u003b((¶m_42), (¶m_43), (¶m_44), (¶m_45)); - let _e474 = uv_3; - param_46 = _e474; - param_47 = _e473; - let _e475 = tile_3; - param_48 = _e475; - let _e476 = range_3; - param_49 = _e476; - let _e477 = receiver_2; - param_50 = _e477; - let _e478 = PointShadowTap_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b_f1_u003b((¶m_46), (¶m_47), (¶m_48), (¶m_49), (¶m_50)); - let _e479 = lit_1; - lit_1 = (_e479 + _e478); + let _e468 = i_3; + if (_e468 < 8i) { + let _e470 = i_3; + param_42 = _e470; + let _e471 = ca_2; + param_43 = _e471; + let _e472 = sa_2; + param_44 = _e472; + let _e473 = radius_1; + param_45 = _e473; + let _e474 = PointShadowOffset_u0028_i1_u003b_f1_u003b_f1_u003b_f1_u003b((¶m_42), (¶m_43), (¶m_44), (¶m_45)); + let _e475 = uv_3; + param_46 = _e475; + param_47 = _e474; + let _e476 = tile_3; + param_48 = _e476; + let _e477 = range_3; + param_49 = _e477; + let _e478 = receiver_2; + param_50 = _e478; + let _e479 = PointShadowTap_u0028_vf2_u003b_vf2_u003b_vf2_u003b_f1_u003b_f1_u003b((¶m_46), (¶m_47), (¶m_48), (¶m_49), (¶m_50)); + let _e480 = lit_1; + lit_1 = (_e480 + _e479); continue; } else { break; } continuing { - let _e481 = i_3; - i_3 = (_e481 + 1i); + let _e482 = i_3; + i_3 = (_e482 + 1i); } } - let _e483 = lit_1; - lit_1 = (_e483 * 0.11111111f); + let _e484 = lit_1; + lit_1 = (_e484 * 0.11111111f); } - let _e485 = lit_1; - let _e486 = strength; - return mix(1f, _e485, clamp(_e486, 0f, 1f)); + let _e486 = lit_1; + let _e487 = strength; + return mix(1f, _e486, clamp(_e487, 0f, 1f)); } fn VogelDisc_u0028_i1_u003b_i1_u003b_f1_u003b(i_4: ptr, n_1: ptr, turn: ptr) -> vec2 { var r: f32; var theta: f32; - let _e183 = (*i_4); - let _e186 = (*n_1); - r = sqrt(((f32(_e183) + 0.5f) / f32(_e186))); - let _e190 = (*i_4); - let _e193 = (*turn); - theta = ((f32(_e190) * 2.3999631f) + _e193); - let _e195 = r; - let _e196 = theta; - let _e198 = theta; - return (vec2(cos(_e196), sin(_e198)) * _e195); + let _e184 = (*i_4); + let _e187 = (*n_1); + r = sqrt(((f32(_e184) + 0.5f) / f32(_e187))); + let _e191 = (*i_4); + let _e194 = (*turn); + theta = ((f32(_e191) * 2.3999631f) + _e194); + let _e196 = r; + let _e197 = theta; + let _e199 = theta; + return (vec2(cos(_e197), sin(_e199)) * _e196); } fn ShadowNoise_u0028_() -> f32 { var at: vec2; var param_51: f32; - let _e182 = frag_info.target_origin[0u]; - param_51 = _e182; - let _e183 = FragCoordFromTop_u0028_f1_u003b((¶m_51)); - let _e186 = frag_info.target_origin[3u]; - at = (_e183 + vec2((5.588238f * max(_e186, 0f)))); - let _e191 = at; - return fract((52.982918f * fract(dot(_e191, vec2(0.06711056f, 0.00583715f))))); + let _e183 = frag_info.target_origin[0u]; + param_51 = _e183; + let _e184 = FragCoordFromTop_u0028_f1_u003b((¶m_51)); + let _e187 = frag_info.target_origin[3u]; + at = (_e184 + vec2((5.588238f * max(_e187, 0f)))); + let _e192 = at; + return fract((52.982918f * fract(dot(_e192, vec2(0.06711056f, 0.00583715f))))); } fn EvsmChebyshev_u0028_vf2_u003b_f1_u003b_f1_u003b_f1_u003b(moments: ptr>, t: ptr, minVariance: ptr, bleed: ptr) -> f32 { @@ -47129,37 +47304,37 @@ fn EvsmChebyshev_u0028_vf2_u003b_f1_u003b_f1_u003b_f1_u003b(moments: ptr) -> vec2 { var d_2: f32; - let _e180 = (*depth); - d_2 = ((2f * clamp(_e180, 0f, 1f)) - 1f); - let _e184 = d_2; - let _e187 = d_2; - return vec2(exp((40f * _e184)), -(exp((-5f * _e187)))); + let _e181 = (*depth); + d_2 = ((2f * clamp(_e181, 0f, 1f)) - 1f); + let _e185 = d_2; + let _e188 = d_2; + return vec2(exp((40f * _e185)), -(exp((-5f * _e188)))); } fn EvsmVisibility_u0028_vf4_u003b_f1_u003b_f1_u003b(moments_1: ptr>, depth_1: ptr, bleed_1: ptr) -> f32 { @@ -47177,37 +47352,37 @@ fn EvsmVisibility_u0028_vf4_u003b_f1_u003b_f1_u003b(moments_1: ptr(0.004f, 0.0005f) * _e196); - let _e199 = scale[0u]; - let _e201 = scale[0u]; - let _e203 = (*moments_1); - param_53 = _e203.xy; - let _e206 = warped[0u]; - param_54 = _e206; - param_55 = (_e199 * _e201); - let _e207 = (*bleed_1); - param_56 = _e207; - let _e208 = EvsmChebyshev_u0028_vf2_u003b_f1_u003b_f1_u003b_f1_u003b((¶m_53), (¶m_54), (¶m_55), (¶m_56)); - positive = _e208; - let _e210 = scale[1u]; - let _e212 = scale[1u]; - let _e214 = (*moments_1); - param_57 = _e214.zw; - let _e217 = warped[1u]; - param_58 = _e217; - param_59 = (_e210 * _e212); - let _e218 = (*bleed_1); - param_60 = _e218; - let _e219 = EvsmChebyshev_u0028_vf2_u003b_f1_u003b_f1_u003b_f1_u003b((¶m_57), (¶m_58), (¶m_59), (¶m_60)); - negative = _e219; - let _e220 = positive; - let _e221 = negative; - return min(_e220, _e221); + let _e195 = (*depth_1); + param_52 = _e195; + let _e196 = EvsmWarp_u0028_f1_u003b((¶m_52)); + warped = _e196; + let _e197 = warped; + scale = (vec2(0.004f, 0.0005f) * _e197); + let _e200 = scale[0u]; + let _e202 = scale[0u]; + let _e204 = (*moments_1); + param_53 = _e204.xy; + let _e207 = warped[0u]; + param_54 = _e207; + param_55 = (_e200 * _e202); + let _e208 = (*bleed_1); + param_56 = _e208; + let _e209 = EvsmChebyshev_u0028_vf2_u003b_f1_u003b_f1_u003b_f1_u003b((¶m_53), (¶m_54), (¶m_55), (¶m_56)); + positive = _e209; + let _e211 = scale[1u]; + let _e213 = scale[1u]; + let _e215 = (*moments_1); + param_57 = _e215.zw; + let _e218 = warped[1u]; + param_58 = _e218; + param_59 = (_e211 * _e213); + let _e219 = (*bleed_1); + param_60 = _e219; + let _e220 = EvsmChebyshev_u0028_vf2_u003b_f1_u003b_f1_u003b_f1_u003b((¶m_57), (¶m_58), (¶m_59), (¶m_60)); + negative = _e220; + let _e221 = positive; + let _e222 = negative; + return min(_e221, _e222); } fn ShadowFactor_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_struct_u002d_LightSample_u002d_vf3_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf31_u003b_i1_u003b(s_2: ptr, light_1: ptr, lightIndex_1: ptr) -> f32 { @@ -47245,6 +47420,8 @@ fn ShadowFactor_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf var tileLo: vec2; var tileHi: vec2; var stored_2: vec4; + var y: i32; + var x: i32; var through: vec3; var softness: f32; var lit_2: f32; @@ -47252,8 +47429,8 @@ fn ShadowFactor_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf var param_61: vec4; var param_62: f32; var param_63: f32; - var y: i32; - var x: i32; + var y_1: i32; + var x_1: i32; var occluder: f32; var spread: f32; var turn_1: f32; @@ -47282,45 +47459,45 @@ fn ShadowFactor_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf var phi_3162_: bool; var phi_3169_: bool; - let _e248 = frag_info.shadow_params[3u]; - strength_1 = _e248; - let _e249 = strength_1; - if (_e249 <= 0f) { + let _e251 = frag_info.shadow_params[3u]; + strength_1 = _e251; + let _e252 = strength_1; + if (_e252 <= 0f) { return 1f; } - let _e251 = (*lightIndex_1); - let _e254 = frag_info.frame_params[2u]; - if (_e251 != i32((_e254 + 0.5f))) { + let _e254 = (*lightIndex_1); + let _e257 = frag_info.frame_params[2u]; + if (_e254 != i32((_e257 + 0.5f))) { return 1f; } - let _e260 = frag_info.shadow_cascades[2u]; - cascadeCount = i32((_e260 + 0.5f)); - let _e263 = v_world_position_1; - let _e265 = frag_info.camera_position; - viewDistance = length((_e263 - _e265.xyz)); + let _e263 = frag_info.shadow_cascades[2u]; + cascadeCount = i32((_e263 + 0.5f)); + let _e266 = v_world_position_1; + let _e268 = frag_info.camera_position; + viewDistance = length((_e266 - _e268.xyz)); cascade = 0i; - let _e269 = cascadeCount; - let _e270 = (_e269 > 1i); - phi_2983_ = _e270; - if _e270 { - let _e271 = viewDistance; - let _e274 = frag_info.shadow_cascades[0u]; - phi_2983_ = (_e271 > _e274); - } - let _e277 = phi_2983_; - if _e277 { + let _e272 = cascadeCount; + let _e273 = (_e272 > 1i); + phi_2983_ = _e273; + if _e273 { + let _e274 = viewDistance; + let _e277 = frag_info.shadow_cascades[0u]; + phi_2983_ = (_e274 > _e277); + } + let _e280 = phi_2983_; + if _e280 { cascade = 1i; } - let _e278 = cascadeCount; - let _e279 = (_e278 > 2i); - phi_2994_ = _e279; - if _e279 { - let _e280 = viewDistance; - let _e283 = frag_info.shadow_cascades[1u]; - phi_2994_ = (_e280 > _e283); + let _e281 = cascadeCount; + let _e282 = (_e281 > 2i); + phi_2994_ = _e282; + if _e282 { + let _e283 = viewDistance; + let _e286 = frag_info.shadow_cascades[1u]; + phi_2994_ = (_e283 > _e286); } - let _e286 = phi_2994_; - if _e286 { + let _e289 = phi_2994_; + if _e289 { cascade = 2i; } uv_4 = vec2(0f, 0f); @@ -47331,247 +47508,280 @@ fn ShadowFactor_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf receiverSlope = 0f; attempt = 0i; loop { - let _e287 = attempt; - if (_e287 < 3i) { - let _e289 = cascade; - let _e290 = attempt; - which = (_e289 + _e290); - let _e292 = which; - let _e293 = cascadeCount; - if (_e292 >= _e293) { + let _e290 = attempt; + if (_e290 < 3i) { + let _e292 = cascade; + let _e293 = attempt; + which = (_e292 + _e293); + let _e295 = which; + let _e296 = cascadeCount; + if (_e295 >= _e296) { break; } - let _e295 = which; - if (_e295 == 0i) { - let _e298 = frag_info.shadow_matrix; - local_8 = _e298; + let _e298 = which; + if (_e298 == 0i) { + let _e301 = frag_info.shadow_matrix; + local_8 = _e301; } else { - let _e299 = which; - if (_e299 == 1i) { - let _e302 = frag_info.shadow_matrix_far; - local_9 = _e302; + let _e302 = which; + if (_e302 == 1i) { + let _e305 = frag_info.shadow_matrix_far; + local_9 = _e305; } else { - let _e304 = frag_info.shadow_matrix_farthest; - local_9 = _e304; + let _e307 = frag_info.shadow_matrix_farthest; + local_9 = _e307; } - let _e305 = local_9; - local_8 = _e305; - } - let _e306 = local_8; - matrix = _e306; - let _e309 = matrix[0][0u]; - let _e312 = matrix[1][0u]; - let _e315 = matrix[2][0u]; - axisX = vec3(_e309, _e312, _e315); - let _e319 = matrix[0][1u]; - let _e322 = matrix[1][1u]; - let _e325 = matrix[2][1u]; - axisY = vec3(_e319, _e322, _e325); - let _e327 = axisX; - rowX = max(length(_e327), 0.000001f); - let _e330 = axisY; - rowY = max(length(_e330), 0.000001f); - let _e335 = frag_info.shadow_cascades[3u]; - let _e337 = rowX; - texelMetres = ((2f * _e335) / _e337); - let _e341 = frag_info.shadow_cascades[3u]; - let _e344 = (*s_2).n; - let _e345 = axisX; - let _e348 = rowX; - let _e349 = rowX; - let _e353 = (*s_2).n; - let _e354 = axisY; - let _e357 = rowY; - let _e358 = rowY; - reach = ((3f * _e341) * ((abs(dot(_e344, _e345)) / (_e348 * _e349)) + (abs(dot(_e353, _e354)) / (_e357 * _e358)))); - let _e365 = frag_info.shadow_params[2u]; - let _e366 = texelMetres; - flatOffset = min(_e365, _e366); - let _e368 = v_world_position_1; - let _e370 = (*s_2).n; - let _e371 = flatOffset; - let _e372 = reach; - origin_1 = (_e368 + (_e370 * (_e371 + _e372))); - let _e376 = matrix; - let _e377 = origin_1; - lightSpace = (_e376 * vec4(_e377.x, _e377.y, _e377.z, 1f)); - let _e384 = lightSpace[3u]; - if (_e384 <= 0f) { + let _e308 = local_9; + local_8 = _e308; + } + let _e309 = local_8; + matrix = _e309; + let _e312 = matrix[0][0u]; + let _e315 = matrix[1][0u]; + let _e318 = matrix[2][0u]; + axisX = vec3(_e312, _e315, _e318); + let _e322 = matrix[0][1u]; + let _e325 = matrix[1][1u]; + let _e328 = matrix[2][1u]; + axisY = vec3(_e322, _e325, _e328); + let _e330 = axisX; + rowX = max(length(_e330), 0.000001f); + let _e333 = axisY; + rowY = max(length(_e333), 0.000001f); + let _e338 = frag_info.shadow_cascades[3u]; + let _e340 = rowX; + texelMetres = ((2f * _e338) / _e340); + let _e344 = frag_info.shadow_cascades[3u]; + let _e347 = (*s_2).n; + let _e348 = axisX; + let _e351 = rowX; + let _e352 = rowX; + let _e356 = (*s_2).n; + let _e357 = axisY; + let _e360 = rowY; + let _e361 = rowY; + reach = ((3f * _e344) * ((abs(dot(_e347, _e348)) / (_e351 * _e352)) + (abs(dot(_e356, _e357)) / (_e360 * _e361)))); + let _e368 = frag_info.shadow_params[2u]; + let _e369 = texelMetres; + flatOffset = min(_e368, _e369); + let _e371 = v_world_position_1; + let _e373 = (*s_2).n; + let _e374 = flatOffset; + let _e375 = reach; + origin_1 = (_e371 + (_e373 * (_e374 + _e375))); + let _e379 = matrix; + let _e380 = origin_1; + lightSpace = (_e379 * vec4(_e380.x, _e380.y, _e380.z, 1f)); + let _e387 = lightSpace[3u]; + if (_e387 <= 0f) { continue; } - let _e386 = lightSpace; - let _e389 = lightSpace[3u]; - candidate = (_e386.xyz / vec3(_e389)); - let _e393 = candidate[0u]; - let _e397 = candidate[1u]; - inTile = vec2(((_e393 * 0.5f) + 0.5f), (0.5f - (_e397 * 0.5f))); - let _e402 = inTile[0u]; - let _e403 = (_e402 < 0f); - phi_3155_ = _e403; - if !(_e403) { - let _e406 = inTile[0u]; - phi_3155_ = (_e406 > 1f); - } - let _e409 = phi_3155_; - phi_3162_ = _e409; - if !(_e409) { - let _e412 = inTile[1u]; - phi_3162_ = (_e412 < 0f); - } - let _e415 = phi_3162_; - phi_3169_ = _e415; - if !(_e415) { - let _e418 = inTile[1u]; - phi_3169_ = (_e418 > 1f); + let _e389 = lightSpace; + let _e392 = lightSpace[3u]; + candidate = (_e389.xyz / vec3(_e392)); + let _e396 = candidate[0u]; + let _e400 = candidate[1u]; + inTile = vec2(((_e396 * 0.5f) + 0.5f), (0.5f - (_e400 * 0.5f))); + let _e405 = inTile[0u]; + let _e406 = (_e405 < 0f); + phi_3155_ = _e406; + if !(_e406) { + let _e409 = inTile[0u]; + phi_3155_ = (_e409 > 1f); + } + let _e412 = phi_3155_; + phi_3162_ = _e412; + if !(_e412) { + let _e415 = inTile[1u]; + phi_3162_ = (_e415 < 0f); } - let _e421 = phi_3169_; - if _e421 { + let _e418 = phi_3162_; + phi_3169_ = _e418; + if !(_e418) { + let _e421 = inTile[1u]; + phi_3169_ = (_e421 > 1f); + } + let _e424 = phi_3169_; + if _e424 { continue; } - let _e423 = candidate[2u]; - if (_e423 > 1f) { - let _e425 = which; - let _e426 = cascadeCount; - if (_e425 < (_e426 - 1i)) { + let _e426 = candidate[2u]; + if (_e426 > 1f) { + let _e428 = which; + let _e429 = cascadeCount; + if (_e428 < (_e429 - 1i)) { continue; } candidate[2u] = 1f; } - let _e431 = inTile[0u]; - let _e432 = which; - let _e435 = cascadeCount; - let _e439 = inTile[1u]; - uv_4 = vec2(((_e431 + f32(_e432)) / f32(_e435)), _e439); - let _e441 = candidate; - projected = _e441; - let _e442 = which; - cascade = _e442; - let _e443 = texelMetres; - cascadeTexel = _e443; - let _e446 = matrix[0][2u]; - let _e449 = matrix[1][2u]; - let _e452 = matrix[2][2u]; - cascadeDepth = (1f / max(length(vec3(_e446, _e449, _e452)), 0.000001f)); - let _e458 = (*s_2).n; - let _e461 = matrix[0][2u]; - let _e464 = matrix[1][2u]; - let _e467 = matrix[2][2u]; - let _e471 = cascadeDepth; - cosSlope = clamp((abs(dot(_e458, vec3(_e461, _e464, _e467))) * _e471), 0.1f, 1f); - let _e474 = texelMetres; - let _e475 = cosSlope; - let _e476 = cosSlope; - let _e482 = cosSlope; - let _e484 = cascadeDepth; - receiverSlope = (((_e474 * sqrt(max((1f - (_e475 * _e476)), 0f))) / _e482) / _e484); + let _e434 = inTile[0u]; + let _e435 = which; + let _e438 = cascadeCount; + let _e442 = inTile[1u]; + uv_4 = vec2(((_e434 + f32(_e435)) / f32(_e438)), _e442); + let _e444 = candidate; + projected = _e444; + let _e445 = which; + cascade = _e445; + let _e446 = texelMetres; + cascadeTexel = _e446; + let _e449 = matrix[0][2u]; + let _e452 = matrix[1][2u]; + let _e455 = matrix[2][2u]; + cascadeDepth = (1f / max(length(vec3(_e449, _e452, _e455)), 0.000001f)); + let _e461 = (*s_2).n; + let _e464 = matrix[0][2u]; + let _e467 = matrix[1][2u]; + let _e470 = matrix[2][2u]; + let _e474 = cascadeDepth; + cosSlope = clamp((abs(dot(_e461, vec3(_e464, _e467, _e470))) * _e474), 0.1f, 1f); + let _e477 = texelMetres; + let _e478 = cosSlope; + let _e479 = cosSlope; + let _e485 = cosSlope; + let _e487 = cascadeDepth; + receiverSlope = (((_e477 * sqrt(max((1f - (_e478 * _e479)), 0f))) / _e485) / _e487); found = true; break; } else { break; } continuing { - let _e486 = attempt; - attempt = (_e486 + 1i); + let _e489 = attempt; + attempt = (_e489 + 1i); } } - let _e488 = found; - if !(_e488) { + let _e491 = found; + if !(_e491) { return 1f; } - let _e490 = cascade; - if (_e490 == 0i) { - let _e494 = frag_info.shadow_bias[0u]; - local_10 = _e494; + let _e493 = cascade; + if (_e493 == 0i) { + let _e497 = frag_info.shadow_bias[0u]; + local_10 = _e497; } else { - let _e495 = cascade; - if (_e495 == 1i) { - let _e499 = frag_info.shadow_bias[1u]; - local_11 = _e499; - } else { - let _e502 = frag_info.shadow_bias[2u]; + let _e498 = cascade; + if (_e498 == 1i) { + let _e502 = frag_info.shadow_bias[1u]; local_11 = _e502; - } - let _e503 = local_11; - local_10 = _e503; - } - let _e504 = local_10; - bias = _e504; - let _e507 = frag_info.shadow_params[0u]; - let _e510 = frag_info.shadow_cascades[3u]; - texel_1 = vec2(_e507, _e510); - let _e512 = cascade; - let _e514 = cascadeCount; - let _e518 = texel_1; - tileLo = (vec2((f32(_e512) / f32(_e514)), 0f) + (_e518 * 0.5f)); - let _e521 = cascade; - let _e524 = cascadeCount; - let _e528 = texel_1; - tileHi = (vec2((f32((_e521 + 1i)) / f32(_e524)), 1f) - (_e528 * 0.5f)); - let _e533 = frag_info.shadow_bias[3u]; - if (_e533 > 0.5f) { - let _e535 = uv_4; - let _e536 = tileLo; - let _e537 = tileHi; - let _e539 = textureSampleLevel(shadow_texture_tex, shadow_texture_smp, clamp(_e535, _e536, _e537), 0f); - stored_2 = _e539; - let _e541 = stored_2[1u]; - let _e544 = stored_2[2u]; - let _e547 = stored_2[3u]; - through = clamp(vec3((1f - _e541), (1f - _e544), _e547), vec3(0f), vec3(4f)); - let _e552 = through; - let _e553 = strength_1; - light_transmittance = mix(vec3(1f, 1f, 1f), _e552, vec3(clamp(_e553, 0f, 1f))); - } - let _e559 = frag_info.ambient_ground[3u]; - softness = _e559; + } else { + let _e505 = frag_info.shadow_bias[2u]; + local_11 = _e505; + } + let _e506 = local_11; + local_10 = _e506; + } + let _e507 = local_10; + bias = _e507; + let _e510 = frag_info.shadow_params[0u]; + let _e513 = frag_info.shadow_cascades[3u]; + texel_1 = vec2(_e510, _e513); + let _e515 = cascade; + let _e517 = cascadeCount; + let _e521 = texel_1; + tileLo = (vec2((f32(_e515) / f32(_e517)), 0f) + (_e521 * 0.5f)); + let _e524 = cascade; + let _e527 = cascadeCount; + let _e531 = texel_1; + tileHi = (vec2((f32((_e524 + 1i)) / f32(_e527)), 1f) - (_e531 * 0.5f)); + let _e536 = frag_info.shadow_bias[3u]; + if (_e536 > 0.5f) { + stored_2 = vec4(0f, 0f, 0f, 0f); + y = -1i; + loop { + let _e538 = y; + if (_e538 <= 1i) { + x = -1i; + loop { + let _e540 = x; + if (_e540 <= 1i) { + let _e542 = uv_4; + let _e543 = x; + let _e545 = y; + let _e548 = texel_1; + let _e551 = tileLo; + let _e552 = tileHi; + let _e554 = textureSampleLevel(shadow_texture_tex, shadow_texture_smp, clamp((_e542 + (vec2(f32(_e543), f32(_e545)) * _e548)), _e551, _e552), 0f); + let _e555 = stored_2; + stored_2 = (_e555 + _e554); + continue; + } else { + break; + } + continuing { + let _e557 = x; + x = (_e557 + 1i); + } + } + continue; + } else { + break; + } + continuing { + let _e559 = y; + y = (_e559 + 1i); + } + } + let _e561 = stored_2; + stored_2 = (_e561 * 0.11111111f); + let _e564 = stored_2[1u]; + let _e567 = stored_2[2u]; + let _e570 = stored_2[3u]; + through = clamp(vec3((1f - _e564), (1f - _e567), _e570), vec3(0f), vec3(4f)); + let _e575 = through; + let _e576 = strength_1; + light_transmittance = mix(vec3(1f, 1f, 1f), _e575, vec3(clamp(_e576, 0f, 1f))); + } + let _e582 = frag_info.ambient_ground[3u]; + softness = _e582; lit_2 = 0f; - let _e560 = softness; - if (_e560 < 0f) { - let _e562 = uv_4; - let _e563 = tileLo; - let _e564 = tileHi; - let _e566 = textureSampleLevel(shadow_texture_tex, shadow_texture_smp, clamp(_e562, _e563, _e564), 0f); - moments_2 = _e566; - let _e568 = projected[2u]; - let _e569 = bias; - let _e571 = softness; - let _e575 = moments_2; - param_61 = _e575; - param_62 = (_e568 - _e569); - param_63 = clamp((-(_e571) - 1f), 0f, 0.95f); - let _e576 = EvsmVisibility_u0028_vf4_u003b_f1_u003b_f1_u003b((¶m_61), (¶m_62), (¶m_63)); - lit_2 = _e576; - } else { - let _e577 = softness; - if (_e577 <= 0f) { - y = -1i; + let _e583 = softness; + if (_e583 < 0f) { + let _e585 = uv_4; + let _e586 = tileLo; + let _e587 = tileHi; + let _e589 = textureSampleLevel(shadow_texture_tex, shadow_texture_smp, clamp(_e585, _e586, _e587), 0f); + moments_2 = _e589; + let _e591 = projected[2u]; + let _e592 = bias; + let _e594 = softness; + let _e598 = moments_2; + param_61 = _e598; + param_62 = (_e591 - _e592); + param_63 = clamp((-(_e594) - 1f), 0f, 0.95f); + let _e599 = EvsmVisibility_u0028_vf4_u003b_f1_u003b_f1_u003b((¶m_61), (¶m_62), (¶m_63)); + lit_2 = _e599; + } else { + let _e600 = softness; + if (_e600 <= 0f) { + y_1 = -1i; loop { - let _e579 = y; - if (_e579 <= 1i) { - x = -1i; + let _e602 = y_1; + if (_e602 <= 1i) { + x_1 = -1i; loop { - let _e581 = x; - if (_e581 <= 1i) { - let _e583 = uv_4; - let _e584 = x; - let _e586 = y; - let _e589 = texel_1; - let _e592 = tileLo; - let _e593 = tileHi; - let _e595 = textureSampleLevel(shadow_texture_tex, shadow_texture_smp, clamp((_e583 + (vec2(f32(_e584), f32(_e586)) * _e589)), _e592, _e593), 0f); - occluder = _e595.x; - let _e598 = projected[2u]; - let _e599 = bias; - let _e601 = occluder; - let _e604 = lit_2; - lit_2 = (_e604 + select(1f, 0f, ((_e598 - _e599) > _e601))); + let _e604 = x_1; + if (_e604 <= 1i) { + let _e606 = uv_4; + let _e607 = x_1; + let _e609 = y_1; + let _e612 = texel_1; + let _e615 = tileLo; + let _e616 = tileHi; + let _e618 = textureSampleLevel(shadow_texture_tex, shadow_texture_smp, clamp((_e606 + (vec2(f32(_e607), f32(_e609)) * _e612)), _e615, _e616), 0f); + occluder = _e618.x; + let _e621 = projected[2u]; + let _e622 = bias; + let _e624 = occluder; + let _e627 = lit_2; + lit_2 = (_e627 + select(1f, 0f, ((_e621 - _e622) > _e624))); continue; } else { break; } continuing { - let _e606 = x; - x = (_e606 + 1i); + let _e629 = x_1; + x_1 = (_e629 + 1i); } } continue; @@ -47579,125 +47789,125 @@ fn ShadowFactor_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf break; } continuing { - let _e608 = y; - y = (_e608 + 1i); + let _e631 = y_1; + y_1 = (_e631 + 1i); } } - let _e610 = lit_2; - lit_2 = (_e610 * 0.11111111f); + let _e633 = lit_2; + lit_2 = (_e633 * 0.11111111f); } else { - let _e612 = softness; - spread = tan(min(_e612, 0.5f)); - let _e615 = ShadowNoise_u0028_(); - turn_1 = (_e615 * 6.2831855f); - let _e617 = spread; - let _e619 = projected[2u]; - let _e621 = cascadeDepth; - let _e623 = cascadeTexel; - searchRadius = clamp((((_e617 * _e619) * _e621) / _e623), 1f, 16f); + let _e635 = softness; + spread = tan(min(_e635, 0.5f)); + let _e638 = ShadowNoise_u0028_(); + turn_1 = (_e638 * 6.2831855f); + let _e640 = spread; + let _e642 = projected[2u]; + let _e644 = cascadeDepth; + let _e646 = cascadeTexel; + searchRadius = clamp((((_e640 * _e642) * _e644) / _e646), 1f, 16f); blockerSum = 0f; blockerCount = 0f; i_5 = 0i; loop { - let _e626 = i_5; - if (_e626 < 16i) { - let _e628 = i_5; - param_64 = _e628; + let _e649 = i_5; + if (_e649 < 16i) { + let _e651 = i_5; + param_64 = _e651; param_65 = 16i; - let _e629 = turn_1; - param_66 = _e629; - let _e630 = VogelDisc_u0028_i1_u003b_i1_u003b_f1_u003b((¶m_64), (¶m_65), (¶m_66)); - disc = _e630; - let _e631 = bias; - let _e632 = disc; - let _e634 = searchRadius; - let _e638 = receiverSlope; - tapBias = (_e631 + (max(((length(_e632) * _e634) - 1.5f), 0f) * _e638)); - let _e641 = uv_4; - let _e642 = disc; - let _e643 = texel_1; - let _e645 = searchRadius; - let _e648 = tileLo; - let _e649 = tileHi; - let _e651 = textureSampleLevel(shadow_texture_tex, shadow_texture_smp, clamp((_e641 + ((_e642 * _e643) * _e645)), _e648, _e649), 0f); - occluder_1 = _e651.x; - let _e654 = projected[2u]; - let _e655 = tapBias; - let _e657 = occluder_1; - if ((_e654 - _e655) > _e657) { - let _e659 = occluder_1; - let _e660 = blockerSum; - blockerSum = (_e660 + _e659); - let _e662 = blockerCount; - blockerCount = (_e662 + 1f); + let _e652 = turn_1; + param_66 = _e652; + let _e653 = VogelDisc_u0028_i1_u003b_i1_u003b_f1_u003b((¶m_64), (¶m_65), (¶m_66)); + disc = _e653; + let _e654 = bias; + let _e655 = disc; + let _e657 = searchRadius; + let _e661 = receiverSlope; + tapBias = (_e654 + (max(((length(_e655) * _e657) - 1.5f), 0f) * _e661)); + let _e664 = uv_4; + let _e665 = disc; + let _e666 = texel_1; + let _e668 = searchRadius; + let _e671 = tileLo; + let _e672 = tileHi; + let _e674 = textureSampleLevel(shadow_texture_tex, shadow_texture_smp, clamp((_e664 + ((_e665 * _e666) * _e668)), _e671, _e672), 0f); + occluder_1 = _e674.x; + let _e677 = projected[2u]; + let _e678 = tapBias; + let _e680 = occluder_1; + if ((_e677 - _e678) > _e680) { + let _e682 = occluder_1; + let _e683 = blockerSum; + blockerSum = (_e683 + _e682); + let _e685 = blockerCount; + blockerCount = (_e685 + 1f); } continue; } else { break; } continuing { - let _e664 = i_5; - i_5 = (_e664 + 1i); + let _e687 = i_5; + i_5 = (_e687 + 1i); } } - let _e666 = blockerCount; - if (_e666 <= 0f) { + let _e689 = blockerCount; + if (_e689 <= 0f) { return 1f; } - let _e669 = projected[2u]; - let _e670 = blockerSum; - let _e671 = blockerCount; - let _e675 = cascadeDepth; - gap = (max((_e669 - (_e670 / _e671)), 0f) * _e675); - let _e677 = spread; - let _e678 = gap; - let _e680 = cascadeTexel; - radius_2 = clamp(((_e677 * _e678) / _e680), 1f, 16f); + let _e692 = projected[2u]; + let _e693 = blockerSum; + let _e694 = blockerCount; + let _e698 = cascadeDepth; + gap = (max((_e692 - (_e693 / _e694)), 0f) * _e698); + let _e700 = spread; + let _e701 = gap; + let _e703 = cascadeTexel; + radius_2 = clamp(((_e700 * _e701) / _e703), 1f, 16f); i_6 = 0i; loop { - let _e683 = i_6; - if (_e683 < 16i) { - let _e685 = turn_1; - let _e687 = i_6; - param_67 = _e687; + let _e706 = i_6; + if (_e706 < 16i) { + let _e708 = turn_1; + let _e710 = i_6; + param_67 = _e710; param_68 = 16i; - param_69 = (_e685 + 1f); - let _e688 = VogelDisc_u0028_i1_u003b_i1_u003b_f1_u003b((¶m_67), (¶m_68), (¶m_69)); - disc_1 = _e688; - let _e689 = bias; - let _e690 = disc_1; - let _e692 = radius_2; - let _e696 = receiverSlope; - tapBias_1 = (_e689 + (max(((length(_e690) * _e692) - 1.5f), 0f) * _e696)); - let _e699 = uv_4; - let _e700 = disc_1; - let _e701 = texel_1; - let _e703 = radius_2; - let _e706 = tileLo; - let _e707 = tileHi; - let _e709 = textureSampleLevel(shadow_texture_tex, shadow_texture_smp, clamp((_e699 + ((_e700 * _e701) * _e703)), _e706, _e707), 0f); - occluder_2 = _e709.x; - let _e712 = projected[2u]; - let _e713 = tapBias_1; - let _e715 = occluder_2; - let _e718 = lit_2; - lit_2 = (_e718 + select(1f, 0f, ((_e712 - _e713) > _e715))); + param_69 = (_e708 + 1f); + let _e711 = VogelDisc_u0028_i1_u003b_i1_u003b_f1_u003b((¶m_67), (¶m_68), (¶m_69)); + disc_1 = _e711; + let _e712 = bias; + let _e713 = disc_1; + let _e715 = radius_2; + let _e719 = receiverSlope; + tapBias_1 = (_e712 + (max(((length(_e713) * _e715) - 1.5f), 0f) * _e719)); + let _e722 = uv_4; + let _e723 = disc_1; + let _e724 = texel_1; + let _e726 = radius_2; + let _e729 = tileLo; + let _e730 = tileHi; + let _e732 = textureSampleLevel(shadow_texture_tex, shadow_texture_smp, clamp((_e722 + ((_e723 * _e724) * _e726)), _e729, _e730), 0f); + occluder_2 = _e732.x; + let _e735 = projected[2u]; + let _e736 = tapBias_1; + let _e738 = occluder_2; + let _e741 = lit_2; + lit_2 = (_e741 + select(1f, 0f, ((_e735 - _e736) > _e738))); continue; } else { break; } continuing { - let _e720 = i_6; - i_6 = (_e720 + 1i); + let _e743 = i_6; + i_6 = (_e743 + 1i); } } - let _e722 = lit_2; - lit_2 = (_e722 * 0.0625f); + let _e745 = lit_2; + lit_2 = (_e745 * 0.0625f); } } - let _e724 = lit_2; - let _e725 = strength_1; - return mix(1f, _e724, clamp(_e725, 0f, 1f)); + let _e747 = lit_2; + let _e748 = strength_1; + return mix(1f, _e747, clamp(_e748, 0f, 1f)); } fn LightVisibility_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_struct_u002d_LightSample_u002d_vf3_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf31_u003b_i1_u003b(s_3: ptr, light_2: ptr, index: ptr) -> f32 { @@ -47705,19 +47915,19 @@ fn LightVisibility_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d var param_71: LightSample; var param_72: i32; - let _e184 = (*s_3); - param_70 = _e184; - let _e185 = (*light_2); - param_71 = _e185; - let _e186 = (*index); - param_72 = _e186; - let _e187 = ShadowFactor_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_struct_u002d_LightSample_u002d_vf3_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf31_u003b_i1_u003b((¶m_70), (¶m_71), (¶m_72)); - return _e187; + let _e185 = (*s_3); + param_70 = _e185; + let _e186 = (*light_2); + param_71 = _e186; + let _e187 = (*index); + param_72 = _e187; + let _e188 = ShadowFactor_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_struct_u002d_LightSample_u002d_vf3_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf31_u003b_i1_u003b((¶m_70), (¶m_71), (¶m_72)); + return _e188; } fn LightHasShadow_u0028_i1_u003b(index_1: ptr) -> bool { - let _e179 = (*index_1); - return (_e179 < 8i); + let _e180 = (*index_1); + return (_e180 < 8i); } fn PunctualAttenuation_u0028_f1_u003b_f1_u003b(distance_1: ptr, range_4: ptr) -> f32 { @@ -47725,26 +47935,26 @@ fn PunctualAttenuation_u0028_f1_u003b_f1_u003b(distance_1: ptr, r var ratio: f32; var window: f32; - let _e183 = (*distance_1); let _e184 = (*distance_1); - attenuation = (1f / max((_e183 * _e184), 0.0001f)); - let _e188 = (*range_4); - if (_e188 > 0f) { - let _e190 = (*distance_1); - let _e191 = (*range_4); - ratio = (_e190 / _e191); - let _e193 = ratio; + let _e185 = (*distance_1); + attenuation = (1f / max((_e184 * _e185), 0.0001f)); + let _e189 = (*range_4); + if (_e189 > 0f) { + let _e191 = (*distance_1); + let _e192 = (*range_4); + ratio = (_e191 / _e192); let _e194 = ratio; - let _e196 = ratio; - let _e198 = ratio; - window = clamp((1f - (((_e193 * _e194) * _e196) * _e198)), 0f, 1f); - let _e202 = window; + let _e195 = ratio; + let _e197 = ratio; + let _e199 = ratio; + window = clamp((1f - (((_e194 * _e195) * _e197) * _e199)), 0f, 1f); let _e203 = window; - let _e205 = attenuation; - attenuation = (_e205 * (_e202 * _e203)); + let _e204 = window; + let _e206 = attenuation; + attenuation = (_e206 * (_e203 * _e204)); } - let _e207 = attenuation; - return _e207; + let _e208 = attenuation; + return _e208; } fn RectangleClosestPoint_u0028_vf3_u003b_vf3_u003b_vf3_u003b_vf3_u003b_vf3_u003b(centre: ptr>, halfWidth: ptr>, halfHeight: ptr>, world_2: ptr>, mirror: ptr>) -> vec3 { @@ -47761,75 +47971,75 @@ fn RectangleClosestPoint_u0028_vf3_u003b_vf3_u003b_vf3_u003b_vf3_u003b_vf3_u003b var u: f32; var v: f32; - let _e195 = (*halfWidth); - let _e196 = (*halfHeight); - n_2 = cross(_e195, _e196); - let _e198 = n_2; - nLen = length(_e198); - let _e200 = nLen; - if (_e200 < 0.000000000001f) { - let _e202 = (*centre); - return _e202; - } - let _e203 = nLen; - let _e204 = n_2; - n_2 = (_e204 / vec3(_e203)); - let _e207 = (*centre); - let _e208 = (*world_2); - toPlane = (_e207 - _e208); - let _e210 = (*mirror); - let _e211 = n_2; - denom = dot(_e210, _e211); - let _e213 = denom; - if (abs(_e213) < 0.00001f) { - let _e216 = toPlane; - let _e217 = n_2; - let _e218 = toPlane; - let _e219 = n_2; - onPlane = (_e216 - (_e217 * dot(_e218, _e219))); - } else { - let _e223 = toPlane; - let _e224 = n_2; - let _e226 = denom; - t_1 = (dot(_e223, _e224) / _e226); - let _e228 = t_1; - if (_e228 > 0f) { - let _e230 = (*mirror); - let _e231 = t_1; - local_12 = (_e230 * _e231); + let _e196 = (*halfWidth); + let _e197 = (*halfHeight); + n_2 = cross(_e196, _e197); + let _e199 = n_2; + nLen = length(_e199); + let _e201 = nLen; + if (_e201 < 0.000000000001f) { + let _e203 = (*centre); + return _e203; + } + let _e204 = nLen; + let _e205 = n_2; + n_2 = (_e205 / vec3(_e204)); + let _e208 = (*centre); + let _e209 = (*world_2); + toPlane = (_e208 - _e209); + let _e211 = (*mirror); + let _e212 = n_2; + denom = dot(_e211, _e212); + let _e214 = denom; + if (abs(_e214) < 0.00001f) { + let _e217 = toPlane; + let _e218 = n_2; + let _e219 = toPlane; + let _e220 = n_2; + onPlane = (_e217 - (_e218 * dot(_e219, _e220))); + } else { + let _e224 = toPlane; + let _e225 = n_2; + let _e227 = denom; + t_1 = (dot(_e224, _e225) / _e227); + let _e229 = t_1; + if (_e229 > 0f) { + let _e231 = (*mirror); + let _e232 = t_1; + local_12 = (_e231 * _e232); } else { - let _e233 = toPlane; - let _e234 = n_2; - let _e235 = toPlane; - let _e236 = n_2; - local_12 = (_e233 - (_e234 * dot(_e235, _e236))); - } - let _e240 = local_12; - onPlane = _e240; - } - let _e241 = onPlane; - let _e242 = toPlane; - offset_2 = (_e241 - _e242); - let _e244 = (*halfWidth); + let _e234 = toPlane; + let _e235 = n_2; + let _e236 = toPlane; + let _e237 = n_2; + local_12 = (_e234 - (_e235 * dot(_e236, _e237))); + } + let _e241 = local_12; + onPlane = _e241; + } + let _e242 = onPlane; + let _e243 = toPlane; + offset_2 = (_e242 - _e243); let _e245 = (*halfWidth); - wLen2_ = max(dot(_e244, _e245), 0.000000000001f); - let _e248 = (*halfHeight); + let _e246 = (*halfWidth); + wLen2_ = max(dot(_e245, _e246), 0.000000000001f); let _e249 = (*halfHeight); - hLen2_ = max(dot(_e248, _e249), 0.000000000001f); - let _e252 = offset_2; - let _e253 = (*halfWidth); - let _e255 = wLen2_; - u = clamp((dot(_e252, _e253) / _e255), -1f, 1f); - let _e258 = offset_2; - let _e259 = (*halfHeight); - let _e261 = hLen2_; - v = clamp((dot(_e258, _e259) / _e261), -1f, 1f); - let _e264 = (*centre); - let _e265 = (*halfWidth); - let _e266 = u; - let _e269 = (*halfHeight); - let _e270 = v; - return ((_e264 + (_e265 * _e266)) + (_e269 * _e270)); + let _e250 = (*halfHeight); + hLen2_ = max(dot(_e249, _e250), 0.000000000001f); + let _e253 = offset_2; + let _e254 = (*halfWidth); + let _e256 = wLen2_; + u = clamp((dot(_e253, _e254) / _e256), -1f, 1f); + let _e259 = offset_2; + let _e260 = (*halfHeight); + let _e262 = hLen2_; + v = clamp((dot(_e259, _e260) / _e262), -1f, 1f); + let _e265 = (*centre); + let _e266 = (*halfWidth); + let _e267 = u; + let _e270 = (*halfHeight); + let _e271 = v; + return ((_e265 + (_e266 * _e267)) + (_e270 * _e271)); } fn LambertEdge_u0028_vf3_u003b_vf3_u003b_vf3_u003b(a_1: ptr>, b: ptr>, n_3: ptr>) -> f32 { @@ -47840,32 +48050,32 @@ fn LambertEdge_u0028_vf3_u003b_vf3_u003b_vf3_u003b(a_1: ptr> var len: f32; var local_13: f32; - let _e187 = (*a_1); let _e188 = (*a_1); - ua = (_e187 / vec3(max(length(_e188), 0.000000000001f))); - let _e193 = (*b); + let _e189 = (*a_1); + ua = (_e188 / vec3(max(length(_e189), 0.000000000001f))); let _e194 = (*b); - ub = (_e193 / vec3(max(length(_e194), 0.000000000001f))); - let _e199 = ua; - let _e200 = ub; - angle_1 = acos(clamp(dot(_e199, _e200), -1f, 1f)); - let _e204 = ua; - let _e205 = ub; - axis = cross(_e204, _e205); - let _e207 = axis; - len = length(_e207); - let _e209 = len; - if (_e209 > 0.000001f) { - let _e211 = angle_1; - let _e212 = axis; - let _e213 = (*n_3); - let _e216 = len; - local_13 = ((_e211 * dot(_e212, _e213)) / _e216); + let _e195 = (*b); + ub = (_e194 / vec3(max(length(_e195), 0.000000000001f))); + let _e200 = ua; + let _e201 = ub; + angle_1 = acos(clamp(dot(_e200, _e201), -1f, 1f)); + let _e205 = ua; + let _e206 = ub; + axis = cross(_e205, _e206); + let _e208 = axis; + len = length(_e208); + let _e210 = len; + if (_e210 > 0.000001f) { + let _e212 = angle_1; + let _e213 = axis; + let _e214 = (*n_3); + let _e217 = len; + local_13 = ((_e212 * dot(_e213, _e214)) / _e217); } else { local_13 = 0f; } - let _e218 = local_13; - return _e218; + let _e219 = local_13; + return _e219; } fn RectangleFormFactor_u0028_vf3_u005b_4_u005d_u003b_vf3_u003b(corners: ptr, 4>>, n_4: ptr>) -> f32 { @@ -47896,98 +48106,98 @@ fn RectangleFormFactor_u0028_vf3_u005b_4_u005d_u003b_vf3_u003b(corners: ptr(0f, 0f, 0f); i_7 = 0i; loop { - let _e201 = i_7; - if (_e201 < 4i) { - let _e203 = i_7; - let _e205 = (*corners)[_e203]; - a_2 = _e205; - let _e206 = i_7; - if (_e206 == 3i) { + let _e202 = i_7; + if (_e202 < 4i) { + let _e204 = i_7; + let _e206 = (*corners)[_e204]; + a_2 = _e206; + let _e207 = i_7; + if (_e207 == 3i) { local_14 = 0i; } else { - let _e208 = i_7; - local_14 = (_e208 + 1i); - } - let _e210 = local_14; - let _e212 = (*corners)[_e210]; - b_1 = _e212; - let _e213 = a_2; - let _e214 = (*n_4); - ha = dot(_e213, _e214); - let _e216 = b_1; - let _e217 = (*n_4); - hb = dot(_e216, _e217); - let _e219 = ha; - let _e220 = hb; - d_3 = (_e219 - _e220); - let _e222 = a_2; - let _e223 = b_1; - let _e224 = a_2; - let _e226 = d_3; - if (abs(_e226) > 0.000000000001f) { - let _e229 = ha; - let _e230 = d_3; - local_15 = (_e229 / _e230); + let _e209 = i_7; + local_14 = (_e209 + 1i); + } + let _e211 = local_14; + let _e213 = (*corners)[_e211]; + b_1 = _e213; + let _e214 = a_2; + let _e215 = (*n_4); + ha = dot(_e214, _e215); + let _e217 = b_1; + let _e218 = (*n_4); + hb = dot(_e217, _e218); + let _e220 = ha; + let _e221 = hb; + d_3 = (_e220 - _e221); + let _e223 = a_2; + let _e224 = b_1; + let _e225 = a_2; + let _e227 = d_3; + if (abs(_e227) > 0.000000000001f) { + let _e230 = ha; + let _e231 = d_3; + local_15 = (_e230 / _e231); } else { local_15 = 0f; } - let _e232 = local_15; - q = (_e222 + ((_e223 - _e224) * _e232)); - let _e235 = ha; - aAbove = (_e235 > 0f); - let _e237 = hb; - bAbove = (_e237 > 0f); - let _e239 = aAbove; - let _e240 = bAbove; - if (_e239 || _e240) { - let _e242 = aAbove; - let _e243 = a_2; - let _e244 = q; - let _e247 = bAbove; - let _e248 = b_1; - let _e249 = q; - param_73 = select(_e244, _e243, vec3(_e242)); - param_74 = select(_e249, _e248, vec3(_e247)); - let _e252 = (*n_4); - param_75 = _e252; - let _e253 = LambertEdge_u0028_vf3_u003b_vf3_u003b_vf3_u003b((¶m_73), (¶m_74), (¶m_75)); - local_16 = _e253; + let _e233 = local_15; + q = (_e223 + ((_e224 - _e225) * _e233)); + let _e236 = ha; + aAbove = (_e236 > 0f); + let _e238 = hb; + bAbove = (_e238 > 0f); + let _e240 = aAbove; + let _e241 = bAbove; + if (_e240 || _e241) { + let _e243 = aAbove; + let _e244 = a_2; + let _e245 = q; + let _e248 = bAbove; + let _e249 = b_1; + let _e250 = q; + param_73 = select(_e245, _e244, vec3(_e243)); + param_74 = select(_e250, _e249, vec3(_e248)); + let _e253 = (*n_4); + param_75 = _e253; + let _e254 = LambertEdge_u0028_vf3_u003b_vf3_u003b_vf3_u003b((¶m_73), (¶m_74), (¶m_75)); + local_16 = _e254; } else { local_16 = 0f; } - let _e254 = local_16; - let _e255 = total; - total = (_e255 + _e254); - let _e257 = aAbove; - let _e258 = bAbove; - let _e261 = q; - let _e262 = exit; - exit = select(_e262, _e261, vec3((_e257 && !(_e258)))); - let _e265 = aAbove; - let _e267 = bAbove; - let _e269 = q; - let _e270 = entry; - entry = select(_e270, _e269, vec3((!(_e265) && _e267))); + let _e255 = local_16; + let _e256 = total; + total = (_e256 + _e255); + let _e258 = aAbove; + let _e259 = bAbove; + let _e262 = q; + let _e263 = exit; + exit = select(_e263, _e262, vec3((_e258 && !(_e259)))); + let _e266 = aAbove; + let _e268 = bAbove; + let _e270 = q; + let _e271 = entry; + entry = select(_e271, _e270, vec3((!(_e266) && _e268))); continue; } else { break; } continuing { - let _e273 = i_7; - i_7 = (_e273 + 1i); + let _e274 = i_7; + i_7 = (_e274 + 1i); } } - let _e275 = exit; - param_76 = _e275; - let _e276 = entry; - param_77 = _e276; - let _e277 = (*n_4); - param_78 = _e277; - let _e278 = LambertEdge_u0028_vf3_u003b_vf3_u003b_vf3_u003b((¶m_76), (¶m_77), (¶m_78)); - let _e279 = total; - total = (_e279 + _e278); - let _e281 = total; - return max((-(_e281) * 0.5f), 0f); + let _e276 = exit; + param_76 = _e276; + let _e277 = entry; + param_77 = _e277; + let _e278 = (*n_4); + param_78 = _e278; + let _e279 = LambertEdge_u0028_vf3_u003b_vf3_u003b_vf3_u003b((¶m_76), (¶m_77), (¶m_78)); + let _e280 = total; + total = (_e280 + _e279); + let _e282 = total; + return max((-(_e282) * 0.5f), 0f); } fn LightListLane_u0028_vf4_u003b_i1_u003b(four: ptr>, slot_1: ptr) -> f32 { @@ -47996,91 +48206,91 @@ fn LightListLane_u0028_vf4_u003b_i1_u003b(four: ptr>, slot_1 var local_18: f32; var local_19: f32; - let _e184 = (*slot_1); let _e185 = (*slot_1); - lane = (_e184 - ((_e185 / 4i) * 4i)); - let _e189 = lane; - if (_e189 == 0i) { - let _e192 = (*four)[0u]; - local_17 = _e192; - } else { - let _e193 = lane; - if (_e193 == 1i) { - let _e196 = (*four)[1u]; - local_18 = _e196; + let _e186 = (*slot_1); + lane = (_e185 - ((_e186 / 4i) * 4i)); + let _e190 = lane; + if (_e190 == 0i) { + let _e193 = (*four)[0u]; + local_17 = _e193; + } else { + let _e194 = lane; + if (_e194 == 1i) { + let _e197 = (*four)[1u]; + local_18 = _e197; } else { - let _e197 = lane; - if (_e197 == 2i) { - let _e200 = (*four)[2u]; - local_19 = _e200; + let _e198 = lane; + if (_e198 == 2i) { + let _e201 = (*four)[2u]; + local_19 = _e201; } else { - let _e202 = (*four)[3u]; - local_19 = _e202; + let _e203 = (*four)[3u]; + local_19 = _e203; } - let _e203 = local_19; - local_18 = _e203; + let _e204 = local_19; + local_18 = _e204; } - let _e204 = local_18; - local_17 = _e204; + let _e205 = local_18; + local_17 = _e205; } - let _e205 = local_17; - return _e205; + let _e206 = local_17; + return _e206; } fn LightListScale_u0028_i1_u003b(slot_2: ptr) -> f32 { var param_79: vec4; var param_80: i32; - let _e181 = (*slot_2); - let _e185 = light_list_info.scales[(_e181 / 4i)]; - param_79 = _e185; - let _e186 = (*slot_2); - param_80 = _e186; - let _e187 = LightListLane_u0028_vf4_u003b_i1_u003b((¶m_79), (¶m_80)); - return _e187; + let _e182 = (*slot_2); + let _e186 = light_list_info.scales[(_e182 / 4i)]; + param_79 = _e186; + let _e187 = (*slot_2); + param_80 = _e187; + let _e188 = LightListLane_u0028_vf4_u003b_i1_u003b((¶m_79), (¶m_80)); + return _e188; } fn InSlots_u0028_f1_u003b(row: ptr) -> bool { var a_3: vec4; var b_2: vec4; - let _e183 = light_list_info.slot_rows[0i]; - let _e184 = (*row); - a_3 = abs((_e183 - vec4(_e184))); - let _e190 = light_list_info.slot_rows[1i]; - let _e191 = (*row); - b_2 = abs((_e190 - vec4(_e191))); - let _e196 = a_3[0u]; - let _e198 = a_3[1u]; - let _e201 = a_3[2u]; - let _e203 = a_3[3u]; - let _e207 = b_2[0u]; - let _e209 = b_2[1u]; - let _e212 = b_2[2u]; - let _e214 = b_2[3u]; - return (min(min(min(_e196, _e198), min(_e201, _e203)), min(min(_e207, _e209), min(_e212, _e214))) < 0.5f); + let _e184 = light_list_info.slot_rows[0i]; + let _e185 = (*row); + a_3 = abs((_e184 - vec4(_e185))); + let _e191 = light_list_info.slot_rows[1i]; + let _e192 = (*row); + b_2 = abs((_e191 - vec4(_e192))); + let _e197 = a_3[0u]; + let _e199 = a_3[1u]; + let _e202 = a_3[2u]; + let _e204 = a_3[3u]; + let _e208 = b_2[0u]; + let _e210 = b_2[1u]; + let _e213 = b_2[2u]; + let _e215 = b_2[3u]; + return (min(min(min(_e197, _e199), min(_e202, _e204)), min(min(_e208, _e210), min(_e213, _e215))) < 0.5f); } fn LightListRow_u0028_i1_u003b(slot_3: ptr) -> f32 { var param_81: vec4; var param_82: i32; - let _e181 = (*slot_3); - let _e185 = light_list_info.indices[(_e181 / 4i)]; - param_81 = _e185; - let _e186 = (*slot_3); - param_82 = _e186; - let _e187 = LightListLane_u0028_vf4_u003b_i1_u003b((¶m_81), (¶m_82)); - return _e187; + let _e182 = (*slot_3); + let _e186 = light_list_info.indices[(_e182 / 4i)]; + param_81 = _e186; + let _e187 = (*slot_3); + param_82 = _e187; + let _e188 = LightListLane_u0028_vf4_u003b_i1_u003b((¶m_81), (¶m_82)); + return _e188; } fn LightListTexel_u0028_f1_u003b_f1_u003b(texel_2: ptr, row_1: ptr) -> vec4 { - let _e180 = (*texel_2); - let _e184 = light_list_info.list[1u]; - let _e186 = (*row_1); - let _e190 = light_list_info.list[2u]; - let _e193 = textureSampleLevel(light_list_texture_tex, light_list_texture_smp, vec2(((_e180 + 0.5f) * _e184), ((_e186 + 0.5f) * _e190)), 0f); - return _e193; + let _e181 = (*texel_2); + let _e185 = light_list_info.list[1u]; + let _e187 = (*row_1); + let _e191 = light_list_info.list[2u]; + let _e194 = textureSampleLevel(light_list_texture_tex, light_list_texture_smp, vec2(((_e181 + 0.5f) * _e185), ((_e187 + 0.5f) * _e191)), 0f); + return _e194; } fn ClusterRow_u0028_i1_u003b(slot_4: ptr) -> f32 { @@ -48094,35 +48304,35 @@ fn ClusterRow_u0028_i1_u003b(slot_4: ptr) -> f32 { var param_85: vec4; var param_86: i32; - let _e188 = g_cluster_offset; - let _e189 = (*slot_4); - entry_1 = (_e188 + f32(_e189)); - let _e192 = entry_1; - row_2 = floor((_e192 / 16f)); - let _e195 = entry_1; - let _e196 = row_2; - within = (_e195 - (_e196 * 16f)); - let _e199 = within; - texel_3 = floor((_e199 / 4f)); - let _e204 = light_list_info.cluster_depth[3u]; - let _e205 = row_2; - let _e207 = texel_3; - param_83 = _e207; - param_84 = (_e204 + _e205); - let _e208 = LightListTexel_u0028_f1_u003b_f1_u003b((¶m_83), (¶m_84)); - four_1 = _e208; - let _e209 = within; - let _e210 = texel_3; - let _e215 = four_1; - param_85 = _e215; - param_86 = i32(((_e209 - (_e210 * 4f)) + 0.5f)); - let _e216 = LightListLane_u0028_vf4_u003b_i1_u003b((¶m_85), (¶m_86)); - return _e216; + let _e189 = g_cluster_offset; + let _e190 = (*slot_4); + entry_1 = (_e189 + f32(_e190)); + let _e193 = entry_1; + row_2 = floor((_e193 / 16f)); + let _e196 = entry_1; + let _e197 = row_2; + within = (_e196 - (_e197 * 16f)); + let _e200 = within; + texel_3 = floor((_e200 / 4f)); + let _e205 = light_list_info.cluster_depth[3u]; + let _e206 = row_2; + let _e208 = texel_3; + param_83 = _e208; + param_84 = (_e205 + _e206); + let _e209 = LightListTexel_u0028_f1_u003b_f1_u003b((¶m_83), (¶m_84)); + four_1 = _e209; + let _e210 = within; + let _e211 = texel_3; + let _e216 = four_1; + param_85 = _e216; + param_86 = i32(((_e210 - (_e211 * 4f)) + 0.5f)); + let _e217 = LightListLane_u0028_vf4_u003b_i1_u003b((¶m_85), (¶m_86)); + return _e217; } fn Clustered_u0028_() -> bool { - let _e180 = light_list_info.cluster_grid[3u]; - return (_e180 > 0.5f); + let _e181 = light_list_info.cluster_grid[3u]; + return (_e181 > 0.5f); } fn SampleLight_u0028_i1_u003b_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b(index_2: ptr, s_4: ptr) -> LightSample { @@ -48178,264 +48388,264 @@ fn SampleLight_u0028_i1_u003b_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_ light_3.integrated = 0f; light_3.ltc = vec3(0f, 0f, 0f); - let _e231 = (*index_2); - if (_e231 < 8i) { - let _e233 = (*index_2); - let _e236 = frag_info.light_position[_e233]; - position = _e236; - let _e237 = (*index_2); - let _e240 = frag_info.light_color[_e237]; - color_1 = _e240; - let _e241 = (*index_2); - let _e244 = frag_info.light_direction[_e241]; - direction = _e244; - let _e245 = (*index_2); - let _e248 = frag_info.light_cone[_e245]; - cone = _e248; - } else { - let _e249 = (*index_2); - slot_5 = (_e249 - 8i); - let _e251 = Clustered_u0028_(); - clustered = _e251; - let _e252 = clustered; - if _e252 { - let _e253 = slot_5; - param_87 = _e253; - let _e254 = ClusterRow_u0028_i1_u003b((¶m_87)); - local_20 = _e254; + let _e232 = (*index_2); + if (_e232 < 8i) { + let _e234 = (*index_2); + let _e237 = frag_info.light_position[_e234]; + position = _e237; + let _e238 = (*index_2); + let _e241 = frag_info.light_color[_e238]; + color_1 = _e241; + let _e242 = (*index_2); + let _e245 = frag_info.light_direction[_e242]; + direction = _e245; + let _e246 = (*index_2); + let _e249 = frag_info.light_cone[_e246]; + cone = _e249; + } else { + let _e250 = (*index_2); + slot_5 = (_e250 - 8i); + let _e252 = Clustered_u0028_(); + clustered = _e252; + let _e253 = clustered; + if _e253 { + let _e254 = slot_5; + param_87 = _e254; + let _e255 = ClusterRow_u0028_i1_u003b((¶m_87)); + local_20 = _e255; } else { - let _e255 = slot_5; - param_88 = _e255; - let _e256 = LightListRow_u0028_i1_u003b((¶m_88)); - local_20 = _e256; - } - let _e257 = local_20; - listRow = _e257; - let _e258 = listRow; - let _e262 = light_list_info.list[2u]; - v_1 = ((_e258 + 0.5f) * _e262); - let _e266 = light_list_info.list[1u]; - u_1 = _e266; - let _e267 = u_1; - let _e269 = v_1; - let _e271 = textureSampleLevel(light_list_texture_tex, light_list_texture_smp, vec2((0.5f * _e267), _e269), 0f); - position = _e271; - let _e272 = u_1; - let _e274 = v_1; - let _e276 = textureSampleLevel(light_list_texture_tex, light_list_texture_smp, vec2((1.5f * _e272), _e274), 0f); - color_1 = _e276; - let _e277 = u_1; - let _e279 = v_1; - let _e281 = textureSampleLevel(light_list_texture_tex, light_list_texture_smp, vec2((2.5f * _e277), _e279), 0f); - direction = _e281; - let _e282 = u_1; - let _e284 = v_1; - let _e286 = textureSampleLevel(light_list_texture_tex, light_list_texture_smp, vec2((3.5f * _e282), _e284), 0f); - cone = _e286; - let _e287 = clustered; - if _e287 { - let _e288 = listRow; - param_89 = _e288; - let _e289 = InSlots_u0028_f1_u003b((¶m_89)); - local_21 = select(1f, 0f, _e289); + let _e256 = slot_5; + param_88 = _e256; + let _e257 = LightListRow_u0028_i1_u003b((¶m_88)); + local_20 = _e257; + } + let _e258 = local_20; + listRow = _e258; + let _e259 = listRow; + let _e263 = light_list_info.list[2u]; + v_1 = ((_e259 + 0.5f) * _e263); + let _e267 = light_list_info.list[1u]; + u_1 = _e267; + let _e268 = u_1; + let _e270 = v_1; + let _e272 = textureSampleLevel(light_list_texture_tex, light_list_texture_smp, vec2((0.5f * _e268), _e270), 0f); + position = _e272; + let _e273 = u_1; + let _e275 = v_1; + let _e277 = textureSampleLevel(light_list_texture_tex, light_list_texture_smp, vec2((1.5f * _e273), _e275), 0f); + color_1 = _e277; + let _e278 = u_1; + let _e280 = v_1; + let _e282 = textureSampleLevel(light_list_texture_tex, light_list_texture_smp, vec2((2.5f * _e278), _e280), 0f); + direction = _e282; + let _e283 = u_1; + let _e285 = v_1; + let _e287 = textureSampleLevel(light_list_texture_tex, light_list_texture_smp, vec2((3.5f * _e283), _e285), 0f); + cone = _e287; + let _e288 = clustered; + if _e288 { + let _e289 = listRow; + param_89 = _e289; + let _e290 = InSlots_u0028_f1_u003b((¶m_89)); + local_21 = select(1f, 0f, _e290); } else { - let _e291 = slot_5; - param_90 = _e291; - let _e292 = LightListScale_u0028_i1_u003b((¶m_90)); - local_21 = _e292; - } - let _e293 = local_21; - let _e295 = color_1[3u]; - color_1[3u] = (_e295 * _e293); - } - let _e299 = position[3u]; - type_39 = _e299; - let _e300 = type_39; - if (_e300 > 2.5f) { - let _e302 = direction; - halfWidth_1 = _e302.xyz; - let _e304 = cone; - halfHeight_1 = _e304.xyz; - let _e306 = position; - let _e308 = v_world_position_1; - toCentre = (_e306.xyz - _e308); - let _e310 = toCentre; - let _e311 = halfWidth_1; - let _e313 = halfHeight_1; - corners_1[0i] = ((_e310 - _e311) - _e313); - let _e316 = toCentre; - let _e317 = halfWidth_1; - let _e319 = halfHeight_1; - corners_1[1i] = ((_e316 + _e317) - _e319); - let _e322 = toCentre; - let _e323 = halfWidth_1; - let _e325 = halfHeight_1; - corners_1[2i] = ((_e322 + _e323) + _e325); - let _e328 = toCentre; - let _e329 = halfWidth_1; - let _e331 = halfHeight_1; - corners_1[3i] = ((_e328 - _e329) + _e331); - let _e334 = toCentre; - let _e335 = halfWidth_1; - let _e336 = halfHeight_1; - behind = (dot(_e334, cross(_e335, _e336)) >= 0f); - let _e340 = behind; - if _e340 { + let _e292 = slot_5; + param_90 = _e292; + let _e293 = LightListScale_u0028_i1_u003b((¶m_90)); + local_21 = _e293; + } + let _e294 = local_21; + let _e296 = color_1[3u]; + color_1[3u] = (_e296 * _e294); + } + let _e300 = position[3u]; + type_39 = _e300; + let _e301 = type_39; + if (_e301 > 2.5f) { + let _e303 = direction; + halfWidth_1 = _e303.xyz; + let _e305 = cone; + halfHeight_1 = _e305.xyz; + let _e307 = position; + let _e309 = v_world_position_1; + toCentre = (_e307.xyz - _e309); + let _e311 = toCentre; + let _e312 = halfWidth_1; + let _e314 = halfHeight_1; + corners_1[0i] = ((_e311 - _e312) - _e314); + let _e317 = toCentre; + let _e318 = halfWidth_1; + let _e320 = halfHeight_1; + corners_1[1i] = ((_e317 + _e318) - _e320); + let _e323 = toCentre; + let _e324 = halfWidth_1; + let _e326 = halfHeight_1; + corners_1[2i] = ((_e323 + _e324) + _e326); + let _e329 = toCentre; + let _e330 = halfWidth_1; + let _e332 = halfHeight_1; + corners_1[3i] = ((_e329 - _e330) + _e332); + let _e335 = toCentre; + let _e336 = halfWidth_1; + let _e337 = halfHeight_1; + behind = (dot(_e335, cross(_e336, _e337)) >= 0f); + let _e341 = behind; + if _e341 { local_22 = 0f; } else { - let _e341 = corners_1; - param_91 = _e341; - let _e343 = (*s_4).n; - param_92 = _e343; - let _e344 = RectangleFormFactor_u0028_vf3_u005b_4_u005d_u003b_vf3_u003b((¶m_91), (¶m_92)); - local_22 = _e344; - } - let _e345 = local_22; - formFactor = _e345; - let _e346 = halfWidth_1; - let _e347 = halfHeight_1; - area = (length(cross(_e346, _e347)) * 4f); - let _e351 = area; - if (_e351 > 0.000000001f) { - let _e353 = area; - local_23 = (1f / _e353); + let _e342 = corners_1; + param_91 = _e342; + let _e344 = (*s_4).n; + param_92 = _e344; + let _e345 = RectangleFormFactor_u0028_vf3_u005b_4_u005d_u003b_vf3_u003b((¶m_91), (¶m_92)); + local_22 = _e345; + } + let _e346 = local_22; + formFactor = _e346; + let _e347 = halfWidth_1; + let _e348 = halfHeight_1; + area = (length(cross(_e347, _e348)) * 4f); + let _e352 = area; + if (_e352 > 0.000000001f) { + let _e354 = area; + local_23 = (1f / _e354); } else { local_23 = 0f; } - let _e355 = local_23; - radiance = _e355; - let _e356 = toCentre; - distance_2 = length(_e356); - let _e359 = direction[3u]; - if (_e359 > 0f) { - let _e361 = distance_2; - let _e363 = direction[3u]; - ratio_1 = (_e361 / _e363); - let _e365 = ratio_1; + let _e356 = local_23; + radiance = _e356; + let _e357 = toCentre; + distance_2 = length(_e357); + let _e360 = direction[3u]; + if (_e360 > 0f) { + let _e362 = distance_2; + let _e364 = direction[3u]; + ratio_1 = (_e362 / _e364); let _e366 = ratio_1; - let _e368 = ratio_1; - let _e370 = ratio_1; - window_1 = clamp((1f - (((_e365 * _e366) * _e368) * _e370)), 0f, 1f); - let _e374 = window_1; + let _e367 = ratio_1; + let _e369 = ratio_1; + let _e371 = ratio_1; + window_1 = clamp((1f - (((_e366 * _e367) * _e369) * _e371)), 0f, 1f); let _e375 = window_1; - let _e377 = radiance; - radiance = (_e377 * (_e374 * _e375)); - } - let _e380 = (*s_4).v; - let _e383 = (*s_4).n; - mirror_1 = reflect(-(_e380), _e383); - let _e385 = position; - param_93 = _e385.xyz; - let _e387 = halfWidth_1; - param_94 = _e387; - let _e388 = halfHeight_1; - param_95 = _e388; - let _e389 = v_world_position_1; - param_96 = _e389; - let _e390 = mirror_1; - param_97 = _e390; - let _e391 = RectangleClosestPoint_u0028_vf3_u003b_vf3_u003b_vf3_u003b_vf3_u003b_vf3_u003b((¶m_93), (¶m_94), (¶m_95), (¶m_96), (¶m_97)); - representative = _e391; - let _e392 = representative; - let _e393 = v_world_position_1; - toPoint = (_e392 - _e393); - let _e395 = toPoint; - pointDistance = length(_e395); - let _e397 = pointDistance; - if (_e397 > 0.000001f) { - let _e399 = toPoint; - let _e400 = pointDistance; - local_24 = (_e399 / vec3(_e400)); + let _e376 = window_1; + let _e378 = radiance; + radiance = (_e378 * (_e375 * _e376)); + } + let _e381 = (*s_4).v; + let _e384 = (*s_4).n; + mirror_1 = reflect(-(_e381), _e384); + let _e386 = position; + param_93 = _e386.xyz; + let _e388 = halfWidth_1; + param_94 = _e388; + let _e389 = halfHeight_1; + param_95 = _e389; + let _e390 = v_world_position_1; + param_96 = _e390; + let _e391 = mirror_1; + param_97 = _e391; + let _e392 = RectangleClosestPoint_u0028_vf3_u003b_vf3_u003b_vf3_u003b_vf3_u003b_vf3_u003b((¶m_93), (¶m_94), (¶m_95), (¶m_96), (¶m_97)); + representative = _e392; + let _e393 = representative; + let _e394 = v_world_position_1; + toPoint = (_e393 - _e394); + let _e396 = toPoint; + pointDistance = length(_e396); + let _e398 = pointDistance; + if (_e398 > 0.000001f) { + let _e400 = toPoint; + let _e401 = pointDistance; + local_24 = (_e400 / vec3(_e401)); } else { - let _e404 = (*s_4).n; - local_24 = _e404; - } - let _e405 = local_24; - light_3.l = _e405; - let _e408 = light_3.l; - let _e410 = (*s_4).v; - light_3.h = normalize((_e408 + _e410)); - let _e414 = formFactor; - light_3.n_dot_l = _e414; - let _e417 = (*s_4).n; - let _e419 = light_3.h; - light_3.n_dot_h = max(dot(_e417, _e419), 0f); - let _e424 = (*s_4).v; - let _e426 = light_3.h; - light_3.v_dot_h = max(dot(_e424, _e426), 0f); - let _e430 = color_1; - let _e433 = color_1[3u]; - let _e435 = radiance; - light_3.radiance = ((_e430.xyz * _e433) * _e435); - let _e438 = light_3; - return _e438; - } - let _e439 = direction; - aim = normalize(_e439.xyz); + let _e405 = (*s_4).n; + local_24 = _e405; + } + let _e406 = local_24; + light_3.l = _e406; + let _e409 = light_3.l; + let _e411 = (*s_4).v; + light_3.h = normalize((_e409 + _e411)); + let _e415 = formFactor; + light_3.n_dot_l = _e415; + let _e418 = (*s_4).n; + let _e420 = light_3.h; + light_3.n_dot_h = max(dot(_e418, _e420), 0f); + let _e425 = (*s_4).v; + let _e427 = light_3.h; + light_3.v_dot_h = max(dot(_e425, _e427), 0f); + let _e431 = color_1; + let _e434 = color_1[3u]; + let _e436 = radiance; + light_3.radiance = ((_e431.xyz * _e434) * _e436); + let _e439 = light_3; + return _e439; + } + let _e440 = direction; + aim = normalize(_e440.xyz); attenuation_1 = 1f; - let _e442 = type_39; - if (_e442 < 0.5f) { - let _e444 = aim; - light_3.l = -(_e444); - } else { - let _e447 = position; - let _e449 = v_world_position_1; - toLight_1 = (_e447.xyz - _e449); - let _e451 = toLight_1; - distance_3 = length(_e451); - let _e453 = distance_3; - if (_e453 < 0.000001f) { - let _e456 = (*s_4).n; - light_3.l = _e456; - let _e459 = (*s_4).n; - light_3.h = _e459; + let _e443 = type_39; + if (_e443 < 0.5f) { + let _e445 = aim; + light_3.l = -(_e445); + } else { + let _e448 = position; + let _e450 = v_world_position_1; + toLight_1 = (_e448.xyz - _e450); + let _e452 = toLight_1; + distance_3 = length(_e452); + let _e454 = distance_3; + if (_e454 < 0.000001f) { + let _e457 = (*s_4).n; + light_3.l = _e457; + let _e460 = (*s_4).n; + light_3.h = _e460; light_3.radiance = vec3(0f, 0f, 0f); light_3.n_dot_l = 0f; light_3.n_dot_h = 0f; light_3.v_dot_h = 0f; - let _e465 = light_3; - return _e465; - } - let _e466 = toLight_1; - let _e467 = distance_3; - light_3.l = (_e466 / vec3(_e467)); - let _e471 = distance_3; - param_98 = _e471; - let _e473 = direction[3u]; - param_99 = _e473; - let _e474 = PunctualAttenuation_u0028_f1_u003b_f1_u003b((¶m_98), (¶m_99)); - attenuation_1 = _e474; - let _e475 = type_39; - if (_e475 > 1.5f) { - let _e477 = aim; - let _e479 = light_3.l; - cosAngle = dot(_e477, -(_e479)); - let _e482 = cosAngle; - let _e484 = cone[1u]; - let _e487 = cone[0u]; - let _e489 = cone[1u]; - let _e493 = attenuation_1; - attenuation_1 = (_e493 * clamp(((_e482 - _e484) / (_e487 - _e489)), 0f, 1f)); - } - } - let _e496 = light_3.l; - let _e498 = (*s_4).v; - light_3.h = normalize((_e496 + _e498)); - let _e503 = (*s_4).n; - let _e505 = light_3.l; - light_3.n_dot_l = max(dot(_e503, _e505), 0f); - let _e510 = (*s_4).n; - let _e512 = light_3.h; - light_3.n_dot_h = max(dot(_e510, _e512), 0f); - let _e517 = (*s_4).v; - let _e519 = light_3.h; - light_3.v_dot_h = max(dot(_e517, _e519), 0f); - let _e523 = color_1; - let _e526 = color_1[3u]; - let _e528 = attenuation_1; - light_3.radiance = ((_e523.xyz * _e526) * _e528); - let _e531 = light_3; - return _e531; + let _e466 = light_3; + return _e466; + } + let _e467 = toLight_1; + let _e468 = distance_3; + light_3.l = (_e467 / vec3(_e468)); + let _e472 = distance_3; + param_98 = _e472; + let _e474 = direction[3u]; + param_99 = _e474; + let _e475 = PunctualAttenuation_u0028_f1_u003b_f1_u003b((¶m_98), (¶m_99)); + attenuation_1 = _e475; + let _e476 = type_39; + if (_e476 > 1.5f) { + let _e478 = aim; + let _e480 = light_3.l; + cosAngle = dot(_e478, -(_e480)); + let _e483 = cosAngle; + let _e485 = cone[1u]; + let _e488 = cone[0u]; + let _e490 = cone[1u]; + let _e494 = attenuation_1; + attenuation_1 = (_e494 * clamp(((_e483 - _e485) / (_e488 - _e490)), 0f, 1f)); + } + } + let _e497 = light_3.l; + let _e499 = (*s_4).v; + light_3.h = normalize((_e497 + _e499)); + let _e504 = (*s_4).n; + let _e506 = light_3.l; + light_3.n_dot_l = max(dot(_e504, _e506), 0f); + let _e511 = (*s_4).n; + let _e513 = light_3.h; + light_3.n_dot_h = max(dot(_e511, _e513), 0f); + let _e518 = (*s_4).v; + let _e520 = light_3.h; + light_3.v_dot_h = max(dot(_e518, _e520), 0f); + let _e524 = color_1; + let _e527 = color_1[3u]; + let _e529 = attenuation_1; + light_3.radiance = ((_e524.xyz * _e527) * _e529); + let _e532 = light_3; + return _e532; } fn FindCluster_u0028_vf3_u003b(world_3: ptr>) { @@ -48453,58 +48663,58 @@ fn FindCluster_u0028_vf3_u003b(world_3: ptr>) { var param_100: f32; var param_101: f32; - let _e193 = light_list_info.cluster_view_projection; - let _e194 = (*world_3); - clip_1 = (_e193 * vec4(_e194.x, _e194.y, _e194.z, 1f)); - let _e200 = clip_1; - let _e203 = clip_1[3u]; - ndc_1 = (_e200.xy / vec2(max(_e203, 0.000001f))); - let _e208 = light_list_info.cluster_grid; - grid = _e208.xyz; - let _e212 = light_list_info.cluster_depth[0u]; - near_1 = _e212; - let _e214 = ndc_1[0u]; - let _e218 = grid[0u]; - let _e222 = grid[0u]; - tx = clamp(floor((((_e214 * 0.5f) + 0.5f) * _e218)), 0f, (_e222 - 1f)); - let _e226 = ndc_1[1u]; - let _e230 = grid[1u]; - let _e234 = grid[1u]; - ty = clamp(floor((((_e226 * 0.5f) + 0.5f) * _e230)), 0f, (_e234 - 1f)); - let _e238 = clip_1[3u]; - let _e239 = near_1; - if (_e238 <= _e239) { + let _e194 = light_list_info.cluster_view_projection; + let _e195 = (*world_3); + clip_1 = (_e194 * vec4(_e195.x, _e195.y, _e195.z, 1f)); + let _e201 = clip_1; + let _e204 = clip_1[3u]; + ndc_1 = (_e201.xy / vec2(max(_e204, 0.000001f))); + let _e209 = light_list_info.cluster_grid; + grid = _e209.xyz; + let _e213 = light_list_info.cluster_depth[0u]; + near_1 = _e213; + let _e215 = ndc_1[0u]; + let _e219 = grid[0u]; + let _e223 = grid[0u]; + tx = clamp(floor((((_e215 * 0.5f) + 0.5f) * _e219)), 0f, (_e223 - 1f)); + let _e227 = ndc_1[1u]; + let _e231 = grid[1u]; + let _e235 = grid[1u]; + ty = clamp(floor((((_e227 * 0.5f) + 0.5f) * _e231)), 0f, (_e235 - 1f)); + let _e239 = clip_1[3u]; + let _e240 = near_1; + if (_e239 <= _e240) { local_25 = 0f; } else { - let _e242 = clip_1[3u]; - let _e243 = near_1; - let _e248 = light_list_info.cluster_depth[1u]; - let _e252 = grid[2u]; - local_25 = clamp(floor((log((_e242 / _e243)) * _e248)), 0f, (_e252 - 1f)); - } - let _e255 = local_25; - tz = _e255; - let _e256 = tx; - let _e257 = ty; - let _e259 = grid[0u]; - let _e262 = tz; - let _e264 = grid[0u]; - let _e267 = grid[1u]; - cell = ((_e256 + (_e257 * _e259)) + ((_e262 * _e264) * _e267)); - let _e270 = cell; - row_3 = floor((_e270 / 4f)); - let _e273 = cell; - let _e274 = row_3; - let _e279 = light_list_info.cluster_depth[2u]; - let _e280 = row_3; - param_100 = (_e273 - (_e274 * 4f)); - param_101 = (_e279 + _e280); - let _e282 = LightListTexel_u0028_f1_u003b_f1_u003b((¶m_100), (¶m_101)); - header = _e282; - let _e284 = header[0u]; - g_cluster_offset = _e284; - let _e286 = header[1u]; - g_cluster_count = _e286; + let _e243 = clip_1[3u]; + let _e244 = near_1; + let _e249 = light_list_info.cluster_depth[1u]; + let _e253 = grid[2u]; + local_25 = clamp(floor((log((_e243 / _e244)) * _e249)), 0f, (_e253 - 1f)); + } + let _e256 = local_25; + tz = _e256; + let _e257 = tx; + let _e258 = ty; + let _e260 = grid[0u]; + let _e263 = tz; + let _e265 = grid[0u]; + let _e268 = grid[1u]; + cell = ((_e257 + (_e258 * _e260)) + ((_e263 * _e265) * _e268)); + let _e271 = cell; + row_3 = floor((_e271 / 4f)); + let _e274 = cell; + let _e275 = row_3; + let _e280 = light_list_info.cluster_depth[2u]; + let _e281 = row_3; + param_100 = (_e274 - (_e275 * 4f)); + param_101 = (_e280 + _e281); + let _e283 = LightListTexel_u0028_f1_u003b_f1_u003b((¶m_100), (¶m_101)); + header = _e283; + let _e285 = header[0u]; + g_cluster_offset = _e285; + let _e287 = header[1u]; + g_cluster_count = _e287; return; } @@ -48512,19 +48722,19 @@ fn LightCount_u0028_() -> i32 { var tail: f32; var param_102: vec3; - let _e182 = light_list_info.list[0u]; - tail = _e182; - let _e183 = Clustered_u0028_(); - if _e183 { - let _e184 = v_world_position_1; - param_102 = _e184; + let _e183 = light_list_info.list[0u]; + tail = _e183; + let _e184 = Clustered_u0028_(); + if _e184 { + let _e185 = v_world_position_1; + param_102 = _e185; FindCluster_u0028_vf3_u003b((¶m_102)); - let _e185 = g_cluster_count; - tail = _e185; + let _e186 = g_cluster_count; + tail = _e186; } - let _e188 = frag_info.frame_params[1u]; - let _e192 = tail; - return (clamp(i32((_e188 + 0.5f)), 0i, 8i) + clamp(i32((_e192 + 0.5f)), 0i, 24i)); + let _e189 = frag_info.frame_params[1u]; + let _e193 = tail; + return (clamp(i32((_e189 + 0.5f)), 0i, 8i) + clamp(i32((_e193 + 0.5f)), 0i, 24i)); } fn AccumulateLights_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b(s_5: ptr) -> vec3 { @@ -48547,116 +48757,116 @@ fn AccumulateLights_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002 var param_113: LightSample; total_1 = vec3(0f, 0f, 0f); - let _e196 = LightCount_u0028_(); - count_1 = _e196; + let _e197 = LightCount_u0028_(); + count_1 = _e197; i_8 = 0i; loop { - let _e197 = i_8; - if (_e197 < 32i) { - let _e199 = i_8; - let _e200 = count_1; - if (_e199 >= _e200) { + let _e198 = i_8; + if (_e198 < 32i) { + let _e200 = i_8; + let _e201 = count_1; + if (_e200 >= _e201) { break; } - let _e202 = i_8; - param_103 = _e202; - let _e203 = (*s_5); - param_104 = _e203; - let _e204 = SampleLight_u0028_i1_u003b_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b((¶m_103), (¶m_104)); - light_4 = _e204; - let _e206 = light_4.n_dot_l; - if (_e206 <= 0f) { + let _e203 = i_8; + param_103 = _e203; + let _e204 = (*s_5); + param_104 = _e204; + let _e205 = SampleLight_u0028_i1_u003b_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b((¶m_103), (¶m_104)); + light_4 = _e205; + let _e207 = light_4.n_dot_l; + if (_e207 <= 0f) { continue; } light_transmittance = vec3(1f, 1f, 1f); - let _e208 = i_8; - param_105 = _e208; - let _e209 = LightHasShadow_u0028_i1_u003b((¶m_105)); - if _e209 { - let _e210 = (*s_5); - param_106 = _e210; - let _e211 = light_4; - param_107 = _e211; - let _e212 = i_8; - param_108 = _e212; - let _e213 = LightVisibility_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_struct_u002d_LightSample_u002d_vf3_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf31_u003b_i1_u003b((¶m_106), (¶m_107), (¶m_108)); - let _e214 = v_world_position_1; - param_109 = _e214; - let _e216 = (*s_5).n; - param_110 = _e216; - let _e217 = i_8; - param_111 = _e217; - let _e218 = PointShadowFactor_u0028_vf3_u003b_vf3_u003b_i1_u003b((¶m_109), (¶m_110), (¶m_111)); - local_26 = (_e213 * _e218); + let _e209 = i_8; + param_105 = _e209; + let _e210 = LightHasShadow_u0028_i1_u003b((¶m_105)); + if _e210 { + let _e211 = (*s_5); + param_106 = _e211; + let _e212 = light_4; + param_107 = _e212; + let _e213 = i_8; + param_108 = _e213; + let _e214 = LightVisibility_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_struct_u002d_LightSample_u002d_vf3_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf31_u003b_i1_u003b((¶m_106), (¶m_107), (¶m_108)); + let _e215 = v_world_position_1; + param_109 = _e215; + let _e217 = (*s_5).n; + param_110 = _e217; + let _e218 = i_8; + param_111 = _e218; + let _e219 = PointShadowFactor_u0028_vf3_u003b_vf3_u003b_i1_u003b((¶m_109), (¶m_110), (¶m_111)); + local_26 = (_e214 * _e219); } else { local_26 = 1f; } - let _e220 = local_26; - visibility = _e220; - let _e221 = visibility; - if (_e221 <= 0f) { + let _e221 = local_26; + visibility = _e221; + let _e222 = visibility; + if (_e222 <= 0f) { continue; } - let _e223 = (*s_5); - param_112 = _e223; - let _e224 = light_4; - param_113 = _e224; - let _e225 = ShadeLight_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_struct_u002d_LightSample_u002d_vf3_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf31_u003b((¶m_112), (¶m_113)); - let _e227 = light_4.radiance; - let _e230 = light_4.n_dot_l; - let _e232 = visibility; - let _e234 = light_transmittance; - let _e236 = total_1; - total_1 = (_e236 + ((((_e225 * _e227) * _e230) * _e232) * _e234)); + let _e224 = (*s_5); + param_112 = _e224; + let _e225 = light_4; + param_113 = _e225; + let _e226 = ShadeLight_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_struct_u002d_LightSample_u002d_vf3_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf31_u003b((¶m_112), (¶m_113)); + let _e228 = light_4.radiance; + let _e231 = light_4.n_dot_l; + let _e233 = visibility; + let _e235 = light_transmittance; + let _e237 = total_1; + total_1 = (_e237 + ((((_e226 * _e228) * _e231) * _e233) * _e235)); continue; } else { break; } continuing { - let _e238 = i_8; - i_8 = (_e238 + 1i); + let _e239 = i_8; + i_8 = (_e239 + 1i); } } - let _e240 = total_1; - return _e240; + let _e241 = total_1; + return _e241; } fn ImpostorRight_u0028_vf3_u003b(d_4: ptr>) -> vec3 { var up: vec3; - let _e181 = (*d_4)[1u]; - up = select(vec3(0f, 1f, 0f), vec3(0f, 0f, -1f), vec3((abs(_e181) > 0.999f))); - let _e186 = up; - let _e187 = (*d_4); - return normalize(cross(_e186, _e187)); + let _e182 = (*d_4)[1u]; + up = select(vec3(0f, 1f, 0f), vec3(0f, 0f, -1f), vec3((abs(_e182) > 0.999f))); + let _e187 = up; + let _e188 = (*d_4); + return normalize(cross(_e187, _e188)); } fn ImpostorDecode_u0028_vf2_u003b(uv_5: ptr>) -> vec3 { var p_1: vec2; - var y_1: f32; + var y_2: f32; var s_6: vec2; var folded: vec2; var xz: vec2; - let _e184 = (*uv_5); - p_1 = ((_e184 * 2f) - vec2(1f, 1f)); - let _e188 = p_1[0u]; - let _e192 = p_1[1u]; - y_1 = ((1f - abs(_e188)) - abs(_e192)); - let _e196 = p_1[0u]; - let _e200 = p_1[1u]; - s_6 = vec2(select(-1f, 1f, (_e196 >= 0f)), select(-1f, 1f, (_e200 >= 0f))); - let _e204 = p_1; - let _e208 = s_6; - folded = ((vec2(1f, 1f) - abs(_e204.yx)) * _e208); - let _e210 = y_1; - let _e212 = p_1; - let _e213 = folded; - xz = select(_e213, _e212, vec2((_e210 >= 0f))); - let _e217 = xz[0u]; - let _e218 = y_1; - let _e220 = xz[1u]; - return normalize(vec3(_e217, _e218, _e220)); + let _e185 = (*uv_5); + p_1 = ((_e185 * 2f) - vec2(1f, 1f)); + let _e189 = p_1[0u]; + let _e193 = p_1[1u]; + y_2 = ((1f - abs(_e189)) - abs(_e193)); + let _e197 = p_1[0u]; + let _e201 = p_1[1u]; + s_6 = vec2(select(-1f, 1f, (_e197 >= 0f)), select(-1f, 1f, (_e201 >= 0f))); + let _e205 = p_1; + let _e209 = s_6; + folded = ((vec2(1f, 1f) - abs(_e205.yx)) * _e209); + let _e211 = y_2; + let _e213 = p_1; + let _e214 = folded; + xz = select(_e214, _e213, vec2((_e211 >= 0f))); + let _e218 = xz[0u]; + let _e219 = y_2; + let _e221 = xz[1u]; + return normalize(vec3(_e218, _e219, _e221)); } fn ImpostorViewUv_u0028_vf2_u003b_vf3_u003b(cell_1: ptr>, offset_3: ptr>) -> vec2 { @@ -48667,25 +48877,25 @@ fn ImpostorViewUv_u0028_vf2_u003b_vf3_u003b(cell_1: ptr>, of var up_1: vec3; var local_27: vec2; - let _e186 = (*cell_1); - param_114 = (_e186 / vec2(7f)); - let _e189 = ImpostorDecode_u0028_vf2_u003b((¶m_114)); - d_5 = _e189; - let _e190 = d_5; - param_115 = _e190; - let _e191 = ImpostorRight_u0028_vf3_u003b((¶m_115)); - right = _e191; - let _e192 = d_5; - let _e193 = right; - up_1 = cross(_e192, _e193); - let _e195 = (*offset_3); - let _e196 = right; - let _e200 = (*offset_3); - let _e201 = up_1; - local_27 = vec2(((dot(_e195, _e196) * 0.5f) + 0.5f), (0.5f - (dot(_e200, _e201) * 0.5f))); - let _e206 = (*cell_1); - let _e207 = local_27; - return ((_e206 + clamp(_e207, vec2(0f, 0f), vec2(1f, 1f))) / vec2(8f)); + let _e187 = (*cell_1); + param_114 = (_e187 / vec2(7f)); + let _e190 = ImpostorDecode_u0028_vf2_u003b((¶m_114)); + d_5 = _e190; + let _e191 = d_5; + param_115 = _e191; + let _e192 = ImpostorRight_u0028_vf3_u003b((¶m_115)); + right = _e192; + let _e193 = d_5; + let _e194 = right; + up_1 = cross(_e193, _e194); + let _e196 = (*offset_3); + let _e197 = right; + let _e201 = (*offset_3); + let _e202 = up_1; + local_27 = vec2(((dot(_e196, _e197) * 0.5f) + 0.5f), (0.5f - (dot(_e201, _e202) * 0.5f))); + let _e207 = (*cell_1); + let _e208 = local_27; + return ((_e207 + clamp(_e208, vec2(0f, 0f), vec2(1f, 1f))) / vec2(8f)); } fn ImpostorEncode_u0028_vf3_u003b(d_6: ptr>) -> vec2 { @@ -48694,44 +48904,44 @@ fn ImpostorEncode_u0028_vf3_u003b(d_6: ptr>) -> vec2 { var s_7: vec2; var folded_1: vec2; - let _e183 = (*d_6); - a_4 = abs(_e183); - let _e185 = (*d_6); - let _e188 = a_4[0u]; - let _e190 = a_4[1u]; - let _e193 = a_4[2u]; - p_2 = (_e185.xz / vec2(max(((_e188 + _e190) + _e193), 0.00000001f))); - let _e199 = p_2[0u]; - let _e203 = p_2[1u]; - s_7 = vec2(select(-1f, 1f, (_e199 >= 0f)), select(-1f, 1f, (_e203 >= 0f))); - let _e207 = p_2; - let _e211 = s_7; - folded_1 = ((vec2(1f, 1f) - abs(_e207.yx)) * _e211); - let _e214 = (*d_6)[1u]; - let _e216 = p_2; - let _e217 = folded_1; - return ((select(_e217, _e216, vec2((_e214 >= 0f))) * 0.5f) + vec2(0.5f, 0.5f)); + let _e184 = (*d_6); + a_4 = abs(_e184); + let _e186 = (*d_6); + let _e189 = a_4[0u]; + let _e191 = a_4[1u]; + let _e194 = a_4[2u]; + p_2 = (_e186.xz / vec2(max(((_e189 + _e191) + _e194), 0.00000001f))); + let _e200 = p_2[0u]; + let _e204 = p_2[1u]; + s_7 = vec2(select(-1f, 1f, (_e200 >= 0f)), select(-1f, 1f, (_e204 >= 0f))); + let _e208 = p_2; + let _e212 = s_7; + folded_1 = ((vec2(1f, 1f) - abs(_e208.yx)) * _e212); + let _e215 = (*d_6)[1u]; + let _e217 = p_2; + let _e218 = folded_1; + return ((select(_e218, _e217, vec2((_e215 >= 0f))) * 0.5f) + vec2(0.5f, 0.5f)); } fn TowardsEye_u0028_() -> vec3 { var local_28: vec3; - let _e179 = Orthographic_u0028_(); - if _e179 { - let _e181 = fog_info.forward; - local_28 = -(_e181.xyz); + let _e180 = Orthographic_u0028_(); + if _e180 { + let _e182 = fog_info.forward; + local_28 = -(_e182.xyz); } else { - let _e185 = fog_info.eye; - let _e187 = v_world_position_1; - local_28 = normalize((_e185.xyz - _e187)); + let _e186 = fog_info.eye; + let _e188 = v_world_position_1; + local_28 = normalize((_e186.xyz - _e188)); } - let _e190 = local_28; - return _e190; + let _e191 = local_28; + return _e191; } fn MaterialLodBias_u0028_() -> f32 { - let _e180 = frag_info.target_origin[1u]; - return _e180; + let _e181 = frag_info.target_origin[1u]; + return _e181; } fn ReadSurface_u0028_() -> Surface { @@ -48744,89 +48954,89 @@ fn ReadSurface_u0028_() -> Surface { var anchored: vec3; var noise_1: f32; - let _e186 = v_texcoord_1; - let _e187 = MaterialLodBias_u0028_(); - let _e188 = textureSampleBias(base_color_texture_tex, base_color_texture_smp, _e186, _e187); - texel_4 = _e188; - let _e189 = texel_4; - param_116 = _e189.xyz; - let _e191 = SrgbToLinear_u0028_vf3_u003b((¶m_116)); - let _e193 = frag_info.base_color; - param_117 = _e193.xyz; - let _e195 = SrgbToLinear_u0028_vf3_u003b((¶m_117)); - let _e197 = v_color_1; - s_8.albedo = ((_e191 * _e195) * _e197.xyz); - let _e202 = texel_4[3u]; - let _e205 = frag_info.base_color[3u]; - let _e208 = v_color_1[3u]; - s_8.alpha = ((_e202 * _e205) * _e208); - let _e212 = s_8.albedo; - g_albedo = _e212; - let _e215 = frag_info.material2_[0u]; - cutoff = _e215; - let _e216 = cutoff; - if (_e216 > 1f) { - let _e218 = cutoff; - edge = (_e218 - 1f); - let _e221 = s_8.alpha; - let _e222 = edge; - let _e225 = s_8.alpha; - let _e226 = fwidth(_e225); - s_8.alpha = clamp((((_e221 - _e222) / max(_e226, 0.0001f)) + 0.5f), 0f, 1f); - } else { - let _e232 = cutoff; - if (_e232 >= 0f) { - let _e235 = s_8.alpha; - let _e236 = cutoff; - if (_e235 < _e236) { + let _e187 = v_texcoord_1; + let _e188 = MaterialLodBias_u0028_(); + let _e189 = textureSampleBias(base_color_texture_tex, base_color_texture_smp, _e187, _e188); + texel_4 = _e189; + let _e190 = texel_4; + param_116 = _e190.xyz; + let _e192 = SrgbToLinear_u0028_vf3_u003b((¶m_116)); + let _e194 = frag_info.base_color; + param_117 = _e194.xyz; + let _e196 = SrgbToLinear_u0028_vf3_u003b((¶m_117)); + let _e198 = v_color_1; + s_8.albedo = ((_e192 * _e196) * _e198.xyz); + let _e203 = texel_4[3u]; + let _e206 = frag_info.base_color[3u]; + let _e209 = v_color_1[3u]; + s_8.alpha = ((_e203 * _e206) * _e209); + let _e213 = s_8.albedo; + g_albedo = _e213; + let _e216 = frag_info.material2_[0u]; + cutoff = _e216; + let _e217 = cutoff; + if (_e217 > 1f) { + let _e219 = cutoff; + edge = (_e219 - 1f); + let _e222 = s_8.alpha; + let _e223 = edge; + let _e226 = s_8.alpha; + let _e227 = fwidth(_e226); + s_8.alpha = clamp((((_e222 - _e223) / max(_e227, 0.0001f)) + 0.5f), 0f, 1f); + } else { + let _e233 = cutoff; + if (_e233 >= 0f) { + let _e236 = s_8.alpha; + let _e237 = cutoff; + if (_e236 < _e237) { discard; } s_8.alpha = 1f; } else { - let _e239 = cutoff; - if (_e239 < -1.5f) { - let _e241 = v_world_position_1; - anchored = floor((_e241 * 16f)); - let _e244 = anchored; - noise_1 = fract((sin(dot(_e244, vec3(12.9898f, 78.233f, 37.719f))) * 43758.547f)); - let _e250 = s_8.alpha; - let _e251 = noise_1; - if (_e250 < _e251) { + let _e240 = cutoff; + if (_e240 < -1.5f) { + let _e242 = v_world_position_1; + anchored = floor((_e242 * 16f)); + let _e245 = anchored; + noise_1 = fract((sin(dot(_e245, vec3(12.9898f, 78.233f, 37.719f))) * 43758.547f)); + let _e251 = s_8.alpha; + let _e252 = noise_1; + if (_e251 < _e252) { discard; } } } } - let _e253 = cutoff; - let _e255 = cutoff; - g_premultiply = ((_e253 < 0f) && (_e255 > -0.75f)); - let _e258 = v_normal_1; - s_8.n = normalize(_e258); - let _e261 = gl_FrontFacing_1; - if !(_e261) { - let _e264 = s_8.n; - s_8.n = -(_e264); - } - let _e267 = TowardsEye_u0028_(); - s_8.v = _e267; - let _e270 = s_8.n; - let _e272 = s_8.v; - s_8.n_dot_v = max(dot(_e270, _e272), 0.0001f); - let _e278 = frag_info.material[0u]; - s_8.metallic = clamp(_e278, 0f, 1f); - let _e283 = frag_info.material[1u]; - s_8.roughness = clamp(_e283, 0.02f, 1f); - let _e287 = frag_info.ambient_ground; - let _e290 = frag_info.ambient_sky; - let _e294 = s_8.n[1u]; - let _e301 = frag_info.material[2u]; - s_8.ambient = (mix(_e287.xyz, _e290.xyz, vec3(((_e294 * 0.5f) + 0.5f))) * _e301); - let _e306 = frag_info.frame_params[0u]; - s_8.exposure = max(_e306, 0f); + let _e254 = cutoff; + let _e256 = cutoff; + g_premultiply = ((_e254 < 0f) && (_e256 > -0.75f)); + let _e259 = v_normal_1; + s_8.n = normalize(_e259); + let _e262 = gl_FrontFacing_1; + if !(_e262) { + let _e265 = s_8.n; + s_8.n = -(_e265); + } + let _e268 = TowardsEye_u0028_(); + s_8.v = _e268; + let _e271 = s_8.n; + let _e273 = s_8.v; + s_8.n_dot_v = max(dot(_e271, _e273), 0.0001f); + let _e279 = frag_info.material[0u]; + s_8.metallic = clamp(_e279, 0f, 1f); + let _e284 = frag_info.material[1u]; + s_8.roughness = clamp(_e284, 0.02f, 1f); + let _e288 = frag_info.ambient_ground; + let _e291 = frag_info.ambient_sky; + let _e295 = s_8.n[1u]; + let _e302 = frag_info.material[2u]; + s_8.ambient = (mix(_e288.xyz, _e291.xyz, vec3(((_e295 * 0.5f) + 0.5f))) * _e302); + let _e307 = frag_info.frame_params[0u]; + s_8.exposure = max(_e307, 0f); s_8.occlusion = 1f; s_8.emissive = vec3(0f, 0f, 0f); - let _e311 = s_8; - return _e311; + let _e312 = s_8; + return _e312; } fn main_1() { @@ -48888,186 +49098,186 @@ fn main_1() { g_cluster_offset = 0f; g_cluster_count = 0f; light_transmittance = vec3(1f, 1f, 1f); - let _e227 = ReadSurface_u0028_(); - s_9 = _e227; - let _e228 = v_color_1; - d_7 = normalize(_e228.xyz); - let _e231 = d_7; - param_118 = _e231; - let _e232 = ImpostorRight_u0028_vf3_u003b((¶m_118)); - right_1 = _e232; - let _e233 = d_7; - let _e234 = right_1; - up_2 = cross(_e233, _e234); - let _e236 = right_1; - let _e238 = v_texcoord_1[0u]; - let _e242 = up_2; - let _e244 = v_texcoord_1[1u]; - offset_4 = ((_e236 * ((_e238 * 2f) - 1f)) + (_e242 * (1f - (_e244 * 2f)))); - let _e249 = d_7; - param_119 = _e249; - let _e250 = ImpostorEncode_u0028_vf3_u003b((¶m_119)); - g = (_e250 * 7f); - let _e252 = g; - base = clamp(floor(_e252), vec2(0f, 0f), vec2(6f, 6f)); - let _e255 = g; - let _e256 = base; - f = (_e255 - _e256); - let _e259 = f[0u]; - let _e261 = f[1u]; - lower = ((_e259 + _e261) < 1f); - let _e264 = lower; - if _e264 { - let _e265 = base; - local_29 = _e265; - } else { + let _e228 = ReadSurface_u0028_(); + s_9 = _e228; + let _e229 = v_color_1; + d_7 = normalize(_e229.xyz); + let _e232 = d_7; + param_118 = _e232; + let _e233 = ImpostorRight_u0028_vf3_u003b((¶m_118)); + right_1 = _e233; + let _e234 = d_7; + let _e235 = right_1; + up_2 = cross(_e234, _e235); + let _e237 = right_1; + let _e239 = v_texcoord_1[0u]; + let _e243 = up_2; + let _e245 = v_texcoord_1[1u]; + offset_4 = ((_e237 * ((_e239 * 2f) - 1f)) + (_e243 * (1f - (_e245 * 2f)))); + let _e250 = d_7; + param_119 = _e250; + let _e251 = ImpostorEncode_u0028_vf3_u003b((¶m_119)); + g = (_e251 * 7f); + let _e253 = g; + base = clamp(floor(_e253), vec2(0f, 0f), vec2(6f, 6f)); + let _e256 = g; + let _e257 = base; + f = (_e256 - _e257); + let _e260 = f[0u]; + let _e262 = f[1u]; + lower = ((_e260 + _e262) < 1f); + let _e265 = lower; + if _e265 { let _e266 = base; - local_29 = (_e266 + vec2(1f, 1f)); - } - let _e268 = local_29; - c0_ = _e268; - let _e269 = base; - c1_ = (_e269 + vec2(1f, 0f)); - let _e271 = base; - c2_ = (_e271 + vec2(0f, 1f)); - let _e273 = lower; - if _e273 { - let _e275 = f[0u]; - let _e278 = f[1u]; - let _e281 = f[0u]; - let _e283 = f[1u]; - local_30 = vec3(((1f - _e275) - _e278), _e281, _e283); - } else { - let _e286 = f[0u]; - let _e288 = f[1u]; - let _e292 = f[1u]; - let _e295 = f[0u]; - local_30 = vec3(((_e286 + _e288) - 1f), (1f - _e292), (1f - _e295)); - } - let _e298 = local_30; - w = _e298; - let _e299 = c0_; - param_120 = _e299; - let _e300 = offset_4; - param_121 = _e300; - let _e301 = ImpostorViewUv_u0028_vf2_u003b_vf3_u003b((¶m_120), (¶m_121)); - uv0_ = _e301; - let _e302 = c1_; - param_122 = _e302; - let _e303 = offset_4; - param_123 = _e303; - let _e304 = ImpostorViewUv_u0028_vf2_u003b_vf3_u003b((¶m_122), (¶m_123)); - uv1_ = _e304; - let _e305 = c2_; - param_124 = _e305; - let _e306 = offset_4; - param_125 = _e306; - let _e307 = ImpostorViewUv_u0028_vf2_u003b_vf3_u003b((¶m_124), (¶m_125)); - uv2_ = _e307; - let _e308 = uv0_; - let _e309 = textureSampleLevel(base_color_texture_tex, base_color_texture_smp, _e308, 0f); - a0_ = _e309; - let _e310 = uv1_; - let _e311 = textureSampleLevel(base_color_texture_tex, base_color_texture_smp, _e310, 0f); - a1_ = _e311; - let _e312 = uv2_; - let _e313 = textureSampleLevel(base_color_texture_tex, base_color_texture_smp, _e312, 0f); - a2_ = _e313; - let _e314 = uv0_; - let _e315 = textureSampleLevel(normal_texture_tex, normal_texture_smp, _e314, 0f); - n0_ = _e315; - let _e316 = uv1_; - let _e317 = textureSampleLevel(normal_texture_tex, normal_texture_smp, _e316, 0f); - n1_ = _e317; - let _e318 = uv2_; - let _e319 = textureSampleLevel(normal_texture_tex, normal_texture_smp, _e318, 0f); - n2_ = _e319; - let _e320 = w; - let _e322 = a0_[3u]; - let _e324 = a1_[3u]; - let _e326 = a2_[3u]; - wa = (_e320 * vec3(_e322, _e324, _e326)); - let _e330 = wa[0u]; - let _e332 = wa[1u]; - let _e335 = wa[2u]; - alpha_3 = ((_e330 + _e332) + _e335); - let _e337 = alpha_3; - if (_e337 < 0.5f) { + local_29 = _e266; + } else { + let _e267 = base; + local_29 = (_e267 + vec2(1f, 1f)); + } + let _e269 = local_29; + c0_ = _e269; + let _e270 = base; + c1_ = (_e270 + vec2(1f, 0f)); + let _e272 = base; + c2_ = (_e272 + vec2(0f, 1f)); + let _e274 = lower; + if _e274 { + let _e276 = f[0u]; + let _e279 = f[1u]; + let _e282 = f[0u]; + let _e284 = f[1u]; + local_30 = vec3(((1f - _e276) - _e279), _e282, _e284); + } else { + let _e287 = f[0u]; + let _e289 = f[1u]; + let _e293 = f[1u]; + let _e296 = f[0u]; + local_30 = vec3(((_e287 + _e289) - 1f), (1f - _e293), (1f - _e296)); + } + let _e299 = local_30; + w = _e299; + let _e300 = c0_; + param_120 = _e300; + let _e301 = offset_4; + param_121 = _e301; + let _e302 = ImpostorViewUv_u0028_vf2_u003b_vf3_u003b((¶m_120), (¶m_121)); + uv0_ = _e302; + let _e303 = c1_; + param_122 = _e303; + let _e304 = offset_4; + param_123 = _e304; + let _e305 = ImpostorViewUv_u0028_vf2_u003b_vf3_u003b((¶m_122), (¶m_123)); + uv1_ = _e305; + let _e306 = c2_; + param_124 = _e306; + let _e307 = offset_4; + param_125 = _e307; + let _e308 = ImpostorViewUv_u0028_vf2_u003b_vf3_u003b((¶m_124), (¶m_125)); + uv2_ = _e308; + let _e309 = uv0_; + let _e310 = textureSampleLevel(base_color_texture_tex, base_color_texture_smp, _e309, 0f); + a0_ = _e310; + let _e311 = uv1_; + let _e312 = textureSampleLevel(base_color_texture_tex, base_color_texture_smp, _e311, 0f); + a1_ = _e312; + let _e313 = uv2_; + let _e314 = textureSampleLevel(base_color_texture_tex, base_color_texture_smp, _e313, 0f); + a2_ = _e314; + let _e315 = uv0_; + let _e316 = textureSampleLevel(normal_texture_tex, normal_texture_smp, _e315, 0f); + n0_ = _e316; + let _e317 = uv1_; + let _e318 = textureSampleLevel(normal_texture_tex, normal_texture_smp, _e317, 0f); + n1_ = _e318; + let _e319 = uv2_; + let _e320 = textureSampleLevel(normal_texture_tex, normal_texture_smp, _e319, 0f); + n2_ = _e320; + let _e321 = w; + let _e323 = a0_[3u]; + let _e325 = a1_[3u]; + let _e327 = a2_[3u]; + wa = (_e321 * vec3(_e323, _e325, _e327)); + let _e331 = wa[0u]; + let _e333 = wa[1u]; + let _e336 = wa[2u]; + alpha_3 = ((_e331 + _e333) + _e336); + let _e338 = alpha_3; + if (_e338 < 0.5f) { discard; } - let _e339 = a0_; - let _e342 = wa[0u]; - let _e344 = a1_; - let _e347 = wa[1u]; - let _e350 = a2_; - let _e353 = wa[2u]; - let _e356 = alpha_3; - srgb_1 = ((((_e339.xyz * _e342) + (_e344.xyz * _e347)) + (_e350.xyz * _e353)) / vec3(_e356)); - let _e359 = n0_; - let _e364 = wa[0u]; - let _e366 = n1_; - let _e371 = wa[1u]; - let _e374 = n2_; - let _e379 = wa[2u]; - local_31 = (((((_e359.xyz * 2f) - vec3(1f, 1f, 1f)) * _e364) + (((_e366.xyz * 2f) - vec3(1f, 1f, 1f)) * _e371)) + (((_e374.xyz * 2f) - vec3(1f, 1f, 1f)) * _e379)); - let _e382 = local_31; + let _e340 = a0_; + let _e343 = wa[0u]; + let _e345 = a1_; + let _e348 = wa[1u]; + let _e351 = a2_; + let _e354 = wa[2u]; + let _e357 = alpha_3; + srgb_1 = ((((_e340.xyz * _e343) + (_e345.xyz * _e348)) + (_e351.xyz * _e354)) / vec3(_e357)); + let _e360 = n0_; + let _e365 = wa[0u]; + let _e367 = n1_; + let _e372 = wa[1u]; + let _e375 = n2_; + let _e380 = wa[2u]; + local_31 = (((((_e360.xyz * 2f) - vec3(1f, 1f, 1f)) * _e365) + (((_e367.xyz * 2f) - vec3(1f, 1f, 1f)) * _e372)) + (((_e375.xyz * 2f) - vec3(1f, 1f, 1f)) * _e380)); let _e383 = local_31; - let _e386 = local_31; - let _e387 = d_7; - local_31 = normalize(select(_e387, _e386, vec3((dot(_e382, _e383) > 0.000000000001f)))); - let _e391 = v_tangent_1; - worldRight = normalize(_e391.xyz); - let _e394 = v_normal_1; - worldFacing = normalize(_e394); - let _e396 = worldFacing; - let _e397 = worldRight; - worldUp = cross(_e396, _e397); - let _e399 = worldRight; - let _e400 = local_31; - let _e401 = right_1; - let _e404 = worldUp; - let _e405 = local_31; - let _e406 = up_2; - let _e410 = worldFacing; - let _e411 = local_31; - let _e412 = d_7; - s_9.n = normalize((((_e399 * dot(_e400, _e401)) + (_e404 * dot(_e405, _e406))) + (_e410 * dot(_e411, _e412)))); - let _e419 = s_9.n; - let _e421 = s_9.v; - s_9.n_dot_v = max(dot(_e419, _e421), 0.0001f); - let _e425 = srgb_1; - param_126 = _e425; - let _e426 = SrgbToLinear_u0028_vf3_u003b((¶m_126)); - let _e428 = frag_info.base_color; - param_127 = _e428.xyz; - let _e430 = SrgbToLinear_u0028_vf3_u003b((¶m_127)); - s_9.albedo = (_e426 * _e430); + let _e384 = local_31; + let _e387 = local_31; + let _e388 = d_7; + local_31 = normalize(select(_e388, _e387, vec3((dot(_e383, _e384) > 0.000000000001f)))); + let _e392 = v_tangent_1; + worldRight = normalize(_e392.xyz); + let _e395 = v_normal_1; + worldFacing = normalize(_e395); + let _e397 = worldFacing; + let _e398 = worldRight; + worldUp = cross(_e397, _e398); + let _e400 = worldRight; + let _e401 = local_31; + let _e402 = right_1; + let _e405 = worldUp; + let _e406 = local_31; + let _e407 = up_2; + let _e411 = worldFacing; + let _e412 = local_31; + let _e413 = d_7; + s_9.n = normalize((((_e400 * dot(_e401, _e402)) + (_e405 * dot(_e406, _e407))) + (_e411 * dot(_e412, _e413)))); + let _e420 = s_9.n; + let _e422 = s_9.v; + s_9.n_dot_v = max(dot(_e420, _e422), 0.0001f); + let _e426 = srgb_1; + param_126 = _e426; + let _e427 = SrgbToLinear_u0028_vf3_u003b((¶m_126)); + let _e429 = frag_info.base_color; + param_127 = _e429.xyz; + let _e431 = SrgbToLinear_u0028_vf3_u003b((¶m_127)); + s_9.albedo = (_e427 * _e431); s_9.alpha = 1f; - let _e435 = s_9.albedo; - g_albedo = _e435; - let _e437 = frag_info.ambient_ground; - let _e440 = frag_info.ambient_sky; - let _e444 = s_9.n[1u]; - let _e451 = frag_info.material[2u]; - s_9.ambient = (mix(_e437.xyz, _e440.xyz, vec3(((_e444 * 0.5f) + 0.5f))) * _e451); - let _e455 = s_9.albedo; - let _e457 = s_9.ambient; - ambient = (_e455 * _e457); - let _e459 = s_9; - param_128 = _e459; - let _e460 = AccumulateLights_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b((¶m_128)); - let _e461 = ambient; - lit_3 = (_e460 + _e461); - let _e463 = s_9; - param_129 = _e463; - let _e464 = lit_3; - param_130 = _e464; - let _e465 = WriteDebugView_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_vf3_u003b((¶m_129), (¶m_130)); - if _e465 { + let _e436 = s_9.albedo; + g_albedo = _e436; + let _e438 = frag_info.ambient_ground; + let _e441 = frag_info.ambient_sky; + let _e445 = s_9.n[1u]; + let _e452 = frag_info.material[2u]; + s_9.ambient = (mix(_e438.xyz, _e441.xyz, vec3(((_e445 * 0.5f) + 0.5f))) * _e452); + let _e456 = s_9.albedo; + let _e458 = s_9.ambient; + ambient = (_e456 * _e458); + let _e460 = s_9; + param_128 = _e460; + let _e461 = AccumulateLights_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b((¶m_128)); + let _e462 = ambient; + lit_3 = (_e461 + _e462); + let _e464 = s_9; + param_129 = _e464; + let _e465 = lit_3; + param_130 = _e465; + let _e466 = WriteDebugView_u0028_struct_u002d_Surface_u002d_vf3_u002d_f1_u002d_vf3_u002d_vf3_u002d_f1_u002d_f1_u002d_f1_u002d_f1_u002d_vf3_u002d_vf3_u002d_f11_u003b_vf3_u003b((¶m_129), (¶m_130)); + if _e466 { return; } - let _e466 = lit_3; - param_131 = _e466; + let _e467 = lit_3; + param_131 = _e467; param_132 = 1f; param_133 = 1f; WriteSurface_u0028_vf3_u003b_f1_u003b_f1_u003b((¶m_131), (¶m_132), (¶m_133)); From 8a489b091a87fd300c6dff0d5b7d3d79e9784e7c Mon Sep 17 00:00:00 2001 From: Dmitrii Zolotov Date: Sat, 3 Oct 2026 14:34:12 +0300 Subject: [PATCH 14/34] fix: Keep a poured liquid's colour and soften the bench's shadows The clean tube's liquid material was made with the first drops, where its round bottom is nearly no width, and never remade, so what was poured into it showed a fraction of its colour. It is remade whenever the width at the level changes. A vessel emptied and filled again now fills with what it last held rather than plain water. The bench's sun has its quarter-degree size, so shadow edges get their penumbra instead of stepping along the map's texels. --- packages/education/chemlab/lib/src/bench.dart | 33 ++++++++++++--- .../education/chemlab/lib/src/glassware.dart | 8 ++++ .../education/chemlab/test/bench_test.dart | 38 ++++++++++++++++++ .../education/chemlab/test/goldens/bench.png | Bin 1936077 -> 1936077 bytes 4 files changed, 73 insertions(+), 6 deletions(-) diff --git a/packages/education/chemlab/lib/src/bench.dart b/packages/education/chemlab/lib/src/bench.dart index 49ff15b71..0f6c8fd9b 100644 --- a/packages/education/chemlab/lib/src/bench.dart +++ b/packages/education/chemlab/lib/src/bench.dart @@ -61,6 +61,10 @@ final class Vessel { /// What its label says; null for glass that wears none. final Solution? solution; + /// What it last held, as concentrations: what filling it again from + /// empty fills it with. Null until it has held anything. + Map? _held; + /// How far it leans, in radians, and about which horizontal axis. State. double tilt = 0.0; @@ -535,15 +539,21 @@ final class Bench { final now = vessel.liquid.volume; if (target > now) { final layers = vessel.liquid.layers; + // From empty: what it last held. The clean tube, emptied of what was + // poured into it and filled again, came back as plain water, its + // label being none. vessel.liquid.pour( target - now, - concentrations: layers.isEmpty - ? (vessel.dye.toARGB32() == 0xFFFFFFFF - ? const {} - : {vessel.name: 1.0}) - : layers.last.concentrations, + concentrations: layers.isNotEmpty + ? layers.last.concentrations + : vessel._held ?? + (vessel.dye.toARGB32() == 0xFFFFFFFF + ? const {} + : {vessel.name: 1.0}), ); } else if (target < now) { + final layers = vessel.liquid.layers; + if (layers.isNotEmpty) vessel._held = layers.last.concentrations; vessel.liquid.drain(now - target); } _redraw(vessel); @@ -1034,6 +1044,10 @@ final class Bench { /// moves, so the caller knows to ask for another frame. bool step(double seconds) { var moving = false; + for (final vessel in vessels) { + final layers = vessel.liquid.layers; + if (layers.isNotEmpty) vessel._held = layers.last.concentrations; + } for (final vessel in vessels) { if (identical(vessel, _transfer?.from)) continue; // **Lifted out of the row before it leans, and put back after.** The @@ -1147,7 +1161,14 @@ final class Bench { final layer = vessel.layers[i]; _swap(layer.node, meshes[i].mesh); layer.reflection.mesh = layer.node.mesh; - if (layer.colour != colour) { + // Made again when the colour changes, and when the width across the + // glass at the level does: the clean tube's first layer was made with + // the first drops, a hair up its round bottom where the glass is + // nearly no width, and kept so, the half poured into it showed a + // fraction of the colour of the half left behind. + final thickness = layer.node.material.extensions?.thickness ?? 0.0; + if (layer.colour != colour || + (thickness - depth).abs() > 0.02 * depth) { layer.node.material = liquid(_rgb(colour), depth: depth); layer.reflection.material = _reflection( albedo: null, diff --git a/packages/education/chemlab/lib/src/glassware.dart b/packages/education/chemlab/lib/src/glassware.dart index f702c6081..3d8db4532 100644 --- a/packages/education/chemlab/lib/src/glassware.dart +++ b/packages/education/chemlab/lib/src/glassware.dart @@ -260,10 +260,17 @@ Material paper([TextureHandle? label]) => /// is most of a tube. The map is twice the default's edge: at a metre and /// 1024 texels a tube's shadow edge stepped by most of a millimetre, which a /// close look at a sixteen-millimetre tube shows as stairs. +/// +/// **The sun has a size**, a quarter of a degree across, and a tube ten +/// centimetres tall throws a penumbra about a millimetre wide with it, +/// several texels of the map. Drawn as a point, the edge was a hard line +/// that the map's texels, stretched along the bench where the shadow falls +/// long, drew as stairs. final RenderSettings benchSettings = RenderSettings( sky: labSky, shadows: const ShadowSettings( translucentCasters: true, + directionalLightRadius: ShadowSettings.sunAngularRadius, resolution: 2048, viewDistance: 0.6, normalOffset: 0.002, @@ -276,6 +283,7 @@ final RenderSettings photonSettings = RenderSettings( sky: labSky, shadows: const ShadowSettings( translucentCasters: true, + directionalLightRadius: ShadowSettings.sunAngularRadius, caustics: true, causticPhotons: 128, resolution: 2048, diff --git a/packages/education/chemlab/test/bench_test.dart b/packages/education/chemlab/test/bench_test.dart index 883a7f70f..0ea6896f1 100644 --- a/packages/education/chemlab/test/bench_test.dart +++ b/packages/education/chemlab/test/bench_test.dart @@ -373,4 +373,42 @@ void main() { expect(lying.volume, greaterThan(held * 0.9)); expect(lying.puddles.first.volume, greaterThan(held * 0.8)); }); + + test('what is poured into the clean tube is as deep a colour as is left', () { + // Mutation: take the depth of the liquid's material at the level, and + // the clean tube's, made with the first drops near its round bottom, + // is a hair thick: the half poured in shows a fraction of the colour. + final kit = cpuTestDevice(width: 8, height: 8); + final bench = Bench(kit.device); + final from = bench.vessels[1]; + final to = bench.clean; + bench.share(from); + while (bench.busy || bench.world.jets.isNotEmpty) { + bench.step(1 / 60); + } + double depth(Vessel v) => + v.layers.single.node.material.extensions!.thickness; + expect(depth(to), closeTo(depth(from), 1e-9)); + }); + + test('the clean tube emptied and filled again holds what it held', () { + // Mutation: fill it from empty with what its label says, and with none + // it comes back as plain water. + final kit = cpuTestDevice(width: 8, height: 8); + final bench = Bench(kit.device); + final from = bench.vessels[1]; + final to = bench.clean; + bench.share(from); + while (bench.busy || bench.world.jets.isNotEmpty) { + bench.step(1 / 60); + } + bench + ..pour(to, to.lowest) + ..step(1 / 60); + expect(to.liquid.volume, 0.0); + bench + ..pour(to, 0.5 * (to.lowest + to.highest)) + ..step(1 / 60); + expect(bench.colour(to), bench.colour(from)); + }); } diff --git a/packages/education/chemlab/test/goldens/bench.png b/packages/education/chemlab/test/goldens/bench.png index d256e9b5541f1c03079a8c9590bb8f3bcde9cafd..4170ca6a70a450ccbc456eaedced6f4496fffa94 100644 GIT binary patch delta 89510 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 G9{FGUF>nw7 delta 89311 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 Date: Sat, 3 Oct 2026 15:14:45 +0300 Subject: [PATCH 15/34] perf: Make pouring with drops ten times cheaper A pour into a tube spent most of its time working out the surface's modes again: each time the level rose half a cell, conjugate gradients solved the same Laplacian afresh, seventy milliseconds a cross-section. The modes are now cached by the cells a cross-section takes, so a straight-sided glass solves once, and the Laplacian is factored once as a band, three milliseconds a solve. Drops and streams look only at the walls they can reach, and the drops' pair loops no longer make an object for every difference, which had the collector pausing whole frames. A four-second pour costs a tenth of the CPU it did. --- packages/education/chemlab/lib/src/bench.dart | 23 +-- .../lib/src/fluid/free_surface.dart | 152 +++++++++++---- .../flutter3d_physics/lib/src/fluid/jet.dart | 23 ++- .../lib/src/fluid/particle_fluid.dart | 181 ++++++++++++++---- 4 files changed, 286 insertions(+), 93 deletions(-) diff --git a/packages/education/chemlab/lib/src/bench.dart b/packages/education/chemlab/lib/src/bench.dart index 0f6c8fd9b..246d9d318 100644 --- a/packages/education/chemlab/lib/src/bench.dart +++ b/packages/education/chemlab/lib/src/bench.dart @@ -1167,8 +1167,7 @@ final class Bench { // nearly no width, and kept so, the half poured into it showed a // fraction of the colour of the half left behind. final thickness = layer.node.material.extensions?.thickness ?? 0.0; - if (layer.colour != colour || - (thickness - depth).abs() > 0.02 * depth) { + if (layer.colour != colour || (thickness - depth).abs() > 0.02 * depth) { layer.node.material = liquid(_rgb(colour), depth: depth); layer.reflection.material = _reflection( albedo: null, @@ -1238,12 +1237,7 @@ final class Bench { 0.0, radii: [ for (final d in drops) - math - .pow( - 3.0 * d.volume / (4.0 * math.pi), - 1.0 / 3.0, - ) - .toDouble(), + math.pow(3.0 * d.volume / (4.0 * math.pi), 1.0 / 3.0).toDouble(), ], ), ); @@ -1277,10 +1271,7 @@ final class Bench { } final r = puddle.radius(g); if (r < puddle.restRadius(g)) any = true; - _swap( - node, - capMesh([puddle.centre], [r], [puddle.capHeight(r)]), - ); + _swap(node, capMesh([puddle.centre], [r], [puddle.capHeight(r)])); node.visible = true; } _reflectSpilt(); @@ -1293,9 +1284,8 @@ final class Bench { /// mirror nowhere, under glasses whose liquids all did. void _reflectSpilt() { final nodes = [..._streams.values, ..._drops.values, ..._puddles]; - for (final gone in _spiltReflections.keys - .where((n) => !nodes.contains(n)) - .toList()) { + for (final gone + in _spiltReflections.keys.where((n) => !nodes.contains(n)).toList()) { _spiltReflections.remove(gone)!.removeFromParent(); } for (final node in nodes) { @@ -1363,8 +1353,7 @@ final class Bench { : (sum: s.sum..addScaled(positions[i], v), volume: s.volume + v); } return [ - for (final s in sums.values) - (centre: s.sum / s.volume, volume: s.volume), + for (final s in sums.values) (centre: s.sum / s.volume, volume: s.volume), ]; } diff --git a/packages/flutter3d_physics/lib/src/fluid/free_surface.dart b/packages/flutter3d_physics/lib/src/fluid/free_surface.dart index 52751d513..02a35ede9 100644 --- a/packages/flutter3d_physics/lib/src/fluid/free_surface.dart +++ b/packages/flutter3d_physics/lib/src/fluid/free_surface.dart @@ -134,7 +134,7 @@ final class FreeSurface { _rate = Float64List(0); return; } - final (shapes, k2) = _lowestModes(grid, modeCount); + final (shapes, k2) = _modesOf(grid, modeCount); _modes = shapes; _k2 = k2; // The liquid stays: what stood off the old plane stands off the new one @@ -440,47 +440,135 @@ final class FreeSurface { /// The lowest [count] non-flat modes of [grid]'s Laplacian with the wall's /// condition, orthonormal under the area, and their k². + /// [_lowestModes], solved once for each cross-section there is. + /// + /// **They depend on which cells are inside and on nothing else**: the grid + /// is laid on the same lattice at every height, so a straight-sided glass + /// has the one cross-section all the way up, and every tube on the bench + /// the same one. Solved again each time the level rose half a cell, a + /// tube being poured into worked out its modes every other step, fifty + /// milliseconds each, and that was most of a pour's cost. Read only, so + /// shared between surfaces. + static (List, Float64List) _modesOf(_Grid grid, int count) { + final key = Object.hash( + count, + grid.columns, + grid.rows, + grid.cell, + Object.hashAll(grid.index), + ); + final hits = _solved[key]; + if (hits != null) { + for (final hit in hits) { + if (hit.count == count && + hit.columns == grid.columns && + hit.rows == grid.rows && + hit.cell == grid.cell && + _same(hit.index, grid.index)) { + return hit.modes; + } + } + } + final modes = _lowestModes(grid, count); + if (_solved.length >= 256) _solved.remove(_solved.keys.first); + (_solved[key] ??= []).add(( + count: count, + columns: grid.columns, + rows: grid.rows, + cell: grid.cell, + index: Int32List.fromList(grid.index), + modes: modes, + )); + return modes; + } + + static bool _same(Int32List a, Int32List b) { + if (a.length != b.length) return false; + for (var i = 0; i < a.length; i++) { + if (a[i] != b[i]) return false; + } + return true; + } + + static final Map< + int, + List< + ({ + int count, + int columns, + int rows, + double cell, + Int32List index, + (List, Float64List) modes, + }) + > + > + _solved = {}; + static (List, Float64List) _lowestModes(_Grid grid, int count) { final n = grid.count; final inv = 1.0 / grid.cell2; // The graph Laplacian: each cell against the neighbours it has inside. // A neighbour outside is the wall, and leaving it out is ∂φ/∂n = 0. - Float64List apply(Float64List x) { - final y = Float64List(n); - for (var i = 0; i < n; i++) { - var sum = 0.0; - for (final j in grid.neighbours[i]) { - sum += x[i] - x[j]; + // + // The lowest of L are the highest of L⁻¹, and well apart there, where + // near nought they crowd together and Lanczos on L itself would take + // hundreds of steps to tell them apart. + // + // **L + σ factored once, as a band, and each solve two sweeps along + // it.** The cells are numbered row by row, so a cell's neighbours are + // within a row's worth of it and L is a band that wide. The Lanczos + // steps all solve against the same L; conjugate gradients went at it + // afresh each time, some hundreds of passes over the grid each, and a + // cross-section's modes cost seventy milliseconds where the factor + // costs a few. L is singular, the flat mode being free, so σ, a + // millionth of its scale, makes it definite; the modes are the same and + // their values come out σ higher, which is taken off below. + final sigma = 1e-6 * inv; + var band = 0; + for (var i = 0; i < n; i++) { + for (final k in grid.neighbours[i]) { + band = math.max(band, (i - k).abs()); + } + } + final w1 = band + 1; + // Lower band: L(i, j) at i·w1 + (i − j). + final factor = Float64List(n * w1); + for (var i = 0; i < n; i++) { + factor[i * w1] = grid.neighbours[i].length * inv + sigma; + for (final k in grid.neighbours[i]) { + if (k < i) factor[i * w1 + (i - k)] = -inv; + } + } + for (var i = 0; i < n; i++) { + final lo = math.max(0, i - band); + for (var j = lo; j <= i; j++) { + var sum = factor[i * w1 + (i - j)]; + final from = math.max(lo, j - band); + for (var k = from; k < j; k++) { + sum -= factor[i * w1 + (i - k)] * factor[j * w1 + (j - k)]; } - y[i] = sum * inv; + factor[i * w1 + (i - j)] = i == j + ? math.sqrt(math.max(sum, 1e-300)) + : sum / factor[j * w1]; } - return y; } - - // The lowest of L are the highest of L⁻¹, and well apart there, where - // near nought they crowd together and Lanczos on L itself would take - // hundreds of steps to tell them apart. L⁻¹ is applied by conjugate - // gradients, on the flat-free part where L can be inverted. Float64List solve(Float64List b) { - final x = Float64List(n); - final r = Float64List.fromList(b); - _removeMean(r); - final p = Float64List.fromList(r); - var rr = _dot(r, r); - final stop = 1e-24 * math.max(rr, 1e-300); - for (var it = 0; it < 4 * n && rr > stop; it++) { - final ap = apply(p); - final step = rr / _dot(p, ap); - for (var i = 0; i < n; i++) { - x[i] += step * p[i]; - r[i] -= step * ap[i]; + final x = Float64List.fromList(b); + _removeMean(x); + for (var i = 0; i < n; i++) { + var sum = x[i]; + for (var k = math.max(0, i - band); k < i; k++) { + sum -= factor[i * w1 + (i - k)] * x[k]; } - final next = _dot(r, r); - final ratio = next / rr; - rr = next; - for (var i = 0; i < n; i++) { - p[i] = r[i] + ratio * p[i]; + x[i] = sum / factor[i * w1]; + } + for (var i = n - 1; i >= 0; i--) { + var sum = x[i]; + for (var k = i + 1; k <= math.min(n - 1, i + band); k++) { + sum -= factor[k * w1 + (k - i)] * x[k]; } + x[i] = sum / factor[i * w1]; } _removeMean(x); return x; @@ -541,7 +629,7 @@ final class FreeSurface { final scale = 1.0 / math.sqrt(grid.cell2); for (final r in order) { if (values[r] <= 0.0) continue; - final lambda = 1.0 / values[r]; + final lambda = 1.0 / values[r] - sigma; final shape = Float64List(n); for (var j = 0; j < size; j++) { final weight = vectors[j * size + r]; diff --git a/packages/flutter3d_physics/lib/src/fluid/jet.dart b/packages/flutter3d_physics/lib/src/fluid/jet.dart index 333049012..7cd62a729 100644 --- a/packages/flutter3d_physics/lib/src/fluid/jet.dart +++ b/packages/flutter3d_physics/lib/src/fluid/jet.dart @@ -254,6 +254,15 @@ final class Jet { final section = p.section; final radius = math.sqrt(section / math.pi); var touched = false; + // Its own walls: within what it moves this step and the three radii a + // clinging parcel is looked for by. Every wall near the whole stream, + // asked for every piece of every parcel, cost the tail of a pour a + // third of a frame. + final near = obstaclesNear( + walls, + p.position, + p.velocity.length * dt + 3.0 * radius, + ); // **In pieces no longer than its own radius**, held by the walls after // each. A stream falls five millimetres a step into a test tube whose // glass is half a millimetre: moved in one go, a parcel above the @@ -262,7 +271,7 @@ final class Jet { final pieces = (p.velocity.length * dt / radius).ceil().clamp(1, 16); for (var k = 0; k < pieces; k++) { p.position.addScaled(p.velocity, dt / pieces); - for (final wall in walls) { + for (final wall in near) { final hit = wall.touch(p.position, radius); if (hit == null) continue; p.position.addScaled(hit.normal, hit.depth); @@ -280,7 +289,7 @@ final class Jet { final contact = 0.1 * radius; final reach = 2.0 * radius; var held = false; - for (final wall in walls) { + for (final wall in near) { final near = wall.touch(p.position, radius + contact); if (near != null) { held = true; @@ -288,7 +297,7 @@ final class Jet { } } if (!held && p.velocity.length < clingSpeed(2.0 * radius)) { - for (final wall in walls) { + for (final wall in near) { final hit = wall.touch(p.position, radius + reach); if (hit == null) continue; p.position.addScaled(hit.normal, hit.depth - reach); @@ -319,7 +328,11 @@ final class Jet { final looks = (way.length / radius).ceil().clamp(1, 16); search: for (var k = 1; k <= looks; k++) { - final at = p.previous + way * (k / looks); + // One point moved along, not one made per look. + final at = _look + ..setFrom(way) + ..scale(k / looks) + ..add(p.previous); for (final r in receivers) { if (r.catches(at, radius)) { into = r; @@ -388,6 +401,8 @@ final class Jet { return drops; } + final Vector3 _look = Vector3.zero(); + /// Whether anything left the lip since the last step: the newest parcel /// is held to the lip while it does, and its end is free once it stops. bool _fresh = false; diff --git a/packages/flutter3d_physics/lib/src/fluid/particle_fluid.dart b/packages/flutter3d_physics/lib/src/fluid/particle_fluid.dart index 7836ea8fc..347b86fc9 100644 --- a/packages/flutter3d_physics/lib/src/fluid/particle_fluid.dart +++ b/packages/flutter3d_physics/lib/src/fluid/particle_fluid.dart @@ -1,4 +1,5 @@ import 'dart:math' as math; +import 'dart:typed_data'; import 'package:vector_math/vector_math.dart'; @@ -296,8 +297,24 @@ final class ParticleFluid { } } - void _substep(double dt, _V gravity, List obstacles) { + void _substep(double dt, _V gravity, List all) { final n = _x.length; + // **Each particle's own walls**, found once a substep: those within what + // it moves in one and two spacings more, which the density passes never + // carry it past. Asked of every wall for every particle at every pass, + // the profile of every glass on the bench was walked for drops that had + // scattered across it, and thirty of them took most of a frame. + final g = gravity.length; + final walls = [ + for (var i = 0; i < n; i++) + all.isEmpty + ? all + : obstaclesNear( + all, + _x[i].toVector3(), + (_v[i].length + g * dt) * dt + 2.0 * spacing, + ), + ]; // Where a particle starts inside a wall or under the floor, it is put // out first, its velocity left alone. A drop let go near the bottom of a // glass is laid out as a little block round where it parted, and a @@ -306,7 +323,7 @@ final class ParticleFluid { // over a fifth of a millisecond, and it left at eighteen metres a // second. for (var i = 0; i < n; i++) { - _collide(_x[i], obstacles); + _collide(_x[i], walls[i]); } // **What touches a wall is pinned to it.** A drop's edge on glass or // the bench holds where it is until something pushes harder than the @@ -315,14 +332,19 @@ final class ParticleFluid { // moves only off it, or not at all. Left free along it, three // particles that came down on the bench rolled away over each other as // a wheel does, faster with every turn. - final pinned = [for (var i = 0; i < n; i++) _contact(_x[i], obstacles)]; + final pinned = [for (var i = 0; i < n; i++) _contact(_x[i], walls[i])]; + // **Component by component, into buffers made once a substep.** The + // loops over pairs below run tens of thousands of times a frame; with a + // vector made for each difference, gradient and product, thirty drops + // made hundreds of thousands of objects a frame, and the collector's + // pauses were most of what a pour with drops cost. final rho0 = medium.density; final m = _mass; final norm = 1.0 / _latticeSum; // Forces first: gravity, cohesion and curvature, on the velocities. final grid = _Grid(h, _x); final neighbours = [for (var i = 0; i < n; i++) grid.near(i, _x)]; - final density = List.filled(n, 0.0); + final density = Float64List(n); for (var i = 0; i < n; i++) { var w = _poly6(0.0); for (final j in neighbours[i]) { @@ -330,38 +352,68 @@ final class ParticleFluid { } density[i] = rho0 * w * norm; } - final normal = List<_V>.generate(n, (_) => _V(0, 0, 0)); + final normal = Float64List(3 * n); for (var i = 0; i < n; i++) { + final xi = _x[i]; + var nx = 0.0; + var ny = 0.0; + var nz = 0.0; for (final j in neighbours[i]) { - normal[i].addScaled(_spikyGradient(_x[i] - _x[j]), h * m / density[j]); + final xj = _x[j]; + final dx = xi.x - xj.x; + final dy = xi.y - xj.y; + final dz = xi.z - xj.z; + final f = + _spikyScale(math.sqrt(dx * dx + dy * dy + dz * dz)) * + h * + m / + density[j]; + nx += dx * f; + ny += dy * f; + nz += dz * f; } + normal[3 * i] = nx; + normal[3 * i + 1] = ny; + normal[3 * i + 2] = nz; } for (var i = 0; i < n; i++) { - final a = gravity.copy(); + final xi = _x[i]; + var ax = gravity.x; + var ay = gravity.y; + var az = gravity.z; for (final j in neighbours[i]) { - final d = _x[i] - _x[j]; - final r = d.length; + final xj = _x[j]; + final dx = xi.x - xj.x; + final dy = xi.y - xj.y; + final dz = xi.z - xj.z; + final r = math.sqrt(dx * dx + dy * dy + dz * dz); if (r < 1e-12) continue; final k = 2.0 * rho0 / (density[i] + density[j]); - a - ..addScaled(d, -k * _gamma * m * _cohesion(r) / r) - ..addScaled(normal[i] - normal[j], -k * _gamma); + final c = -k * _gamma * m * _cohesion(r) / r; + final t = -k * _gamma; + ax += dx * c + (normal[3 * i] - normal[3 * j]) * t; + ay += dy * c + (normal[3 * i + 1] - normal[3 * j + 1]) * t; + az += dz * c + (normal[3 * i + 2] - normal[3 * j + 2]) * t; } - _v[i].addScaled(a, dt); + _v[i] + ..x += ax * dt + ..y += ay * dt + ..z += az * dt; } // Predict, then hold the density to the rest density. final p = [ for (var i = 0; i < n; i++) if (pinned[i] case final wall?) - _pin(_advance(_x[i], _v[i], dt, obstacles), _x[i], wall) + _pin(_advance(_x[i], _v[i], dt, walls[i]), _x[i], wall) else - _advance(_x[i], _v[i], dt, obstacles), + _advance(_x[i], _v[i], dt, walls[i]), ]; - final lambda = List.filled(n, 0.0); + final lambda = Float64List(n); final grid2 = _Grid(h, p); final near = [for (var i = 0; i < n; i++) grid2.near(i, p)]; final dq = 0.3 * h; final wq = _poly6(dq * dq); + final delta = Float64List(3 * n); for (var it = 0; it < iterations; it++) { for (var i = 0; i < n; i++) { // C = ρ/ρ₀ − 1 with ρ/ρ₀ the kernel sum over the lattice's: only @@ -369,57 +421,91 @@ final class ParticleFluid { // its neighbours missing is pulled in by half a spacing a pass and // the liquid flies apart; a stretched surface is held by cohesion // instead. + final pi = p[i]; var w = _poly6(0.0); var sum2 = 0.0; - final gi = _V(0, 0, 0); + var gx = 0.0; + var gy = 0.0; + var gz = 0.0; for (final j in near[i]) { - final d = p[i] - p[j]; - w += _poly6(d.length2); - final g = _spikyGradient(d) * norm; - sum2 += g.length2; - gi.add(g); + final pj = p[j]; + final dx = pi.x - pj.x; + final dy = pi.y - pj.y; + final dz = pi.z - pj.z; + final r2 = dx * dx + dy * dy + dz * dz; + w += _poly6(r2); + final f = _spikyScale(math.sqrt(r2)) * norm; + sum2 += r2 * f * f; + gx += dx * f; + gy += dy * f; + gz += dz * f; } - sum2 += gi.length2; + sum2 += gx * gx + gy * gy + gz * gz; final c = math.max(w * norm - 1.0, 0.0); lambda[i] = -c / (sum2 + 1e-6 * norm * norm / (h * h)); } - final delta = List<_V>.generate(n, (_) => _V(0, 0, 0)); + delta.fillRange(0, 3 * n, 0.0); for (var i = 0; i < n; i++) { + final pi = p[i]; for (final j in near[i]) { - final d = p[i] - p[j]; - final ratio = _poly6(d.length2) / wq; + final pj = p[j]; + final dx = pi.x - pj.x; + final dy = pi.y - pj.y; + final dz = pi.z - pj.z; + final r2 = dx * dx + dy * dy + dz * dz; + final ratio = _poly6(r2) / wq; // Macklin's artificial pressure, which keeps neighbours from // clumping: a fiftieth of a constraint's worth. At his tenth it // held still water a sixth thinner than its rest density. final corr = -0.02 * ratio * ratio * ratio * ratio / _restStiffness; // Δpᵢ = Σⱼ (λᵢ + λⱼ + s_corr) ∇W(pᵢ − pⱼ), in the same // normalisation as the constraint. - delta[i].addScaled( - _spikyGradient(d), - (lambda[i] + lambda[j] + corr) * norm, - ); + final f = + _spikyScale(math.sqrt(r2)) * + (lambda[i] + lambda[j] + corr) * + norm; + delta[3 * i] += dx * f; + delta[3 * i + 1] += dy * f; + delta[3 * i + 2] += dz * f; } } for (var i = 0; i < n; i++) { - p[i].add(delta[i]); - _collide(p[i], obstacles); + p[i] + ..x += delta[3 * i] + ..y += delta[3 * i + 1] + ..z += delta[3 * i + 2]; + _collide(p[i], walls[i]); if (pinned[i] case final wall?) _pin(p[i], _x[i], wall); } } // Velocities from the move, then XSPH's viscosity. + final inverse = 1.0 / dt; for (var i = 0; i < n; i++) { - _v[i] = (p[i] - _x[i]) * (1.0 / dt); + _v[i] + ..x = (p[i].x - _x[i].x) * inverse + ..y = (p[i].y - _x[i].y) * inverse + ..z = (p[i].z - _x[i].z) * inverse; } final share = math.min( 0.5, medium.kinematicViscosity * dt / (spacing * spacing) * 50.0 + 0.01, ); - final smoothed = [for (final v in _v) v.copy()]; + final smoothed = Float64List(3 * n); for (var i = 0; i < n; i++) { + final vi = _v[i]; + var sx = vi.x; + var sy = vi.y; + var sz = vi.z; for (final j in near[i]) { - final w = _poly6(p[i].distance2(p[j])) * norm; - smoothed[i].addScaled(_v[j] - _v[i], share * w); + final w = _poly6(p[i].distance2(p[j])) * norm * share; + final vj = _v[j]; + sx += (vj.x - vi.x) * w; + sy += (vj.y - vi.y) * w; + sz += (vj.z - vi.z) * w; } + smoothed[3 * i] = sx; + smoothed[3 * i + 1] = sy; + smoothed[3 * i + 2] = sz; } // A viscous liquid's velocity at a wall at rest is nil along it, and // nothing goes on into it: what touches one keeps only the part of its @@ -429,11 +515,19 @@ final class ParticleFluid { // were inside. final onWall = List.filled(n, false); for (var i = 0; i < n; i++) { - final wall = _contact(p[i], obstacles); + final v = _v[i] + ..x = smoothed[3 * i] + ..y = smoothed[3 * i + 1] + ..z = smoothed[3 * i + 2]; + final wall = _contact(p[i], walls[i]); onWall[i] = wall != null; - _v[i] = wall == null - ? smoothed[i] - : wall * math.max(_dot(smoothed[i], wall), 0.0); + if (wall != null) { + final off = math.max(_dot(v, wall), 0.0); + v + ..x = wall.x * off + ..y = wall.y * off + ..z = wall.z * off; + } _x[i] = p[i]; } _holdSmallDrops(near, onWall, gravity); @@ -553,6 +647,13 @@ final class ParticleFluid { return 315.0 / (64.0 * math.pi * _pow9(h)) * d * d * d; } + /// What a difference d of length [r] is scaled by to be the spiky + /// kernel's gradient: ∇W = d·f(r). + double _spikyScale(double r) { + if (r <= 1e-12 || r >= h) return 0.0; + return -45.0 / (math.pi * _pow6(h)) * (h - r) * (h - r) / r; + } + _V _spikyGradient(_V d) { final r = d.length; if (r <= 1e-12 || r >= h) return _V(0, 0, 0); From bbb4bdd14d89324719b48d510df03992f07257a2 Mon Sep 17 00:00:00 2001 From: Dmitrii Zolotov Date: Sat, 3 Oct 2026 15:29:05 +0300 Subject: [PATCH 16/34] feat: Give the fluid world air: drag, wind and evaporation A FluidWorld now has an Atmosphere, room air by default, its density, viscosity and vapour diffusivity worked out from temperature, pressure and humidity. Drops fall against a sphere's drag at their own size, streams bend in a crosswind, and open liquid evaporates: a tube up Stefan's column and out of its mouth, a puddle by Hu and Larson or a flat plate's boundary layer in a wind, a drop by Ranz and Marshall. Only the solvent leaves, so solutions grow stronger, and the vapour is kept in the world's accounts. Only water has a vapour curve so far. --- ARCHITECTURE.md | 2 +- README.md | 2 +- .../education/chemlab/test/bench_test.dart | 22 ++- .../lib/flutter3d_physics.dart | 1 + .../lib/src/fluid/atmosphere.dart | 166 ++++++++++++++++++ .../lib/src/fluid/fluid_medium.dart | 11 ++ .../lib/src/fluid/fluid_world.dart | 27 ++- .../flutter3d_physics/lib/src/fluid/jet.dart | 25 +++ .../lib/src/fluid/liquid_body.dart | 45 +++++ .../lib/src/fluid/particle_fluid.dart | 111 +++++++++++- .../lib/src/fluid/puddle.dart | 45 +++++ .../test/fluid/atmosphere_test.dart | 144 +++++++++++++++ site/content/core/liquids.md | 10 ++ site/content/quickstart.md | 2 +- site/content/reference/testing.md | 8 +- 15 files changed, 606 insertions(+), 15 deletions(-) create mode 100644 packages/flutter3d_physics/lib/src/fluid/atmosphere.dart create mode 100644 packages/flutter3d_physics/test/fluid/atmosphere_test.dart diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 0411b568a..86b91cf63 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -2691,7 +2691,7 @@ storage. |---|---| | Style | `dart format` | | Analysis | `flutter analyze` clean across the workspace, no warnings | -| Unit tests | **11349 tests** across 43 packages and 10 applications | +| Unit tests | **11355 tests** across 43 packages and 10 applications | | Structure rules | 35, `dart run tool/structure.dart`, the first CI step | | CI | GitHub Actions over `tool/ci.sh`, on `ubuntu-latest`, with no graphics card | diff --git a/README.md b/README.md index f45309053..a1ad6c9ea 100644 --- a/README.md +++ b/README.md @@ -158,7 +158,7 @@ Or one package at a time: (cd packages/flutter3d_physics && dart test) # plain Dart, no Flutter needed ``` -There are 11349 tests across forty-three packages and nine applications. The +There are 11355 tests across forty-three packages and nine applications. The only ones that need a GPU are the Impeller half of the golden set. The other half is rendered by the software backend, which is what makes 90 scenes checkable in a headless run. diff --git a/packages/education/chemlab/test/bench_test.dart b/packages/education/chemlab/test/bench_test.dart index 0ea6896f1..37b63af40 100644 --- a/packages/education/chemlab/test/bench_test.dart +++ b/packages/education/chemlab/test/bench_test.dart @@ -209,7 +209,9 @@ void main() { bench.step(1 / 60); seconds += 1 / 60; expect(seconds, lessThan(30)); - if (from.liquid.volume < before - 1e-12) { + // Pouring, not evaporating: a step's pour is a tenth of a millilitre, + // what evaporates is let go a nanolitre at a time. + if (from.liquid.volume < before - 1e-10) { poured = true; // While it runs, its lip is over the clean tube's mouth. // Its own matrix: it hangs off the root, and the world's is only @@ -231,7 +233,7 @@ void main() { expect(theirs, closeTo(total / 2, total * 0.05)); expect(bench.world.volume, closeTo(everything, everything * 1e-9)); // And the clean tube holds the colour poured into it. - expect(bench.colour(to), bench.colour(from)); + _expectSameColour(bench.colour(to), bench.colour(from)); }); test('two dyes poured together are the colour light through both is', () { @@ -333,8 +335,12 @@ void main() { } expect(tube.tilt, closeTo(lean.clamp(0.0, bench.maxLean(tube)), 1e-3)); } - expect(tube.liquid.volume, closeTo(start, start * 1e-9)); + // None of it ran out: not as a stream, drops or a puddle. Only what + // evaporated in the twenty seconds is gone, a few millionths of it. expect(bench.world.jets, isEmpty); + expect(bench.world.particles.values.fold(0, (s, p) => s + p.count), 0); + expect(bench.world.spills.fold(0.0, (s, p) => s + p.volume), 0.0); + expect(tube.liquid.volume, closeTo(start, start * 1e-5)); }); test('a tube leaned either way is lifted out of the row alike', () { @@ -409,6 +415,14 @@ void main() { bench ..pour(to, 0.5 * (to.lowest + to.highest)) ..step(1 / 60); - expect(bench.colour(to), bench.colour(from)); + _expectSameColour(bench.colour(to), bench.colour(from)); }); } + +/// [a] and [b] the same colour but for the nanolitres of water each lost to +/// the air while the test ran, which leave a solution a hair stronger. +void _expectSameColour(Color a, Color b) { + expect(a.r, closeTo(b.r, 1e-3)); + expect(a.g, closeTo(b.g, 1e-3)); + expect(a.b, closeTo(b.b, 1e-3)); +} diff --git a/packages/flutter3d_physics/lib/flutter3d_physics.dart b/packages/flutter3d_physics/lib/flutter3d_physics.dart index f4a06e3fc..2dcc34151 100644 --- a/packages/flutter3d_physics/lib/flutter3d_physics.dart +++ b/packages/flutter3d_physics/lib/flutter3d_physics.dart @@ -39,6 +39,7 @@ export 'src/collision_shape.dart'; export 'src/collision_world.dart'; export 'src/contact.dart'; export 'src/dynamics.dart'; +export 'src/fluid/atmosphere.dart'; export 'src/fluid/buoyancy.dart'; export 'src/fluid/capillary.dart'; export 'src/fluid/fluid_medium.dart'; diff --git a/packages/flutter3d_physics/lib/src/fluid/atmosphere.dart b/packages/flutter3d_physics/lib/src/fluid/atmosphere.dart new file mode 100644 index 000000000..3b7bf1b28 --- /dev/null +++ b/packages/flutter3d_physics/lib/src/fluid/atmosphere.dart @@ -0,0 +1,166 @@ +import 'dart:math' as math; + +import 'package:vector_math/vector_math.dart'; + +import '../portable_math.dart'; +import 'fluid_medium.dart'; + +/// The air round the liquids: how warm, at what pressure, how damp, and how +/// it moves. What drops and streams fall through and what liquid left open +/// evaporates into. +/// +/// Every property follows from the four it is made with: +/// +/// - **Density**, moist air as an ideal gas: the dry part at 28.96 g/mol, +/// the vapour at 18.02, ρ = (p_d·M_d + p_v·M_v)/RT. +/// - **Viscosity**, Sutherland's law for air: μ = 1.716×10⁻⁵ Pa·s at +/// 273.15 K, as (T/T₀)^1.5·(T₀ + 110.4)/(T + 110.4). +/// - **Vapour diffusivity**, water vapour in air, 2.42×10⁻⁵ m²/s at 20 °C +/// and an atmosphere, as T^1.81/p (Marrero and Mason, 1972). +final class Atmosphere { + Atmosphere({ + this.temperature = 293.15, + this.pressure = 101325.0, + this.humidity = 0.5, + Vector3? wind, + }) : wind = wind ?? Vector3.zero(); + + /// Air at 20 °C and one atmosphere, half saturated, still. + factory Atmosphere.standard() => Atmosphere(); + + /// Kelvin. + final double temperature; + + /// Pascals. + final double pressure; + + /// Relative humidity, nought to one: water vapour against what the air + /// holds saturated at [temperature]. + final double humidity; + + /// Metres per second, everywhere: the air's velocity. + final Vector3 wind; + + static const double _gas = 8.314462618; + static const double _dryMolar = 0.0289644; + static const double _waterMolar = 0.01801528; + + /// The air's velocity at [point]: a vector of the caller's own. + Vector3 windAt(Vector3 point) => wind.clone(); + + /// Partial pressure of water vapour, pascals. + double get vapourPressure => + humidity * VapourCurve.water.saturationPressure(temperature); + + /// Kilograms per cubic metre. + double get density { + final vapour = math.min(vapourPressure, pressure); + return ((pressure - vapour) * _dryMolar + vapour * _waterMolar) / + (_gas * temperature); + } + + /// Dynamic viscosity, pascal seconds. + double get viscosity { + const t0 = 273.15; + const s = 110.4; + return 1.716e-5 * + Portable.pow(temperature / t0, 1.5) * + (t0 + s) / + (temperature + s); + } + + /// How fast vapour spreads through the air, square metres per second. + double get vapourDiffusivity => + 2.42e-5 * + Portable.pow(temperature / 293.15, 1.81) * + (101325.0 / pressure); + + /// The vapour of [medium] the air would take up, kilograms per cubic + /// metre: saturated at the surface less what the air already holds far + /// off. Nought for a liquid that does not evaporate. + double vapourDeficit(FluidMedium medium) { + final curve = medium.vapour; + if (curve == null) return 0.0; + final saturated = curve.saturationDensity(temperature); + // The air's own damp is water's; another vapour is not in it. + final held = curve.isWater ? humidity * saturated : 0.0; + return math.max(saturated - held, 0.0); + } + + /// The drag coefficient of a sphere at Reynolds number [re]: Stokes's + /// 24/Re with Schiller and Naumann's correction (1933), and Newton's + /// 0.44 past a thousand. + static double sphereDrag(double re) { + if (re <= 0.0) return 0.0; + if (re >= 1000.0) return 0.44; + return 24.0 / re * (1.0 + 0.15 * Portable.pow(re, 0.687)); + } + + /// The drag coefficient of a long cylinder crossways to the flow at + /// Reynolds number [re]: White's fit, 1 + 10/Re^(2/3), for 1 to 2×10⁵. + static double cylinderDrag(double re) { + if (re <= 0.0) return 0.0; + return 1.0 + 10.0 / Portable.pow(math.max(re, 1.0), 2.0 / 3.0); + } + + /// The acceleration the air gives a sphere [diameter] across of density + /// [density] moving at [velocity] at [point]: −¾·C_d·ρ_a·|u|·u/(ρ·d), u + /// its velocity through the air. + Vector3 dragOnSphere( + Vector3 velocity, + Vector3 point, + double diameter, + double density, + ) { + final u = velocity - windAt(point); + final speed = u.length; + if (speed <= 0.0 || diameter <= 0.0) return Vector3.zero(); + final re = this.density * speed * diameter / viscosity; + final k = + -0.75 * sphereDrag(re) * this.density * speed / (density * diameter); + return u..scale(k); + } +} + +/// How much vapour a liquid gives off at a temperature: its saturation +/// pressure as the Magnus form p = a·exp(b·t/(c + t)), t in °C, and its +/// molar mass. +final class VapourCurve { + const VapourCurve({ + required this.a, + required this.b, + required this.c, + required this.molarMass, + this.isWater = false, + }); + + /// Water over a flat surface, Alduchov and Eskridge (1996): within a + /// tenth of a percent from −40 to 50 °C. + static const VapourCurve water = VapourCurve( + a: 610.94, + b: 17.625, + c: 243.04, + molarMass: 0.01801528, + isWater: true, + ); + + final double a; + final double b; + final double c; + + /// Kilograms per mole. + final double molarMass; + + /// Whether this is water's vapour, which the air's humidity is. + final bool isWater; + + /// Pascals at [temperature] kelvin. + double saturationPressure(double temperature) { + final t = temperature - 273.15; + return a * Portable.exp(b * t / (c + t)); + } + + /// Kilograms per cubic metre of saturated vapour at [temperature]. + double saturationDensity(double temperature) => + saturationPressure(temperature) * molarMass / (8.314462618 * temperature); +} diff --git a/packages/flutter3d_physics/lib/src/fluid/fluid_medium.dart b/packages/flutter3d_physics/lib/src/fluid/fluid_medium.dart index aa253bb7b..0efc0be4f 100644 --- a/packages/flutter3d_physics/lib/src/fluid/fluid_medium.dart +++ b/packages/flutter3d_physics/lib/src/fluid/fluid_medium.dart @@ -1,5 +1,7 @@ import 'dart:math' as math; +import 'atmosphere.dart'; + /// A liquid, by the properties that decide how it moves: how heavy it is, /// how thick, how strongly its surface pulls, and how it meets a wall. /// @@ -14,6 +16,7 @@ final class FluidMedium { required this.viscosity, required this.surfaceTension, this.contactAngle = 0.0, + this.vapour, }); /// Water: 998 kg/m³, 1.0 mPa·s, 72.8 mN/m, wetting glass at about 20°. @@ -23,6 +26,7 @@ final class FluidMedium { viscosity: 1.002e-3, surfaceTension: 0.0728, contactAngle: 0.35, + vapour: VapourCurve.water, ); /// Glycerol: heavy and fourteen hundred times as viscous as water. @@ -76,6 +80,11 @@ final class FluidMedium { /// nought wets completely, past a quarter turn does not wet. final double contactAngle; + /// How much vapour it gives off, for evaporating into an [Atmosphere]; + /// null for a liquid that is taken not to. Only water has one so far: the + /// others' curves are not here yet, not nought. + final VapourCurve? vapour; + /// Kinematic viscosity, square metres per second: what the damping of /// waves and the thickness of a boundary layer go by, which /// [FreeSurface] reads. @@ -91,12 +100,14 @@ final class FluidMedium { double? viscosity, double? surfaceTension, double? contactAngle, + VapourCurve? vapour, }) => FluidMedium( name: name ?? this.name, density: density ?? this.density, viscosity: viscosity ?? this.viscosity, surfaceTension: surfaceTension ?? this.surfaceTension, contactAngle: contactAngle ?? this.contactAngle, + vapour: vapour ?? this.vapour, ); @override diff --git a/packages/flutter3d_physics/lib/src/fluid/fluid_world.dart b/packages/flutter3d_physics/lib/src/fluid/fluid_world.dart index 8011b25db..0cbb840bb 100644 --- a/packages/flutter3d_physics/lib/src/fluid/fluid_world.dart +++ b/packages/flutter3d_physics/lib/src/fluid/fluid_world.dart @@ -1,6 +1,7 @@ import 'package:vector_math/vector_math.dart'; import '../rigid_body.dart'; +import 'atmosphere.dart'; import 'buoyancy.dart'; import 'jet.dart'; import 'liquid_body.dart'; @@ -26,7 +27,18 @@ final class FluidWorld { this.step = 1.0 / 240.0, this.particleSpacing = 0.002, this.floor, - }); + Atmosphere? atmosphere, + }) : atmosphere = atmosphere ?? Atmosphere.standard(); + + /// The air: what drops and streams fall through and what open liquid + /// evaporates into. Room air by default, as a bench stands in. + final Atmosphere atmosphere; + + /// Cubic metres of liquid gone to vapour, from vessels, puddles and + /// drops: counted, so that every cubic metre poured in is still found. + double get evaporated => + _evaporated + particles.values.fold(0.0, (s, p) => s + p.evaporated); + double _evaporated = 0.0; /// Metres per second squared, shared with whoever else falls. final Vector3 gravity; @@ -65,12 +77,13 @@ final class FluidWorld { ]; /// Every cubic metre the world holds: in vessels, in the air, as - /// particles, in puddles. + /// particles, in puddles, and gone to vapour as the liquid it was. double get volume => bodies.fold(0.0, (s, b) => s + b.volume) + jets.values.fold(0.0, (s, j) => s + j.inFlight) + particles.values.fold(0.0, (s, p) => s + p.volume) + - spills.fold(0.0, (s, p) => s + p.volume); + spills.fold(0.0, (s, p) => s + p.volume) + + evaporated; double _carried = 0.0; int _ran = 0; @@ -141,6 +154,7 @@ final class FluidWorld { gravity: gravity, obstacles: walls, receivers: [...bodies, ...spills], + air: atmosphere, )) { particles .putIfAbsent( @@ -171,8 +185,15 @@ final class FluidWorld { gravity: gravity, obstacles: everywhere, receivers: [...bodies, ...spills], + air: atmosphere, ); } + for (final body in bodies) { + _evaporated += body.evaporate(dt, atmosphere); + } + for (final spill in spills) { + _evaporated += spill.evaporate(dt, atmosphere); + } for (final spill in spills) { spill.step(dt, gravity: gravity); } diff --git a/packages/flutter3d_physics/lib/src/fluid/jet.dart b/packages/flutter3d_physics/lib/src/fluid/jet.dart index 7cd62a729..3a0ced499 100644 --- a/packages/flutter3d_physics/lib/src/fluid/jet.dart +++ b/packages/flutter3d_physics/lib/src/fluid/jet.dart @@ -3,6 +3,7 @@ import 'dart:math' as math; import 'package:vector_math/vector_math.dart'; import '../portable_math.dart'; +import 'atmosphere.dart'; import 'fluid_medium.dart'; /// When something thrown at [velocity] from [height] reaches [floor] under @@ -222,6 +223,7 @@ final class Jet { required Vector3 gravity, List obstacles = const [], List receivers = const [], + Atmosphere? air, }) { final drops = []; _retract(dt); @@ -254,6 +256,29 @@ final class Jet { final section = p.section; final radius = math.sqrt(section / math.pi); var touched = false; + // **The air across it**, as on a long cylinder: what blows across a + // stream bends it, at ½·C_d·ρ_a·u⊥²·d a metre over its ρ·πd²/4, + // White's C_d for a cylinder. Along it the air only rubs, a skin + // friction that over the centimetres of a pour comes to nothing. + if (air != null && !p.onWall && radius > 0.0) { + final speed = p.velocity.length; + final u = p.velocity - air.windAt(p.position); + if (speed > 0.0) { + u.addScaled(p.velocity, -u.dot(p.velocity) / (speed * speed)); + } + final across = u.length; + if (across > 0.0) { + final d = 2.0 * radius; + final re = air.density * across * d / air.viscosity; + final k = + -2.0 * + Atmosphere.cylinderDrag(re) * + air.density * + across / + (math.pi * rho * d); + p.velocity.addScaled(u, k * dt); + } + } // Its own walls: within what it moves this step and the three radii a // clinging parcel is looked for by. Every wall near the whole stream, // asked for every piece of every parcel, cost the tail of a pour a diff --git a/packages/flutter3d_physics/lib/src/fluid/liquid_body.dart b/packages/flutter3d_physics/lib/src/fluid/liquid_body.dart index 5319716e8..db282f98d 100644 --- a/packages/flutter3d_physics/lib/src/fluid/liquid_body.dart +++ b/packages/flutter3d_physics/lib/src/fluid/liquid_body.dart @@ -3,6 +3,7 @@ import 'dart:math' as math; import 'package:vector_math/vector_math.dart'; import '../portable_math.dart'; +import 'atmosphere.dart'; import 'capillary.dart'; import 'fluid_medium.dart'; import 'free_surface.dart'; @@ -368,6 +369,50 @@ final class LiquidBody implements JetReceiver { return spill; } + /// **What evaporates from its open surface in [dt]** into [air], + /// cubic metres of liquid, taken from the top layer's solvent: what is + /// dissolved stays, and grows stronger. + /// + /// Vapour leaves the surface by diffusing up the air standing over it to + /// the mouth, and from the mouth out into the room: Stefan's tube, a + /// column L tall over the surface's area A, then the mouth as a disc of + /// radius r, whose diffusive conductance is 4·D·r. In series, the rate + /// is Δc / (L/(D·A) + 1/(4·D·r)): about three microlitres an hour from + /// a test tube in room air. Applied a nanolitre at a time, about once a + /// second there, a few nanometres off the level; each step would wake a + /// sleeping glass to lower it by a fraction of that. + double evaporate(double dt, Atmosphere air) { + if (_layers.isEmpty) return 0.0; + final top = _layers.last; + final shape = this.shape; + if (shape is! RevolvedVessel) return 0.0; + final deficit = air.vapourDeficit(top.medium); + if (deficit <= 0.0) return 0.0; + final d = air.vapourDiffusivity; + final surfaceRadius = shape.radiusAt(height); + final mouth = shape.radiusAt(shape.top); + if (surfaceRadius <= 0.0 || mouth <= 0.0) return 0.0; + final edge = shape.lip(_up); + final column = math.max((edge?.height ?? shape.top) - height, 0.0); + final area = math.pi * surfaceRadius * surfaceRadius; + final resistance = column / (d * area) + 1.0 / (4.0 * d * mouth); + _evaporating += deficit / resistance / top.medium.density * dt; + if (_evaporating < 1e-12) return 0.0; + final gone = math.min(_evaporating, top.volume); + _evaporating = 0.0; + top.volume -= gone; + if (top.volume <= 0.0) _layers.removeLast(); + if (_asleep) { + // A few nanometres lower and still asleep. + _sleptVolume = volume; + } else { + _relayIfMoved(); + } + return gone; + } + + double _evaporating = 0.0; + bool _asleep = false; double _sleptVolume = double.nan; double _sleptDisplaced = double.nan; diff --git a/packages/flutter3d_physics/lib/src/fluid/particle_fluid.dart b/packages/flutter3d_physics/lib/src/fluid/particle_fluid.dart index 347b86fc9..53145a25d 100644 --- a/packages/flutter3d_physics/lib/src/fluid/particle_fluid.dart +++ b/packages/flutter3d_physics/lib/src/fluid/particle_fluid.dart @@ -3,6 +3,8 @@ import 'dart:typed_data'; import 'package:vector_math/vector_math.dart'; +import '../portable_math.dart'; +import 'atmosphere.dart'; import 'fluid_medium.dart'; import 'jet.dart'; @@ -224,12 +226,13 @@ final class ParticleFluid { } /// Moves the particles on by [dt] under [gravity], against [obstacles], - /// into [receivers]. + /// into [receivers], through [air] when there is any. void step( double dt, { required Vector3 gravity, List obstacles = const [], List receivers = const [], + Atmosphere? air, }) { // **What is less than a particle is let go too**, once no more liquid // comes to make it one: as a particle of its own amount, where the last @@ -276,6 +279,8 @@ final class ParticleFluid { (fastest + gravity.length * dt) * dt + spacing, ); + _air = air; + if (air != null) _measureDrops(dt, air); for (var s = 0; s < count; s++) { _substep(sub, g, walls); } @@ -297,6 +302,96 @@ final class ParticleFluid { } } + /// The air the particles are being stepped through, and each particle's + /// drop's diameter: set at the start of a step, read by its substeps. + Atmosphere? _air; + Float64List _drop = Float64List(0); + + /// Cubic metres evaporated from the drops so far. + double get evaporated => _evaporated; + double _evaporated = 0.0; + + /// **The drops, as drops**: particles nearer each other than a spacing + /// and a half are one, of their summed volume. A drop's drag goes with + /// its own size, d² against a mass of d³; worked out per particle, a + /// drop of thirty would be slowed as thirty drops each a third its size. + /// + /// And what each drop loses to the air in [dt]: a sphere's evaporation, + /// π·d·D·Δc·Sh, with Ranz and Marshall's Sherwood number + /// 2 + 0.6·Re^½·Sc^⅓ for its speed through the air. Taken from its + /// particles by their share, what is dissolved in them left behind. + void _measureDrops(double dt, Atmosphere air) { + final n = _x.length; + final parent = List.generate(n, (i) => i); + int root(int i) { + var r = i; + while (parent[r] != r) { + r = parent[r]; + } + return parent[i] = r; + } + + final grid = _Grid(h, _x); + final touching = 2.25 * spacing * spacing; + for (var i = 0; i < n; i++) { + for (final j in grid.near(i, _x)) { + if (_x[i].distance2(_x[j]) < touching) parent[root(i)] = root(j); + } + } + final volume = {}; + final speed = {}; + for (var i = 0; i < n; i++) { + final r = root(i); + volume[r] = (volume[r] ?? 0.0) + _vol[i]; + (speed[r] ??= _V(0, 0, 0)).addScaled(_v[i], _vol[i]); + } + _drop = Float64List(n); + final deficit = air.vapourDeficit(medium); + final d = air.vapourDiffusivity; + final sc = air.viscosity / (air.density * d); + final lost = {}; + for (final MapEntry(key: r, value: v) in volume.entries) { + final diameter = Portable.pow(6.0 * v / math.pi, 1.0 / 3.0); + if (deficit > 0.0) { + final u = speed[r]! * (1.0 / v); + final wind = air.windAt(Vector3.zero()); + final through = _V(u.x - wind.x, u.y - wind.y, u.z - wind.z).length; + final re = air.density * through * diameter / air.viscosity; + final sherwood = + 2.0 + 0.6 * math.sqrt(re) * Portable.pow(sc, 1.0 / 3.0); + final rate = math.pi * diameter * d * deficit * sherwood; + lost[r] = math.min(rate / medium.density * dt, v) / v; + } + volume[r] = diameter; + } + for (var i = 0; i < n; i++) { + final r = root(i); + _drop[i] = volume[r]!; + final share = lost[r]; + if (share != null && share > 0.0) { + final gone = _vol[i] * share; + _evaporated += gone; + // What is dissolved stays: the same amount in less liquid. + final kept = _vol[i] - gone; + if (kept > 0.0) { + _c[i] = { + for (final e in _c[i].entries) e.key: e.value * _vol[i] / kept, + }; + } + _vol[i] = kept; + } + } + // A drop dried away is gone. + for (var i = n - 1; i >= 0; i--) { + if (_vol[i] > 0.0) continue; + _x.removeAt(i); + _v.removeAt(i); + _vol.removeAt(i); + _c.removeAt(i); + } + if (_x.length != n) _drop = Float64List(0); + } + void _substep(double dt, _V gravity, List all) { final n = _x.length; // **Each particle's own walls**, found once a substep: those within what @@ -395,6 +490,20 @@ final class ParticleFluid { ay += dy * c + (normal[3 * i + 1] - normal[3 * j + 1]) * t; az += dz * c + (normal[3 * i + 2] - normal[3 * j + 2]) * t; } + // The air, on the drop it is in: its drag over the drop's mass, + // which every particle of it feels alike. + final air = _air; + if (air != null && i < _drop.length && _drop[i] > 0.0) { + final drag = air.dragOnSphere( + _v[i].toVector3(), + xi.toVector3(), + _drop[i], + rho0, + ); + ax += drag.x; + ay += drag.y; + az += drag.z; + } _v[i] ..x += ax * dt ..y += ay * dt diff --git a/packages/flutter3d_physics/lib/src/fluid/puddle.dart b/packages/flutter3d_physics/lib/src/fluid/puddle.dart index 7a6f576af..730f3a15c 100644 --- a/packages/flutter3d_physics/lib/src/fluid/puddle.dart +++ b/packages/flutter3d_physics/lib/src/fluid/puddle.dart @@ -3,6 +3,7 @@ import 'dart:math' as math; import 'package:vector_math/vector_math.dart'; import '../portable_math.dart'; +import 'atmosphere.dart'; import 'fluid_medium.dart'; import 'jet.dart'; import 'particle_fluid.dart'; @@ -72,6 +73,39 @@ final class Puddle { age = math.max(age, other.age); } + /// **What evaporates from it in [dt]** into [air], cubic metres, taken + /// from its solvent: what is dissolved stays behind in less liquid. + /// + /// In still air vapour diffuses away from a sessile drop at + /// π·R·D·Δc·(0.27θ² + 1.30) kilograms a second, R its radius and θ its + /// contact angle (Hu and Larson, 2002); at θ → 0 that is the flat disc's + /// 4·R·D·Δc. In a wind the vapour is carried off over it as from a flat + /// plate 2R long: a laminar boundary layer's mean Sherwood number + /// 0.664·Re^½·Sc^⅓. Whichever takes it faster does. + double evaporate(double dt, Atmosphere air, double g) { + if (_volume <= 0.0) return 0.0; + final deficit = air.vapourDeficit(medium); + if (deficit <= 0.0) return 0.0; + final r = radius(g); + if (r <= 0.0) return 0.0; + final d = air.vapourDiffusivity; + final theta = medium.contactAngle.clamp(0.0, math.pi / 2); + final still = math.pi * r * d * deficit * (0.27 * theta * theta + 1.30); + final across = air.windAt(centre) + ..addScaled(normal, -air.windAt(centre).dot(normal)); + final length = 2.0 * r; + final re = air.density * across.length * length / air.viscosity; + final sc = air.viscosity / (air.density * d); + final sherwood = 0.664 * math.sqrt(re) * Portable.pow(sc, 1.0 / 3.0); + final carried = sherwood * d / length * deficit * math.pi * r * r; + final gone = math.min( + math.max(still, carried) / medium.density * dt, + _volume, + ); + _volume -= gone; + return gone; + } + /// How far it reaches across the surface, metres. double radius(double g) { if (_volume <= 0.0) return 0.0; @@ -192,6 +226,17 @@ final class PuddleSurface implements JetReceiver { _join(); } + /// What evaporates from every puddle in [dt] into [air], cubic metres; + /// a puddle dried out is gone. + double evaporate(double dt, Atmosphere air) { + var gone = 0.0; + for (final p in puddles) { + gone += p.evaporate(dt, air, _g); + } + puddles.removeWhere((p) => p.volume <= 0.0); + return gone; + } + /// Spreads every puddle on by [dt] under [gravity], and runs together /// those that meet. void step(double dt, {required Vector3 gravity}) { diff --git a/packages/flutter3d_physics/test/fluid/atmosphere_test.dart b/packages/flutter3d_physics/test/fluid/atmosphere_test.dart new file mode 100644 index 000000000..1de215c07 --- /dev/null +++ b/packages/flutter3d_physics/test/fluid/atmosphere_test.dart @@ -0,0 +1,144 @@ +import 'dart:math' as math; + +import 'package:flutter3d_physics/flutter3d_physics.dart'; +import 'package:test/test.dart'; +import 'package:vector_math/vector_math.dart'; + +void main() { + test('room air is what the tables say', () { + // Dry air at 20 °C and an atmosphere: 1.204 kg/m³ and 18.1 µPa·s; + // water's saturation pressure there, 2339 Pa. + final dry = Atmosphere(humidity: 0.0); + expect(dry.density, closeTo(1.204, 1.204 * 0.005)); + expect(dry.viscosity, closeTo(1.81e-5, 1.81e-5 * 0.01)); + expect( + VapourCurve.water.saturationPressure(293.15), + closeTo(2339.0, 2339.0 * 0.005), + ); + // Damp air is lighter: water vapour is lighter than the air it + // displaces. + expect(Atmosphere(humidity: 1.0).density, lessThan(dry.density)); + }); + + test('a millimetre drop falls at the speed Gunn and Kinzer measured', () { + // 4.03 m/s for a drop a millimetre across (Gunn and Kinzer, 1949). + // Mutation: leave the air out, and it is still gathering speed at + // thirty metres a second. + const d = 0.001; + // One particle holding a millimetre drop's volume. + final spacing = math.pow(math.pi / 6.0, 1.0 / 3.0) * d; + final fluid = ParticleFluid(medium: FluidMedium.water, spacing: spacing) + ..inject(math.pi / 6.0 * d * d * d, Vector3(0, 100, 0), Vector3.zero()); + final air = Atmosphere(); + final before = fluid.positions.single.y; + for (var i = 0; i < 240 * 3; i++) { + fluid.step(1 / 240, gravity: Vector3(0, -9.81, 0), air: air); + } + final y0 = fluid.positions.single.y; + fluid.step(1 / 240, gravity: Vector3(0, -9.81, 0), air: air); + final speed = (y0 - fluid.positions.single.y) * 240; + expect(before, greaterThan(y0)); + // Schiller and Naumann's is a rigid sphere's drag, and gives 3.83: a + // drop's inside circulates and it falls a little faster than a ball, + // which this does not model. Within six percent of the measurement. + expect(speed, closeTo(4.03, 4.03 * 0.06)); + }); + + test('a wind across a stream carries it downwind', () { + Vector3 lowest(Atmosphere? air) { + final jet = Jet(medium: FluidMedium.water, breakupGrowth: 1e9); + for (var k = 0; k < 200; k++) { + jet.emit( + flow: 1e-6, + dt: 1 / 1000, + point: Vector3(0, 1, 0), + velocity: Vector3(0, -0.1, 0), + width: 0.002, + across: Vector3(0, 0, 1), + ); + jet.step(1 / 1000, gravity: Vector3(0, -9.81, 0), air: air); + } + return jet.runs.single.last.position; + } + + // Mutation: drop the drag, and the stream falls straight. + expect(lowest(null).x, closeTo(0.0, 1e-12)); + final blown = lowest(Atmosphere(wind: Vector3(3, 0, 0))); + expect(blown.x, greaterThan(1e-4)); + }); + + test('a puddle evaporates, leaves what was in it, and is counted', () { + final world = FluidWorld( + gravity: Vector3(0, -9.81, 0), + floor: [PlaneObstacle(normal: Vector3(0, 1, 0), offset: 0)], + atmosphere: Atmosphere(humidity: 0.3), + ); + final bench = world.spills.single + ..receive( + 1e-7, + Vector3(0, 0.001, 0), + Vector3.zero(), + FluidMedium.water, + const {'salt': 2.0}, + ); + final total = world.volume; + final puddle = bench.puddles.single; + for (var i = 0; i < 240 * 60; i++) { + world.advance(world.step); + } + // A minute in drier air takes some of it. + expect(world.evaporated, greaterThan(0.0)); + expect(puddle.volume, lessThan(1e-7)); + // The salt stayed: the same amount in less water. + expect( + puddle.concentrations['salt']! * puddle.volume, + closeTo(2.0 * 1e-7, 1e-15), + ); + // Mutation: lose the vapour from the count, and the world is short. + expect(world.volume, closeTo(total, total * 1e-9)); + }); + + test('flat, a puddle evaporates as a disc does, 4·R·D·Δc', () { + final air = Atmosphere(humidity: 0.5); + final flat = FluidMedium.water.copyWith(contactAngle: 0.0); + final puddle = Puddle( + medium: flat, + centre: Vector3.zero(), + normal: Vector3(0, 1, 0), + )..add(1e-6, Vector3.zero(), const {}); + final r = puddle.radius(9.81); + final gone = puddle.evaporate(1.0, air, 9.81); + final disc = + 4.0 * + r * + air.vapourDiffusivity * + air.vapourDeficit(flat) / + flat.density; + expect(gone, closeTo(disc, disc * 0.03)); + }); + + test('a tube evaporates up the air over its liquid and out of its mouth', () { + // Stefan's tube: L/(D·A) for the column to the mouth, then 1/(4·D·r) + // from the mouth out, in series. An hour, in one go. + const r = 0.008; + final tube = LiquidBody( + shape: RevolvedVessel([Vector2(0, 0), Vector2(r, 0), Vector2(r, 0.1)]), + medium: FluidMedium.water, + volume: math.pi * r * r * 0.06, + modes: 2, + )..place(Matrix3.identity(), Vector3.zero()); + tube.pour(0.0, concentrations: const {}); + final air = Atmosphere(humidity: 0.5); + final before = tube.volume; + final gone = tube.evaporate(3600.0, air); + final d = air.vapourDiffusivity; + final column = 0.1 - tube.height; + final rate = + air.vapourDeficit(FluidMedium.water) / + (column / (d * math.pi * r * r) + 1.0 / (4.0 * d * r)); + expect(gone, closeTo(rate * 3600.0 / 998.2, rate * 3600.0 / 998.2 * 0.01)); + expect(tube.volume, closeTo(before - gone, 1e-18)); + // About three microlitres an hour: why an open tube on a bench keeps. + expect(gone, inInclusiveRange(1e-9, 1e-8)); + }); +} diff --git a/site/content/core/liquids.md b/site/content/core/liquids.md index 1928074a1..e80841176 100644 --- a/site/content/core/liquids.md +++ b/site/content/core/liquids.md @@ -71,6 +71,16 @@ A drop is stopped by the wall it touches: a viscous liquid has no velocity along What reaches a floor given to the world becomes a `Puddle` on its `PuddleSurface`, one body with a volume and what is dissolved in it, not particles. A spread puddle is 2ℓc·sin(θ/2) deep, under a millimetre for water on glass; a smaller one is a spherical cap meeting the surface at the contact angle. It spreads there as a viscous gravity current, R ∝ (ρgV³/μ)^⅛·t^⅛ (Huppert), which water finishes in milliseconds. Puddles that meet run together. Draw them with `capMesh(...)`. +## Air + +A `FluidWorld` has an `Atmosphere`: temperature, pressure, humidity and wind, room air unless told otherwise. Its density is moist air's as an ideal gas, its viscosity Sutherland's, and water vapour diffuses through it at Marrero and Mason's rate. + +- A drop falls against Schiller and Naumann's drag on a sphere of the drop's own size, so a millimetre drop settles at 3.8 m/s. Gunn and Kinzer measured 4.03: a drop's inside circulates, and a rigid sphere's drag does not know that. +- A stream bends in a crosswind, with White's drag on a cylinder across it. +- Open liquid evaporates. A tube does so up the air standing over its liquid and out of its mouth, Stefan's tube, about three microlitres an hour. A puddle follows Hu and Larson in still air and a flat plate's boundary layer in a wind, and a drop follows Ranz and Marshall. Only the solvent leaves, so what is dissolved grows stronger, and `FluidWorld.evaporated` keeps the vapour in the accounts. + +Only water has a vapour curve so far; the other media do not evaporate yet. + ## Capillarity `TubeMeniscus` solves the Young–Laplace equation for a tube's radius and the liquid's contact angle by shooting, so a narrow tube's meniscus is the right curve, not a fillet. `jurinHeight` is the rise in a thin tube, and the tests check one against the other. A `LiquidBody` lifts its drawn surface by the meniscus and adds the capillary pressure where it matters, in pipes. diff --git a/site/content/quickstart.md b/site/content/quickstart.md index 5217d9aa5..c66c7f4be 100644 --- a/site/content/quickstart.md +++ b/site/content/quickstart.md @@ -91,7 +91,7 @@ tool/ci.sh # shaders, analyze, every test (cd packages/flutter3d_physics && dart test) # plain Dart, no Flutter needed ``` -There are 11349 tests across 43 packages and twelve applications, and only about thirty need a GPU: the Impeller half of the golden set. The other half renders through the software backend, so ninety scenes stay checkable in a headless run. +There are 11355 tests across 43 packages and twelve applications, and only about thirty need a GPU: the Impeller half of the golden set. The other half renders through the software backend, so ninety scenes stay checkable in a headless run. ## Your own application diff --git a/site/content/reference/testing.md b/site/content/reference/testing.md index e11561873..6dca74c2e 100644 --- a/site/content/reference/testing.md +++ b/site/content/reference/testing.md @@ -1,10 +1,10 @@ --- -description: Four independent golden sets, mutation-checking every new test, determinism and snapshots, and why only about thirty of 11349 tests need a GPU. +description: Four independent golden sets, mutation-checking every new test, determinism and snapshots, and why only about thirty of 11355 tests need a GPU. --- # Testing -11349 tests across 43 packages and nine applications, counted the same way the `the document says how many tests there are` rule does: a scan of every `test(`/`testWidgets(` call. The rule holds `ARCHITECTURE.md` §13, the README and this page to the answer. The README went on saying 1242 across thirteen packages for as long as nothing compared it with anything. About thirty need a GPU; the [architecture](/core/architecture/) is what keeps the number that low. +11355 tests across 43 packages and nine applications, counted the same way the `the document says how many tests there are` rule does: a scan of every `test(`/`testWidgets(` call. The rule holds `ARCHITECTURE.md` §13, the README and this page to the answer. The README went on saying 1242 across thirteen packages for as long as nothing compared it with anything. About thirty need a GPU; the [architecture](/core/architecture/) is what keeps the number that low. | Package | Tests | | Package | Tests | |---|---|---|---|---| @@ -23,7 +23,7 @@ description: Four independent golden sets, mutation-checking every new test, det | `flutter3d_cpu` | 380 | | `apps/flutter3d_demo_strategy` | 50 | | `apps/flutter3d_editor` | 234 | | `apps/flutter3d_demo_arcade` | 20 | | `apps/flutter3d_demo_racing` | 162 | | `pointer_lock` | 28 | -| `flutter3d_physics` | 276 | | `flutter3d_webgpu` | 193 | +| `flutter3d_physics` | 282 | | `flutter3d_webgpu` | 193 | | `flutter3d_game_strategy` | 133 | | `flutter3d_editor_mcp` | 36 | | `apps/flutter3d_demo_river` | 54 | | `flutter3d_testing` | 45 | | `flutter3d_editor_core` | 141 | | `flutter3d_editor_widgets` | 91 | @@ -40,7 +40,7 @@ description: Four independent golden sets, mutation-checking every new test, det | `flame_flutter3d` | 140 | | `apps/flutter3d_showcase` | 88 | | `flame_multiplayer` | 9 | | `flame_multiplayer_dashwire` | 3 | -The rows sum to 11322 rather than 11349: the remaining 26 live in `packages/*/example/test`, which the count includes and this table does not, among them the two seeds a new project starts from, `packages/flutter3d_app/example` and `packages/flutter3d_game/example`. +The rows sum to 11328 rather than 11355: the remaining 26 live in `packages/*/example/test`, which the count includes and this table does not, among them the two seeds a new project starts from, `packages/flutter3d_app/example` and `packages/flutter3d_game/example`. `flutter3d_samples` is not in the table and has no `test/` at all: it is test data with two path constants over it, and other packages' decoder tests are what exercise it. `flutter3d_conformance` is missing for a different reason: it is invoked as a script harness rather than through `flutter test`, so it does not surface in a grep of `test(` calls either. See below for what that cost once. From cd3159066a3664b254675950c456e4138aafc204 Mon Sep 17 00:00:00 2001 From: Dmitrii Zolotov Date: Sat, 3 Oct 2026 15:33:07 +0300 Subject: [PATCH 17/34] feat: Let the Reynolds number choose laminar or turbulent flow Pipes between vessels now lose to Darcy friction: 64/Re laminar, Haaland's form of Colebrook turbulent for the bore's roughness, and a straight line through the transition. A stream leaving a lip above a Reynolds number of 2300 parts at Grant and Middleman's turbulent intact length rather than its laminar one. --- ARCHITECTURE.md | 2 +- README.md | 2 +- .../flutter3d_physics/lib/src/fluid/jet.dart | 28 +++++++- .../flutter3d_physics/lib/src/fluid/pipe.dart | 64 ++++++++++++++++--- .../test/fluid/regime_test.dart | 59 +++++++++++++++++ site/content/core/liquids.md | 8 +++ site/content/quickstart.md | 2 +- site/content/reference/testing.md | 8 +-- 8 files changed, 157 insertions(+), 16 deletions(-) create mode 100644 packages/flutter3d_physics/test/fluid/regime_test.dart diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 86b91cf63..7f9050cd4 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -2691,7 +2691,7 @@ storage. |---|---| | Style | `dart format` | | Analysis | `flutter analyze` clean across the workspace, no warnings | -| Unit tests | **11355 tests** across 43 packages and 10 applications | +| Unit tests | **11357 tests** across 43 packages and 10 applications | | Structure rules | 35, `dart run tool/structure.dart`, the first CI step | | CI | GitHub Actions over `tool/ci.sh`, on `ubuntu-latest`, with no graphics card | diff --git a/README.md b/README.md index a1ad6c9ea..200d427f6 100644 --- a/README.md +++ b/README.md @@ -158,7 +158,7 @@ Or one package at a time: (cd packages/flutter3d_physics && dart test) # plain Dart, no Flutter needed ``` -There are 11355 tests across forty-three packages and nine applications. The +There are 11357 tests across forty-three packages and nine applications. The only ones that need a GPU are the Impeller half of the golden set. The other half is rendered by the software backend, which is what makes 90 scenes checkable in a headless run. diff --git a/packages/flutter3d_physics/lib/src/fluid/jet.dart b/packages/flutter3d_physics/lib/src/fluid/jet.dart index 3a0ced499..e1d09f60e 100644 --- a/packages/flutter3d_physics/lib/src/fluid/jet.dart +++ b/packages/flutter3d_physics/lib/src/fluid/jet.dart @@ -201,8 +201,26 @@ final class Jet { _fresh = true; final speed = math.max(velocity.length, 1e-6); final w = math.max(width, 1e-6); + // **Laminar or turbulent, from how it leaves.** Under a Reynolds number + // of 2300 the stream is smooth, and parts where its own ripples have + // grown e¹² times, as [breakupGrowth] counts. Past 4000 it leaves the + // lip already disturbed, and parts sooner, at L/D = 8.51·We^0.32 + // (Grant and Middleman, 1966, for turbulent jets). Between the two the + // length runs from one correlation to the other with Re. + final m = medium ?? this.medium; + final d = 2.0 * math.sqrt(flow / (speed * math.pi)); + final re = m.density * speed * d / m.viscosity; + var intact = double.infinity; + if (re > 2300.0 && m.surfaceTension > 0.0) { + final we = m.density * speed * speed * d / m.surfaceTension; + final laminar = 12.0 * d * (math.sqrt(we) + 3.0 * we / re); + final turbulent = 8.51 * d * Portable.pow(we, 0.32); + final t = ((re - 2300.0) / 1700.0).clamp(0.0, 1.0); + intact = laminar + t * (turbulent - laminar); + } _parcels.add( _Parcel( + intact: intact, position: point.clone(), velocity: velocity.clone(), volume: volume, @@ -253,6 +271,7 @@ final class Jet { p.velocity.addScaled(gravity, dt); p.previous.setFrom(p.position); p.age += dt; + p.travelled += p.velocity.length * dt; final section = p.section; final radius = math.sqrt(section / math.pi); var touched = false; @@ -400,7 +419,7 @@ final class Jet { continue; } // A rivulet on a wall does not part: the wall holds it. - if (!p.onWall && p.growth >= breakupGrowth) { + if (!p.onWall && (p.growth >= breakupGrowth || p.travelled >= p.intact)) { // Drops of 1.89 diameters, as many as its volume makes. final d = 2.0 * math.sqrt(p.section / math.pi) * 1.89; final one = math.pi * d * d * d / 6.0; @@ -542,6 +561,7 @@ final class Jet { final class _Parcel { _Parcel({ + required this.intact, required this.position, required this.velocity, required this.volume, @@ -573,6 +593,12 @@ final class _Parcel { double age = 0.0; double growth = 0.0; + + /// How far it has come from the lip, and how far a stream that left as + /// it did goes before it parts: infinite for a laminar one, which parts + /// by [growth] instead. + double travelled = 0.0; + final double intact; bool onWall = false; /// Where it was at the start of the step. diff --git a/packages/flutter3d_physics/lib/src/fluid/pipe.dart b/packages/flutter3d_physics/lib/src/fluid/pipe.dart index 5740038fa..27b73f1f9 100644 --- a/packages/flutter3d_physics/lib/src/fluid/pipe.dart +++ b/packages/flutter3d_physics/lib/src/fluid/pipe.dart @@ -2,6 +2,7 @@ import 'dart:math' as math; import 'package:vector_math/vector_math.dart'; +import '../portable_math.dart'; import 'liquid_body.dart'; /// A round pipe joining two vessels below their surfaces: communicating @@ -10,9 +11,10 @@ import 'liquid_body.dart'; /// **The liquid in it has mass**, so it is not pushed through at once but /// accelerated: the pressure difference between its ends drives the column /// — the pipe's own length over its section, and the liquid standing in each -/// vessel above it over the vessel's — and friction holds it back, linearly -/// for a slow viscous flow (Hagen–Poiseuille, 8μL/πr⁴) and as the square of -/// the flow for the losses where it enters and leaves (K·ρQ|Q|/2a²). Two +/// vessel above it over the vessel's — and friction holds it back: along +/// the pipe as Darcy's f·(L/D)·ρv²/2, f the [frictionFactor] at the flow's +/// Reynolds number, laminar or turbulent, and as the square of the flow for +/// the losses where it enters and leaves (K·ρQ|Q|/2a²). Two /// vessels joined this way swing about a common level before they settle on /// it — a U-tube's period 2π√(l/2g) for a column l long — and a thick liquid /// creeps to it without swinging. @@ -31,6 +33,7 @@ final class Pipe { required this.radius, required this.length, this.minorLoss = 1.5, + this.roughness = 1.5e-6, }); /// The two vessels, and where the pipe opens into each (vessel frame). @@ -47,9 +50,45 @@ final class Pipe { /// and 1 out for sharp ends. final double minorLoss; + /// The height of the bumps on the bore, metres: 1.5 µm, drawn glass and + /// plastic tubing. What turbulent friction feels; a laminar flow does not. + final double roughness; + /// Cubic metres a second from [from] to [to]; negative the other way. double flow = 0.0; + /// The flow's Reynolds number, ρ·v·D/μ: under 2300 laminar, over 4000 + /// turbulent. + double get reynolds { + final medium = from.medium; + final v = flow.abs() / (math.pi * radius * radius); + return medium.density * v * 2.0 * radius / medium.viscosity; + } + + /// Darcy's friction factor at Reynolds number [re] in a bore of + /// [relativeRoughness] ε/D. + /// + /// Laminar, Hagen and Poiseuille's 64/Re, exact. Turbulent, Haaland's + /// explicit form of Colebrook's, 1/√f = −1.8·log₁₀((ε/D/3.7)^1.11 + + /// 6.9/Re), within a couple of percent of it. Between 2300 and 4000 the + /// flow is neither, and goes from one to the other with Re: no law + /// holds there, and a straight line between the two does not pretend to + /// one. + static double frictionFactor(double re, {double relativeRoughness = 0.0}) { + if (re <= 0.0) return double.infinity; + double turbulent(double re) { + final x = Portable.pow(relativeRoughness / 3.7, 1.11) + 6.9 / re; + final inverse = -1.8 * Portable.log(x) / math.ln10; + return 1.0 / (inverse * inverse); + } + + final laminar = 64.0 / re; + if (re <= 2300.0) return laminar; + if (re >= 4000.0) return turbulent(re); + final t = (re - 2300.0) / 1700.0; + return (1.0 - t) * laminar + t * turbulent(re); + } + /// Moves the liquid in the pipe on by [dt] under [gravity]. void step(double dt, {required Vector3 gravity}) { final medium = from.medium; @@ -72,11 +111,20 @@ final class Pipe { (length / a + math.max(head0, 0.0) / math.max(from.surface.area, a) + math.max(head1, 0.0) / math.max(to.surface.area, a)); - final viscous = - 8.0 * - medium.viscosity * - length / - (math.pi * (radius * radius * radius * radius)); + // Darcy's loss as a resistance, Δp/Q = f·L·ρ·|Q|/(2·D·a²); laminar it + // is Poiseuille's 8μL/πr⁴, whatever the flow, and that is what it is + // at no flow at all. + final re = reynolds; + final viscous = re < 1.0 + ? 8.0 * + medium.viscosity * + length / + (math.pi * (radius * radius * radius * radius)) + : frictionFactor(re, relativeRoughness: roughness / (2.0 * radius)) * + length * + rho * + flow.abs() / + (2.0 * 2.0 * radius * a * a); final quadratic = minorLoss * rho * flow.abs() / (2.0 * a * a); // Friction taken implicitly, so a thick liquid in a thin pipe is stable // at any step. diff --git a/packages/flutter3d_physics/test/fluid/regime_test.dart b/packages/flutter3d_physics/test/fluid/regime_test.dart new file mode 100644 index 000000000..42a1629a0 --- /dev/null +++ b/packages/flutter3d_physics/test/fluid/regime_test.dart @@ -0,0 +1,59 @@ +import 'dart:math' as math; + +import 'package:flutter3d_physics/flutter3d_physics.dart'; +import 'package:test/test.dart'; +import 'package:vector_math/vector_math.dart'; + +void main() { + test('a pipe rubs as Poiseuille laminar and as Blasius turbulent', () { + // Laminar, exactly 64/Re. + expect(Pipe.frictionFactor(1000.0), closeTo(0.064, 1e-12)); + // Smooth and turbulent, Blasius's 0.316·Re^−¼ to a few percent at a + // hundred thousand, where it holds. + final blasius = 0.316 * math.pow(1e5, -0.25); + expect(Pipe.frictionFactor(1e5), closeTo(blasius, blasius * 0.03)); + // A rough bore rubs harder, once the flow is turbulent; laminar, it + // does not care. + expect( + Pipe.frictionFactor(1e5, relativeRoughness: 0.01), + greaterThan(1.5 * Pipe.frictionFactor(1e5)), + ); + expect( + Pipe.frictionFactor(1000.0, relativeRoughness: 0.01), + Pipe.frictionFactor(1000.0), + ); + // Through the transition it climbs from one to the other, without a + // jump at either end. + expect(Pipe.frictionFactor(2300.0), closeTo(64.0 / 2300.0, 1e-12)); + expect(Pipe.frictionFactor(2300.0 + 1e-6), closeTo(64.0 / 2300.0, 1e-6)); + }); + + test('a turbulent stream parts at L/D = 8.51·We^0.32', () { + // Five millimetres at two metres a second: Re 10 000, We 275. Laminar + // it would hold for a metre; turbulent, for a quarter of one (Grant + // and Middleman). Mutation: let it part only by its ripples, and it + // flies a metre whole. + const d = 0.005; + const v = 2.0; + final q = v * math.pi * d * d / 4.0; + final jet = Jet(medium: FluidMedium.water); + final water = FluidMedium.water; + final we = water.density * v * v * d / water.surfaceTension; + final expected = 8.51 * d * math.pow(we, 0.32); + double? first; + for (var k = 0; k < 400 && first == null; k++) { + jet.emit( + flow: q, + dt: 1 / 1000, + point: Vector3.zero(), + velocity: Vector3(v, 0, 0), + width: d, + across: Vector3(0, 0, 1), + ); + final drops = jet.step(1 / 1000, gravity: Vector3.zero()); + if (drops.isNotEmpty) first = drops.first.position.x; + } + expect(first, isNotNull); + expect(first, closeTo(expected, expected * 0.05)); + }); +} diff --git a/site/content/core/liquids.md b/site/content/core/liquids.md index e80841176..4a3830c6e 100644 --- a/site/content/core/liquids.md +++ b/site/content/core/liquids.md @@ -71,6 +71,14 @@ A drop is stopped by the wall it touches: a viscous liquid has no velocity along What reaches a floor given to the world becomes a `Puddle` on its `PuddleSurface`, one body with a volume and what is dissolved in it, not particles. A spread puddle is 2ℓc·sin(θ/2) deep, under a millimetre for water on glass; a smaller one is a spherical cap meeting the surface at the contact angle. It spreads there as a viscous gravity current, R ∝ (ρgV³/μ)^⅛·t^⅛ (Huppert), which water finishes in milliseconds. Puddles that meet run together. Draw them with `capMesh(...)`. +## Laminar and turbulent + +Where it matters, the Reynolds number decides the law. + +- In a `Pipe`, friction is Darcy's, with 64/Re under 2300 and Haaland's form of Colebrook over 4000, for the bore's `roughness`. In between the flow is neither, and the factor goes from one to the other along a straight line, which claims no law it does not have. `Pipe.reynolds` says where a flow is. +- A stream that leaves the lip under 2300 is smooth and parts by its own ripples. Past 4000 it leaves already disturbed and parts at Grant and Middleman's turbulent L/D = 8.51·We^0.32, a quarter of the laminar length for a brisk five-millimetre stream. A pour from a test tube is usually in between. +- Waves in a vessel are damped in the laminar boundary layer at the wall, which is what they have at a bench's sizes. + ## Air A `FluidWorld` has an `Atmosphere`: temperature, pressure, humidity and wind, room air unless told otherwise. Its density is moist air's as an ideal gas, its viscosity Sutherland's, and water vapour diffuses through it at Marrero and Mason's rate. diff --git a/site/content/quickstart.md b/site/content/quickstart.md index c66c7f4be..48af5c35d 100644 --- a/site/content/quickstart.md +++ b/site/content/quickstart.md @@ -91,7 +91,7 @@ tool/ci.sh # shaders, analyze, every test (cd packages/flutter3d_physics && dart test) # plain Dart, no Flutter needed ``` -There are 11355 tests across 43 packages and twelve applications, and only about thirty need a GPU: the Impeller half of the golden set. The other half renders through the software backend, so ninety scenes stay checkable in a headless run. +There are 11357 tests across 43 packages and twelve applications, and only about thirty need a GPU: the Impeller half of the golden set. The other half renders through the software backend, so ninety scenes stay checkable in a headless run. ## Your own application diff --git a/site/content/reference/testing.md b/site/content/reference/testing.md index 6dca74c2e..6f7bac254 100644 --- a/site/content/reference/testing.md +++ b/site/content/reference/testing.md @@ -1,10 +1,10 @@ --- -description: Four independent golden sets, mutation-checking every new test, determinism and snapshots, and why only about thirty of 11355 tests need a GPU. +description: Four independent golden sets, mutation-checking every new test, determinism and snapshots, and why only about thirty of 11357 tests need a GPU. --- # Testing -11355 tests across 43 packages and nine applications, counted the same way the `the document says how many tests there are` rule does: a scan of every `test(`/`testWidgets(` call. The rule holds `ARCHITECTURE.md` §13, the README and this page to the answer. The README went on saying 1242 across thirteen packages for as long as nothing compared it with anything. About thirty need a GPU; the [architecture](/core/architecture/) is what keeps the number that low. +11357 tests across 43 packages and nine applications, counted the same way the `the document says how many tests there are` rule does: a scan of every `test(`/`testWidgets(` call. The rule holds `ARCHITECTURE.md` §13, the README and this page to the answer. The README went on saying 1242 across thirteen packages for as long as nothing compared it with anything. About thirty need a GPU; the [architecture](/core/architecture/) is what keeps the number that low. | Package | Tests | | Package | Tests | |---|---|---|---|---| @@ -23,7 +23,7 @@ description: Four independent golden sets, mutation-checking every new test, det | `flutter3d_cpu` | 380 | | `apps/flutter3d_demo_strategy` | 50 | | `apps/flutter3d_editor` | 234 | | `apps/flutter3d_demo_arcade` | 20 | | `apps/flutter3d_demo_racing` | 162 | | `pointer_lock` | 28 | -| `flutter3d_physics` | 282 | | `flutter3d_webgpu` | 193 | +| `flutter3d_physics` | 284 | | `flutter3d_webgpu` | 193 | | `flutter3d_game_strategy` | 133 | | `flutter3d_editor_mcp` | 36 | | `apps/flutter3d_demo_river` | 54 | | `flutter3d_testing` | 45 | | `flutter3d_editor_core` | 141 | | `flutter3d_editor_widgets` | 91 | @@ -40,7 +40,7 @@ description: Four independent golden sets, mutation-checking every new test, det | `flame_flutter3d` | 140 | | `apps/flutter3d_showcase` | 88 | | `flame_multiplayer` | 9 | | `flame_multiplayer_dashwire` | 3 | -The rows sum to 11328 rather than 11355: the remaining 26 live in `packages/*/example/test`, which the count includes and this table does not, among them the two seeds a new project starts from, `packages/flutter3d_app/example` and `packages/flutter3d_game/example`. +The rows sum to 11330 rather than 11357: the remaining 26 live in `packages/*/example/test`, which the count includes and this table does not, among them the two seeds a new project starts from, `packages/flutter3d_app/example` and `packages/flutter3d_game/example`. `flutter3d_samples` is not in the table and has no `test/` at all: it is test data with two path constants over it, and other packages' decoder tests are what exercise it. `flutter3d_conformance` is missing for a different reason: it is invoked as a script harness rather than through `flutter test`, so it does not surface in a grep of `test(` calls either. See below for what that cost once. From 70afe24ed00a4c8d85c49558243a78451d7ca7a4 Mon Sep 17 00:00:00 2001 From: Dmitrii Zolotov Date: Sat, 3 Oct 2026 15:39:28 +0300 Subject: [PATCH 18/34] feat: Hold drops by contact angle hysteresis, per surface Walls now say what they are made of: a SolidSurface with water's contact angle and its hysteresis. A drop stays where it is while its weight along the wall is no more than Furmidge's sigma*w*(cos receding - cos advancing) across the circle it wets, and slides when it is: a microlitre hangs on a pane, twenty run down. Puddles take their surface's angle, so water beads on the bench's lacquer and spreads on glass. --- ARCHITECTURE.md | 2 +- README.md | 2 +- packages/education/chemlab/lib/src/bench.dart | 11 +- .../lib/flutter3d_physics.dart | 1 + .../flutter3d_physics/lib/src/fluid/jet.dart | 5 + .../lib/src/fluid/liquid_body.dart | 7 + .../lib/src/fluid/particle_fluid.dart | 135 ++++++++++++------ .../lib/src/fluid/puddle.dart | 18 ++- .../lib/src/fluid/wetting.dart | 93 ++++++++++++ .../test/fluid/wetting_test.dart | 60 ++++++++ site/content/core/liquids.md | 4 +- site/content/quickstart.md | 2 +- site/content/reference/testing.md | 8 +- 13 files changed, 291 insertions(+), 57 deletions(-) create mode 100644 packages/flutter3d_physics/lib/src/fluid/wetting.dart create mode 100644 packages/flutter3d_physics/test/fluid/wetting_test.dart diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 7f9050cd4..c546bf191 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -2691,7 +2691,7 @@ storage. |---|---| | Style | `dart format` | | Analysis | `flutter analyze` clean across the workspace, no warnings | -| Unit tests | **11357 tests** across 43 packages and 10 applications | +| Unit tests | **11359 tests** across 43 packages and 10 applications | | Structure rules | 35, `dart run tool/structure.dart`, the first CI step | | CI | GitHub Actions over `tool/ci.sh`, on `ubuntu-latest`, with no graphics card | diff --git a/README.md b/README.md index 200d427f6..83d0b49ea 100644 --- a/README.md +++ b/README.md @@ -158,7 +158,7 @@ Or one package at a time: (cd packages/flutter3d_physics && dart test) # plain Dart, no Flutter needed ``` -There are 11357 tests across forty-three packages and nine applications. The +There are 11359 tests across forty-three packages and nine applications. The only ones that need a GPU are the Impeller half of the golden set. The other half is rendered by the software backend, which is what makes 90 scenes checkable in a headless run. diff --git a/packages/education/chemlab/lib/src/bench.dart b/packages/education/chemlab/lib/src/bench.dart index 246d9d318..6414a75e2 100644 --- a/packages/education/chemlab/lib/src/bench.dart +++ b/packages/education/chemlab/lib/src/bench.dart @@ -10,6 +10,7 @@ import 'package:flutter3d_physics/flutter3d_physics.dart' LiquidLayer, PlaneObstacle, RevolvedVessel, + SolidSurface, VesselVolumes, fallTime, overCircularLip, @@ -391,7 +392,15 @@ final class Bench { final FluidWorld world = FluidWorld( gravity: Vector3(0, -9.81, 0), particleSpacing: 0.001, - floor: [PlaneObstacle(normal: Vector3(0, 1, 0), offset: 0.0)], + // The bench top is lacquered: water beads on it rather than spreading + // as it would on glass. + floor: [ + PlaneObstacle( + normal: Vector3(0, 1, 0), + offset: 0.0, + solid: SolidSurface.laminate, + ), + ], ); /// Whether the shadows come from the engine's caustics diff --git a/packages/flutter3d_physics/lib/flutter3d_physics.dart b/packages/flutter3d_physics/lib/flutter3d_physics.dart index 2dcc34151..2c3c98c89 100644 --- a/packages/flutter3d_physics/lib/flutter3d_physics.dart +++ b/packages/flutter3d_physics/lib/flutter3d_physics.dart @@ -53,6 +53,7 @@ export 'src/fluid/particle_fluid.dart'; export 'src/fluid/pipe.dart'; export 'src/fluid/puddle.dart'; export 'src/fluid/vessel_shape.dart'; +export 'src/fluid/wetting.dart'; export 'src/inertia.dart'; export 'src/portable_math.dart'; export 'src/rigid_body.dart'; diff --git a/packages/flutter3d_physics/lib/src/fluid/jet.dart b/packages/flutter3d_physics/lib/src/fluid/jet.dart index e1d09f60e..5ff229d09 100644 --- a/packages/flutter3d_physics/lib/src/fluid/jet.dart +++ b/packages/flutter3d_physics/lib/src/fluid/jet.dart @@ -5,6 +5,7 @@ import 'package:vector_math/vector_math.dart'; import '../portable_math.dart'; import 'atmosphere.dart'; import 'fluid_medium.dart'; +import 'wetting.dart'; /// When something thrown at [velocity] from [height] reaches [floor] under /// gravity [g] pointing down: the later root of height + v_y·t − g t²/2 = @@ -52,6 +53,10 @@ abstract interface class JetObstacle { /// for everything in flight together, so the walls far from it are not /// asked again for each parcel, piece and pass. bool reaches(Vector3 centre, double distance); + + /// What it is made of: how a liquid wets it, and how hard its edge holds + /// a drop. + SolidSurface get solid; } /// [obstacles] that something within [distance] of [centre] could touch. diff --git a/packages/flutter3d_physics/lib/src/fluid/liquid_body.dart b/packages/flutter3d_physics/lib/src/fluid/liquid_body.dart index db282f98d..d7729e35e 100644 --- a/packages/flutter3d_physics/lib/src/fluid/liquid_body.dart +++ b/packages/flutter3d_physics/lib/src/fluid/liquid_body.dart @@ -11,6 +11,7 @@ import 'jet.dart'; import 'liquid_layer.dart'; import 'outflow.dart'; import 'vessel_shape.dart'; +import 'wetting.dart'; /// What ran over a vessel's lip in one step, in the world. final class Spill { @@ -685,6 +686,9 @@ final class InsideWalls implements JetObstacle { final LiquidBody body; + @override + SolidSurface get solid => SolidSurface.glass; + @override bool reaches(Vector3 centre, double distance) => body._reaches(centre, distance + body.wallThickness); @@ -727,6 +731,9 @@ final class OutsideWalls implements JetObstacle { final LiquidBody body; final double thickness; + @override + SolidSurface get solid => SolidSurface.glass; + @override bool reaches(Vector3 centre, double distance) => body._reaches(centre, distance + thickness); diff --git a/packages/flutter3d_physics/lib/src/fluid/particle_fluid.dart b/packages/flutter3d_physics/lib/src/fluid/particle_fluid.dart index 53145a25d..76cfc9cc7 100644 --- a/packages/flutter3d_physics/lib/src/fluid/particle_fluid.dart +++ b/packages/flutter3d_physics/lib/src/fluid/particle_fluid.dart @@ -7,12 +7,19 @@ import '../portable_math.dart'; import 'atmosphere.dart'; import 'fluid_medium.dart'; import 'jet.dart'; +import 'wetting.dart'; /// A flat surface particles rest on — a bench, a floor: the points with /// `normal · p ≥ offset` are clear of it. final class PlaneObstacle implements JetObstacle { - PlaneObstacle({required Vector3 normal, required this.offset}) - : normal = normal.normalized(); + PlaneObstacle({ + required Vector3 normal, + required this.offset, + this.solid = SolidSurface.glass, + }) : normal = normal.normalized(); + + @override + final SolidSurface solid; final Vector3 normal; final double offset; @@ -427,7 +434,15 @@ final class ParticleFluid { // moves only off it, or not at all. Left free along it, three // particles that came down on the bench rolled away over each other as // a wheel does, faster with every turn. - final pinned = [for (var i = 0; i < n; i++) _contact(_x[i], walls[i])]; + // + // **Unless the drop's weight along the wall is more than its edge can + // hold**, by Furmidge's σ·w·(cos θr − cos θa): then it slides, its + // particles kept out of the wall and free along it. + final touching = [for (var i = 0; i < n; i++) _touching(_x[i], walls[i])]; + final held = _held(touching, gravity); + final pinned = [ + for (var i = 0; i < n; i++) held[i] ? touching[i]?.normal : null, + ]; // **Component by component, into buffers made once a substep.** The // loops over pairs below run tens of thousands of times a frame; with a // vector made for each difference, gradient and product, thirty drops @@ -622,37 +637,65 @@ final class ParticleFluid { // on the bench slid off at five centimetres a second and never // stopped, and ended up under another glass's foot, looking as if it // were inside. - final onWall = List.filled(n, false); + // A drop that slides keeps only out of the wall. for (var i = 0; i < n; i++) { final v = _v[i] ..x = smoothed[3 * i] ..y = smoothed[3 * i + 1] ..z = smoothed[3 * i + 2]; final wall = _contact(p[i], walls[i]); - onWall[i] = wall != null; if (wall != null) { - final off = math.max(_dot(v, wall), 0.0); + final into = _dot(v, wall); + if (held[i]) { + final off = math.max(into, 0.0); + v + ..x = wall.x * off + ..y = wall.y * off + ..z = wall.z * off; + } else if (into < 0.0) { + v + ..x -= wall.x * into + ..y -= wall.y * into + ..z -= wall.z * into; + } + } + // A drop its edge holds stands still, as a whole: pinning only the + // particles that touch let the others turn over them, and a drop of + // three on the bench rolled away. + if (held[i]) { v - ..x = wall.x * off - ..y = wall.y * off - ..z = wall.z * off; + ..x = 0.0 + ..y = 0.0 + ..z = 0.0; } _x[i] = p[i]; } - _holdSmallDrops(near, onWall, gravity); } - /// **A drop smaller than the capillary length, pinned, stands still.** - /// Under ℓc = √(σ/ρg), 2.7 mm for water, surface tension holds a drop's - /// shape against its weight, and what of it touches a wall is pinned: - /// it stays as a whole where it is. Pinning only the particles that touch - /// let the others turn over them, and a three-particle drop on the bench - /// rolled away; a puddle wider than ℓc still spreads. - void _holdSmallDrops(List> near, List onWall, _V gravity) { + /// The wall [p] touches and its normal there, if it touches one. + ({_V normal, JetObstacle wall})? _touching(_V p, List walls) { + final reach = 0.55 * spacing; + for (final o in walls) { + final hit = o.touch(p.toVector3(), reach); + if (hit != null) { + return (normal: _V(hit.normal.x, hit.normal.y, hit.normal.z), wall: o); + } + } + return null; + } + + /// For each particle, whether the drop it is in is held where it is by + /// the wall it touches: its weight along the wall, ρ·V·g∥, no more than + /// the wall's [SolidSurface.retention] across the circle a drop of its + /// volume wets. Held, a drop stands still; on a level bench every drop + /// is, its weight being all into the bench. + List _held( + List<({_V normal, JetObstacle wall})?> touching, + _V gravity, + ) { final n = _x.length; - final g = gravity.length; - if (n == 0 || g <= 0.0 || medium.surfaceTension <= 0.0) return; - final capillary = math.sqrt(medium.surfaceTension / (medium.density * g)); + final out = List.filled(n, false); + if (n == 0 || medium.surfaceTension <= 0.0) return out; final parent = List.generate(n, (i) => i); int root(int i) { var r = i; @@ -663,38 +706,42 @@ final class ParticleFluid { } // One drop: particles nearer each other than a spacing and a half. - final touching = 2.25 * spacing * spacing; + final grid = _Grid(h, _x); + final close = 2.25 * spacing * spacing; for (var i = 0; i < n; i++) { - for (final j in near[i]) { - if (_x[i].distance2(_x[j]) < touching) parent[root(i)] = root(j); + for (final j in grid.near(i, _x)) { + if (_x[i].distance2(_x[j]) < close) parent[root(i)] = root(j); } } - final low = {}; - final high = {}; - final held = {}; + final volume = {}; + final normal = {}; + final solid = {}; for (var i = 0; i < n; i++) { final r = root(i); - final p = _x[i]; - final lo = low[r] ??= p.copy(); - final hi = high[r] ??= p.copy(); - lo - ..x = math.min(lo.x, p.x) - ..y = math.min(lo.y, p.y) - ..z = math.min(lo.z, p.z); - hi - ..x = math.max(hi.x, p.x) - ..y = math.max(hi.y, p.y) - ..z = math.max(hi.z, p.z); - if (onWall[i]) held.add(r); + volume[r] = (volume[r] ?? 0.0) + _vol[i]; + final t = touching[i]; + if (t == null) continue; + (normal[r] ??= _V(0, 0, 0)).add(t.normal); + solid[r] ??= t.wall.solid; + } + final holds = {}; + for (final MapEntry(key: r, value: sum) in normal.entries) { + final length = sum.length; + if (length <= 0.0) continue; + final nx = sum.x / length; + final ny = sum.y / length; + final nz = sum.z / length; + final into = gravity.x * nx + gravity.y * ny + gravity.z * nz; + final along = math.sqrt(math.max(gravity.length2 - into * into, 0.0)); + final v = volume[r]!; + final weight = medium.density * v * along; + final width = 2.0 * solid[r]!.baseRadius(medium, v); + if (weight <= solid[r]!.retention(medium, width)) holds.add(r); } for (var i = 0; i < n; i++) { - final r = root(i); - if (!held.contains(r)) continue; - // Across it, a particle's width beyond the centres. - if ((high[r]! - low[r]!).length + spacing < capillary) { - _v[i] = _V(0, 0, 0); - } + out[i] = holds.contains(root(i)); } + return out; } /// The normal of the wall [p] touches, if it touches one. Put out a diff --git a/packages/flutter3d_physics/lib/src/fluid/puddle.dart b/packages/flutter3d_physics/lib/src/fluid/puddle.dart index 730f3a15c..b82a28930 100644 --- a/packages/flutter3d_physics/lib/src/fluid/puddle.dart +++ b/packages/flutter3d_physics/lib/src/fluid/puddle.dart @@ -7,6 +7,7 @@ import 'atmosphere.dart'; import 'fluid_medium.dart'; import 'jet.dart'; import 'particle_fluid.dart'; +import 'wetting.dart'; /// Liquid lying on a flat surface: a drop or a puddle, as one body. /// @@ -24,10 +25,20 @@ import 'particle_fluid.dart'; /// where it reaches its shape. Water reaches it in milliseconds; honey /// takes its time. final class Puddle { - Puddle({required this.medium, required this.centre, required this.normal}); + Puddle({ + required this.medium, + required this.centre, + required this.normal, + double? angle, + }) : angle = angle ?? medium.contactAngle; final FluidMedium medium; + /// The angle it meets the surface at, radians: the surface's for this + /// liquid ([SolidSurface.angleFor]). Water beads on a lacquered bench + /// and spreads on glass. + final double angle; + /// Its middle, on the surface. final Vector3 centre; @@ -89,7 +100,7 @@ final class Puddle { final r = radius(g); if (r <= 0.0) return 0.0; final d = air.vapourDiffusivity; - final theta = medium.contactAngle.clamp(0.0, math.pi / 2); + final theta = angle.clamp(0.0, math.pi / 2); final still = math.pi * r * d * deficit * (0.27 * theta * theta + 1.30); final across = air.windAt(centre) ..addScaled(normal, -air.windAt(centre).dot(normal)); @@ -130,7 +141,7 @@ final class Puddle { /// whichever is wider. double restRadius(double g) { if (_volume <= 0.0) return 0.0; - final theta = medium.contactAngle.clamp(0.05, math.pi - 0.05); + final theta = angle.clamp(0.05, math.pi - 0.05); final s = Portable.sin(theta); final c = Portable.cos(theta); // A spherical cap of base R meeting the plane at θ holds @@ -218,6 +229,7 @@ final class PuddleSurface implements JetReceiver { medium: medium, centre: onPlane.clone(), normal: surface.normal.clone(), + angle: surface.solid.angleFor(medium), ); puddles.add(made); return made; diff --git a/packages/flutter3d_physics/lib/src/fluid/wetting.dart b/packages/flutter3d_physics/lib/src/fluid/wetting.dart new file mode 100644 index 000000000..1dd614dce --- /dev/null +++ b/packages/flutter3d_physics/lib/src/fluid/wetting.dart @@ -0,0 +1,93 @@ +import 'dart:math' as math; + +import '../portable_math.dart'; +import 'fluid_medium.dart'; + +/// A solid a liquid lies on or runs down: how water meets it. +/// +/// **A contact angle is not one angle.** A drop's edge moving forward meets +/// the solid at the advancing angle θa, drawing back at the receding angle +/// θr, and anywhere between the edge does not move at all: the hysteresis +/// θa − θr is what holds a raindrop still on a window. The force it can +/// hold a drop with is σ·w·(cos θr − cos θa) across a contact w wide +/// (Furmidge, 1962), and a drop slides when the pull along the solid is +/// more than that. +/// +/// The angles here are water's, typical of the clean surface and not of +/// one measurement: a solid's angles move with how it was cleaned, coated +/// and worn. For another liquid the solid's own angles are not known here, +/// and its angle against glass ([FluidMedium.contactAngle]) stands in, with +/// the same hysteresis. +final class SolidSurface { + const SolidSurface({ + required this.name, + required this.waterAngle, + required this.hysteresis, + }); + + /// Clean glass: water spreads on it, 20° (as [FluidMedium.water]), and its + /// edge holds over about 10°. + static const SolidSurface glass = SolidSurface( + name: 'glass', + waterAngle: 0.35, + hysteresis: 0.17, + ); + + /// A lacquered or laminate bench top: water beads on it at about 75° and + /// its edge holds over about 25°. + static const SolidSurface laminate = SolidSurface( + name: 'laminate', + waterAngle: 1.31, + hysteresis: 0.44, + ); + + /// PTFE: water stands up on it at about 110° and rolls off easily. + static const SolidSurface ptfe = SolidSurface( + name: 'ptfe', + waterAngle: 1.92, + hysteresis: 0.17, + ); + + final String name; + + /// Water's contact angle at rest, radians. + final double waterAngle; + + /// The advancing angle less the receding one, radians. + final double hysteresis; + + /// [medium]'s angle at rest on this solid. + double angleFor(FluidMedium medium) => + medium.vapour?.isWater ?? false ? waterAngle : medium.contactAngle; + + /// The angles [medium]'s edge advances and recedes at. + ({double advancing, double receding}) anglesFor(FluidMedium medium) { + final rest = angleFor(medium); + return ( + advancing: math.min(rest + 0.5 * hysteresis, math.pi), + receding: math.max(rest - 0.5 * hysteresis, 0.0), + ); + } + + /// The most this solid holds a drop of [medium] [width] wide by its edge, + /// newtons: σ·w·(cos θr − cos θa). + double retention(FluidMedium medium, double width) { + final a = anglesFor(medium); + return medium.surfaceTension * + width * + (Portable.cos(a.receding) - Portable.cos(a.advancing)); + } + + /// The radius of the circle a drop of [volume] of [medium] wets on this + /// solid at rest: a spherical cap meeting it at its angle, which holds + /// πR³(2 − 3cosθ + cos³θ)/(3sin³θ). + double baseRadius(FluidMedium medium, double volume) { + final theta = angleFor(medium).clamp(0.05, math.pi - 0.05); + final s = Portable.sin(theta); + final c = Portable.cos(theta); + return Portable.pow( + 3.0 * volume * s * s * s / (math.pi * (2.0 - 3.0 * c + c * c * c)), + 1.0 / 3.0, + ); + } +} diff --git a/packages/flutter3d_physics/test/fluid/wetting_test.dart b/packages/flutter3d_physics/test/fluid/wetting_test.dart new file mode 100644 index 000000000..c761f9ad1 --- /dev/null +++ b/packages/flutter3d_physics/test/fluid/wetting_test.dart @@ -0,0 +1,60 @@ +import 'package:flutter3d_physics/flutter3d_physics.dart'; +import 'package:test/test.dart'; +import 'package:vector_math/vector_math.dart'; + +void main() { + /// Where a drop of [microlitres] left against a vertical pane of glass is + /// after a second, and where it started. + (double, double) onPane(int microlitres) { + final fluid = ParticleFluid(medium: FluidMedium.water, spacing: 0.001); + final pane = [PlaneObstacle(normal: Vector3(1, 0, 0), offset: 0.0)]; + fluid.inject(microlitres * 1e-9, Vector3(0.002, 0.1, 0), Vector3.zero()); + double low() => + fluid.positions.map((p) => p.y).reduce((a, b) => a < b ? a : b); + // Let it come to the glass first. + for (var i = 0; i < 24; i++) { + fluid.step(1 / 240, gravity: Vector3(-9.81, 0, 0), obstacles: pane); + } + final start = low(); + for (var i = 0; i < 240; i++) { + fluid.step(1 / 240, gravity: Vector3(0, -9.81, 0), obstacles: pane); + } + return (start, low()); + } + + test('a small drop hangs on a pane and a big one runs down it', () { + // Furmidge: a microlitre weighs three quarters of what clean glass's + // edge holds it with; twenty weigh five times what holds them. + // Mutation: hold every drop under the capillary length, as before, + // and the big one, under it at its four-millimetre base, stays. + final (smallStart, smallEnd) = onPane(1); + expect(smallEnd, closeTo(smallStart, 1e-3)); + final (bigStart, bigEnd) = onPane(20); + expect(bigStart - bigEnd, greaterThan(0.01)); + }); + + test('water beads on a lacquered bench and spreads on glass', () { + Puddle lying(SolidSurface solid) { + final bench = + PuddleSurface( + PlaneObstacle(normal: Vector3(0, 1, 0), offset: 0, solid: solid), + )..receive( + 5e-7, + Vector3.zero(), + Vector3.zero(), + FluidMedium.water, + const {}, + ); + return bench.puddles.single; + } + + final glass = lying(SolidSurface.glass); + final laminate = lying(SolidSurface.laminate); + expect(laminate.restRadius(9.81), lessThan(glass.restRadius(9.81))); + final r = laminate.restRadius(9.81); + expect( + laminate.capHeight(r), + greaterThan(glass.capHeight(glass.restRadius(9.81))), + ); + }); +} diff --git a/site/content/core/liquids.md b/site/content/core/liquids.md index 4a3830c6e..a9b78ec3e 100644 --- a/site/content/core/liquids.md +++ b/site/content/core/liquids.md @@ -65,11 +65,11 @@ The world keeps the accounts: every jet's `emitted` is `inFlight + landed + drop Drops are `ParticleFluid`, position-based fluids on the CPU, in double precision. Particles are held to the rest density only where they are compressed, so a surface does not pull itself inward. Cohesion follows Akinci, with the coefficient worked out so that pulling a slab of particles apart costs 2σ per square metre, which is what surface tension is. A particle is stepped in substeps short against the capillary time √(ρs³/σ), a third of a millisecond for millimetre water, and short enough that nothing passes through glass between one look and the next. Drops that land in a vessel become its liquid, with what was dissolved in them. Liquid arrives in any amount and leaves as whole particles; what is short of one waits only while more is coming, and then goes as a last, smaller particle where the rest came in. -A drop is stopped by the wall it touches: a viscous liquid has no velocity along a wall at rest, and a drop smaller than the capillary length √(σ/ρg), 2.7 mm for water, is held whole by its pinned edge. A drop that touches a vessel's glass from inside runs down into its liquid. +A drop is stopped by the wall it touches: a viscous liquid has no velocity along a wall at rest, and a drop's edge holds it there. Every wall is a `SolidSurface` with water's contact angle and its hysteresis, the advancing angle less the receding one: glass, a lacquered bench, PTFE. The edge holds a drop with Furmidge's σ·w·(cos θr − cos θa) across the circle it wets, so a microlitre hangs on a pane while twenty run down it, and every drop on a level bench stays where it fell. A drop that touches a vessel's glass from inside runs down into its liquid. For liquids other than water the solids' own angles are not known here, and the liquid's angle on glass stands in. ## Puddles -What reaches a floor given to the world becomes a `Puddle` on its `PuddleSurface`, one body with a volume and what is dissolved in it, not particles. A spread puddle is 2ℓc·sin(θ/2) deep, under a millimetre for water on glass; a smaller one is a spherical cap meeting the surface at the contact angle. It spreads there as a viscous gravity current, R ∝ (ρgV³/μ)^⅛·t^⅛ (Huppert), which water finishes in milliseconds. Puddles that meet run together. Draw them with `capMesh(...)`. +What reaches a floor given to the world becomes a `Puddle` on its `PuddleSurface`, one body with a volume and what is dissolved in it, not particles. Its angle θ is the surface's, so water beads on a lacquered bench and spreads on glass. A spread puddle is 2ℓc·sin(θ/2) deep, under a millimetre for water on glass; a smaller one is a spherical cap meeting the surface at the contact angle. It spreads there as a viscous gravity current, R ∝ (ρgV³/μ)^⅛·t^⅛ (Huppert), which water finishes in milliseconds. Puddles that meet run together. Draw them with `capMesh(...)`. ## Laminar and turbulent diff --git a/site/content/quickstart.md b/site/content/quickstart.md index 48af5c35d..051c8e87e 100644 --- a/site/content/quickstart.md +++ b/site/content/quickstart.md @@ -91,7 +91,7 @@ tool/ci.sh # shaders, analyze, every test (cd packages/flutter3d_physics && dart test) # plain Dart, no Flutter needed ``` -There are 11357 tests across 43 packages and twelve applications, and only about thirty need a GPU: the Impeller half of the golden set. The other half renders through the software backend, so ninety scenes stay checkable in a headless run. +There are 11359 tests across 43 packages and twelve applications, and only about thirty need a GPU: the Impeller half of the golden set. The other half renders through the software backend, so ninety scenes stay checkable in a headless run. ## Your own application diff --git a/site/content/reference/testing.md b/site/content/reference/testing.md index 6f7bac254..43dcf9246 100644 --- a/site/content/reference/testing.md +++ b/site/content/reference/testing.md @@ -1,10 +1,10 @@ --- -description: Four independent golden sets, mutation-checking every new test, determinism and snapshots, and why only about thirty of 11357 tests need a GPU. +description: Four independent golden sets, mutation-checking every new test, determinism and snapshots, and why only about thirty of 11359 tests need a GPU. --- # Testing -11357 tests across 43 packages and nine applications, counted the same way the `the document says how many tests there are` rule does: a scan of every `test(`/`testWidgets(` call. The rule holds `ARCHITECTURE.md` §13, the README and this page to the answer. The README went on saying 1242 across thirteen packages for as long as nothing compared it with anything. About thirty need a GPU; the [architecture](/core/architecture/) is what keeps the number that low. +11359 tests across 43 packages and nine applications, counted the same way the `the document says how many tests there are` rule does: a scan of every `test(`/`testWidgets(` call. The rule holds `ARCHITECTURE.md` §13, the README and this page to the answer. The README went on saying 1242 across thirteen packages for as long as nothing compared it with anything. About thirty need a GPU; the [architecture](/core/architecture/) is what keeps the number that low. | Package | Tests | | Package | Tests | |---|---|---|---|---| @@ -23,7 +23,7 @@ description: Four independent golden sets, mutation-checking every new test, det | `flutter3d_cpu` | 380 | | `apps/flutter3d_demo_strategy` | 50 | | `apps/flutter3d_editor` | 234 | | `apps/flutter3d_demo_arcade` | 20 | | `apps/flutter3d_demo_racing` | 162 | | `pointer_lock` | 28 | -| `flutter3d_physics` | 284 | | `flutter3d_webgpu` | 193 | +| `flutter3d_physics` | 286 | | `flutter3d_webgpu` | 193 | | `flutter3d_game_strategy` | 133 | | `flutter3d_editor_mcp` | 36 | | `apps/flutter3d_demo_river` | 54 | | `flutter3d_testing` | 45 | | `flutter3d_editor_core` | 141 | | `flutter3d_editor_widgets` | 91 | @@ -40,7 +40,7 @@ description: Four independent golden sets, mutation-checking every new test, det | `flame_flutter3d` | 140 | | `apps/flutter3d_showcase` | 88 | | `flame_multiplayer` | 9 | | `flame_multiplayer_dashwire` | 3 | -The rows sum to 11330 rather than 11357: the remaining 26 live in `packages/*/example/test`, which the count includes and this table does not, among them the two seeds a new project starts from, `packages/flutter3d_app/example` and `packages/flutter3d_game/example`. +The rows sum to 11332 rather than 11359: the remaining 26 live in `packages/*/example/test`, which the count includes and this table does not, among them the two seeds a new project starts from, `packages/flutter3d_app/example` and `packages/flutter3d_game/example`. `flutter3d_samples` is not in the table and has no `test/` at all: it is test data with two path constants over it, and other packages' decoder tests are what exercise it. `flutter3d_conformance` is missing for a different reason: it is invoked as a script harness rather than through `flutter test`, so it does not surface in a grep of `test(` calls either. See below for what that cost once. From f60ad1b88570ed264df9890fcc20079e6a6ee874 Mon Sep 17 00:00:00 2001 From: Dmitrii Zolotov Date: Sat, 3 Oct 2026 15:43:13 +0300 Subject: [PATCH 19/34] feat: Slow a body turning in a liquid by Stokes's torque A floating body's spin was never touched by the liquid round it, and a ball spun in glycerol spun on for ever. The part under the surface now feels 8*pi*mu*R^3*omega on the sphere of its volume, taken implicitly about the body's own axes. --- ARCHITECTURE.md | 2 +- README.md | 2 +- .../lib/src/fluid/buoyancy.dart | 21 ++++++++++ .../test/fluid/buoyancy_test.dart | 39 +++++++++++++++++++ site/content/core/liquids.md | 2 + site/content/quickstart.md | 2 +- site/content/reference/testing.md | 8 ++-- 7 files changed, 69 insertions(+), 7 deletions(-) diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index c546bf191..68e1cc392 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -2691,7 +2691,7 @@ storage. |---|---| | Style | `dart format` | | Analysis | `flutter analyze` clean across the workspace, no warnings | -| Unit tests | **11359 tests** across 43 packages and 10 applications | +| Unit tests | **11360 tests** across 43 packages and 10 applications | | Structure rules | 35, `dart run tool/structure.dart`, the first CI step | | CI | GitHub Actions over `tool/ci.sh`, on `ubuntu-latest`, with no graphics card | diff --git a/README.md b/README.md index 83d0b49ea..a73700646 100644 --- a/README.md +++ b/README.md @@ -158,7 +158,7 @@ Or one package at a time: (cd packages/flutter3d_physics && dart test) # plain Dart, no Flutter needed ``` -There are 11359 tests across forty-three packages and nine applications. The +There are 11360 tests across forty-three packages and nine applications. The only ones that need a GPU are the Impeller half of the golden set. The other half is rendered by the software backend, which is what makes 90 scenes checkable in a headless run. diff --git a/packages/flutter3d_physics/lib/src/fluid/buoyancy.dart b/packages/flutter3d_physics/lib/src/fluid/buoyancy.dart index 0c5d4891e..a324fc0a8 100644 --- a/packages/flutter3d_physics/lib/src/fluid/buoyancy.dart +++ b/packages/flutter3d_physics/lib/src/fluid/buoyancy.dart @@ -166,6 +166,27 @@ final class FloatingBody { ..scale(1.0 / (1.0 + k * dt)) ..addScaled(gravity, -dt); } + // **Turning, the liquid holds it back too**: a sphere spinning slowly in + // a viscous liquid feels Stokes's torque 8πμR³ω, here for the sphere of + // the body's volume and the share of it under, taken implicitly about + // the body's own axes. Without it a body set spinning in glycerol spun + // on for ever. + final spin = body.angularVelocity; + if (spin.length2 > 0.0) { + final shape = body.collider.shape; + final whole = _wholeVolume(shape); + final r = Portable.pow(3.0 * whole / (4.0 * math.pi), 1.0 / 3.0); + final share = (under / whole).clamp(0.0, 1.0); + final c = 8.0 * math.pi * medium.viscosity * r * r * r * share; + final turn = body.orientation.asRotationMatrix(); + final local = (turn.clone()..transpose()).transformed(spin); + final inverse = body.inverseInertiaLocal; + local + ..x /= 1.0 + c * inverse.x * dt + ..y /= 1.0 + c * inverse.y * dt + ..z /= 1.0 + c * inverse.z * dt; + spin.setFrom(turn.transformed(local)); + } return under; } diff --git a/packages/flutter3d_physics/test/fluid/buoyancy_test.dart b/packages/flutter3d_physics/test/fluid/buoyancy_test.dart index a9f046e0c..470eb2c09 100644 --- a/packages/flutter3d_physics/test/fluid/buoyancy_test.dart +++ b/packages/flutter3d_physics/test/fluid/buoyancy_test.dart @@ -113,6 +113,45 @@ void main() { expect(-ball.velocity.y, closeTo(stokes, stokes * 0.03)); }); + test('a ball spun in glycerol slows as Stokes\'s torque says', () { + // 8πμR³ω against a ball's 2/5·mR²: its spin falls by e in ρR²/15μ, six + // milliseconds for a centimetre ball as heavy as the glycerol. Slow + // enough, a tenth of a Reynolds number, for Stokes to hold. Mutation: + // leave the torque out, and it spins on as it was. + final gravity = Vector3(0, -9.81, 0); + final collisions = CollisionWorld(); + final dynamics = Dynamics(world: collisions, gravity: gravity); + const r = 0.01; + final rho = FluidMedium.glycerol.density; + final ball = RigidBody( + world: collisions, + shape: CollisionSphere(r), + position: Vector3(0, 0.1, 0), + mass: rho * 4 / 3 * math.pi * r * r * r, + canRotate: true, + ); + ball.angularVelocity.setValues(0, 1, 0); + dynamics.add(ball); + const dt = 1 / 20000; + final world = FluidWorld(gravity: gravity, step: dt); + final vat = LiquidBody( + shape: _vat(0.05, 0.4), + medium: FluidMedium.glycerol, + volume: math.pi * 0.0025 * 0.3, + modes: 2, + ); + world.bodies.add(vat); + world.float(ball); + final tau = rho * r * r / (15 * FluidMedium.glycerol.viscosity); + final steps = (tau / dt).round(); + for (var i = 0; i < steps; i++) { + vat.place(Matrix3.identity(), Vector3.zero()); + world.advance(dt); + dynamics.step(dt); + } + expect(ball.angularVelocity.y, closeTo(math.exp(-1), math.exp(-1) * 0.02)); + }); + test('a body under the surface raises the level by its volume', () { final collisions = CollisionWorld(); final world = FluidWorld(gravity: Vector3(0, -9.81, 0)); diff --git a/site/content/core/liquids.md b/site/content/core/liquids.md index a9b78ec3e..17545a6d1 100644 --- a/site/content/core/liquids.md +++ b/site/content/core/liquids.md @@ -105,6 +105,8 @@ A body holds layers. Liquids that mix are one layer, keeping amounts of solutes, `FloatingBody` wraps a rigid body. The liquid pushes up with ρgV of what it displaces, exactly for spheres, boxes and capsules, and drags with White's coefficient for the part that is under. The displaced volume raises the level. A small ball sinking in glycerol settles at Stokes's speed; the tests check it within three percent. +A body turning in the liquid is held back too, by Stokes's torque 8πμR³ω on the sphere of its volume, for the part of it that is under: a ball spun in glycerol slows by e in ρR²/15μ. + ## Being honest about it - The surface is linear, so it rocks harder where real water would break. diff --git a/site/content/quickstart.md b/site/content/quickstart.md index 051c8e87e..37a850b11 100644 --- a/site/content/quickstart.md +++ b/site/content/quickstart.md @@ -91,7 +91,7 @@ tool/ci.sh # shaders, analyze, every test (cd packages/flutter3d_physics && dart test) # plain Dart, no Flutter needed ``` -There are 11359 tests across 43 packages and twelve applications, and only about thirty need a GPU: the Impeller half of the golden set. The other half renders through the software backend, so ninety scenes stay checkable in a headless run. +There are 11360 tests across 43 packages and twelve applications, and only about thirty need a GPU: the Impeller half of the golden set. The other half renders through the software backend, so ninety scenes stay checkable in a headless run. ## Your own application diff --git a/site/content/reference/testing.md b/site/content/reference/testing.md index 43dcf9246..595eadb58 100644 --- a/site/content/reference/testing.md +++ b/site/content/reference/testing.md @@ -1,10 +1,10 @@ --- -description: Four independent golden sets, mutation-checking every new test, determinism and snapshots, and why only about thirty of 11359 tests need a GPU. +description: Four independent golden sets, mutation-checking every new test, determinism and snapshots, and why only about thirty of 11360 tests need a GPU. --- # Testing -11359 tests across 43 packages and nine applications, counted the same way the `the document says how many tests there are` rule does: a scan of every `test(`/`testWidgets(` call. The rule holds `ARCHITECTURE.md` §13, the README and this page to the answer. The README went on saying 1242 across thirteen packages for as long as nothing compared it with anything. About thirty need a GPU; the [architecture](/core/architecture/) is what keeps the number that low. +11360 tests across 43 packages and nine applications, counted the same way the `the document says how many tests there are` rule does: a scan of every `test(`/`testWidgets(` call. The rule holds `ARCHITECTURE.md` §13, the README and this page to the answer. The README went on saying 1242 across thirteen packages for as long as nothing compared it with anything. About thirty need a GPU; the [architecture](/core/architecture/) is what keeps the number that low. | Package | Tests | | Package | Tests | |---|---|---|---|---| @@ -23,7 +23,7 @@ description: Four independent golden sets, mutation-checking every new test, det | `flutter3d_cpu` | 380 | | `apps/flutter3d_demo_strategy` | 50 | | `apps/flutter3d_editor` | 234 | | `apps/flutter3d_demo_arcade` | 20 | | `apps/flutter3d_demo_racing` | 162 | | `pointer_lock` | 28 | -| `flutter3d_physics` | 286 | | `flutter3d_webgpu` | 193 | +| `flutter3d_physics` | 287 | | `flutter3d_webgpu` | 193 | | `flutter3d_game_strategy` | 133 | | `flutter3d_editor_mcp` | 36 | | `apps/flutter3d_demo_river` | 54 | | `flutter3d_testing` | 45 | | `flutter3d_editor_core` | 141 | | `flutter3d_editor_widgets` | 91 | @@ -40,7 +40,7 @@ description: Four independent golden sets, mutation-checking every new test, det | `flame_flutter3d` | 140 | | `apps/flutter3d_showcase` | 88 | | `flame_multiplayer` | 9 | | `flame_multiplayer_dashwire` | 3 | -The rows sum to 11332 rather than 11359: the remaining 26 live in `packages/*/example/test`, which the count includes and this table does not, among them the two seeds a new project starts from, `packages/flutter3d_app/example` and `packages/flutter3d_game/example`. +The rows sum to 11333 rather than 11360: the remaining 26 live in `packages/*/example/test`, which the count includes and this table does not, among them the two seeds a new project starts from, `packages/flutter3d_app/example` and `packages/flutter3d_game/example`. `flutter3d_samples` is not in the table and has no `test/` at all: it is test data with two path constants over it, and other packages' decoder tests are what exercise it. `flutter3d_conformance` is missing for a different reason: it is invoked as a script harness rather than through `flutter test`, so it does not surface in a grep of `test(` calls either. See below for what that cost once. From e95a1270521357cf955f027567b1ba24dc693a7a Mon Sep 17 00:00:00 2001 From: Dmitrii Zolotov Date: Sat, 3 Oct 2026 15:47:24 +0300 Subject: [PATCH 20/34] feat: Let gravity vary from place to place with attractors A FluidWorld can now take a GravityField, a uniform part and any number of attractors pulling as mu/r^2 outside and as a uniform ball inside. Each vessel levels across the gravity where it stands, and each drop and parcel of a stream falls by the gravity at its own place. --- ARCHITECTURE.md | 2 +- README.md | 2 +- .../lib/flutter3d_physics.dart | 1 + .../lib/src/fluid/fluid_world.dart | 32 ++++++-- .../lib/src/fluid/gravity_field.dart | 76 +++++++++++++++++++ .../flutter3d_physics/lib/src/fluid/jet.dart | 4 +- .../lib/src/fluid/particle_fluid.dart | 18 +++-- .../test/fluid/gravity_field_test.dart | 74 ++++++++++++++++++ site/content/core/liquids.md | 4 + site/content/quickstart.md | 2 +- site/content/reference/testing.md | 8 +- 11 files changed, 203 insertions(+), 20 deletions(-) create mode 100644 packages/flutter3d_physics/lib/src/fluid/gravity_field.dart create mode 100644 packages/flutter3d_physics/test/fluid/gravity_field_test.dart diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 68e1cc392..4193cf693 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -2691,7 +2691,7 @@ storage. |---|---| | Style | `dart format` | | Analysis | `flutter analyze` clean across the workspace, no warnings | -| Unit tests | **11360 tests** across 43 packages and 10 applications | +| Unit tests | **11363 tests** across 43 packages and 10 applications | | Structure rules | 35, `dart run tool/structure.dart`, the first CI step | | CI | GitHub Actions over `tool/ci.sh`, on `ubuntu-latest`, with no graphics card | diff --git a/README.md b/README.md index a73700646..6ab7a58af 100644 --- a/README.md +++ b/README.md @@ -158,7 +158,7 @@ Or one package at a time: (cd packages/flutter3d_physics && dart test) # plain Dart, no Flutter needed ``` -There are 11360 tests across forty-three packages and nine applications. The +There are 11363 tests across forty-three packages and nine applications. The only ones that need a GPU are the Impeller half of the golden set. The other half is rendered by the software backend, which is what makes 90 scenes checkable in a headless run. diff --git a/packages/flutter3d_physics/lib/flutter3d_physics.dart b/packages/flutter3d_physics/lib/flutter3d_physics.dart index 2c3c98c89..82d82edd0 100644 --- a/packages/flutter3d_physics/lib/flutter3d_physics.dart +++ b/packages/flutter3d_physics/lib/flutter3d_physics.dart @@ -45,6 +45,7 @@ export 'src/fluid/capillary.dart'; export 'src/fluid/fluid_medium.dart'; export 'src/fluid/fluid_world.dart'; export 'src/fluid/free_surface.dart'; +export 'src/fluid/gravity_field.dart'; export 'src/fluid/jet.dart'; export 'src/fluid/liquid_body.dart'; export 'src/fluid/liquid_layer.dart'; diff --git a/packages/flutter3d_physics/lib/src/fluid/fluid_world.dart b/packages/flutter3d_physics/lib/src/fluid/fluid_world.dart index 0cbb840bb..58c829ee2 100644 --- a/packages/flutter3d_physics/lib/src/fluid/fluid_world.dart +++ b/packages/flutter3d_physics/lib/src/fluid/fluid_world.dart @@ -3,6 +3,7 @@ import 'package:vector_math/vector_math.dart'; import '../rigid_body.dart'; import 'atmosphere.dart'; import 'buoyancy.dart'; +import 'gravity_field.dart'; import 'jet.dart'; import 'liquid_body.dart'; import 'particle_fluid.dart'; @@ -28,8 +29,17 @@ final class FluidWorld { this.particleSpacing = 0.002, this.floor, Atmosphere? atmosphere, + this.field, }) : atmosphere = atmosphere ?? Atmosphere.standard(); + /// Gravity that differs from place to place, when there is some: then + /// each vessel, drop and parcel of a stream feels [GravityField.at] where + /// it is, and [gravity] is not read. Null, every one feels [gravity]. + final GravityField? field; + + /// The gravity at [point]. + Vector3 gravityAt(Vector3 point) => field?.at(point) ?? gravity; + /// The air: what drops and streams fall through and what open liquid /// evaporates into. Room air by default, as a bench stands in. final Atmosphere atmosphere; @@ -112,19 +122,20 @@ final class FluidWorld { for (final liquid in bodies) { var displaced = 0.0; for (final f in floating) { - displaced += f.push(liquid, dt, gravity); + displaced += f.push(liquid, dt, gravityAt(f.body.position)); } liquid.displaced = displaced; } for (final pipe in pipes) { - pipe.step(dt, gravity: gravity); + pipe.step(dt, gravity: gravityAt(pipe.from.position)); } for (final body in bodies) { - final spill = body.step(dt, gravity: gravity); + final here = gravityAt(body.position); + final spill = body.step(dt, gravity: here); final jet = jets[body]; if (spill.flow > 0.0 || jet != null) { final stream = jets.putIfAbsent(body, () => Jet(medium: body.medium)); - final across = gravity.cross(spill.velocity); + final across = here.cross(spill.velocity); stream.emit( flow: spill.flow, dt: dt, @@ -151,7 +162,8 @@ final class FluidWorld { ]; for (final drop in jet.step( dt, - gravity: gravity, + gravity: gravityAt(source.position), + gravityAt: field?.at, obstacles: walls, receivers: [...bodies, ...spills], air: atmosphere, @@ -182,7 +194,10 @@ final class FluidWorld { for (final fluid in particles.values) { fluid.step( dt, - gravity: gravity, + gravity: field == null || fluid.count == 0 + ? gravity + : gravityAt(fluid.positions.first), + gravityAt: field?.at, obstacles: everywhere, receivers: [...bodies, ...spills], air: atmosphere, @@ -195,7 +210,10 @@ final class FluidWorld { _evaporated += spill.evaporate(dt, atmosphere); } for (final spill in spills) { - spill.step(dt, gravity: gravity); + spill.step( + dt, + gravity: gravityAt(spill.surface.normal * spill.surface.offset), + ); } } } diff --git a/packages/flutter3d_physics/lib/src/fluid/gravity_field.dart b/packages/flutter3d_physics/lib/src/fluid/gravity_field.dart new file mode 100644 index 000000000..0299199c9 --- /dev/null +++ b/packages/flutter3d_physics/lib/src/fluid/gravity_field.dart @@ -0,0 +1,76 @@ +import 'dart:math' as math; + +import 'package:vector_math/vector_math.dart'; + +/// Gravity that is not the same everywhere: a uniform part, and the pull of +/// every [Attractor] in it, added. +/// +/// **Newton's law for each**: g = μ·r̂/r², μ = G·M the attractor's standard +/// gravitational parameter, pointing at it. Inside an attractor of +/// [Attractor.radius], uniform in density, it falls off to nought at the +/// middle as μ·r/R³ (the shell outside pulls equally every way), so a drop +/// that passes through one is not flung off by a pull growing without +/// bound. +/// +/// A liquid asks it where it is: each vessel's surface lies across its own +/// local gravity, and each drop and parcel of a stream falls by the gravity +/// at its own place. +final class GravityField { + GravityField({Vector3? uniform, List? attractors}) + : uniform = uniform ?? Vector3.zero(), + attractors = attractors ?? []; + + /// Metres per second squared, everywhere. + final Vector3 uniform; + + final List attractors; + + /// The gravity at [point]: a vector of the caller's own. + Vector3 at(Vector3 point) { + final g = uniform.clone(); + for (final a in attractors) { + final dx = a.position.x - point.x; + final dy = a.position.y - point.y; + final dz = a.position.z - point.z; + final r2 = dx * dx + dy * dy + dz * dz; + if (r2 <= 0.0) continue; + final r = math.sqrt(r2); + final k = r < a.radius + ? a.mu / (a.radius * a.radius * a.radius) + : a.mu / (r2 * r); + g + ..x += dx * k + ..y += dy * k + ..z += dz * k; + } + return g; + } +} + +/// A mass that pulls: where it is, how hard, and how big. +final class Attractor { + Attractor({required this.position, required this.mu, this.radius = 0.0}); + + /// An attractor of [mass] kilograms, by Newton's constant. + factory Attractor.ofMass({ + required Vector3 position, + required double mass, + double radius = 0.0, + }) => Attractor( + position: position, + mu: gravitationalConstant * mass, + radius: radius, + ); + + /// Newton's G, m³/(kg·s²) (CODATA 2018). + static const double gravitationalConstant = 6.67430e-11; + + /// Where it is; move it and the field moves with it. + final Vector3 position; + + /// G·M, cubic metres per second squared. + final double mu; + + /// Metres: inside it the pull falls to nought at the middle. + final double radius; +} diff --git a/packages/flutter3d_physics/lib/src/fluid/jet.dart b/packages/flutter3d_physics/lib/src/fluid/jet.dart index 5ff229d09..7d2704b0a 100644 --- a/packages/flutter3d_physics/lib/src/fluid/jet.dart +++ b/packages/flutter3d_physics/lib/src/fluid/jet.dart @@ -247,6 +247,7 @@ final class Jet { List obstacles = const [], List receivers = const [], Atmosphere? air, + Vector3 Function(Vector3 point)? gravityAt, }) { final drops = []; _retract(dt); @@ -273,7 +274,8 @@ final class Jet { final rho = p.medium.density; final sigma = p.medium.surfaceTension; final mu = p.medium.viscosity; - p.velocity.addScaled(gravity, dt); + // Its own gravity, where it is, when gravity is not one vector. + p.velocity.addScaled(gravityAt?.call(p.position) ?? gravity, dt); p.previous.setFrom(p.position); p.age += dt; p.travelled += p.velocity.length * dt; diff --git a/packages/flutter3d_physics/lib/src/fluid/particle_fluid.dart b/packages/flutter3d_physics/lib/src/fluid/particle_fluid.dart index 76cfc9cc7..509133cab 100644 --- a/packages/flutter3d_physics/lib/src/fluid/particle_fluid.dart +++ b/packages/flutter3d_physics/lib/src/fluid/particle_fluid.dart @@ -240,6 +240,7 @@ final class ParticleFluid { List obstacles = const [], List receivers = const [], Atmosphere? air, + Vector3 Function(Vector3 point)? gravityAt, }) { // **What is less than a particle is let go too**, once no more liquid // comes to make it one: as a particle of its own amount, where the last @@ -287,6 +288,7 @@ final class ParticleFluid { spacing, ); _air = air; + _gravityAt = gravityAt; if (air != null) _measureDrops(dt, air); for (var s = 0; s < count; s++) { _substep(sub, g, walls); @@ -314,6 +316,9 @@ final class ParticleFluid { Atmosphere? _air; Float64List _drop = Float64List(0); + /// The gravity at a point, when it is not one vector everywhere. + Vector3 Function(Vector3 point)? _gravityAt; + /// Cubic metres evaporated from the drops so far. double get evaporated => _evaporated; double _evaporated = 0.0; @@ -488,9 +493,10 @@ final class ParticleFluid { } for (var i = 0; i < n; i++) { final xi = _x[i]; - var ax = gravity.x; - var ay = gravity.y; - var az = gravity.z; + final here = _gravityAt?.call(xi.toVector3()); + var ax = here?.x ?? gravity.x; + var ay = here?.y ?? gravity.y; + var az = here?.z ?? gravity.z; for (final j in neighbours[i]) { final xj = _x[j]; final dx = xi.x - xj.x; @@ -731,8 +737,10 @@ final class ParticleFluid { final nx = sum.x / length; final ny = sum.y / length; final nz = sum.z / length; - final into = gravity.x * nx + gravity.y * ny + gravity.z * nz; - final along = math.sqrt(math.max(gravity.length2 - into * into, 0.0)); + final at = _gravityAt?.call(_x[r].toVector3()); + final g = at == null ? gravity : _V(at.x, at.y, at.z); + final into = g.x * nx + g.y * ny + g.z * nz; + final along = math.sqrt(math.max(g.length2 - into * into, 0.0)); final v = volume[r]!; final weight = medium.density * v * along; final width = 2.0 * solid[r]!.baseRadius(medium, v); diff --git a/packages/flutter3d_physics/test/fluid/gravity_field_test.dart b/packages/flutter3d_physics/test/fluid/gravity_field_test.dart new file mode 100644 index 000000000..477c7fc07 --- /dev/null +++ b/packages/flutter3d_physics/test/fluid/gravity_field_test.dart @@ -0,0 +1,74 @@ +import 'package:flutter3d_physics/flutter3d_physics.dart'; +import 'package:test/test.dart'; +import 'package:vector_math/vector_math.dart'; + +void main() { + test('the Earth pulls 9.82 at its surface and half that halfway down', () { + // μ = 3.986×10¹⁴ m³/s², R = 6371 km. + const r = 6.371e6; + final earth = GravityField( + attractors: [ + Attractor(position: Vector3.zero(), mu: 3.986e14, radius: r), + ], + ); + final surface = earth.at(Vector3(0, r, 0)); + expect(surface.length, closeTo(9.82, 0.01)); + expect(surface.y, lessThan(0.0)); + // Inside a uniform ball the pull falls straight to nought at the middle. + expect(earth.at(Vector3(0, r / 2, 0)).length, closeTo(9.82 / 2, 0.01)); + // Between two equal masses, none at all. + final pair = GravityField( + attractors: [ + Attractor(position: Vector3(-1, 0, 0), mu: 10), + Attractor(position: Vector3(1, 0, 0), mu: 10), + ], + ); + expect(pair.at(Vector3.zero()).length, closeTo(0.0, 1e-12)); + }); + + test('a glass beside an attractor levels across its own gravity', () { + // A pull of 9.81 at a metre, sideways to the glass, and no other: + // the liquid lies along the glass's side, its surface facing the + // attractor's way out. Mutation: hand every vessel the world's one + // gravity, which here is nought, and the surface never turns. + final field = GravityField( + attractors: [Attractor(position: Vector3.zero(), mu: 9.81)], + ); + final world = FluidWorld(gravity: Vector3.zero(), field: field); + final glass = LiquidBody( + shape: RevolvedVessel([ + Vector2(0, 0), + Vector2(0.02, 0), + Vector2(0.02, 0.1), + ]), + medium: FluidMedium.water, + volume: 2e-5, + modes: 2, + ); + world.bodies.add(glass); + for (var i = 0; i < 240; i++) { + glass.place( + Matrix3.identity(), + Vector3(1, 0, 0), + time: world.time + world.step, + ); + world.advance(world.step); + } + expect(glass.up.x, closeTo(1.0, 1e-6)); + }); + + test('a drop between two attractors falls to the nearer', () { + final field = GravityField( + attractors: [ + Attractor(position: Vector3(-0.1, 0, 0), mu: 1e-3), + Attractor(position: Vector3(0.1, 0, 0), mu: 1e-3), + ], + ); + final fluid = ParticleFluid(medium: FluidMedium.water, spacing: 0.001) + ..inject(1e-9, Vector3(0.01, 0, 0), Vector3.zero()); + for (var i = 0; i < 24; i++) { + fluid.step(1 / 240, gravity: Vector3.zero(), gravityAt: field.at); + } + expect(fluid.positions.single.x, greaterThan(0.01)); + }); +} diff --git a/site/content/core/liquids.md b/site/content/core/liquids.md index 17545a6d1..6be8104be 100644 --- a/site/content/core/liquids.md +++ b/site/content/core/liquids.md @@ -29,6 +29,10 @@ world.advance(dt); Draw it with `liquidMeshes(tube)`, `jetMesh(jet)` and `particleMesh(...)` from `flutter3d_core`'s geometry. The chemistry bench is built this way; its [article](/education/chemlab/) shows what that looks like. +## Gravity that varies + +`FluidWorld.gravity` is one vector for everything. Give the world a `GravityField` instead, a uniform part and any number of `Attractor`s, and each vessel, drop and parcel of a stream feels the gravity where it is. Each attractor pulls as μ·r̂/r², μ = G·M, and inside its radius it pulls as a uniform ball does, less the deeper in. A glass beside an attractor levels across its own pull, and a drop between two falls to the nearer. + ## Volume first A vessel is a `VesselShape`: something that can say how much of it lies under a plane. `RevolvedVessel` does it exactly upright, as a sum of frustums, and tilted as a sum of circular segments. `MeshVessel` takes any closed mesh and does it with the divergence theorem over the triangles the plane cuts. Everything else is built on that one question. The surface's height is the plane that leaves the liquid's volume under it, and the most a tipped glass holds is the volume under its lowest point of rim. diff --git a/site/content/quickstart.md b/site/content/quickstart.md index 37a850b11..93732614d 100644 --- a/site/content/quickstart.md +++ b/site/content/quickstart.md @@ -91,7 +91,7 @@ tool/ci.sh # shaders, analyze, every test (cd packages/flutter3d_physics && dart test) # plain Dart, no Flutter needed ``` -There are 11360 tests across 43 packages and twelve applications, and only about thirty need a GPU: the Impeller half of the golden set. The other half renders through the software backend, so ninety scenes stay checkable in a headless run. +There are 11363 tests across 43 packages and twelve applications, and only about thirty need a GPU: the Impeller half of the golden set. The other half renders through the software backend, so ninety scenes stay checkable in a headless run. ## Your own application diff --git a/site/content/reference/testing.md b/site/content/reference/testing.md index 595eadb58..e0efcd010 100644 --- a/site/content/reference/testing.md +++ b/site/content/reference/testing.md @@ -1,10 +1,10 @@ --- -description: Four independent golden sets, mutation-checking every new test, determinism and snapshots, and why only about thirty of 11360 tests need a GPU. +description: Four independent golden sets, mutation-checking every new test, determinism and snapshots, and why only about thirty of 11363 tests need a GPU. --- # Testing -11360 tests across 43 packages and nine applications, counted the same way the `the document says how many tests there are` rule does: a scan of every `test(`/`testWidgets(` call. The rule holds `ARCHITECTURE.md` §13, the README and this page to the answer. The README went on saying 1242 across thirteen packages for as long as nothing compared it with anything. About thirty need a GPU; the [architecture](/core/architecture/) is what keeps the number that low. +11363 tests across 43 packages and nine applications, counted the same way the `the document says how many tests there are` rule does: a scan of every `test(`/`testWidgets(` call. The rule holds `ARCHITECTURE.md` §13, the README and this page to the answer. The README went on saying 1242 across thirteen packages for as long as nothing compared it with anything. About thirty need a GPU; the [architecture](/core/architecture/) is what keeps the number that low. | Package | Tests | | Package | Tests | |---|---|---|---|---| @@ -23,7 +23,7 @@ description: Four independent golden sets, mutation-checking every new test, det | `flutter3d_cpu` | 380 | | `apps/flutter3d_demo_strategy` | 50 | | `apps/flutter3d_editor` | 234 | | `apps/flutter3d_demo_arcade` | 20 | | `apps/flutter3d_demo_racing` | 162 | | `pointer_lock` | 28 | -| `flutter3d_physics` | 287 | | `flutter3d_webgpu` | 193 | +| `flutter3d_physics` | 290 | | `flutter3d_webgpu` | 193 | | `flutter3d_game_strategy` | 133 | | `flutter3d_editor_mcp` | 36 | | `apps/flutter3d_demo_river` | 54 | | `flutter3d_testing` | 45 | | `flutter3d_editor_core` | 141 | | `flutter3d_editor_widgets` | 91 | @@ -40,7 +40,7 @@ description: Four independent golden sets, mutation-checking every new test, det | `flame_flutter3d` | 140 | | `apps/flutter3d_showcase` | 88 | | `flame_multiplayer` | 9 | | `flame_multiplayer_dashwire` | 3 | -The rows sum to 11333 rather than 11360: the remaining 26 live in `packages/*/example/test`, which the count includes and this table does not, among them the two seeds a new project starts from, `packages/flutter3d_app/example` and `packages/flutter3d_game/example`. +The rows sum to 11336 rather than 11363: the remaining 26 live in `packages/*/example/test`, which the count includes and this table does not, among them the two seeds a new project starts from, `packages/flutter3d_app/example` and `packages/flutter3d_game/example`. `flutter3d_samples` is not in the table and has no `test/` at all: it is test data with two path constants over it, and other packages' decoder tests are what exercise it. `flutter3d_conformance` is missing for a different reason: it is invoked as a script harness rather than through `flutter test`, so it does not surface in a grep of `test(` calls either. See below for what that cost once. From 12d6459f602172d18b3e055ab8b9e3db06e7ff58 Mon Sep 17 00:00:00 2001 From: Dmitrii Zolotov Date: Sat, 3 Oct 2026 16:08:56 +0300 Subject: [PATCH 21/34] refactor: Run the particle fluid's pair loops as kernels over flat buffers The loops over neighbour pairs in a Position Based Fluids substep, density, normals, forces, the density constraint and XSPH, now live behind PbfKernels and work on Float64List positions and velocities and compressed neighbour rows, so another implementation can take them as they are. The Dart one is the reference and adds in the same order as before: a run of drops with walls and wind comes out bit for bit the same. Walls, receivers and drops stay with ParticleFluid between calls. --- .../lib/src/fluid/particle_fluid.dart | 226 ++++------- .../lib/src/fluid/pbf_kernels.dart | 381 ++++++++++++++++++ 2 files changed, 464 insertions(+), 143 deletions(-) create mode 100644 packages/flutter3d_physics/lib/src/fluid/pbf_kernels.dart diff --git a/packages/flutter3d_physics/lib/src/fluid/particle_fluid.dart b/packages/flutter3d_physics/lib/src/fluid/particle_fluid.dart index 509133cab..97cbfe4b9 100644 --- a/packages/flutter3d_physics/lib/src/fluid/particle_fluid.dart +++ b/packages/flutter3d_physics/lib/src/fluid/particle_fluid.dart @@ -7,6 +7,7 @@ import '../portable_math.dart'; import 'atmosphere.dart'; import 'fluid_medium.dart'; import 'jet.dart'; +import 'pbf_kernels.dart'; import 'wetting.dart'; /// A flat surface particles rest on — a bench, a floor: the points with @@ -311,6 +312,58 @@ final class ParticleFluid { } } + /// What runs the loops over pairs: the Dart reference unless something + /// faster is put in its place. + late PbfKernels kernels = DartPbfKernels( + PbfConstants( + h: h, + restDensity: medium.density, + mass: _mass, + norm: 1.0 / _latticeSum, + gamma: _gamma, + restStiffness: _restStiffness, + ), + ); + + /// [points] as one flat buffer of x, y, z in turn. + static Float64List _flat(List<_V> points) { + final out = Float64List(3 * points.length); + for (var i = 0; i < points.length; i++) { + final p = points[i]; + out[3 * i] = p.x; + out[3 * i + 1] = p.y; + out[3 * i + 2] = p.z; + } + return out; + } + + /// [flat] back into [points]. + static void _unflat(Float64List flat, List<_V> points) { + for (var i = 0; i < points.length; i++) { + points[i] + ..x = flat[3 * i] + ..y = flat[3 * i + 1] + ..z = flat[3 * i + 2]; + } + } + + /// The neighbours of each of [points] within the kernel's reach, as + /// compressed rows: [PbfKernels]' layout. + (Int32List, Int32List) _rows(List<_V> points) { + final grid = _Grid(h, points); + final n = points.length; + final lists = [for (var i = 0; i < n; i++) grid.near(i, points)]; + final start = Int32List(n + 1); + for (var i = 0; i < n; i++) { + start[i + 1] = start[i] + lists[i].length; + } + final list = Int32List(start[n]); + for (var i = 0; i < n; i++) { + list.setAll(start[i], lists[i]); + } + return (start, list); + } + /// The air the particles are being stepped through, and each particle's /// drop's diameter: set at the start of a step, read by its substeps. Atmosphere? _air; @@ -453,83 +506,44 @@ final class ParticleFluid { // vector made for each difference, gradient and product, thirty drops // made hundreds of thousands of objects a frame, and the collector's // pauses were most of what a pour with drops cost. + // **The loops over pairs, by [kernels]**, over flat buffers: positions + // and velocities copied out of the particles before each call and back + // after, a few hundred numbers against the tens of thousands of pair + // terms the call works through. final rho0 = medium.density; - final m = _mass; - final norm = 1.0 / _latticeSum; + final ker = kernels; // Forces first: gravity, cohesion and curvature, on the velocities. - final grid = _Grid(h, _x); - final neighbours = [for (var i = 0; i < n; i++) grid.near(i, _x)]; + final xs = _flat(_x); + final vs = _flat(_v); + final (start, list) = _rows(_x); final density = Float64List(n); - for (var i = 0; i < n; i++) { - var w = _poly6(0.0); - for (final j in neighbours[i]) { - w += _poly6(_x[i].distance2(_x[j])); - } - density[i] = rho0 * w * norm; - } + ker.densities(xs, start, list, n, density); final normal = Float64List(3 * n); + ker.normals(xs, start, list, n, density, normal); + final before = Float64List(3 * n); + final after = Float64List(3 * n); + final air = _air; for (var i = 0; i < n; i++) { - final xi = _x[i]; - var nx = 0.0; - var ny = 0.0; - var nz = 0.0; - for (final j in neighbours[i]) { - final xj = _x[j]; - final dx = xi.x - xj.x; - final dy = xi.y - xj.y; - final dz = xi.z - xj.z; - final f = - _spikyScale(math.sqrt(dx * dx + dy * dy + dz * dz)) * - h * - m / - density[j]; - nx += dx * f; - ny += dy * f; - nz += dz * f; - } - normal[3 * i] = nx; - normal[3 * i + 1] = ny; - normal[3 * i + 2] = nz; - } - for (var i = 0; i < n; i++) { - final xi = _x[i]; - final here = _gravityAt?.call(xi.toVector3()); - var ax = here?.x ?? gravity.x; - var ay = here?.y ?? gravity.y; - var az = here?.z ?? gravity.z; - for (final j in neighbours[i]) { - final xj = _x[j]; - final dx = xi.x - xj.x; - final dy = xi.y - xj.y; - final dz = xi.z - xj.z; - final r = math.sqrt(dx * dx + dy * dy + dz * dz); - if (r < 1e-12) continue; - final k = 2.0 * rho0 / (density[i] + density[j]); - final c = -k * _gamma * m * _cohesion(r) / r; - final t = -k * _gamma; - ax += dx * c + (normal[3 * i] - normal[3 * j]) * t; - ay += dy * c + (normal[3 * i + 1] - normal[3 * j + 1]) * t; - az += dz * c + (normal[3 * i + 2] - normal[3 * j + 2]) * t; - } + final here = _gravityAt?.call(_x[i].toVector3()); + before[3 * i] = here?.x ?? gravity.x; + before[3 * i + 1] = here?.y ?? gravity.y; + before[3 * i + 2] = here?.z ?? gravity.z; // The air, on the drop it is in: its drag over the drop's mass, // which every particle of it feels alike. - final air = _air; if (air != null && i < _drop.length && _drop[i] > 0.0) { final drag = air.dragOnSphere( _v[i].toVector3(), - xi.toVector3(), + _x[i].toVector3(), _drop[i], rho0, ); - ax += drag.x; - ay += drag.y; - az += drag.z; + after[3 * i] = drag.x; + after[3 * i + 1] = drag.y; + after[3 * i + 2] = drag.z; } - _v[i] - ..x += ax * dt - ..y += ay * dt - ..z += az * dt; } + ker.forces(xs, start, list, n, density, normal, before, after, vs, dt); + _unflat(vs, _v); // Predict, then hold the density to the rest density. final p = [ for (var i = 0; i < n; i++) @@ -539,66 +553,14 @@ final class ParticleFluid { _advance(_x[i], _v[i], dt, walls[i]), ]; final lambda = Float64List(n); - final grid2 = _Grid(h, p); - final near = [for (var i = 0; i < n; i++) grid2.near(i, p)]; - final dq = 0.3 * h; - final wq = _poly6(dq * dq); + final (near, rows) = _rows(p); final delta = Float64List(3 * n); for (var it = 0; it < iterations; it++) { - for (var i = 0; i < n; i++) { - // C = ρ/ρ₀ − 1 with ρ/ρ₀ the kernel sum over the lattice's: only - // where it is compressed. Both ways, a surface particle with half - // its neighbours missing is pulled in by half a spacing a pass and - // the liquid flies apart; a stretched surface is held by cohesion - // instead. - final pi = p[i]; - var w = _poly6(0.0); - var sum2 = 0.0; - var gx = 0.0; - var gy = 0.0; - var gz = 0.0; - for (final j in near[i]) { - final pj = p[j]; - final dx = pi.x - pj.x; - final dy = pi.y - pj.y; - final dz = pi.z - pj.z; - final r2 = dx * dx + dy * dy + dz * dz; - w += _poly6(r2); - final f = _spikyScale(math.sqrt(r2)) * norm; - sum2 += r2 * f * f; - gx += dx * f; - gy += dy * f; - gz += dz * f; - } - sum2 += gx * gx + gy * gy + gz * gz; - final c = math.max(w * norm - 1.0, 0.0); - lambda[i] = -c / (sum2 + 1e-6 * norm * norm / (h * h)); - } - delta.fillRange(0, 3 * n, 0.0); - for (var i = 0; i < n; i++) { - final pi = p[i]; - for (final j in near[i]) { - final pj = p[j]; - final dx = pi.x - pj.x; - final dy = pi.y - pj.y; - final dz = pi.z - pj.z; - final r2 = dx * dx + dy * dy + dz * dz; - final ratio = _poly6(r2) / wq; - // Macklin's artificial pressure, which keeps neighbours from - // clumping: a fiftieth of a constraint's worth. At his tenth it - // held still water a sixth thinner than its rest density. - final corr = -0.02 * ratio * ratio * ratio * ratio / _restStiffness; - // Δpᵢ = Σⱼ (λᵢ + λⱼ + s_corr) ∇W(pᵢ − pⱼ), in the same - // normalisation as the constraint. - final f = - _spikyScale(math.sqrt(r2)) * - (lambda[i] + lambda[j] + corr) * - norm; - delta[3 * i] += dx * f; - delta[3 * i + 1] += dy * f; - delta[3 * i + 2] += dz * f; - } - } + // C = ρ/ρ₀ − 1, only where it is compressed: see [PbfKernels]. + final ps = _flat(p); + ker + ..lambdas(ps, near, rows, n, lambda) + ..deltas(ps, near, rows, n, lambda, delta); for (var i = 0; i < n; i++) { p[i] ..x += delta[3 * i] @@ -621,22 +583,7 @@ final class ParticleFluid { medium.kinematicViscosity * dt / (spacing * spacing) * 50.0 + 0.01, ); final smoothed = Float64List(3 * n); - for (var i = 0; i < n; i++) { - final vi = _v[i]; - var sx = vi.x; - var sy = vi.y; - var sz = vi.z; - for (final j in near[i]) { - final w = _poly6(p[i].distance2(p[j])) * norm * share; - final vj = _v[j]; - sx += (vj.x - vi.x) * w; - sy += (vj.y - vi.y) * w; - sz += (vj.z - vi.z) * w; - } - smoothed[3 * i] = sx; - smoothed[3 * i + 1] = sy; - smoothed[3 * i + 2] = sz; - } + ker.viscosity(_flat(p), _flat(_v), near, rows, n, share, smoothed); // A viscous liquid's velocity at a wall at rest is nil along it, and // nothing goes on into it: what touches one keeps only the part of its // velocity that leaves. Left its speed along the wall, a drop that fell @@ -811,13 +758,6 @@ final class ParticleFluid { return 315.0 / (64.0 * math.pi * _pow9(h)) * d * d * d; } - /// What a difference d of length [r] is scaled by to be the spiky - /// kernel's gradient: ∇W = d·f(r). - double _spikyScale(double r) { - if (r <= 1e-12 || r >= h) return 0.0; - return -45.0 / (math.pi * _pow6(h)) * (h - r) * (h - r) / r; - } - _V _spikyGradient(_V d) { final r = d.length; if (r <= 1e-12 || r >= h) return _V(0, 0, 0); diff --git a/packages/flutter3d_physics/lib/src/fluid/pbf_kernels.dart b/packages/flutter3d_physics/lib/src/fluid/pbf_kernels.dart new file mode 100644 index 000000000..a41fd39e1 --- /dev/null +++ b/packages/flutter3d_physics/lib/src/fluid/pbf_kernels.dart @@ -0,0 +1,381 @@ +import 'dart:math' as math; +import 'dart:typed_data'; + +/// The loops over pairs of neighbours that a Position Based Fluids substep +/// is made of, over flat buffers: what [ParticleFluid] hands to whichever +/// implementation runs them, this one in Dart or a native one. +/// +/// **Flat, so another language can take them as they are.** Positions, +/// velocities and every per-particle vector are `Float64List`s of x, y, z +/// in turn; the neighbours are compressed rows, particle i's being +/// `list[start[i]]` up to `list[start[i + 1]]`, itself left out. Nothing +/// here knows about walls, receivers or drops: [ParticleFluid] keeps those, +/// between the calls. +/// +/// **This implementation is the reference**: the order of every sum is the +/// order [ParticleFluid] has always added in, so a step is the same step to +/// the last bit. A native one, free to vectorise, is held to it within a +/// tolerance instead. +abstract interface class PbfKernels { + /// Each particle's density, from its neighbours at [x]: ρ₀·ΣW/ΣW_rest. + void densities( + Float64List x, + Int32List start, + Int32List list, + int n, + Float64List density, + ); + + /// Each particle's colour-field normal, h·Σ m/ρⱼ·∇W, into [normal]. + void normals( + Float64List x, + Int32List start, + Int32List list, + int n, + Float64List density, + Float64List normal, + ); + + /// The forces on each particle as accelerations, added to its velocity + /// [v] over [dt]: [before] (gravity), then cohesion and curvature from + /// its neighbours, then [after] (the air's drag), in that order. + void forces( + Float64List x, + Int32List start, + Int32List list, + int n, + Float64List density, + Float64List normal, + Float64List before, + Float64List after, + Float64List v, + double dt, + ); + + /// Each particle's density constraint multiplier λ, from the predicted + /// positions [p]: only where it is compressed. + void lambdas( + Float64List p, + Int32List start, + Int32List list, + int n, + Float64List lambda, + ); + + /// Each particle's position correction Δp from [lambda], with the + /// artificial pressure that keeps neighbours from clumping, into [delta]. + void deltas( + Float64List p, + Int32List start, + Int32List list, + int n, + Float64List lambda, + Float64List delta, + ); + + /// XSPH: each velocity drawn towards its neighbours' by [share] of the + /// kernel weight, into [smoothed]. + void viscosity( + Float64List p, + Float64List v, + Int32List start, + Int32List list, + int n, + double share, + Float64List smoothed, + ); +} + +/// The constants the kernels share, worked out once for a fluid. +final class PbfConstants { + PbfConstants({ + required this.h, + required this.restDensity, + required this.mass, + required this.norm, + required this.gamma, + required this.restStiffness, + }) : h2 = h * h, + poly6 = 315.0 / (64.0 * math.pi * _pow9(h)), + spiky = -45.0 / (math.pi * _pow6(h)), + cohesion = 32.0 / (math.pi * _pow9(h)), + h6 = _pow6(h), + wq = _poly6Of((0.3 * h) * (0.3 * h), h); + + /// The kernel's reach, and its square. + final double h; + final double h2; + + /// ρ₀, and one particle's mass. + final double restDensity; + final double mass; + + /// One over the kernel summed over the lattice at rest. + final double norm; + + /// Akinci's cohesion coefficient. + final double gamma; + + /// Σ|∇C|² on the lattice, which the artificial pressure is a share of. + final double restStiffness; + + /// The kernels' own normalisations. + final double poly6; + final double spiky; + final double cohesion; + final double h6; + + /// W at 0.3·h, the artificial pressure's reference. + final double wq; + + static double _pow6(double x) => x * x * x * x * x * x; + static double _pow9(double x) => _pow6(x) * x * x * x; + static double _poly6Of(double r2, double h) { + final h2 = h * h; + if (r2 >= h2) return 0.0; + final d = h2 - r2; + return 315.0 / (64.0 * math.pi * _pow9(h)) * d * d * d; + } +} + +/// [PbfKernels] in Dart: the reference. +final class DartPbfKernels implements PbfKernels { + DartPbfKernels(this.k); + + final PbfConstants k; + + double _poly6(double r2) { + if (r2 >= k.h2) return 0.0; + final d = k.h2 - r2; + return k.poly6 * d * d * d; + } + + double _spikyScale(double r) { + if (r <= 1e-12 || r >= k.h) return 0.0; + return k.spiky * (k.h - r) * (k.h - r) / r; + } + + double _cohesion(double r) { + final h = k.h; + if (r >= h || r <= 0.0) return 0.0; + final a = (h - r) * (h - r) * (h - r) * r * r * r; + if (2.0 * r > h) return k.cohesion * a; + return k.cohesion * (2.0 * a - k.h6 / 64.0); + } + + @override + void densities( + Float64List x, + Int32List start, + Int32List list, + int n, + Float64List density, + ) { + for (var i = 0; i < n; i++) { + final xi = x[3 * i]; + final yi = x[3 * i + 1]; + final zi = x[3 * i + 2]; + var w = _poly6(0.0); + for (var q = start[i]; q < start[i + 1]; q++) { + final j = list[q]; + final dx = xi - x[3 * j]; + final dy = yi - x[3 * j + 1]; + final dz = zi - x[3 * j + 2]; + w += _poly6(dx * dx + dy * dy + dz * dz); + } + density[i] = k.restDensity * w * k.norm; + } + } + + @override + void normals( + Float64List x, + Int32List start, + Int32List list, + int n, + Float64List density, + Float64List normal, + ) { + for (var i = 0; i < n; i++) { + final xi = x[3 * i]; + final yi = x[3 * i + 1]; + final zi = x[3 * i + 2]; + var nx = 0.0; + var ny = 0.0; + var nz = 0.0; + for (var q = start[i]; q < start[i + 1]; q++) { + final j = list[q]; + final dx = xi - x[3 * j]; + final dy = yi - x[3 * j + 1]; + final dz = zi - x[3 * j + 2]; + final f = + _spikyScale(math.sqrt(dx * dx + dy * dy + dz * dz)) * + k.h * + k.mass / + density[j]; + nx += dx * f; + ny += dy * f; + nz += dz * f; + } + normal[3 * i] = nx; + normal[3 * i + 1] = ny; + normal[3 * i + 2] = nz; + } + } + + @override + void forces( + Float64List x, + Int32List start, + Int32List list, + int n, + Float64List density, + Float64List normal, + Float64List before, + Float64List after, + Float64List v, + double dt, + ) { + final rho0 = k.restDensity; + for (var i = 0; i < n; i++) { + final xi = x[3 * i]; + final yi = x[3 * i + 1]; + final zi = x[3 * i + 2]; + var ax = before[3 * i]; + var ay = before[3 * i + 1]; + var az = before[3 * i + 2]; + for (var q = start[i]; q < start[i + 1]; q++) { + final j = list[q]; + final dx = xi - x[3 * j]; + final dy = yi - x[3 * j + 1]; + final dz = zi - x[3 * j + 2]; + final r = math.sqrt(dx * dx + dy * dy + dz * dz); + if (r < 1e-12) continue; + final kk = 2.0 * rho0 / (density[i] + density[j]); + final c = -kk * k.gamma * k.mass * _cohesion(r) / r; + final t = -kk * k.gamma; + ax += dx * c + (normal[3 * i] - normal[3 * j]) * t; + ay += dy * c + (normal[3 * i + 1] - normal[3 * j + 1]) * t; + az += dz * c + (normal[3 * i + 2] - normal[3 * j + 2]) * t; + } + ax += after[3 * i]; + ay += after[3 * i + 1]; + az += after[3 * i + 2]; + v[3 * i] += ax * dt; + v[3 * i + 1] += ay * dt; + v[3 * i + 2] += az * dt; + } + } + + @override + void lambdas( + Float64List p, + Int32List start, + Int32List list, + int n, + Float64List lambda, + ) { + final norm = k.norm; + for (var i = 0; i < n; i++) { + final xi = p[3 * i]; + final yi = p[3 * i + 1]; + final zi = p[3 * i + 2]; + var w = _poly6(0.0); + var sum2 = 0.0; + var gx = 0.0; + var gy = 0.0; + var gz = 0.0; + for (var q = start[i]; q < start[i + 1]; q++) { + final j = list[q]; + final dx = xi - p[3 * j]; + final dy = yi - p[3 * j + 1]; + final dz = zi - p[3 * j + 2]; + final r2 = dx * dx + dy * dy + dz * dz; + w += _poly6(r2); + final f = _spikyScale(math.sqrt(r2)) * norm; + sum2 += r2 * f * f; + gx += dx * f; + gy += dy * f; + gz += dz * f; + } + sum2 += gx * gx + gy * gy + gz * gz; + final c = math.max(w * norm - 1.0, 0.0); + lambda[i] = -c / (sum2 + 1e-6 * norm * norm / (k.h * k.h)); + } + } + + @override + void deltas( + Float64List p, + Int32List start, + Int32List list, + int n, + Float64List lambda, + Float64List delta, + ) { + final norm = k.norm; + for (var i = 0; i < n; i++) { + final xi = p[3 * i]; + final yi = p[3 * i + 1]; + final zi = p[3 * i + 2]; + var sx = 0.0; + var sy = 0.0; + var sz = 0.0; + for (var q = start[i]; q < start[i + 1]; q++) { + final j = list[q]; + final dx = xi - p[3 * j]; + final dy = yi - p[3 * j + 1]; + final dz = zi - p[3 * j + 2]; + final r2 = dx * dx + dy * dy + dz * dz; + final ratio = _poly6(r2) / k.wq; + // Macklin's artificial pressure: a fiftieth of a constraint's worth. + final corr = -0.02 * ratio * ratio * ratio * ratio / k.restStiffness; + final f = + _spikyScale(math.sqrt(r2)) * (lambda[i] + lambda[j] + corr) * norm; + sx += dx * f; + sy += dy * f; + sz += dz * f; + } + delta[3 * i] = sx; + delta[3 * i + 1] = sy; + delta[3 * i + 2] = sz; + } + } + + @override + void viscosity( + Float64List p, + Float64List v, + Int32List start, + Int32List list, + int n, + double share, + Float64List smoothed, + ) { + final norm = k.norm; + for (var i = 0; i < n; i++) { + final xi = p[3 * i]; + final yi = p[3 * i + 1]; + final zi = p[3 * i + 2]; + final vx = v[3 * i]; + final vy = v[3 * i + 1]; + final vz = v[3 * i + 2]; + var sx = vx; + var sy = vy; + var sz = vz; + for (var q = start[i]; q < start[i + 1]; q++) { + final j = list[q]; + final dx = xi - p[3 * j]; + final dy = yi - p[3 * j + 1]; + final dz = zi - p[3 * j + 2]; + final w = _poly6(dx * dx + dy * dy + dz * dz) * norm * share; + sx += (v[3 * j] - vx) * w; + sy += (v[3 * j + 1] - vy) * w; + sz += (v[3 * j + 2] - vz) * w; + } + smoothed[3 * i] = sx; + smoothed[3 * i + 1] = sy; + smoothed[3 * i + 2] = sz; + } + } +} From 6f763a137c938b51df0df6043c716f93f85f0774 Mon Sep 17 00:00:00 2001 From: Dmitrii Zolotov Date: Sat, 3 Oct 2026 16:24:30 +0300 Subject: [PATCH 22/34] feat: Run the particle fluid's kernels natively where a C compiler is flutter3d_physics now builds src/pbf_kernels.c with a build hook and binds it through @Native, passing the fluid's own buffers by address. A fluid made with native: true, or a FluidWorld with nativeKernels: true, runs its pair loops and its neighbour search in C, summing two neighbours at a time with the compiler's vector extensions; held to the Dart kernels within a part in 10^12 per kernel. Without a compiler the hook builds nothing and the fluid runs on Dart, as it does on the web. The neighbour search is now a sort by cell instead of a map of lists, in Dart too, with the same rows in the same order, so the Dart path steps exactly as before. --- ARCHITECTURE.md | 2 +- README.md | 2 +- packages/flutter3d_physics/hook/build.dart | 43 ++ .../lib/flutter3d_physics.dart | 2 + .../lib/src/fluid/fluid_world.dart | 13 +- .../lib/src/fluid/native/pbf_backend.dart | 2 + .../lib/src/fluid/native/pbf_native.dart | 393 ++++++++++++++++++ .../lib/src/fluid/native/pbf_none.dart | 8 + .../lib/src/fluid/particle_fluid.dart | 109 ++--- .../lib/src/fluid/pbf_kernels.dart | 133 ++++++ packages/flutter3d_physics/pubspec.yaml | 7 + packages/flutter3d_physics/src/pbf_kernels.c | 344 +++++++++++++++ .../test/fluid/native_kernels_test.dart | 174 ++++++++ site/content/quickstart.md | 2 +- site/content/reference/testing.md | 8 +- 15 files changed, 1157 insertions(+), 85 deletions(-) create mode 100644 packages/flutter3d_physics/hook/build.dart create mode 100644 packages/flutter3d_physics/lib/src/fluid/native/pbf_backend.dart create mode 100644 packages/flutter3d_physics/lib/src/fluid/native/pbf_native.dart create mode 100644 packages/flutter3d_physics/lib/src/fluid/native/pbf_none.dart create mode 100644 packages/flutter3d_physics/src/pbf_kernels.c create mode 100644 packages/flutter3d_physics/test/fluid/native_kernels_test.dart diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 4193cf693..275cb129d 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -2691,7 +2691,7 @@ storage. |---|---| | Style | `dart format` | | Analysis | `flutter analyze` clean across the workspace, no warnings | -| Unit tests | **11363 tests** across 43 packages and 10 applications | +| Unit tests | **11367 tests** across 43 packages and 10 applications | | Structure rules | 35, `dart run tool/structure.dart`, the first CI step | | CI | GitHub Actions over `tool/ci.sh`, on `ubuntu-latest`, with no graphics card | diff --git a/README.md b/README.md index 6ab7a58af..f1f365bb9 100644 --- a/README.md +++ b/README.md @@ -158,7 +158,7 @@ Or one package at a time: (cd packages/flutter3d_physics && dart test) # plain Dart, no Flutter needed ``` -There are 11363 tests across forty-three packages and nine applications. The +There are 11367 tests across forty-three packages and nine applications. The only ones that need a GPU are the Impeller half of the golden set. The other half is rendered by the software backend, which is what makes 90 scenes checkable in a headless run. diff --git a/packages/flutter3d_physics/hook/build.dart b/packages/flutter3d_physics/hook/build.dart new file mode 100644 index 000000000..f7f09f297 --- /dev/null +++ b/packages/flutter3d_physics/hook/build.dart @@ -0,0 +1,43 @@ +// Builds the native Position Based Fluids kernels, `src/pbf_kernels.c`, +// into a library `NativePbfKernels` binds to through `@Native`. +// +// **Never the reason a build fails.** The C compiler is the machine's own: +// Xcode's, the NDK's, MSVC's, the system clang or gcc. Where there is none, +// or the build of the library fails for any other reason, this says so and +// builds nothing, and the fluid runs on the Dart kernels it would have run +// on anyway; `NativePbfKernels.available` is false. +// +// **Optimised, and vectorised where it can be**: -O3, and on x86-64 the +// SSE2 every such processor has. The kernels sum two neighbours at a time +// with the compiler's vector extensions, which is why they are held to the +// Dart reference within a tolerance rather than to the bit. +import 'package:code_assets/code_assets.dart'; +import 'package:hooks/hooks.dart'; +import 'package:logging/logging.dart'; +import 'package:native_toolchain_c/native_toolchain_c.dart'; + +void main(List arguments) async { + await build(arguments, (input, output) async { + if (!input.config.buildCodeAssets) return; + final logger = Logger('flutter3d_physics') + // A hook's output is its standard output; there is no other logger. + // ignore: avoid_print + ..onRecord.listen((record) => print(record.message)); + // Windows builds with MSVC, whose flags are its own. + final msvc = input.config.code.targetOS == OS.windows; + final builder = CBuilder.library( + name: 'flutter3d_physics_native', + assetName: 'src/fluid/native/pbf_native.dart', + sources: ['src/pbf_kernels.c'], + flags: msvc ? const ['/O2'] : const ['-O3', '-fno-math-errno'], + ); + try { + await builder.run(input: input, output: output, logger: logger); + } on Object catch (error) { + logger.warning( + 'flutter3d_physics: no native fluid kernels ($error); the fluid ' + 'runs on its Dart kernels.', + ); + } + }); +} diff --git a/packages/flutter3d_physics/lib/flutter3d_physics.dart b/packages/flutter3d_physics/lib/flutter3d_physics.dart index 82d82edd0..8673f51cc 100644 --- a/packages/flutter3d_physics/lib/flutter3d_physics.dart +++ b/packages/flutter3d_physics/lib/flutter3d_physics.dart @@ -49,8 +49,10 @@ export 'src/fluid/gravity_field.dart'; export 'src/fluid/jet.dart'; export 'src/fluid/liquid_body.dart'; export 'src/fluid/liquid_layer.dart'; +export 'src/fluid/native/pbf_backend.dart' show nativePbfAvailable; export 'src/fluid/outflow.dart'; export 'src/fluid/particle_fluid.dart'; +export 'src/fluid/pbf_kernels.dart'; export 'src/fluid/pipe.dart'; export 'src/fluid/puddle.dart'; export 'src/fluid/vessel_shape.dart'; diff --git a/packages/flutter3d_physics/lib/src/fluid/fluid_world.dart b/packages/flutter3d_physics/lib/src/fluid/fluid_world.dart index 58c829ee2..f632d6403 100644 --- a/packages/flutter3d_physics/lib/src/fluid/fluid_world.dart +++ b/packages/flutter3d_physics/lib/src/fluid/fluid_world.dart @@ -30,6 +30,7 @@ final class FluidWorld { this.floor, Atmosphere? atmosphere, this.field, + this.nativeKernels = false, }) : atmosphere = atmosphere ?? Atmosphere.standard(); /// Gravity that differs from place to place, when there is some: then @@ -37,6 +38,11 @@ final class FluidWorld { /// it is, and [gravity] is not read. Null, every one feels [gravity]. final GravityField? field; + /// Whether drops run their loops over pairs natively where that was built: + /// see [ParticleFluid.native]. Off, the world steps the same to the bit + /// on every machine. + final bool nativeKernels; + /// The gravity at [point]. Vector3 gravityAt(Vector3 point) => field?.at(point) ?? gravity; @@ -171,8 +177,11 @@ final class FluidWorld { particles .putIfAbsent( drop.medium.name, - () => - ParticleFluid(medium: drop.medium, spacing: particleSpacing), + () => ParticleFluid( + medium: drop.medium, + spacing: particleSpacing, + native: nativeKernels, + ), ) .inject( drop.volume, diff --git a/packages/flutter3d_physics/lib/src/fluid/native/pbf_backend.dart b/packages/flutter3d_physics/lib/src/fluid/native/pbf_backend.dart new file mode 100644 index 000000000..6be1db8d3 --- /dev/null +++ b/packages/flutter3d_physics/lib/src/fluid/native/pbf_backend.dart @@ -0,0 +1,2 @@ +// The native kernels where `dart:ffi` is, none where it is not. +export 'pbf_none.dart' if (dart.library.ffi) 'pbf_native.dart'; diff --git a/packages/flutter3d_physics/lib/src/fluid/native/pbf_native.dart b/packages/flutter3d_physics/lib/src/fluid/native/pbf_native.dart new file mode 100644 index 000000000..3ed4e41e7 --- /dev/null +++ b/packages/flutter3d_physics/lib/src/fluid/native/pbf_native.dart @@ -0,0 +1,393 @@ +// The native Position Based Fluids kernels, `src/pbf_kernels.c`, as built by +// `hook/build.dart`, bound through `@Native` and passed the fluid's own +// buffers by address: nothing is copied in or out. +import 'dart:ffi'; +import 'dart:typed_data'; + +import '../pbf_kernels.dart'; + +@Native(symbol: 'f3d_pbf_version', isLeaf: true) +external int _version(); + +@Native< + Void Function( + Pointer, + Pointer, + Pointer, + Int32, + Pointer, + Pointer, + ) +>(symbol: 'f3d_pbf_densities', isLeaf: true) +external void _densities( + Pointer x, + Pointer start, + Pointer list, + int n, + Pointer k, + Pointer density, +); + +@Native< + Void Function( + Pointer, + Pointer, + Pointer, + Int32, + Pointer, + Pointer, + Pointer, + ) +>(symbol: 'f3d_pbf_normals', isLeaf: true) +external void _normals( + Pointer x, + Pointer start, + Pointer list, + int n, + Pointer k, + Pointer density, + Pointer normal, +); + +@Native< + Void Function( + Pointer, + Pointer, + Pointer, + Int32, + Pointer, + Pointer, + Pointer, + Pointer, + Pointer, + Pointer, + Double, + ) +>(symbol: 'f3d_pbf_forces', isLeaf: true) +external void _forces( + Pointer x, + Pointer start, + Pointer list, + int n, + Pointer k, + Pointer density, + Pointer normal, + Pointer before, + Pointer after, + Pointer v, + double dt, +); + +@Native< + Void Function( + Pointer, + Pointer, + Pointer, + Int32, + Pointer, + Pointer, + ) +>(symbol: 'f3d_pbf_lambdas', isLeaf: true) +external void _lambdas( + Pointer p, + Pointer start, + Pointer list, + int n, + Pointer k, + Pointer lambda, +); + +@Native< + Void Function( + Pointer, + Pointer, + Pointer, + Int32, + Pointer, + Pointer, + Pointer, + ) +>(symbol: 'f3d_pbf_deltas', isLeaf: true) +external void _deltas( + Pointer p, + Pointer start, + Pointer list, + int n, + Pointer k, + Pointer lambda, + Pointer delta, +); + +@Native< + Void Function( + Pointer, + Pointer, + Pointer, + Pointer, + Int32, + Pointer, + Double, + Pointer, + ) +>(symbol: 'f3d_pbf_viscosity', isLeaf: true) +external void _viscosity( + Pointer p, + Pointer v, + Pointer start, + Pointer list, + int n, + Pointer k, + double share, + Pointer smoothed, +); + +@Native< + Int32 Function( + Pointer, + Int32, + Double, + Pointer, + Pointer, + Int32, + Pointer, + ) +>(symbol: 'f3d_pbf_neighbours', isLeaf: true) +external int _neighbours( + Pointer x, + int n, + double radius, + Pointer start, + Pointer list, + int capacity, + Pointer scratch, +); + +@Native< + Int32 Function( + Pointer, + Int32, + Pointer, + Pointer, + Double, + Pointer, + Pointer, + ) +>(symbol: 'f3d_pbf_within', isLeaf: true) +external int _within( + Pointer x, + int n, + Pointer start, + Pointer list, + double radius, + Pointer outStart, + Pointer out, +); + +/// Whether the native kernels were built and load: false where the build +/// had no C compiler, and asked once. +final bool nativePbfAvailable = () { + try { + return _version() == 3; + } on Object { + return false; + } +}(); + +/// [PbfKernels] in C, vectorised: [DartPbfKernels]' results to within a +/// tolerance, several times as fast. +final class NativePbfKernels implements PbfKernels { + NativePbfKernels(PbfConstants k) + : _k = Float64List.fromList([ + k.h, + k.h2, + k.restDensity, + k.mass, + k.norm, + k.gamma, + k.restStiffness, + k.poly6, + k.spiky, + k.cohesion, + k.h6, + k.wq, + ]); + + final Float64List _k; + + // Kept between calls, grown as the fluid does. + Int32List _list = Int32List(1024); + Int64List _scratch = Int64List(5); + + @override + (Int32List, Int32List) within( + Float64List x, + int n, + Int32List start, + Int32List list, + double radius, + ) { + final outStart = Int32List(n + 1); + final out = Int32List(list.length + 1); + final count = _within( + x.address, + n, + start.address, + _rows(list).address, + radius, + outStart.address, + out.address, + ); + return (outStart, Int32List.sublistView(out, 0, count)); + } + + @override + (Int32List, Int32List) neighbours(Float64List x, int n, double radius) { + final start = Int32List(n + 1); + if (n == 0) return (start, Int32List(0)); + if (_scratch.length < 5 * n) _scratch = Int64List(5 * n); + var count = _neighbours( + x.address, + n, + radius, + start.address, + _list.address, + _list.length, + _scratch.address, + ); + if (count > _list.length) { + _list = Int32List(count * 2); + count = _neighbours( + x.address, + n, + radius, + start.address, + _list.address, + _list.length, + _scratch.address, + ); + } + return (start, Int32List.fromList(Int32List.sublistView(_list, 0, count))); + } + + // A list with nothing in it has no address to give; one element stands in. + static final Int32List _none = Int32List(1); + static Int32List _rows(Int32List list) => list.isEmpty ? _none : list; + + @override + void densities( + Float64List x, + Int32List start, + Int32List list, + int n, + Float64List density, + ) => _densities( + x.address, + start.address, + _rows(list).address, + n, + _k.address, + density.address, + ); + + @override + void normals( + Float64List x, + Int32List start, + Int32List list, + int n, + Float64List density, + Float64List normal, + ) => _normals( + x.address, + start.address, + _rows(list).address, + n, + _k.address, + density.address, + normal.address, + ); + + @override + void forces( + Float64List x, + Int32List start, + Int32List list, + int n, + Float64List density, + Float64List normal, + Float64List before, + Float64List after, + Float64List v, + double dt, + ) => _forces( + x.address, + start.address, + _rows(list).address, + n, + _k.address, + density.address, + normal.address, + before.address, + after.address, + v.address, + dt, + ); + + @override + void lambdas( + Float64List p, + Int32List start, + Int32List list, + int n, + Float64List lambda, + ) => _lambdas( + p.address, + start.address, + _rows(list).address, + n, + _k.address, + lambda.address, + ); + + @override + void deltas( + Float64List p, + Int32List start, + Int32List list, + int n, + Float64List lambda, + Float64List delta, + ) => _deltas( + p.address, + start.address, + _rows(list).address, + n, + _k.address, + lambda.address, + delta.address, + ); + + @override + void viscosity( + Float64List p, + Float64List v, + Int32List start, + Int32List list, + int n, + double share, + Float64List smoothed, + ) => _viscosity( + p.address, + v.address, + start.address, + _rows(list).address, + n, + _k.address, + share, + smoothed.address, + ); +} + +/// The native kernels for [k], or null where there are none. +PbfKernels? nativePbfKernels(PbfConstants k) => + nativePbfAvailable ? NativePbfKernels(k) : null; diff --git a/packages/flutter3d_physics/lib/src/fluid/native/pbf_none.dart b/packages/flutter3d_physics/lib/src/fluid/native/pbf_none.dart new file mode 100644 index 000000000..3f5c5b118 --- /dev/null +++ b/packages/flutter3d_physics/lib/src/fluid/native/pbf_none.dart @@ -0,0 +1,8 @@ +// Where there is no `dart:ffi` (the web): no native kernels. +import '../pbf_kernels.dart'; + +/// Always false here. +const bool nativePbfAvailable = false; + +/// None here. +PbfKernels? nativePbfKernels(PbfConstants k) => null; diff --git a/packages/flutter3d_physics/lib/src/fluid/particle_fluid.dart b/packages/flutter3d_physics/lib/src/fluid/particle_fluid.dart index 97cbfe4b9..53e6f155e 100644 --- a/packages/flutter3d_physics/lib/src/fluid/particle_fluid.dart +++ b/packages/flutter3d_physics/lib/src/fluid/particle_fluid.dart @@ -7,6 +7,7 @@ import '../portable_math.dart'; import 'atmosphere.dart'; import 'fluid_medium.dart'; import 'jet.dart'; +import 'native/pbf_backend.dart'; import 'pbf_kernels.dart'; import 'wetting.dart'; @@ -69,6 +70,7 @@ final class ParticleFluid { required this.spacing, this.iterations = 4, this.substeps = 2, + this.native = false, }) : h = 2.0 * spacing { _gamma = _cohesionForWorkOfCohesion(); // The kernel summed over the lattice at rest: what a particle's density @@ -312,18 +314,25 @@ final class ParticleFluid { } } - /// What runs the loops over pairs: the Dart reference unless something - /// faster is put in its place. - late PbfKernels kernels = DartPbfKernels( - PbfConstants( + /// Whether to run the loops over pairs natively where that was built + /// ([nativePbfAvailable]): several times as fast, and the same to within + /// a tolerance rather than to the bit, so not for a world that must + /// replay exactly. + final bool native; + + /// What runs the loops over pairs: the Dart reference, or the native + /// kernels when [native] asks for them and they are there. + late PbfKernels kernels = () { + final k = PbfConstants( h: h, restDensity: medium.density, mass: _mass, norm: 1.0 / _latticeSum, gamma: _gamma, restStiffness: _restStiffness, - ), - ); + ); + return (native ? nativePbfKernels(k) : null) ?? DartPbfKernels(k); + }(); /// [points] as one flat buffer of x, y, z in turn. static Float64List _flat(List<_V> points) { @@ -349,20 +358,13 @@ final class ParticleFluid { /// The neighbours of each of [points] within the kernel's reach, as /// compressed rows: [PbfKernels]' layout. - (Int32List, Int32List) _rows(List<_V> points) { - final grid = _Grid(h, points); - final n = points.length; - final lists = [for (var i = 0; i < n; i++) grid.near(i, points)]; - final start = Int32List(n + 1); - for (var i = 0; i < n; i++) { - start[i + 1] = start[i] + lists[i].length; - } - final list = Int32List(start[n]); - for (var i = 0; i < n; i++) { - list.setAll(start[i], lists[i]); - } - return (start, list); - } + /// + /// Searched afresh each time. Candidates kept from one search to the next + /// (Verlet's list, half the reach again) were measured and cost more + /// here: drops landing while others still fall move apart faster than + /// any skin outlasts, and the wider search came round nearly every time. + (Int32List, Int32List) _rows(List<_V> points) => + kernels.neighbours(_flat(points), points.length, h); /// The air the particles are being stepped through, and each particle's /// drop's diameter: set at the start of a step, read by its substeps. @@ -396,10 +398,11 @@ final class ParticleFluid { return parent[i] = r; } - final grid = _Grid(h, _x); + final (start, list) = _rows(_x); final touching = 2.25 * spacing * spacing; for (var i = 0; i < n; i++) { - for (final j in grid.near(i, _x)) { + for (var q = start[i]; q < start[i + 1]; q++) { + final j = list[q]; if (_x[i].distance2(_x[j]) < touching) parent[root(i)] = root(j); } } @@ -496,8 +499,11 @@ final class ParticleFluid { // **Unless the drop's weight along the wall is more than its edge can // hold**, by Furmidge's σ·w·(cos θr − cos θa): then it slides, its // particles kept out of the wall and free along it. + // The neighbours at these places, found once: for which drop each + // particle is in, and for the forces. + final (start, list) = _rows(_x); final touching = [for (var i = 0; i < n; i++) _touching(_x[i], walls[i])]; - final held = _held(touching, gravity); + final held = _held(touching, gravity, start, list); final pinned = [ for (var i = 0; i < n; i++) held[i] ? touching[i]?.normal : null, ]; @@ -515,7 +521,6 @@ final class ParticleFluid { // Forces first: gravity, cohesion and curvature, on the velocities. final xs = _flat(_x); final vs = _flat(_v); - final (start, list) = _rows(_x); final density = Float64List(n); ker.densities(xs, start, list, n, density); final normal = Float64List(3 * n); @@ -645,6 +650,8 @@ final class ParticleFluid { List _held( List<({_V normal, JetObstacle wall})?> touching, _V gravity, + Int32List start, + Int32List list, ) { final n = _x.length; final out = List.filled(n, false); @@ -659,10 +666,10 @@ final class ParticleFluid { } // One drop: particles nearer each other than a spacing and a half. - final grid = _Grid(h, _x); final close = 2.25 * spacing * spacing; for (var i = 0; i < n; i++) { - for (final j in grid.near(i, _x)) { + for (var q = start[i]; q < start[i + 1]; q++) { + final j = list[q]; if (_x[i].distance2(_x[j]) < close) parent[root(i)] = root(j); } } @@ -821,56 +828,6 @@ final class ParticleFluid { static double _pow9(double x) => _pow6(x) * x * x * x; } -/// A uniform grid of cells as wide as the kernel, for finding neighbours. -final class _Grid { - _Grid(this.cell, List<_V> points) { - for (var i = 0; i < points.length; i++) { - _cells.putIfAbsent(_key(points[i]), () => []).add(i); - } - } - - final double cell; - final Map> _cells = {}; - - int _key(_V p) => - _pack((p.x / cell).floor(), (p.y / cell).floor(), (p.z / cell).floor()); - - /// By multiplication, as `spatial_grid.dart` does, and not by shifting - /// into the high bits: on the web an int's bitwise operations are 32 bits - /// wide, `x << 42` kept almost nothing of `x`, cells far apart shared a - /// key, a particle met the same neighbour several times over, and the - /// liquid read as many times its density and flew apart. Each index is - /// held to ±2¹⁶ cells and the key under 2⁵¹, which a double holds exactly. - static int _pack(int x, int y, int z) { - const span = 1 << 17; - const half = 1 << 16; - int wrap(int v) => (v + half) % span; - return (wrap(x) * span + wrap(y)) * span + wrap(z); - } - - /// The points within [cell] of point [i], itself left out. - List near(int i, List<_V> points) { - final p = points[i]; - final cx = (p.x / cell).floor(); - final cy = (p.y / cell).floor(); - final cz = (p.z / cell).floor(); - final out = []; - final reach2 = cell * cell; - for (var dx = -1; dx <= 1; dx++) { - for (var dy = -1; dy <= 1; dy++) { - for (var dz = -1; dz <= 1; dz++) { - final list = _cells[_pack(cx + dx, cy + dy, cz + dz)]; - if (list == null) continue; - for (final j in list) { - if (j != i && points[j].distance2(p) < reach2) out.add(j); - } - } - } - } - return out; - } -} - /// A vector in double precision, for the solver's own arithmetic. final class _V { _V(this.x, this.y, this.z); diff --git a/packages/flutter3d_physics/lib/src/fluid/pbf_kernels.dart b/packages/flutter3d_physics/lib/src/fluid/pbf_kernels.dart index a41fd39e1..b08c399c8 100644 --- a/packages/flutter3d_physics/lib/src/fluid/pbf_kernels.dart +++ b/packages/flutter3d_physics/lib/src/fluid/pbf_kernels.dart @@ -17,6 +17,26 @@ import 'dart:typed_data'; /// the last bit. A native one, free to vectorise, is held to it within a /// tolerance instead. abstract interface class PbfKernels { + /// The neighbours of each of the [n] particles at [x] within [radius], at + /// least the kernel's reach, as compressed rows: in each row the cells + /// about the particle, cells [radius] wide, in x, then y, then z order + /// from −1 to 1, and within a cell by index. + (Int32List start, Int32List list) neighbours( + Float64List x, + int n, + double radius, + ); + + /// Of the rows [start] and [list], those within [radius] of each other at + /// [x], in the order they are in. + (Int32List start, Int32List list) within( + Float64List x, + int n, + Int32List start, + Int32List list, + double radius, + ); + /// Each particle's density, from its neighbours at [x]: ρ₀·ΣW/ΣW_rest. void densities( Float64List x, @@ -144,6 +164,119 @@ final class DartPbfKernels implements PbfKernels { final PbfConstants k; + /// A cell's three indices as one key, by multiplication rather than by + /// shifting into high bits: on the web an int's bitwise operations are 32 + /// bits wide. Each index is held to ±2¹⁶ cells and the key under 2⁵¹, + /// which a double holds exactly. + static double _pack(int x, int y, int z) { + const span = 1 << 17; + const half = 1 << 16; + int wrap(int v) => (v + half) % span; + return ((wrap(x) * span + wrap(y)) * span + wrap(z)).toDouble(); + } + + /// **Sorted by cell, then searched.** Each particle's cell key, the + /// particles ordered by key and then index, and for each particle the + /// run of every one of its 27 cells found by halving: no map of cells, + /// and no list made per particle. A map of lists, built and asked three + /// times a substep, was two thirds of what a cloud of drops cost. + @override + (Int32List, Int32List) within( + Float64List x, + int n, + Int32List start, + Int32List list, + double radius, + ) { + final reach2 = radius * radius; + final outStart = Int32List(n + 1); + final out = Int32List(list.length); + var count = 0; + for (var i = 0; i < n; i++) { + final xi = x[3 * i]; + final yi = x[3 * i + 1]; + final zi = x[3 * i + 2]; + for (var q = start[i]; q < start[i + 1]; q++) { + final j = list[q]; + final ex = x[3 * j] - xi; + final ey = x[3 * j + 1] - yi; + final ez = x[3 * j + 2] - zi; + if (ex * ex + ey * ey + ez * ez < reach2) out[count++] = j; + } + outStart[i + 1] = count; + } + return (outStart, Int32List.sublistView(out, 0, count)); + } + + @override + (Int32List, Int32List) neighbours(Float64List x, int n, double radius) { + final h = radius; + final cx = Int32List(n); + final cy = Int32List(n); + final cz = Int32List(n); + final keys = Float64List(n); + for (var i = 0; i < n; i++) { + cx[i] = (x[3 * i] / h).floor(); + cy[i] = (x[3 * i + 1] / h).floor(); + cz[i] = (x[3 * i + 2] / h).floor(); + keys[i] = _pack(cx[i], cy[i], cz[i]); + } + final order = List.generate(n, (i) => i) + ..sort((a, b) { + final c = keys[a].compareTo(keys[b]); + return c != 0 ? c : a - b; + }); + final sorted = Float64List(n); + for (var q = 0; q < n; q++) { + sorted[q] = keys[order[q]]; + } + int first(double key) { + var lo = 0; + var hi = n; + while (lo < hi) { + final mid = (lo + hi) >> 1; + if (sorted[mid] < key) { + lo = mid + 1; + } else { + hi = mid; + } + } + return lo; + } + + final start = Int32List(n + 1); + var list = Int32List(n * 16 + 16); + var count = 0; + final reach2 = h * h; + for (var i = 0; i < n; i++) { + final xi = x[3 * i]; + final yi = x[3 * i + 1]; + final zi = x[3 * i + 2]; + for (var dx = -1; dx <= 1; dx++) { + for (var dy = -1; dy <= 1; dy++) { + for (var dz = -1; dz <= 1; dz++) { + final key = _pack(cx[i] + dx, cy[i] + dy, cz[i] + dz); + for (var q = first(key); q < n && sorted[q] == key; q++) { + final j = order[q]; + if (j == i) continue; + final ex = x[3 * j] - xi; + final ey = x[3 * j + 1] - yi; + final ez = x[3 * j + 2] - zi; + // As `_V.distance2` reads it: the other point less this one. + if (ex * ex + ey * ey + ez * ez >= reach2) continue; + if (count == list.length) { + list = Int32List(list.length * 2)..setAll(0, list); + } + list[count++] = j; + } + } + } + } + start[i + 1] = count; + } + return (start, Int32List.sublistView(list, 0, count)); + } + double _poly6(double r2) { if (r2 >= k.h2) return 0.0; final d = k.h2 - r2; diff --git a/packages/flutter3d_physics/pubspec.yaml b/packages/flutter3d_physics/pubspec.yaml index b24693503..391c4ac9f 100644 --- a/packages/flutter3d_physics/pubspec.yaml +++ b/packages/flutter3d_physics/pubspec.yaml @@ -16,6 +16,13 @@ environment: dependencies: vector_math: ^2.2.0 + # The native kernels' build: `hook/build.dart` compiles `src/*.c` with + # whatever C compiler the machine has, and builds nothing, without + # failing, where it has none. See `lib/src/fluid/native/`. + code_assets: ^2.1.0 + hooks: ^2.0.0 + logging: ^1.3.0 + native_toolchain_c: ^0.19.5 dev_dependencies: diff --git a/packages/flutter3d_physics/src/pbf_kernels.c b/packages/flutter3d_physics/src/pbf_kernels.c new file mode 100644 index 000000000..fa3732f8d --- /dev/null +++ b/packages/flutter3d_physics/src/pbf_kernels.c @@ -0,0 +1,344 @@ +// The Position Based Fluids pair loops of `lib/src/fluid/pbf_kernels.dart`, +// in C: the same five kernels over the same flat buffers, for +// `NativePbfKernels` to call through `@Native`. +// +// **Held to the Dart reference within a tolerance, not to the bit.** The +// neighbours of a particle are summed two at a time where the compiler has +// vector extensions (clang and gcc, on NEON and SSE2 alike), which adds in +// another order than Dart's one at a time; a run is the same run to about a +// part in 10¹², not exactly. Where the world must replay to the bit, the +// Dart kernels are the ones to step it with. +// +// The constants come as one array, in this order: +// 0 h, 1 h², 2 ρ₀, 3 m, 4 norm, 5 γ, 6 rest stiffness, +// 7 poly6, 8 spiky, 9 cohesion, 10 h⁶, 11 W(0.3h). + +#include +#include +#include + +#if defined(__clang__) || defined(__GNUC__) +#define F3D_VECTOR 1 +typedef double f3d_d2 __attribute__((vector_size(16))); +#else +#define F3D_VECTOR 0 +#endif + +#if defined(_WIN32) +#define F3D_EXPORT __declspec(dllexport) +#else +#define F3D_EXPORT __attribute__((visibility("default"))) +#endif + +enum { + K_H = 0, + K_H2, + K_RHO0, + K_MASS, + K_NORM, + K_GAMMA, + K_REST_STIFFNESS, + K_POLY6, + K_SPIKY, + K_COHESION, + K_H6, + K_WQ, +}; + +static inline double poly6(const double* k, double r2) { + if (r2 >= k[K_H2]) return 0.0; + const double d = k[K_H2] - r2; + return k[K_POLY6] * d * d * d; +} + +static inline double spiky_scale(const double* k, double r) { + if (r <= 1e-12 || r >= k[K_H]) return 0.0; + const double hr = k[K_H] - r; + return k[K_SPIKY] * hr * hr / r; +} + +static inline double cohesion(const double* k, double r) { + const double h = k[K_H]; + if (r >= h || r <= 0.0) return 0.0; + const double a = (h - r) * (h - r) * (h - r) * r * r * r; + if (2.0 * r > h) return k[K_COHESION] * a; + return k[K_COHESION] * (2.0 * a - k[K_H6] / 64.0); +} + +#if F3D_VECTOR +// The kernel weight of two squared distances at once, a lane each. +static inline f3d_d2 poly6_2(const double* k, f3d_d2 r2) { + const f3d_d2 h2 = {k[K_H2], k[K_H2]}; + f3d_d2 d = h2 - r2; + d = (f3d_d2){d[0] > 0.0 ? d[0] : 0.0, d[1] > 0.0 ? d[1] : 0.0}; + const f3d_d2 c = {k[K_POLY6], k[K_POLY6]}; + return c * d * d * d; +} +#endif + +F3D_EXPORT int32_t f3d_pbf_version(void) { return 3; } + +// Of the rows [start] and [list], those within [radius] at [x], in order, +// into [out_start] and [out] (room for as many as [list] has). +F3D_EXPORT int32_t f3d_pbf_within(const double* x, int32_t n, + const int32_t* start, const int32_t* list, + double radius, int32_t* out_start, + int32_t* out) { + const double reach2 = radius * radius; + int32_t count = 0; + out_start[0] = 0; + for (int32_t i = 0; i < n; i++) { + const double xi = x[3 * i], yi = x[3 * i + 1], zi = x[3 * i + 2]; + for (int32_t q = start[i]; q < start[i + 1]; q++) { + const int32_t j = list[q]; + const double ex = x[3 * j] - xi, ey = x[3 * j + 1] - yi, + ez = x[3 * j + 2] - zi; + if (ex * ex + ey * ey + ez * ez < reach2) out[count++] = j; + } + out_start[i + 1] = count; + } + return count; +} + +// ----------------------------------------------------------- neighbours + +static int64_t pack_cell(int64_t x, int64_t y, int64_t z) { + const int64_t span = (int64_t)1 << 17, half = (int64_t)1 << 16; +#define F3D_WRAP(v) ((((v) + half) % span + span) % span) + return (F3D_WRAP(x) * span + F3D_WRAP(y)) * span + F3D_WRAP(z); +#undef F3D_WRAP +} + +typedef struct { + int64_t key; + int64_t index; +} f3d_cell_entry; + +static int compare_entries(const void* a, const void* b) { + const f3d_cell_entry* p = (const f3d_cell_entry*)a; + const f3d_cell_entry* q = (const f3d_cell_entry*)b; + if (p->key != q->key) return p->key < q->key ? -1 : 1; + return p->index < q->index ? -1 : (p->index > q->index ? 1 : 0); +} + +// The neighbours of each particle within h, as compressed rows, the same +// order as the Dart kernel's: cells by x, y, z from −1 to 1, within a cell +// by index. Writes at most [capacity] into [list] and returns how many there +// are: called again with room for that when it is more. [scratch] holds +// 5·n int64s, the caller's own: nothing here is shared between calls, so +// two isolates may step two fluids at once. +F3D_EXPORT int32_t f3d_pbf_neighbours(const double* x, int32_t n, + double radius, int32_t* start, + int32_t* list, int32_t capacity, + int64_t* scratch) { + const double h = radius; + const double reach2 = h * h; + int64_t* cx = scratch; + int64_t* cy = scratch + n; + int64_t* cz = scratch + 2 * n; + // Two words an entry, in the scratch's last 2·n. + f3d_cell_entry* entries = (f3d_cell_entry*)(scratch + 3 * n); + for (int32_t i = 0; i < n; i++) { + cx[i] = (int64_t)floor(x[3 * i] / h); + cy[i] = (int64_t)floor(x[3 * i + 1] / h); + cz[i] = (int64_t)floor(x[3 * i + 2] / h); + entries[i].key = pack_cell(cx[i], cy[i], cz[i]); + entries[i].index = i; + } + qsort(entries, (size_t)n, sizeof(f3d_cell_entry), compare_entries); + int32_t count = 0; + start[0] = 0; + for (int32_t i = 0; i < n; i++) { + const double xi = x[3 * i], yi = x[3 * i + 1], zi = x[3 * i + 2]; + for (int64_t dx = -1; dx <= 1; dx++) { + for (int64_t dy = -1; dy <= 1; dy++) { + for (int64_t dz = -1; dz <= 1; dz++) { + const int64_t key = pack_cell(cx[i] + dx, cy[i] + dy, cz[i] + dz); + int32_t lo = 0, hi = n; + while (lo < hi) { + const int32_t mid = (lo + hi) >> 1; + if (entries[mid].key < key) { + lo = mid + 1; + } else { + hi = mid; + } + } + for (int32_t q = lo; q < n && entries[q].key == key; q++) { + const int32_t j = (int32_t)entries[q].index; + if (j == i) continue; + const double ex = x[3 * j] - xi, ey = x[3 * j + 1] - yi, + ez = x[3 * j + 2] - zi; + if (ex * ex + ey * ey + ez * ez >= reach2) continue; + if (count < capacity) list[count] = j; + count++; + } + } + } + } + start[i + 1] = count; + } + return count; +} + +F3D_EXPORT void f3d_pbf_densities(const double* x, const int32_t* start, + const int32_t* list, int32_t n, + const double* k, double* density) { + const double self = poly6(k, 0.0); + for (int32_t i = 0; i < n; i++) { + const double xi = x[3 * i], yi = x[3 * i + 1], zi = x[3 * i + 2]; + int32_t q = start[i]; + const int32_t end = start[i + 1]; + double w = self; +#if F3D_VECTOR + f3d_d2 acc = {0.0, 0.0}; + for (; q + 2 <= end; q += 2) { + const int32_t a = list[q], b = list[q + 1]; + const f3d_d2 dx = {xi - x[3 * a], xi - x[3 * b]}; + const f3d_d2 dy = {yi - x[3 * a + 1], yi - x[3 * b + 1]}; + const f3d_d2 dz = {zi - x[3 * a + 2], zi - x[3 * b + 2]}; + acc += poly6_2(k, dx * dx + dy * dy + dz * dz); + } + w += acc[0] + acc[1]; +#endif + for (; q < end; q++) { + const int32_t j = list[q]; + const double dx = xi - x[3 * j], dy = yi - x[3 * j + 1], + dz = zi - x[3 * j + 2]; + w += poly6(k, dx * dx + dy * dy + dz * dz); + } + density[i] = k[K_RHO0] * w * k[K_NORM]; + } +} + +F3D_EXPORT void f3d_pbf_normals(const double* x, const int32_t* start, + const int32_t* list, int32_t n, + const double* k, const double* density, + double* normal) { + for (int32_t i = 0; i < n; i++) { + const double xi = x[3 * i], yi = x[3 * i + 1], zi = x[3 * i + 2]; + double nx = 0.0, ny = 0.0, nz = 0.0; + for (int32_t q = start[i]; q < start[i + 1]; q++) { + const int32_t j = list[q]; + const double dx = xi - x[3 * j], dy = yi - x[3 * j + 1], + dz = zi - x[3 * j + 2]; + const double f = spiky_scale(k, sqrt(dx * dx + dy * dy + dz * dz)) * + k[K_H] * k[K_MASS] / density[j]; + nx += dx * f; + ny += dy * f; + nz += dz * f; + } + normal[3 * i] = nx; + normal[3 * i + 1] = ny; + normal[3 * i + 2] = nz; + } +} + +F3D_EXPORT void f3d_pbf_forces(const double* x, const int32_t* start, + const int32_t* list, int32_t n, + const double* k, const double* density, + const double* normal, const double* before, + const double* after, double* v, double dt) { + const double rho0 = k[K_RHO0]; + for (int32_t i = 0; i < n; i++) { + const double xi = x[3 * i], yi = x[3 * i + 1], zi = x[3 * i + 2]; + double ax = before[3 * i], ay = before[3 * i + 1], az = before[3 * i + 2]; + for (int32_t q = start[i]; q < start[i + 1]; q++) { + const int32_t j = list[q]; + const double dx = xi - x[3 * j], dy = yi - x[3 * j + 1], + dz = zi - x[3 * j + 2]; + const double r = sqrt(dx * dx + dy * dy + dz * dz); + if (r < 1e-12) continue; + const double kk = 2.0 * rho0 / (density[i] + density[j]); + const double c = -kk * k[K_GAMMA] * k[K_MASS] * cohesion(k, r) / r; + const double t = -kk * k[K_GAMMA]; + ax += dx * c + (normal[3 * i] - normal[3 * j]) * t; + ay += dy * c + (normal[3 * i + 1] - normal[3 * j + 1]) * t; + az += dz * c + (normal[3 * i + 2] - normal[3 * j + 2]) * t; + } + ax += after[3 * i]; + ay += after[3 * i + 1]; + az += after[3 * i + 2]; + v[3 * i] += ax * dt; + v[3 * i + 1] += ay * dt; + v[3 * i + 2] += az * dt; + } +} + +F3D_EXPORT void f3d_pbf_lambdas(const double* p, const int32_t* start, + const int32_t* list, int32_t n, + const double* k, double* lambda) { + const double norm = k[K_NORM]; + const double self = poly6(k, 0.0); + for (int32_t i = 0; i < n; i++) { + const double xi = p[3 * i], yi = p[3 * i + 1], zi = p[3 * i + 2]; + double w = self, sum2 = 0.0, gx = 0.0, gy = 0.0, gz = 0.0; + for (int32_t q = start[i]; q < start[i + 1]; q++) { + const int32_t j = list[q]; + const double dx = xi - p[3 * j], dy = yi - p[3 * j + 1], + dz = zi - p[3 * j + 2]; + const double r2 = dx * dx + dy * dy + dz * dz; + w += poly6(k, r2); + const double f = spiky_scale(k, sqrt(r2)) * norm; + sum2 += r2 * f * f; + gx += dx * f; + gy += dy * f; + gz += dz * f; + } + sum2 += gx * gx + gy * gy + gz * gz; + double c = w * norm - 1.0; + if (c < 0.0) c = 0.0; + lambda[i] = -c / (sum2 + 1e-6 * norm * norm / (k[K_H] * k[K_H])); + } +} + +F3D_EXPORT void f3d_pbf_deltas(const double* p, const int32_t* start, + const int32_t* list, int32_t n, + const double* k, const double* lambda, + double* delta) { + const double norm = k[K_NORM]; + for (int32_t i = 0; i < n; i++) { + const double xi = p[3 * i], yi = p[3 * i + 1], zi = p[3 * i + 2]; + double sx = 0.0, sy = 0.0, sz = 0.0; + for (int32_t q = start[i]; q < start[i + 1]; q++) { + const int32_t j = list[q]; + const double dx = xi - p[3 * j], dy = yi - p[3 * j + 1], + dz = zi - p[3 * j + 2]; + const double r2 = dx * dx + dy * dy + dz * dz; + const double ratio = poly6(k, r2) / k[K_WQ]; + const double corr = + -0.02 * ratio * ratio * ratio * ratio / k[K_REST_STIFFNESS]; + const double f = + spiky_scale(k, sqrt(r2)) * (lambda[i] + lambda[j] + corr) * norm; + sx += dx * f; + sy += dy * f; + sz += dz * f; + } + delta[3 * i] = sx; + delta[3 * i + 1] = sy; + delta[3 * i + 2] = sz; + } +} + +F3D_EXPORT void f3d_pbf_viscosity(const double* p, const double* v, + const int32_t* start, const int32_t* list, + int32_t n, const double* k, double share, + double* smoothed) { + const double norm = k[K_NORM]; + for (int32_t i = 0; i < n; i++) { + const double xi = p[3 * i], yi = p[3 * i + 1], zi = p[3 * i + 2]; + const double vx = v[3 * i], vy = v[3 * i + 1], vz = v[3 * i + 2]; + double sx = vx, sy = vy, sz = vz; + for (int32_t q = start[i]; q < start[i + 1]; q++) { + const int32_t j = list[q]; + const double dx = xi - p[3 * j], dy = yi - p[3 * j + 1], + dz = zi - p[3 * j + 2]; + const double w = poly6(k, dx * dx + dy * dy + dz * dz) * norm * share; + sx += (v[3 * j] - vx) * w; + sy += (v[3 * j + 1] - vy) * w; + sz += (v[3 * j + 2] - vz) * w; + } + smoothed[3 * i] = sx; + smoothed[3 * i + 1] = sy; + smoothed[3 * i + 2] = sz; + } +} diff --git a/packages/flutter3d_physics/test/fluid/native_kernels_test.dart b/packages/flutter3d_physics/test/fluid/native_kernels_test.dart new file mode 100644 index 000000000..7884ffbe1 --- /dev/null +++ b/packages/flutter3d_physics/test/fluid/native_kernels_test.dart @@ -0,0 +1,174 @@ +import 'dart:math' as math; +import 'dart:typed_data'; + +import 'package:flutter3d_physics/flutter3d_physics.dart'; +import 'package:test/test.dart'; +import 'package:vector_math/vector_math.dart'; + +/// A loose cloud of [n] particles about a millimetre apart, the same every +/// run, and its neighbours within [h] as compressed rows. +(Float64List, Int32List, Int32List) _cloud(int n, double h) { + final random = math.Random(7); + final x = Float64List(3 * n); + for (var i = 0; i < 3 * n; i++) { + x[i] = random.nextDouble() * 0.006; + } + final rows = >[ + for (var i = 0; i < n; i++) + [ + for (var j = 0; j < n; j++) + if (j != i && + math.pow(x[3 * i] - x[3 * j], 2) + + math.pow(x[3 * i + 1] - x[3 * j + 1], 2) + + math.pow(x[3 * i + 2] - x[3 * j + 2], 2) < + h * h) + j, + ], + ]; + final start = Int32List(n + 1); + for (var i = 0; i < n; i++) { + start[i + 1] = start[i] + rows[i].length; + } + final list = Int32List(start[n]); + for (var i = 0; i < n; i++) { + list.setAll(start[i], rows[i]); + } + return (x, start, list); +} + +void _close(Float64List a, Float64List b) { + var scale = 0.0; + for (final v in a) { + scale = math.max(scale, v.abs()); + } + for (var i = 0; i < a.length; i++) { + expect(b[i], closeTo(a[i], 1e-12 * scale + 1e-300), reason: 'entry $i'); + } +} + +void main() { + test('the native kernels are built here', () { + // On a machine with a C compiler the hook builds them; this one has. + expect(nativePbfAvailable, isTrue); + }); + + test('each native kernel matches the Dart one to a part in 10¹²', () { + final fluid = ParticleFluid(medium: FluidMedium.water, spacing: 0.001); + final native = ParticleFluid( + medium: FluidMedium.water, + spacing: 0.001, + native: true, + ); + final dart = fluid.kernels; + final c = native.kernels; + expect(c, isNot(isA())); + const n = 200; + final (x, start, list) = _cloud(n, fluid.h); + expect(list.length, greaterThan(n)); + + final d1 = Float64List(n); + final d2 = Float64List(n); + dart.densities(x, start, list, n, d1); + c.densities(x, start, list, n, d2); + _close(d1, d2); + + final n1 = Float64List(3 * n); + final n2 = Float64List(3 * n); + dart.normals(x, start, list, n, d1, n1); + c.normals(x, start, list, n, d1, n2); + _close(n1, n2); + + final before = Float64List(3 * n)..fillRange(0, 3 * n, -9.81); + final after = Float64List(3 * n)..fillRange(0, 3 * n, 0.1); + final v1 = Float64List(3 * n); + final v2 = Float64List(3 * n); + dart.forces(x, start, list, n, d1, n1, before, after, v1, 1e-4); + c.forces(x, start, list, n, d1, n1, before, after, v2, 1e-4); + _close(v1, v2); + + final l1 = Float64List(n); + final l2 = Float64List(n); + dart.lambdas(x, start, list, n, l1); + c.lambdas(x, start, list, n, l2); + _close(l1, l2); + + final p1 = Float64List(3 * n); + final p2 = Float64List(3 * n); + dart.deltas(x, start, list, n, l1, p1); + c.deltas(x, start, list, n, l1, p2); + _close(p1, p2); + + final s1 = Float64List(3 * n); + final s2 = Float64List(3 * n); + dart.viscosity(x, v1, start, list, n, 0.05, s1); + c.viscosity(x, v1, start, list, n, 0.05, s2); + _close(s1, s2); + }); + + test('both find the same neighbours, in the same order', () { + final fluid = ParticleFluid(medium: FluidMedium.water, spacing: 0.001); + final native = ParticleFluid( + medium: FluidMedium.water, + spacing: 0.001, + native: true, + ); + const n = 300; + final (x, start, list) = _cloud(n, fluid.h); + final (s1, l1) = fluid.kernels.neighbours(x, n, fluid.h); + final (s2, l2) = native.kernels.neighbours(x, n, fluid.h); + expect(s2, s1); + expect(l2, l1); + // And the same as every pair within reach, counted the slow way. + expect(l1.length, list.length); + expect(s1, start); + // Candidates half as far again, cut back to the reach, are the same + // pairs: each row the same set, in the candidates' own order. + for (final kernels in [fluid.kernels, native.kernels]) { + final (cs, cl) = kernels.neighbours(x, n, 1.5 * fluid.h); + expect(cl.length, greaterThan(list.length)); + final (ws, wl) = kernels.within(x, n, cs, cl, fluid.h); + expect(ws, start); + for (var i = 0; i < n; i++) { + expect( + wl.sublist(ws[i], ws[i + 1]).toSet(), + list.sublist(start[i], start[i + 1]).toSet(), + ); + } + } + }); + + test( + 'a drop run natively lands where the Dart one does, every drop of it', + () { + Vector3 run({required bool native}) { + final fluid = ParticleFluid( + medium: FluidMedium.water, + spacing: 0.001, + native: native, + )..inject(27e-9, Vector3(0, 0.01, 0), Vector3(0.05, 0, 0)); + final bench = [PlaneObstacle(normal: Vector3(0, 1, 0), offset: 0)]; + for (var i = 0; i < 120; i++) { + fluid.step(1 / 240, gravity: Vector3(0, -9.81, 0), obstacles: bench); + } + expect(fluid.volume, closeTo(27e-9, 1e-21)); + final centre = Vector3.zero(); + for (final p in fluid.positions) { + centre.add(p); + } + return centre..scale(1.0 / fluid.count); + } + + final reference = run(native: false); + final fast = run(native: true); + // **Not the same path: the same drop.** A step decides things — whether + // a particle touches the bench, whether its edge holds the drop — and a + // part in 10¹² either side of a threshold decides differently: the Dart + // run started a millionth of a micrometre over lands seventy-five + // micrometres off its own. So the two land as the same drop, on the + // bench, within a particle's spacing of each other, every drop of it + // there; to the bit is the Dart kernels' promise, not this. + expect(fast.y, lessThan(0.003)); + expect((fast - reference).length, lessThan(0.001)); + }, + ); +} diff --git a/site/content/quickstart.md b/site/content/quickstart.md index 93732614d..e11cbb000 100644 --- a/site/content/quickstart.md +++ b/site/content/quickstart.md @@ -91,7 +91,7 @@ tool/ci.sh # shaders, analyze, every test (cd packages/flutter3d_physics && dart test) # plain Dart, no Flutter needed ``` -There are 11363 tests across 43 packages and twelve applications, and only about thirty need a GPU: the Impeller half of the golden set. The other half renders through the software backend, so ninety scenes stay checkable in a headless run. +There are 11367 tests across 43 packages and twelve applications, and only about thirty need a GPU: the Impeller half of the golden set. The other half renders through the software backend, so ninety scenes stay checkable in a headless run. ## Your own application diff --git a/site/content/reference/testing.md b/site/content/reference/testing.md index e0efcd010..ef5327407 100644 --- a/site/content/reference/testing.md +++ b/site/content/reference/testing.md @@ -1,10 +1,10 @@ --- -description: Four independent golden sets, mutation-checking every new test, determinism and snapshots, and why only about thirty of 11363 tests need a GPU. +description: Four independent golden sets, mutation-checking every new test, determinism and snapshots, and why only about thirty of 11367 tests need a GPU. --- # Testing -11363 tests across 43 packages and nine applications, counted the same way the `the document says how many tests there are` rule does: a scan of every `test(`/`testWidgets(` call. The rule holds `ARCHITECTURE.md` §13, the README and this page to the answer. The README went on saying 1242 across thirteen packages for as long as nothing compared it with anything. About thirty need a GPU; the [architecture](/core/architecture/) is what keeps the number that low. +11367 tests across 43 packages and nine applications, counted the same way the `the document says how many tests there are` rule does: a scan of every `test(`/`testWidgets(` call. The rule holds `ARCHITECTURE.md` §13, the README and this page to the answer. The README went on saying 1242 across thirteen packages for as long as nothing compared it with anything. About thirty need a GPU; the [architecture](/core/architecture/) is what keeps the number that low. | Package | Tests | | Package | Tests | |---|---|---|---|---| @@ -23,7 +23,7 @@ description: Four independent golden sets, mutation-checking every new test, det | `flutter3d_cpu` | 380 | | `apps/flutter3d_demo_strategy` | 50 | | `apps/flutter3d_editor` | 234 | | `apps/flutter3d_demo_arcade` | 20 | | `apps/flutter3d_demo_racing` | 162 | | `pointer_lock` | 28 | -| `flutter3d_physics` | 290 | | `flutter3d_webgpu` | 193 | +| `flutter3d_physics` | 294 | | `flutter3d_webgpu` | 193 | | `flutter3d_game_strategy` | 133 | | `flutter3d_editor_mcp` | 36 | | `apps/flutter3d_demo_river` | 54 | | `flutter3d_testing` | 45 | | `flutter3d_editor_core` | 141 | | `flutter3d_editor_widgets` | 91 | @@ -40,7 +40,7 @@ description: Four independent golden sets, mutation-checking every new test, det | `flame_flutter3d` | 140 | | `apps/flutter3d_showcase` | 88 | | `flame_multiplayer` | 9 | | `flame_multiplayer_dashwire` | 3 | -The rows sum to 11336 rather than 11363: the remaining 26 live in `packages/*/example/test`, which the count includes and this table does not, among them the two seeds a new project starts from, `packages/flutter3d_app/example` and `packages/flutter3d_game/example`. +The rows sum to 11340 rather than 11367: the remaining 26 live in `packages/*/example/test`, which the count includes and this table does not, among them the two seeds a new project starts from, `packages/flutter3d_app/example` and `packages/flutter3d_game/example`. `flutter3d_samples` is not in the table and has no `test/` at all: it is test data with two path constants over it, and other packages' decoder tests are what exercise it. `flutter3d_conformance` is missing for a different reason: it is invoked as a script harness rather than through `flutter test`, so it does not surface in a grep of `test(` calls either. See below for what that cost once. From 8e8e0ee1c68f75b9a558fc6e3892d7ea291126ca Mon Sep 17 00:00:00 2001 From: Dmitrii Zolotov Date: Sat, 3 Oct 2026 16:42:49 +0300 Subject: [PATCH 23/34] perf: Fly each drop as one body, particles only on walls A drop in flight does not feel its own weight, and the air breaks it up only past an aerodynamic Weber number of about twelve, which drops off a pour are a fifteenth of. So a drop is now one body: a sphere's drag and evaporation, Furmidge's hold or slide on a wall, and drops that touch run together. A drop wider than the capillary length spreads as particles where it meets a wall, and particles that leave every wall gather into a drop again. A free block of particles used to ring until it flew apart; a pour now flies ten bodies at most instead of thirty-eight, and costs two fifths less. --- ARCHITECTURE.md | 2 +- README.md | 2 +- .../lib/src/fluid/particle_fluid.dart | 391 +++++++++++++++++- .../test/fluid/drop_test.dart | 66 +++ .../test/fluid/particle_fluid_test.dart | 38 +- site/content/core/liquids.md | 4 +- site/content/quickstart.md | 2 +- site/content/reference/testing.md | 8 +- 8 files changed, 483 insertions(+), 30 deletions(-) create mode 100644 packages/flutter3d_physics/test/fluid/drop_test.dart diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 275cb129d..dfaf3f5dd 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -2691,7 +2691,7 @@ storage. |---|---| | Style | `dart format` | | Analysis | `flutter analyze` clean across the workspace, no warnings | -| Unit tests | **11367 tests** across 43 packages and 10 applications | +| Unit tests | **11371 tests** across 43 packages and 10 applications | | Structure rules | 35, `dart run tool/structure.dart`, the first CI step | | CI | GitHub Actions over `tool/ci.sh`, on `ubuntu-latest`, with no graphics card | diff --git a/README.md b/README.md index f1f365bb9..ad02b5228 100644 --- a/README.md +++ b/README.md @@ -158,7 +158,7 @@ Or one package at a time: (cd packages/flutter3d_physics && dart test) # plain Dart, no Flutter needed ``` -There are 11367 tests across forty-three packages and nine applications. The +There are 11371 tests across forty-three packages and nine applications. The only ones that need a GPU are the Impeller half of the golden set. The other half is rendered by the software backend, which is what makes 90 scenes checkable in a headless run. diff --git a/packages/flutter3d_physics/lib/src/fluid/particle_fluid.dart b/packages/flutter3d_physics/lib/src/fluid/particle_fluid.dart index 53e6f155e..63bfafc44 100644 --- a/packages/flutter3d_physics/lib/src/fluid/particle_fluid.dart +++ b/packages/flutter3d_physics/lib/src/fluid/particle_fluid.dart @@ -153,25 +153,67 @@ final class ParticleFluid { double get particleVolume => spacing * spacing * spacing; double get _mass => medium.density * particleVolume; - /// The particles' places. - List get positions => [for (final p in _x) p.toVector3()]; - int get count => _x.length; + /// Where the liquid is: each particle's place, then each drop's middle. + List get positions => [ + for (final p in _x) p.toVector3(), + for (final d in _drops) d.x.toVector3(), + ]; - /// Cubic metres here: every particle and the bank. - double get volume => _vol.fold(0.0, (s, v) => s + v) + _bank; + /// How many places [positions] has: particles and drops. + int get count => _x.length + _drops.length; - /// The particles' liquid, cubic metres each. - List get volumes => List.unmodifiable(_vol); + /// How many of them are drops, each one body: the rest are particles. + int get dropCount => _drops.length; - /// What is dissolved in the particles, as concentrations over all of - /// them: for drawing them the colour of what they are. + /// Cubic metres here: every particle, every drop and the bank. + double get volume => + _vol.fold(0.0, (s, v) => s + v) + + _drops.fold(0.0, (s, d) => s + d.volume) + + _bank; + + /// The liquid at each of [positions], cubic metres. + List get volumes => + List.unmodifiable([..._vol, for (final d in _drops) d.volume]); + + /// What is dissolved in the particles and drops, as concentrations over + /// all of them: for drawing them the colour of what they are. Map get concentrations { - if (_c.isEmpty) return const {}; + final all = [..._c, for (final d in _drops) d.c]; + if (all.isEmpty) return const {}; final sum = {}; - for (final c in _c) { + for (final c in all) { c.forEach((k, v) => sum[k] = (sum[k] ?? 0.0) + v); } - return {for (final e in sum.entries) e.key: e.value / _c.length}; + return {for (final e in sum.entries) e.key: e.value / all.length}; + } + + /// **A drop in flight is one body.** Falling, it does not feel its own + /// weight, and what would break it up is the air: it holds together while + /// its aerodynamic Weber number ρ_a·u²·d/σ is under about twelve (Pilch + /// and Erdman, 1987), and a four-millimetre drop at a metre a second is at + /// a fifteenth of one. So it moves as one, its drag a sphere's, its + /// evaporation a sphere's, its hold on a wall Furmidge's. Laid out as + /// particles it was dozens of bodies stepped at the capillary time, + /// which were most of what a pour cost; and a block of them, free in the + /// air, rang until it flew apart. + /// + /// Particles are for liquid on a wall: a block that lands on glass is + /// particles; one that leaves the wall again is a drop. + final List<_Drop> _drops = []; + + /// The air last flown through, for the Weber number at [inject]. + Atmosphere? _lastAir; + + /// The critical aerodynamic Weber number. + static const double _breakupWeber = 12.0; + + bool _isDrop(double volume, Vector3 position, Vector3 velocity) { + if (volume <= 0.0 || medium.surfaceTension <= 0.0) return false; + final air = _lastAir; + if (air == null) return true; + final d = Portable.pow(6.0 * volume / math.pi, 1.0 / 3.0); + final u = velocity - air.windAt(position); + return air.density * u.length2 * d / medium.surfaceTension < _breakupWeber; } /// Cubic metres handed to receivers so far. @@ -181,12 +223,39 @@ final class ParticleFluid { /// [concentrations] dissolved in it: as many whole particles as it and /// the bank make, laid out round [position] at the spacing so none start /// on top of another, each carrying what the bank holds per cubic metre. + /// + /// Less than a drop of the capillary length is one drop, of exactly + /// [amount]: see [dropCount]. + /// + /// [asParticles] lays it out as particles whatever it is: for liquid put + /// straight onto a wall. void inject( double amount, Vector3 position, Vector3 velocity, { Map concentrations = const {}, + bool asParticles = false, }) { + if (!asParticles && _isDrop(amount, position, velocity)) { + _drops.add( + _Drop( + _V(position.x, position.y, position.z), + _V(velocity.x, velocity.y, velocity.z), + amount, + Map.of(concentrations), + ), + ); + return; + } + _addToParticles(amount, position, velocity, concentrations); + } + + void _addToParticles( + double amount, + Vector3 position, + Vector3 velocity, + Map concentrations, + ) { _bank += amount; _injected = true; _lastAt @@ -258,6 +327,8 @@ final class ParticleFluid { _bankAmounts.clear(); } _injected = false; + if (air != null) _lastAir = air; + _stepDrops(dt, gravity, obstacles, receivers, air, gravityAt); if (_x.isEmpty) return; // A quarter of the capillary time a substep at most, and never fewer // than asked. How far a particle goes in one is not held here: it is @@ -312,6 +383,288 @@ final class ParticleFluid { break; } } + _clustersToDrops(walls); + } + + /// Each drop moved on by [dt]: the air's drag and evaporation, a wall + /// holding it or letting it slide, the walls it meets, the receivers it + /// reaches; drops that touch run together, and a drop that touches the + /// particles or outgrows the capillary length becomes particles. + void _stepDrops( + double dt, + Vector3 gravity, + List obstacles, + List receivers, + Atmosphere? air, + Vector3 Function(Vector3 point)? gravityAt, + ) { + if (_drops.isEmpty) return; + _mergeDrops(); + // Into the particles it touches. + for (var i = _drops.length - 1; i >= 0; i--) { + final d = _drops[i]; + final reach = d.radius + 0.5 * spacing; + var touches = false; + for (var j = 0; j < _x.length && !touches; j++) { + touches = _x[j].distance2(d.x) < reach * reach; + } + if (!touches) continue; + _drops.removeAt(i); + _addToParticles(d.volume, d.x.toVector3(), d.v.toVector3(), d.c); + } + final rho = medium.density; + for (var i = _drops.length - 1; i >= 0; i--) { + final d = _drops[i]; + final at = d.x.toVector3(); + final g = gravityAt?.call(at) ?? gravity; + final r = d.radius; + var ax = g.x; + var ay = g.y; + var az = g.z; + if (air != null) { + final drag = air.dragOnSphere(d.v.toVector3(), at, 2.0 * r, rho); + ax += drag.x; + ay += drag.y; + az += drag.z; + _evaporate(d, dt, air); + if (d.volume <= 0.0) { + _drops.removeAt(i); + continue; + } + } + final walls = obstaclesNear( + obstacles, + at, + (d.v.length + g.length * dt) * dt + 2.0 * r, + ); + // On a wall: held whole by its edge, or sliding with what of its + // weight along the wall the edge cannot hold. Wider than the + // capillary length, where its weight flattens it, it spreads there + // as particles. + final touch = _touchingDrop(d, walls); + if (touch != null && + 2.0 * r > medium.capillaryLength(math.max(g.length, 1e-9))) { + _drops.removeAt(i); + _addToParticles(d.volume, at, d.v.toVector3(), d.c); + continue; + } + if (touch != null) { + final n = touch.normal; + final into = g.x * n.x + g.y * n.y + g.z * n.z; + final gx = g.x - n.x * into; + final gy = g.y - n.y * into; + final gz = g.z - n.z * into; + final along = math.sqrt(gx * gx + gy * gy + gz * gz); + final mass = rho * d.volume; + final hold = touch.solid.retention( + medium, + 2.0 * touch.solid.baseRadius(medium, d.volume), + ); + if (mass * along <= hold || along <= 0.0) { + d.v + ..x = 0.0 + ..y = 0.0 + ..z = 0.0; + } else { + final k = 1.0 - hold / (mass * along); + d.v + ..x += gx * k * dt + ..y += gy * k * dt + ..z += gz * k * dt; + final off = _dot(d.v, n); + if (off < 0.0) { + d.v + ..x -= n.x * off + ..y -= n.y * off + ..z -= n.z * off; + } + } + } else { + d.v + ..x += ax * dt + ..y += ay * dt + ..z += az * dt; + } + // In pieces no longer than its radius, held out of the walls after + // each: what meets a wall loses the part of its speed into it. + final pieces = (d.v.length * dt / r).ceil().clamp(1, 64); + for (var k = 0; k < pieces; k++) { + d.x.addScaled(d.v, dt / pieces); + for (final o in walls) { + final hit = o.touch(d.x.toVector3(), r); + if (hit == null) continue; + d.x + ..x += hit.normal.x * hit.depth + ..y += hit.normal.y * hit.depth + ..z += hit.normal.z * hit.depth; + final off = + d.v.x * hit.normal.x + + d.v.y * hit.normal.y + + d.v.z * hit.normal.z; + if (off < 0.0) { + d.v + ..x -= hit.normal.x * off + ..y -= hit.normal.y * off + ..z -= hit.normal.z * off; + } + } + } + final now = d.x.toVector3(); + for (final receiver in receivers) { + if (!receiver.catches(now, r) && !receiver.wets(now, r)) continue; + receiver.receive(d.volume, now, d.v.toVector3(), medium, d.c); + _received += d.volume; + _drops.removeAt(i); + break; + } + } + } + + /// The wall [d] touches and its normal and solid there, if any. + ({_V normal, SolidSurface solid})? _touchingDrop( + _Drop d, + List walls, + ) { + final reach = d.radius * 1.05; + final at = d.x.toVector3(); + for (final o in walls) { + final hit = o.touch(at, reach); + if (hit != null) { + return ( + normal: _V(hit.normal.x, hit.normal.y, hit.normal.z), + solid: o.solid, + ); + } + } + return null; + } + + /// Drops that touch run together: their liquid, momentum and what is + /// dissolved, into one at their centre of volume. + void _mergeDrops() { + var merged = true; + while (merged) { + merged = false; + outer: + for (var i = 0; i < _drops.length; i++) { + for (var j = i + 1; j < _drops.length; j++) { + final a = _drops[i]; + final b = _drops[j]; + final reach = a.radius + b.radius; + if (a.x.distance2(b.x) >= reach * reach) continue; + final total = a.volume + b.volume; + final wa = a.volume / total; + final wb = b.volume / total; + a.x + ..x = a.x.x * wa + b.x.x * wb + ..y = a.x.y * wa + b.x.y * wb + ..z = a.x.z * wa + b.x.z * wb; + a.v + ..x = a.v.x * wa + b.v.x * wb + ..y = a.v.y * wa + b.v.y * wb + ..z = a.v.z * wa + b.v.z * wb; + a.c = { + for (final k in {...a.c.keys, ...b.c.keys}) + k: (a.c[k] ?? 0.0) * wa + (b.c[k] ?? 0.0) * wb, + }; + a.volume = total; + _drops.removeAt(j); + merged = true; + break outer; + } + } + } + } + + /// A drop's evaporation in [dt]: a sphere's, π·d·D·Δc·Sh with Ranz and + /// Marshall's Sherwood number, what is dissolved left behind. + void _evaporate(_Drop d, double dt, Atmosphere air) { + final deficit = air.vapourDeficit(medium); + if (deficit <= 0.0) return; + final diffusivity = air.vapourDiffusivity; + final diameter = 2.0 * d.radius; + final wind = air.windAt(d.x.toVector3()); + final through = _V(d.v.x - wind.x, d.v.y - wind.y, d.v.z - wind.z).length; + final re = air.density * through * diameter / air.viscosity; + final sc = air.viscosity / (air.density * diffusivity); + final sherwood = 2.0 + 0.6 * math.sqrt(re) * Portable.pow(sc, 1.0 / 3.0); + final rate = math.pi * diameter * diffusivity * deficit * sherwood; + final gone = math.min(rate / medium.density * dt, d.volume); + _evaporated += gone; + final kept = d.volume - gone; + if (kept > 0.0) { + d.c = {for (final e in d.c.entries) e.key: e.value * d.volume / kept}; + } + d.volume = kept; + } + + /// Particles gathered into a drop, a spacing and a half apart at most, + /// that touch no wall, become that drop: one body again, in flight. + void _clustersToDrops(List walls) { + final n = _x.length; + if (n == 0 || medium.surfaceTension <= 0.0) return; + final parent = List.generate(n, (i) => i); + int root(int i) { + var r = i; + while (parent[r] != r) { + r = parent[r]; + } + return parent[i] = r; + } + + final (start, list) = _rows(_x); + final close = 2.25 * spacing * spacing; + for (var i = 0; i < n; i++) { + for (var q = start[i]; q < start[i + 1]; q++) { + final j = list[q]; + if (_x[i].distance2(_x[j]) < close) parent[root(i)] = root(j); + } + } + final volume = {}; + final speed = {}; + final onWall = {}; + for (var i = 0; i < n; i++) { + final r = root(i); + volume[r] = (volume[r] ?? 0.0) + _vol[i]; + (speed[r] ??= _V(0, 0, 0)).addScaled(_v[i], _vol[i]); + final near = obstaclesNear(walls, _x[i].toVector3(), spacing); + if (_contact(_x[i], near) != null) onWall.add(r); + } + final into = {}; + for (final MapEntry(key: r, value: v) in volume.entries) { + if (onWall.contains(r)) continue; + final at = _x[r].toVector3(); + if (_isDrop(v, at, (speed[r]! * (1.0 / v)).toVector3())) { + into[r] = _Drop(_V(0, 0, 0), _V(0, 0, 0), 0.0, {}); + } + } + if (into.isEmpty) return; + for (var i = n - 1; i >= 0; i--) { + final d = into[root(i)]; + if (d == null) continue; + final w = _vol[i]; + final total = d.volume + w; + final a = d.volume / total; + final b = w / total; + d.x + ..x = d.x.x * a + _x[i].x * b + ..y = d.x.y * a + _x[i].y * b + ..z = d.x.z * a + _x[i].z * b; + d.v + ..x = d.v.x * a + _v[i].x * b + ..y = d.v.y * a + _v[i].y * b + ..z = d.v.z * a + _v[i].z * b; + d.c = { + for (final k in {...d.c.keys, ..._c[i].keys}) + k: (d.c[k] ?? 0.0) * a + (_c[i][k] ?? 0.0) * b, + }; + d.volume = total; + _x.removeAt(i); + _v.removeAt(i); + _vol.removeAt(i); + _c.removeAt(i); + } + _drops.addAll(into.values); } /// Whether to run the loops over pairs natively where that was built @@ -828,6 +1181,20 @@ final class ParticleFluid { static double _pow9(double x) => _pow6(x) * x * x * x; } +/// A drop small enough to be one body: where, how fast, how much, and +/// what is dissolved in it. +final class _Drop { + _Drop(this.x, this.v, this.volume, this.c); + + final _V x; + final _V v; + double volume; + Map c; + + /// The radius of the sphere it is. + double get radius => Portable.pow(3.0 * volume / (4.0 * math.pi), 1.0 / 3.0); +} + /// A vector in double precision, for the solver's own arithmetic. final class _V { _V(this.x, this.y, this.z); diff --git a/packages/flutter3d_physics/test/fluid/drop_test.dart b/packages/flutter3d_physics/test/fluid/drop_test.dart new file mode 100644 index 000000000..4c4e2edd7 --- /dev/null +++ b/packages/flutter3d_physics/test/fluid/drop_test.dart @@ -0,0 +1,66 @@ +import 'package:flutter3d_physics/flutter3d_physics.dart'; +import 'package:test/test.dart'; +import 'package:vector_math/vector_math.dart'; + +void main() { + final g = Vector3(0, -9.81, 0); + + test('a drop under the capillary length is one body, falling as one', () { + final fluid = ParticleFluid(medium: FluidMedium.water, spacing: 0.001) + ..inject(4e-9, Vector3(0, 1, 0), Vector3.zero()); + expect(fluid.count, 1); + expect(fluid.dropCount, 1); + for (var i = 0; i < 240; i++) { + fluid.step(1 / 240, gravity: g); + } + // A second's fall, as a body falls: ½gt², to the step's first order. + expect(1 - fluid.positions.single.y, closeTo(4.905, 0.03)); + expect(fluid.volume, 4e-9); + }); + + test('two drops that meet run together, liquid and momentum and all', () { + final fluid = ParticleFluid(medium: FluidMedium.water, spacing: 0.001) + ..inject( + 1e-9, + Vector3(0, 0, 0), + Vector3(0.1, 0, 0), + concentrations: const {'dye': 1.0}, + ) + ..inject(2e-9, Vector3(0.002, 0, 0), Vector3(-0.1, 0, 0)); + // Apart at first; they meet within the second step. + fluid + ..step(1 / 240, gravity: Vector3.zero()) + ..step(1 / 240, gravity: Vector3.zero()); + expect(fluid.dropCount, 1); + expect(fluid.volume, closeTo(3e-9, 1e-21)); + // A third of it was dye at one. + expect(fluid.concentrations['dye'], closeTo(1 / 3, 1e-12)); + }); + + test('a block of liquid in the air is one drop, and holds together', () { + // Twenty-seven particles laid out as a block, free in the air, rang + // until they flew apart, ten centimetres in a tenth of a second. A + // drop in flight is held whole by surface tension against the air + // (its Weber number far under twelve): one body. Mutation: leave free + // blocks as particles, and they fly apart. + final fluid = ParticleFluid(medium: FluidMedium.water, spacing: 0.001) + ..inject(27e-9, Vector3(0, 1, 0), Vector3.zero()); + for (var i = 0; i < 24; i++) { + fluid.step(1 / 240, gravity: Vector3.zero()); + } + expect(fluid.dropCount, 1); + expect(fluid.count, 1); + expect(fluid.positions.single.y, closeTo(1.0, 1e-6)); + expect(fluid.volume, closeTo(27e-9, 1e-21)); + }); + + test('a drop that lands on glass is particles there', () { + final fluid = ParticleFluid(medium: FluidMedium.water, spacing: 0.001); + final pane = [PlaneObstacle(normal: Vector3(0, 1, 0), offset: 0)]; + // A block resting on the glass from the start: particles, held there. + fluid.inject(27e-9, Vector3(0, 0.0015, 0), Vector3.zero()); + fluid.step(1 / 240, gravity: Vector3(0, -9.81, 0), obstacles: pane); + expect(fluid.dropCount, 0); + expect(fluid.count, 27); + }); +} diff --git a/packages/flutter3d_physics/test/fluid/particle_fluid_test.dart b/packages/flutter3d_physics/test/fluid/particle_fluid_test.dart index 50e91a835..6e38454c2 100644 --- a/packages/flutter3d_physics/test/fluid/particle_fluid_test.dart +++ b/packages/flutter3d_physics/test/fluid/particle_fluid_test.dart @@ -48,28 +48,46 @@ void main() { test('what is less than a particle waits in the bank, and is counted', () { final fluid = ParticleFluid(medium: FluidMedium.water, spacing: 0.002); - fluid.inject(2.5 * fluid.particleVolume, Vector3.zero(), Vector3.zero()); + fluid.inject( + 2.5 * fluid.particleVolume, + Vector3.zero(), + Vector3.zero(), + asParticles: true, + ); expect(fluid.count, 2); expect(fluid.volume, closeTo(2.5 * fluid.particleVolume, 1e-18)); - fluid.inject(0.5 * fluid.particleVolume, Vector3.zero(), Vector3.zero()); + fluid.inject( + 0.5 * fluid.particleVolume, + Vector3.zero(), + Vector3.zero(), + asParticles: true, + ); expect(fluid.count, 3); }); test('what is left in the bank is let go once no more comes', () { // Mutation: keep it banked, and a third of a particle stays counted // and nowhere, however long the world runs. + // Particles on a pane of glass, which keeps them particles. final fluid = ParticleFluid(medium: FluidMedium.water, spacing: 0.002); + final pane = [PlaneObstacle(normal: Vector3(0, 1, 0), offset: 0.098)]; final at = Vector3(0, 0.1, 0); fluid - ..inject(1.3 * fluid.particleVolume, at, Vector3.zero()) + ..inject( + 3.3 * fluid.particleVolume, + at, + Vector3.zero(), + asParticles: true, + ) // The step it came in on, more may still come. - ..step(1 / 240, gravity: Vector3(0, -9.81, 0)); - expect(fluid.count, 1); - fluid.step(1 / 240, gravity: Vector3(0, -9.81, 0)); - expect(fluid.count, 2); + ..step(1 / 240, gravity: Vector3(0, -9.81, 0), obstacles: pane); + expect(fluid.count, 3); + fluid.step(1 / 240, gravity: Vector3(0, -9.81, 0), obstacles: pane); + expect(fluid.count, 4); + expect(fluid.dropCount, 0); expect(fluid.volumes.last, closeTo(0.3 * fluid.particleVolume, 1e-18)); - expect(fluid.volume, closeTo(1.3 * fluid.particleVolume, 1e-18)); - // And it lands as what it is. + expect(fluid.volume, closeTo(3.3 * fluid.particleVolume, 1e-18)); + // And off the pane, it falls and lands as what it is. final glass = LiquidBody( shape: RevolvedVessel([ Vector2(0, 0), @@ -89,7 +107,7 @@ void main() { ); } expect(fluid.count, 0); - expect(glass.volume, closeTo(1e-6 + 1.3 * fluid.particleVolume, 1e-18)); + expect(glass.volume, closeTo(1e-6 + 3.3 * fluid.particleVolume, 1e-18)); }); test( diff --git a/site/content/core/liquids.md b/site/content/core/liquids.md index 6be8104be..be42f1345 100644 --- a/site/content/core/liquids.md +++ b/site/content/core/liquids.md @@ -67,7 +67,9 @@ The world keeps the accounts: every jet's `emitted` is `inFlight + landed + drop ## Drops -Drops are `ParticleFluid`, position-based fluids on the CPU, in double precision. Particles are held to the rest density only where they are compressed, so a surface does not pull itself inward. Cohesion follows Akinci, with the coefficient worked out so that pulling a slab of particles apart costs 2σ per square metre, which is what surface tension is. A particle is stepped in substeps short against the capillary time √(ρs³/σ), a third of a millisecond for millimetre water, and short enough that nothing passes through glass between one look and the next. Drops that land in a vessel become its liquid, with what was dissolved in them. Liquid arrives in any amount and leaves as whole particles; what is short of one waits only while more is coming, and then goes as a last, smaller particle where the rest came in. +A drop in flight is one body. Falling, it does not feel its own weight, and what would break it up is the air: it holds together while its aerodynamic Weber number ρ_a·u²·d/σ is under about twelve (Pilch and Erdman), which a four-millimetre drop at a metre a second is a fifteenth of. So it moves as a sphere: its drag, its evaporation, and on a wall Furmidge's hold or a slide. Drops that touch run together. A drop wider than the capillary length that comes to a wall spreads there as particles, and particles that leave every wall gather into a drop again. + +Liquid on a wall is `ParticleFluid`'s particles, position-based fluids on the CPU, in double precision. Particles are held to the rest density only where they are compressed, so a surface does not pull itself inward. Cohesion follows Akinci, with the coefficient worked out so that pulling a slab of particles apart costs 2σ per square metre, which is what surface tension is. A particle is stepped in substeps short against the capillary time √(ρs³/σ), a third of a millisecond for millimetre water, and short enough that nothing passes through glass between one look and the next. Drops that land in a vessel become its liquid, with what was dissolved in them. Liquid arrives in any amount and leaves as whole particles; what is short of one waits only while more is coming, and then goes as a last, smaller particle where the rest came in. A drop is stopped by the wall it touches: a viscous liquid has no velocity along a wall at rest, and a drop's edge holds it there. Every wall is a `SolidSurface` with water's contact angle and its hysteresis, the advancing angle less the receding one: glass, a lacquered bench, PTFE. The edge holds a drop with Furmidge's σ·w·(cos θr − cos θa) across the circle it wets, so a microlitre hangs on a pane while twenty run down it, and every drop on a level bench stays where it fell. A drop that touches a vessel's glass from inside runs down into its liquid. For liquids other than water the solids' own angles are not known here, and the liquid's angle on glass stands in. diff --git a/site/content/quickstart.md b/site/content/quickstart.md index e11cbb000..b2621122a 100644 --- a/site/content/quickstart.md +++ b/site/content/quickstart.md @@ -91,7 +91,7 @@ tool/ci.sh # shaders, analyze, every test (cd packages/flutter3d_physics && dart test) # plain Dart, no Flutter needed ``` -There are 11367 tests across 43 packages and twelve applications, and only about thirty need a GPU: the Impeller half of the golden set. The other half renders through the software backend, so ninety scenes stay checkable in a headless run. +There are 11371 tests across 43 packages and twelve applications, and only about thirty need a GPU: the Impeller half of the golden set. The other half renders through the software backend, so ninety scenes stay checkable in a headless run. ## Your own application diff --git a/site/content/reference/testing.md b/site/content/reference/testing.md index ef5327407..ced8659a1 100644 --- a/site/content/reference/testing.md +++ b/site/content/reference/testing.md @@ -1,10 +1,10 @@ --- -description: Four independent golden sets, mutation-checking every new test, determinism and snapshots, and why only about thirty of 11367 tests need a GPU. +description: Four independent golden sets, mutation-checking every new test, determinism and snapshots, and why only about thirty of 11371 tests need a GPU. --- # Testing -11367 tests across 43 packages and nine applications, counted the same way the `the document says how many tests there are` rule does: a scan of every `test(`/`testWidgets(` call. The rule holds `ARCHITECTURE.md` §13, the README and this page to the answer. The README went on saying 1242 across thirteen packages for as long as nothing compared it with anything. About thirty need a GPU; the [architecture](/core/architecture/) is what keeps the number that low. +11371 tests across 43 packages and nine applications, counted the same way the `the document says how many tests there are` rule does: a scan of every `test(`/`testWidgets(` call. The rule holds `ARCHITECTURE.md` §13, the README and this page to the answer. The README went on saying 1242 across thirteen packages for as long as nothing compared it with anything. About thirty need a GPU; the [architecture](/core/architecture/) is what keeps the number that low. | Package | Tests | | Package | Tests | |---|---|---|---|---| @@ -23,7 +23,7 @@ description: Four independent golden sets, mutation-checking every new test, det | `flutter3d_cpu` | 380 | | `apps/flutter3d_demo_strategy` | 50 | | `apps/flutter3d_editor` | 234 | | `apps/flutter3d_demo_arcade` | 20 | | `apps/flutter3d_demo_racing` | 162 | | `pointer_lock` | 28 | -| `flutter3d_physics` | 294 | | `flutter3d_webgpu` | 193 | +| `flutter3d_physics` | 298 | | `flutter3d_webgpu` | 193 | | `flutter3d_game_strategy` | 133 | | `flutter3d_editor_mcp` | 36 | | `apps/flutter3d_demo_river` | 54 | | `flutter3d_testing` | 45 | | `flutter3d_editor_core` | 141 | | `flutter3d_editor_widgets` | 91 | @@ -40,7 +40,7 @@ description: Four independent golden sets, mutation-checking every new test, det | `flame_flutter3d` | 140 | | `apps/flutter3d_showcase` | 88 | | `flame_multiplayer` | 9 | | `flame_multiplayer_dashwire` | 3 | -The rows sum to 11340 rather than 11367: the remaining 26 live in `packages/*/example/test`, which the count includes and this table does not, among them the two seeds a new project starts from, `packages/flutter3d_app/example` and `packages/flutter3d_game/example`. +The rows sum to 11344 rather than 11371: the remaining 26 live in `packages/*/example/test`, which the count includes and this table does not, among them the two seeds a new project starts from, `packages/flutter3d_app/example` and `packages/flutter3d_game/example`. `flutter3d_samples` is not in the table and has no `test/` at all: it is test data with two path constants over it, and other packages' decoder tests are what exercise it. `flutter3d_conformance` is missing for a different reason: it is invoked as a script harness rather than through `flutter test`, so it does not surface in a grep of `test(` calls either. See below for what that cost once. From 989520bc5a88333b7a00e053341a3774836d651a Mon Sep 17 00:00:00 2001 From: Dmitrii Zolotov Date: Sat, 3 Oct 2026 16:56:47 +0300 Subject: [PATCH 24/34] perf: Solve each meniscus once, quickly, for every vessel alike Filling a tube up its round bottom wanted a new meniscus every other step, and each took ten milliseconds: sixty halvings of a shot of 512 Runge-Kutta steps. The curvature is now found by Illinois false position and the shot takes two steps a sample, which against a reference eight times finer is as close as before, at 1.5 ms. Menisci are shared by every vessel of the same liquid and gravity, and a stream asks only the receivers its way passes near. A four-second pour, its caches warm, now steps in 0.3 s with no frame over 14 ms. --- .../lib/src/fluid/capillary.dart | 53 +++++++++++++++++-- .../flutter3d_physics/lib/src/fluid/jet.dart | 18 ++++++- .../lib/src/fluid/liquid_body.dart | 28 +++++++++- .../lib/src/fluid/particle_fluid.dart | 2 + .../lib/src/fluid/puddle.dart | 4 ++ 5 files changed, 97 insertions(+), 8 deletions(-) diff --git a/packages/flutter3d_physics/lib/src/fluid/capillary.dart b/packages/flutter3d_physics/lib/src/fluid/capillary.dart index aa95d7290..bd33ed031 100644 --- a/packages/flutter3d_physics/lib/src/fluid/capillary.dart +++ b/packages/flutter3d_physics/lib/src/fluid/capillary.dart @@ -104,14 +104,56 @@ final class TubeMeniscus { void _solve() { final target = math.pi / 2 - medium.contactAngle; final bond = medium.density * g / medium.surfaceTension; + // **By false position, not by halving.** The angle the surface meets + // the wall at goes smoothly and steadily with the curvature at its + // middle, so the straight line through the two ends of the bracket + // lands near the curvature that meets it at the contact angle, and + // Illinois's halving of the end that stays (Dowell and Jarratt, 1971) + // keeps that from stalling at one end. A dozen shots, where sixty + // halvings took ten milliseconds a meniscus, and a test tube being + // filled up its round bottom wanted a new one every other step. A shot + // that comes back with no angle, or a line that falls outside the + // bracket, is halved instead. var lo = -40.0 / radius; var hi = 40.0 / radius; - for (var i = 0; i < 60; i++) { - final mid = 0.5 * (lo + hi); - if (_shoot(mid, bond).angle < target) { + var flo = _shoot(lo, bond).angle - target; + var fhi = _shoot(hi, bond).angle - target; + var kept = 0; + // As fine as sixty halvings of the bracket went: in a wide tube the + // middle is nearly flat, its curvature a billionth of the bracket's, + // and the angle at the wall goes with it exponentially. + final tolerance = (hi - lo) * math.pow(2.0, -60); + for (var i = 0; i < 200 && hi - lo > tolerance; i++) { + var mid = flo.isFinite && fhi.isFinite && fhi != flo + ? lo - flo * (hi - lo) / (fhi - flo) + : 0.5 * (lo + hi); + if (!(mid > lo && mid < hi)) mid = 0.5 * (lo + hi); + final f = _shoot(mid, bond).angle - target; + if (!f.isFinite) { + // No surface reaches the wall this way: as halving would, take + // the side the bracket's own ends say. + if (flo.isFinite && flo > 0.0) { + hi = mid; + } else { + lo = mid; + } + continue; + } + if (f.abs() < 1e-15) { + lo = mid; + hi = mid; + break; + } + if (f < 0.0) { lo = mid; + flo = f; + if (kept == 1) fhi *= 0.5; + kept = 1; } else { hi = mid; + fhi = f; + if (kept == -1) flo *= 0.5; + kept = -1; } } apexCurvature = 0.5 * (lo + hi); @@ -137,7 +179,10 @@ final class TubeMeniscus { final zs = [0.0]; double turn(double r, double z, double phi) => bond * z + b - Portable.sin(phi) / math.max(r, 1e-12); - final ds = radius / (samples * 8); + // Two steps a kept sample: Runge–Kutta's error goes as the fourth power + // of the step, and eight a sample bought nothing measured against one + // eight times finer again, at four times the cost. + final ds = radius / (samples * 2); var guard = 0; while (r < radius && guard++ < samples * 400) { // Runge–Kutta in arc length. diff --git a/packages/flutter3d_physics/lib/src/fluid/jet.dart b/packages/flutter3d_physics/lib/src/fluid/jet.dart index 7d2704b0a..a15e32de4 100644 --- a/packages/flutter3d_physics/lib/src/fluid/jet.dart +++ b/packages/flutter3d_physics/lib/src/fluid/jet.dart @@ -26,6 +26,12 @@ abstract interface class JetReceiver { /// receiver's surface: whether its underside has. bool catches(Vector3 point, double radius); + /// Whether anything within [distance] of [centre] (world) could be + /// caught: false only when it certainly cannot. What a parcel asks + /// first, so the receivers far from it are not asked at every point of + /// its way. + bool reaches(Vector3 centre, double distance); + /// Whether a drop of [radius] at [point] (world) touches this receiver's /// glass from inside it: water wets glass, and a drop held there by the /// wall runs down into the liquid as a film. @@ -377,14 +383,22 @@ final class Jet { final radius = math.sqrt(p.section / math.pi); final way = p.position - p.previous; final looks = (way.length / radius).ceil().clamp(1, 16); + // Only the receivers its way passes near: every point of every + // parcel's way asked of every glass on the bench was a third of a + // pour's cost. + final middle = (p.position + p.previous)..scale(0.5); + final near = [ + for (final r in receivers) + if (r.reaches(middle, 0.5 * way.length + radius)) r, + ]; search: - for (var k = 1; k <= looks; k++) { + for (var k = 1; k <= looks && near.isNotEmpty; k++) { // One point moved along, not one made per look. final at = _look ..setFrom(way) ..scale(k / looks) ..add(p.previous); - for (final r in receivers) { + for (final r in near) { if (r.catches(at, radius)) { into = r; break search; diff --git a/packages/flutter3d_physics/lib/src/fluid/liquid_body.dart b/packages/flutter3d_physics/lib/src/fluid/liquid_body.dart index d7729e35e..c314abc74 100644 --- a/packages/flutter3d_physics/lib/src/fluid/liquid_body.dart +++ b/packages/flutter3d_physics/lib/src/fluid/liquid_body.dart @@ -243,6 +243,9 @@ final class LiquidBody implements JetReceiver { /// Whether anything within [distance] of [centre] (world) could be at /// this vessel's walls: by the ball round its inside. + @override + bool reaches(Vector3 centre, double distance) => _reaches(centre, distance); + bool _reaches(Vector3 centre, double distance) { final shape = this.shape; if (shape is! RevolvedVessel) return true; @@ -577,10 +580,31 @@ final class LiquidBody implements JetReceiver { _menisciG = _g; } final key = (Portable.log(radius) / 0.01).round(); - return _menisci[key] ??= TubeMeniscus( + return _menisci[key] ??= _sharedMeniscus(medium, key, _menisciG); + } + + /// **One meniscus for every vessel of the liquid and gravity**: the + /// shape depends on nothing else, and a bench's six tubes worked out the + /// same ones six times over, seven at the first frame, a tenth of a + /// second. + static final Map<(double, double, double, double, int), TubeMeniscus> + _menisciShared = {}; + + static TubeMeniscus _sharedMeniscus(FluidMedium medium, int key, double g) { + // Gravity to a part in a thousand, as a vessel's own cache keeps it. + final gKey = (g * 1000).roundToDouble(); + final id = ( + medium.density, + medium.surfaceTension, + medium.contactAngle, + gKey, + key, + ); + if (_menisciShared.length > 4096) _menisciShared.clear(); + return _menisciShared[id] ??= TubeMeniscus( medium: medium, radius: Portable.exp(key * 0.01), - g: _menisciG, + g: gKey / 1000, ); } diff --git a/packages/flutter3d_physics/lib/src/fluid/particle_fluid.dart b/packages/flutter3d_physics/lib/src/fluid/particle_fluid.dart index 63bfafc44..035252794 100644 --- a/packages/flutter3d_physics/lib/src/fluid/particle_fluid.dart +++ b/packages/flutter3d_physics/lib/src/fluid/particle_fluid.dart @@ -373,6 +373,7 @@ final class ParticleFluid { for (var i = _x.length - 1; i >= 0; i--) { final at = _x[i].toVector3(); for (final r in receivers) { + if (!r.reaches(at, radius)) continue; if (!r.catches(at, radius) && !r.wets(at, radius)) continue; r.receive(_vol[i], at, _v[i].toVector3(), medium, _c[i]); _received += _vol[i]; @@ -511,6 +512,7 @@ final class ParticleFluid { } final now = d.x.toVector3(); for (final receiver in receivers) { + if (!receiver.reaches(now, r)) continue; if (!receiver.catches(now, r) && !receiver.wets(now, r)) continue; receiver.receive(d.volume, now, d.v.toVector3(), medium, d.c); _received += d.volume; diff --git a/packages/flutter3d_physics/lib/src/fluid/puddle.dart b/packages/flutter3d_physics/lib/src/fluid/puddle.dart index b82a28930..57d0ebb6f 100644 --- a/packages/flutter3d_physics/lib/src/fluid/puddle.dart +++ b/packages/flutter3d_physics/lib/src/fluid/puddle.dart @@ -205,6 +205,10 @@ final class PuddleSurface implements JetReceiver { @override bool wets(Vector3 point, double radius) => false; + @override + bool reaches(Vector3 centre, double distance) => + surface.reaches(centre, distance); + @override void receive( double volume, From 580a934c720e8aa77ad3541ff06cab5ba1aa4862 Mon Sep 17 00:00:00 2001 From: Dmitrii Zolotov Date: Sat, 3 Oct 2026 17:00:30 +0300 Subject: [PATCH 25/34] fix: Keep the meniscus solve off libm, and record the bench again The tolerance's power of two came from math.pow, which a step may not ask the platform for; it is now the exact constant. The bench's golden moves by one pixel with the new meniscus solve. --- .../education/chemlab/test/goldens/bench.png | Bin 1936077 -> 1936077 bytes .../lib/src/fluid/capillary.dart | 3 ++- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/education/chemlab/test/goldens/bench.png b/packages/education/chemlab/test/goldens/bench.png index 4170ca6a70a450ccbc456eaedced6f4496fffa94..e7bf3b94b52fee5baf6837872e565a3c107658dd 100644 GIT binary patch delta 229 zcmX>*we0NFvW6DM7N!>F7M2#)7Pc1l7LFFq7OocV7M>Q~Eqr$irr-1A64?H>fNzmC z2lo97rQ3rp@crRq?AY#qpYH}gW6E}o_k6-OT+8PE-wVWh)~;%I)#e9c z0U#CxVj&X<#?6|Z=A~j1fH&b JF6*2UngFrQS2X|t delta 259 zcmX>*we0NFvW6DM7N!>F7M2#)7Pc1l7LFFq7OocV7M>Q~Eqr$irXNV;6PWJf#mO`M z{(DZ2=@&GC+y{p^S*Ht#^RaA~D&#A*X1un2!WzDfjxN5-=4K^OS`@G*97 z_rK3~gP$>VyT*GyVH>XHbN}yMHuwLYwJX|PwfTWq0Eh*FSO|!Pfmj5HMS)lhh{b_e p0*EDnSPF=xfmmj{tF~-Oyh!=~+%gxfYkL`hz|+;wWt~$(69AWkVbK5p diff --git a/packages/flutter3d_physics/lib/src/fluid/capillary.dart b/packages/flutter3d_physics/lib/src/fluid/capillary.dart index bd33ed031..f8764f8d2 100644 --- a/packages/flutter3d_physics/lib/src/fluid/capillary.dart +++ b/packages/flutter3d_physics/lib/src/fluid/capillary.dart @@ -122,7 +122,8 @@ final class TubeMeniscus { // As fine as sixty halvings of the bracket went: in a wide tube the // middle is nearly flat, its curvature a billionth of the bracket's, // and the angle at the wall goes with it exponentially. - final tolerance = (hi - lo) * math.pow(2.0, -60); + // 2⁻⁶⁰, exactly: a power of two is, in a double. + final tolerance = (hi - lo) * 8.673617379884035e-19; for (var i = 0; i < 200 && hi - lo > tolerance; i++) { var mid = flo.isFinite && fhi.isFinite && fhi != flo ? lo - flo * (hi - lo) / (fhi - flo) From 4006905093c5ee36dd9f8633fae34b6e7801ff04 Mon Sep 17 00:00:00 2001 From: Dmitrii Zolotov Date: Sat, 3 Oct 2026 17:11:53 +0300 Subject: [PATCH 26/34] perf: Work out new cross-sections and menisci on another isolate A FluidWorld made with background: true hands what would stop a frame, the modes of a cross-section not met before and a meniscus not solved before, to a long-lived isolate, and the vessel carries on its old grid or the nearest meniscus until the answer comes. The answers are the same numbers, checked to the bit; only when they arrive differs, so it is off unless asked for. On the web there are no isolates and nothing changes. The bench asks for it and for the native kernels: the first pour of a session no longer has frames of 40 ms. --- ARCHITECTURE.md | 2 +- README.md | 2 +- packages/education/chemlab/lib/src/bench.dart | 5 + .../lib/flutter3d_physics.dart | 1 + .../fluid/background/fluid_background.dart | 3 + .../fluid/background/fluid_background_io.dart | 151 ++++++++++++++++ .../background/fluid_background_none.dart | 22 +++ .../lib/src/fluid/capillary.dart | 20 +++ .../lib/src/fluid/fluid_world.dart | 16 ++ .../lib/src/fluid/free_surface.dart | 170 ++++++++++++++---- .../lib/src/fluid/liquid_body.dart | 64 ++++++- .../test/fluid/background_test.dart | 108 +++++++++++ site/content/core/liquids.md | 7 + site/content/quickstart.md | 2 +- site/content/reference/testing.md | 8 +- 15 files changed, 526 insertions(+), 55 deletions(-) create mode 100644 packages/flutter3d_physics/lib/src/fluid/background/fluid_background.dart create mode 100644 packages/flutter3d_physics/lib/src/fluid/background/fluid_background_io.dart create mode 100644 packages/flutter3d_physics/lib/src/fluid/background/fluid_background_none.dart create mode 100644 packages/flutter3d_physics/test/fluid/background_test.dart diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index dfaf3f5dd..f8739baf6 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -2691,7 +2691,7 @@ storage. |---|---| | Style | `dart format` | | Analysis | `flutter analyze` clean across the workspace, no warnings | -| Unit tests | **11371 tests** across 43 packages and 10 applications | +| Unit tests | **11374 tests** across 43 packages and 10 applications | | Structure rules | 35, `dart run tool/structure.dart`, the first CI step | | CI | GitHub Actions over `tool/ci.sh`, on `ubuntu-latest`, with no graphics card | diff --git a/README.md b/README.md index ad02b5228..ff737ebb5 100644 --- a/README.md +++ b/README.md @@ -158,7 +158,7 @@ Or one package at a time: (cd packages/flutter3d_physics && dart test) # plain Dart, no Flutter needed ``` -There are 11371 tests across forty-three packages and nine applications. The +There are 11374 tests across forty-three packages and nine applications. The only ones that need a GPU are the Impeller half of the golden set. The other half is rendered by the software backend, which is what makes 90 scenes checkable in a headless run. diff --git a/packages/education/chemlab/lib/src/bench.dart b/packages/education/chemlab/lib/src/bench.dart index 6414a75e2..785b565e9 100644 --- a/packages/education/chemlab/lib/src/bench.dart +++ b/packages/education/chemlab/lib/src/bench.dart @@ -401,6 +401,11 @@ final class Bench { solid: SolidSurface.laminate, ), ], + // A lesson, not a replay: what would stop a frame is worked out on + // another isolate, and drops run their pair loops natively where that + // was built. Neither changes what happens, only when and how fast. + background: true, + nativeKernels: true, ); /// Whether the shadows come from the engine's caustics diff --git a/packages/flutter3d_physics/lib/flutter3d_physics.dart b/packages/flutter3d_physics/lib/flutter3d_physics.dart index 8673f51cc..b6f13dfeb 100644 --- a/packages/flutter3d_physics/lib/flutter3d_physics.dart +++ b/packages/flutter3d_physics/lib/flutter3d_physics.dart @@ -40,6 +40,7 @@ export 'src/collision_world.dart'; export 'src/contact.dart'; export 'src/dynamics.dart'; export 'src/fluid/atmosphere.dart'; +export 'src/fluid/background/fluid_background.dart'; export 'src/fluid/buoyancy.dart'; export 'src/fluid/capillary.dart'; export 'src/fluid/fluid_medium.dart'; diff --git a/packages/flutter3d_physics/lib/src/fluid/background/fluid_background.dart b/packages/flutter3d_physics/lib/src/fluid/background/fluid_background.dart new file mode 100644 index 000000000..8193f66e4 --- /dev/null +++ b/packages/flutter3d_physics/lib/src/fluid/background/fluid_background.dart @@ -0,0 +1,3 @@ +// Another isolate where there are isolates, none where there are not. +export 'fluid_background_none.dart' + if (dart.library.isolate) 'fluid_background_io.dart'; diff --git a/packages/flutter3d_physics/lib/src/fluid/background/fluid_background_io.dart b/packages/flutter3d_physics/lib/src/fluid/background/fluid_background_io.dart new file mode 100644 index 000000000..91bc6e556 --- /dev/null +++ b/packages/flutter3d_physics/lib/src/fluid/background/fluid_background_io.dart @@ -0,0 +1,151 @@ +// The cross-sections' modes and the menisci worked out on another isolate, +// for a world that need not step the same to the bit on every run. +import 'dart:isolate'; +import 'dart:typed_data'; + +import '../capillary.dart'; +import '../fluid_medium.dart'; +import '../free_surface.dart'; + +/// A long-lived isolate that works out what a [FreeSurface] or a vessel's +/// meniscus would otherwise stop a frame for: one for the whole program, +/// started the first time it is asked for. +/// +/// **What comes back is the same as what would have been worked out here**: +/// the same functions, on the same numbers. Only when it comes differs, so +/// a world stepped with it ([FluidWorld.background]) is not the same run to +/// the bit twice; one stepped without it is. +final class FluidBackground implements ModeSolver { + FluidBackground._() { + // Not what keeps a program running: a test or a tool that is done exits + // with this still open. + _port.keepIsolateAlive = false; + _port.handler = _receive; + Isolate.spawn(_work, _port.sendPort, debugName: 'flutter3d fluid'); + } + + static FluidBackground? _instance; + + /// The one there is, started on first use. + static FluidBackground get instance => _instance ??= FluidBackground._(); + + final RawReceivePort _port = RawReceivePort(); + SendPort? _send; + final List> _waiting = []; + final Map)> _replies = {}; + int _next = 0; + + /// How many requests have not come back yet. + int get outstanding => _replies.length; + + void _receive(Object? message) { + if (message is SendPort) { + _send = message; + _waiting.forEach(message.send); + _waiting.clear(); + return; + } + final reply = message! as List; + _replies.remove(reply[0]! as int)?.call(reply); + } + + void _post(List request, void Function(List) reply) { + _replies[request[1]! as int] = reply; + final send = _send; + if (send == null) { + _waiting.add(request); + } else { + send.send(request); + } + } + + @override + void solve( + int n, + List> neighbours, + double cell2, + int count, + void Function((List, Float64List) modes) done, + ) { + _post(['modes', _next++, n, neighbours, cell2, count], (reply) { + done(( + [for (final m in reply[1]! as List) m! as Float64List], + reply[2]! as Float64List, + )); + }); + } + + /// Works out the meniscus of [medium] in a tube of [radius] under [g] and + /// calls [done] with it, later, on this isolate. + void meniscus( + FluidMedium medium, + double radius, + double g, + void Function(TubeMeniscus meniscus) done, + ) { + _post( + [ + 'meniscus', + _next++, + medium.name, + medium.density, + medium.viscosity, + medium.surfaceTension, + medium.contactAngle, + radius, + g, + ], + (reply) { + done( + TubeMeniscus.solved( + medium: medium, + radius: radius, + g: g, + solution: ( + apexCurvature: reply[1]! as double, + r: (reply[2]! as List).cast(), + z: (reply[3]! as List).cast(), + ), + ), + ); + }, + ); + } +} + +/// The other isolate: answers each request with what it asks for. +void _work(SendPort back) { + final port = ReceivePort(); + back.send(port.sendPort); + port.listen((message) { + final request = message as List; + final id = request[1]! as int; + switch (request[0]) { + case 'modes': + final (modes, k2) = FreeSurface.solveModes( + request[2]! as int, + (request[3]! as List).cast>(), + request[4]! as double, + request[5]! as int, + ); + back.send([id, modes, k2]); + case 'meniscus': + final medium = FluidMedium( + name: request[2]! as String, + density: request[3]! as double, + viscosity: request[4]! as double, + surfaceTension: request[5]! as double, + contactAngle: request[6]! as double, + ); + final m = TubeMeniscus( + medium: medium, + radius: request[7]! as double, + g: request[8]! as double, + ).solution; + back.send([id, m.apexCurvature, m.r, m.z]); + } + }); +} + +/// The background where there are isolates. +FluidBackground? get fluidBackground => FluidBackground.instance; diff --git a/packages/flutter3d_physics/lib/src/fluid/background/fluid_background_none.dart b/packages/flutter3d_physics/lib/src/fluid/background/fluid_background_none.dart new file mode 100644 index 000000000..b66d834f3 --- /dev/null +++ b/packages/flutter3d_physics/lib/src/fluid/background/fluid_background_none.dart @@ -0,0 +1,22 @@ +// Where there are no isolates to put work on (the web): none. +import '../capillary.dart'; +import '../fluid_medium.dart'; +import '../free_surface.dart'; + +/// Never made here: the same face as where there are isolates, so the code +/// that asks for one reads the same. +abstract final class FluidBackground implements ModeSolver { + /// How many requests have not come back yet. + int get outstanding; + + /// Works out a meniscus elsewhere; never called here. + void meniscus( + FluidMedium medium, + double radius, + double g, + void Function(TubeMeniscus meniscus) done, + ); +} + +/// None here: what would be put off is worked out at once. +FluidBackground? get fluidBackground => null; diff --git a/packages/flutter3d_physics/lib/src/fluid/capillary.dart b/packages/flutter3d_physics/lib/src/fluid/capillary.dart index f8764f8d2..a7a5dc4f3 100644 --- a/packages/flutter3d_physics/lib/src/fluid/capillary.dart +++ b/packages/flutter3d_physics/lib/src/fluid/capillary.dart @@ -42,6 +42,26 @@ final class TubeMeniscus { _solve(); } + /// A meniscus already solved, from what [solution] gave: for one worked + /// out on another isolate. + TubeMeniscus.solved({ + required this.medium, + required this.radius, + required this.g, + required ({double apexCurvature, List r, List z}) solution, + this.samples = 64, + }) { + apexCurvature = solution.apexCurvature; + _r = solution.r; + _z = solution.z; + wallRise = _z.last; + } + + /// What another isolate sends back: the curvature at the middle and the + /// surface's points. + ({double apexCurvature, List r, List z}) get solution => + (apexCurvature: apexCurvature, r: _r, z: _z); + final FluidMedium medium; final double radius; final double g; diff --git a/packages/flutter3d_physics/lib/src/fluid/fluid_world.dart b/packages/flutter3d_physics/lib/src/fluid/fluid_world.dart index f632d6403..f72946435 100644 --- a/packages/flutter3d_physics/lib/src/fluid/fluid_world.dart +++ b/packages/flutter3d_physics/lib/src/fluid/fluid_world.dart @@ -2,6 +2,7 @@ import 'package:vector_math/vector_math.dart'; import '../rigid_body.dart'; import 'atmosphere.dart'; +import 'background/fluid_background.dart'; import 'buoyancy.dart'; import 'gravity_field.dart'; import 'jet.dart'; @@ -31,6 +32,7 @@ final class FluidWorld { Atmosphere? atmosphere, this.field, this.nativeKernels = false, + this.background = false, }) : atmosphere = atmosphere ?? Atmosphere.standard(); /// Gravity that differs from place to place, when there is some: then @@ -43,6 +45,14 @@ final class FluidWorld { /// on every machine. final bool nativeKernels; + /// Whether what would stop a frame — a cross-section's modes, a + /// meniscus not met before — is worked out on another isolate where + /// there are isolates, the vessel carrying on as it was until it comes. + /// The same numbers, at another time: on, a run is not the same to the + /// bit twice; off, it is. On the web, where there are no isolates, it is + /// all worked out at once either way. + final bool background; + /// The gravity at [point]. Vector3 gravityAt(Vector3 point) => field?.at(point) ?? gravity; @@ -125,6 +135,12 @@ final class FluidWorld { } void _stepOnce(double dt) { + final helper = background ? fluidBackground : null; + for (final body in bodies) { + body + ..background = helper + ..surface.solver = helper; + } for (final liquid in bodies) { var displaced = 0.0; for (final f in floating) { diff --git a/packages/flutter3d_physics/lib/src/fluid/free_surface.dart b/packages/flutter3d_physics/lib/src/fluid/free_surface.dart index 02a35ede9..674c48f4b 100644 --- a/packages/flutter3d_physics/lib/src/fluid/free_surface.dart +++ b/packages/flutter3d_physics/lib/src/fluid/free_surface.dart @@ -108,23 +108,38 @@ final class FreeSurface { _modes.isNotEmpty && 1.0 - old.up.dot(up.normalized()) < 0.5 * reuseTurn * reuseTurn && (height - old.height).abs() < 0.5 * old.cell) { - final moved = old.movedTo(up, height); - final behind = Float64List(moved.count); - for (var i = 0; i < moved.count; i++) { - final p = moved.point(i); - behind[i] = -(old.up.dot(p) - old.height); - } - _grid = moved; - final added = _project(behind); - for (var n = 0; n < added.length; n++) { - _amplitude[n] += added[n]; + _carryOn(old, up, height); + return; + } + final grid = _Grid.cut(shape, up, height, cells); + // **Not waited for, where it may be put off.** A cross-section whose + // modes are not worked out yet is handed to [solver] to work out + // elsewhere, and the surface carries on its old grid moved to where it + // is now, as it does for a small turn, until they come: then it is + // laid out again ([step]). Waited for, a tube tipped to an angle it had + // not been at cost a frame a tenth of a second. + final defer = solver; + if (defer != null && + old != null && + _modes.isNotEmpty && + grid.count >= 6 && + _cachedModes(grid, modeCount) == null) { + _wanted = (shape: shape, up: up.clone(), height: height, grid: grid); + final count = modeCount; + // Asked once, however many steps go by before it comes. + final key = _keyOf(grid, count); + if (_asked.add(key)) { + defer.solve(grid.count, grid.neighbours, grid.cell2, count, (modes) { + _asked.remove(key); + _remember(grid, count, modes); + }); } - _field = null; + _carryOn(old, up, height); return; } + _wanted = null; final oldHeights = old == null ? null : _heights(); final oldRates = old == null ? null : _sumModes(_rate); - final grid = _Grid.cut(shape, up, height, cells); _grid = grid; _field = null; if (grid.count < 6) { @@ -152,11 +167,49 @@ final class FreeSurface { _rate = _project(rates); } + /// The old grid moved to the plane at [height] across [up], its modes + /// kept: what the liquid stood off the old plane it stands off the new. + void _carryOn(_Grid old, Vector3 up, double height) { + final moved = old.movedTo(up, height); + final behind = Float64List(moved.count); + for (var i = 0; i < moved.count; i++) { + final p = moved.point(i); + behind[i] = -(old.up.dot(p) - old.height); + } + _grid = moved; + final added = _project(behind); + for (var n = 0; n < added.length; n++) { + _amplitude[n] += added[n]; + } + _field = null; + } + + /// Where cross-sections not yet worked out are worked out instead of + /// waited for: another isolate, set by a world that may be stepped so + /// (`FluidWorld.background`). Null, they are worked out at once. + ModeSolver? solver; + + /// Whether it is carrying on its old grid while its new cross-section's + /// modes are worked out elsewhere. + bool get waitingForModes => _wanted != null; + + /// The cross-sections asked for and not come yet, by key. + static final Set _asked = {}; + + /// The layout put off until its modes come. + ({VesselShape shape, Vector3 up, double height, _Grid grid})? _wanted; + /// Moves the waves on by [dt] seconds under gravity [g], over a liquid /// [depth] deep on average: each mode exactly, as the damped oscillator it /// is, so any step is stable. void step(double dt, {required double g, required double depth}) { _depth = depth; + // The modes put off for have come: laid out now, as it would have been. + final wanted = _wanted; + if (wanted != null && _cachedModes(wanted.grid, modeCount) != null) { + _wanted = null; + layOut(wanted.shape, wanted.up, wanted.height); + } if (_modes.isEmpty) return; _applyLandings(); // Still water stays still: nothing to ring. @@ -450,28 +503,44 @@ final class FreeSurface { /// milliseconds each, and that was most of a pour's cost. Read only, so /// shared between surfaces. static (List, Float64List) _modesOf(_Grid grid, int count) { - final key = Object.hash( - count, - grid.columns, - grid.rows, - grid.cell, - Object.hashAll(grid.index), - ); - final hits = _solved[key]; - if (hits != null) { - for (final hit in hits) { - if (hit.count == count && - hit.columns == grid.columns && - hit.rows == grid.rows && - hit.cell == grid.cell && - _same(hit.index, grid.index)) { - return hit.modes; - } + final cached = _cachedModes(grid, count); + if (cached != null) return cached; + final modes = _lowestModes(grid, count); + _remember(grid, count, modes); + return modes; + } + + static int _keyOf(_Grid grid, int count) => Object.hash( + count, + grid.columns, + grid.rows, + grid.cell, + Object.hashAll(grid.index), + ); + + static (List, Float64List)? _cachedModes(_Grid grid, int count) { + final hits = _solved[_keyOf(grid, count)]; + if (hits == null) return null; + for (final hit in hits) { + if (hit.count == count && + hit.columns == grid.columns && + hit.rows == grid.rows && + hit.cell == grid.cell && + _same(hit.index, grid.index)) { + return hit.modes; } } - final modes = _lowestModes(grid, count); + return null; + } + + static void _remember( + _Grid grid, + int count, + (List, Float64List) modes, + ) { + if (_cachedModes(grid, count) != null) return; if (_solved.length >= 256) _solved.remove(_solved.keys.first); - (_solved[key] ??= []).add(( + (_solved[_keyOf(grid, count)] ??= []).add(( count: count, columns: grid.columns, rows: grid.rows, @@ -479,7 +548,6 @@ final class FreeSurface { index: Int32List.fromList(grid.index), modes: modes, )); - return modes; } static bool _same(Int32List a, Int32List b) { @@ -505,9 +573,19 @@ final class FreeSurface { > _solved = {}; - static (List, Float64List) _lowestModes(_Grid grid, int count) { - final n = grid.count; - final inv = 1.0 / grid.cell2; + static (List, Float64List) _lowestModes(_Grid grid, int count) => + solveModes(grid.count, grid.neighbours, grid.cell2, count); + + /// The lowest [count] non-flat modes of the graph Laplacian of [n] cells + /// [cell2] square metres each, with [neighbours] inside, and their k²: + /// all the solve needs, so another isolate can do it from these alone. + static (List, Float64List) solveModes( + int n, + List> neighbours, + double cell2, + int count, + ) { + final inv = 1.0 / cell2; // The graph Laplacian: each cell against the neighbours it has inside. // A neighbour outside is the wall, and leaving it out is ∂φ/∂n = 0. // @@ -527,7 +605,7 @@ final class FreeSurface { final sigma = 1e-6 * inv; var band = 0; for (var i = 0; i < n; i++) { - for (final k in grid.neighbours[i]) { + for (final k in neighbours[i]) { band = math.max(band, (i - k).abs()); } } @@ -535,8 +613,8 @@ final class FreeSurface { // Lower band: L(i, j) at i·w1 + (i − j). final factor = Float64List(n * w1); for (var i = 0; i < n; i++) { - factor[i * w1] = grid.neighbours[i].length * inv + sigma; - for (final k in grid.neighbours[i]) { + factor[i * w1] = neighbours[i].length * inv + sigma; + for (final k in neighbours[i]) { if (k < i) factor[i * w1 + (i - k)] = -inv; } } @@ -626,7 +704,7 @@ final class FreeSurface { ..sort((x, y) => values[y].compareTo(values[x])); final modes = []; final k2 = []; - final scale = 1.0 / math.sqrt(grid.cell2); + final scale = 1.0 / math.sqrt(cell2); for (final r in order) { if (values[r] <= 0.0) continue; final lambda = 1.0 / values[r] - sigma; @@ -911,3 +989,17 @@ final class _Grid { return best < 0 ? 0.0 : values[best]; } } + +/// Something that works out a cross-section's modes elsewhere and calls back +/// with them: see [FreeSurface.solver]. +abstract interface class ModeSolver { + /// Works out [FreeSurface.solveModes] for these and calls [done] with the + /// result, later, on this isolate. + void solve( + int n, + List> neighbours, + double cell2, + int count, + void Function((List, Float64List) modes) done, + ); +} diff --git a/packages/flutter3d_physics/lib/src/fluid/liquid_body.dart b/packages/flutter3d_physics/lib/src/fluid/liquid_body.dart index c314abc74..f64da0d72 100644 --- a/packages/flutter3d_physics/lib/src/fluid/liquid_body.dart +++ b/packages/flutter3d_physics/lib/src/fluid/liquid_body.dart @@ -4,6 +4,7 @@ import 'package:vector_math/vector_math.dart'; import '../portable_math.dart'; import 'atmosphere.dart'; +import 'background/fluid_background.dart'; import 'capillary.dart'; import 'fluid_medium.dart'; import 'free_surface.dart'; @@ -580,7 +581,58 @@ final class LiquidBody implements JetReceiver { _menisciG = _g; } final key = (Portable.log(radius) / 0.01).round(); - return _menisci[key] ??= _sharedMeniscus(medium, key, _menisciG); + final have = _menisci[key]; + if (have != null) return have; + final bg = background; + if (bg != null) { + final shared = _menisciShared[_meniscusId(medium, key, _menisciG)]; + if (shared != null) return _menisci[key] = shared; + // **Asked of the background, not waited for**: until it comes, the + // nearest radius's meniscus stands in, or none. + _askMeniscus(bg, medium, key, _menisciG); + TubeMeniscus? nearest; + var gap = 1 << 30; + _menisci.forEach((k, m) { + if ((k - key).abs() < gap) { + gap = (k - key).abs(); + nearest = m; + } + }); + return nearest; + } + return _menisci[key] = _sharedMeniscus(medium, key, _menisciG); + } + + /// Where a meniscus not yet worked out is worked out instead of waited + /// for; set by a world that may be stepped so (`FluidWorld.background`). + FluidBackground? background; + + static final Set<(double, double, double, double, int)> _menisciAsked = {}; + + static (double, double, double, double, int) _meniscusId( + FluidMedium medium, + int key, + double g, + ) => ( + medium.density, + medium.surfaceTension, + medium.contactAngle, + (g * 1000).roundToDouble(), + key, + ); + + static void _askMeniscus( + FluidBackground bg, + FluidMedium medium, + int key, + double g, + ) { + final id = _meniscusId(medium, key, g); + if (!_menisciAsked.add(id)) return; + bg.meniscus(medium, Portable.exp(key * 0.01), id.$4 / 1000, (m) { + _menisciAsked.remove(id); + _menisciShared[id] = m; + }); } /// **One meniscus for every vessel of the liquid and gravity**: the @@ -592,14 +644,8 @@ final class LiquidBody implements JetReceiver { static TubeMeniscus _sharedMeniscus(FluidMedium medium, int key, double g) { // Gravity to a part in a thousand, as a vessel's own cache keeps it. - final gKey = (g * 1000).roundToDouble(); - final id = ( - medium.density, - medium.surfaceTension, - medium.contactAngle, - gKey, - key, - ); + final id = _meniscusId(medium, key, g); + final gKey = id.$4; if (_menisciShared.length > 4096) _menisciShared.clear(); return _menisciShared[id] ??= TubeMeniscus( medium: medium, diff --git a/packages/flutter3d_physics/test/fluid/background_test.dart b/packages/flutter3d_physics/test/fluid/background_test.dart new file mode 100644 index 000000000..049eb761a --- /dev/null +++ b/packages/flutter3d_physics/test/fluid/background_test.dart @@ -0,0 +1,108 @@ +import 'dart:math' as math; +import 'dart:typed_data'; + +import 'package:flutter3d_physics/flutter3d_physics.dart'; +import 'package:test/test.dart'; +import 'package:vector_math/vector_math.dart'; + +/// Lets the other isolate answer everything it has been asked. +Future _settle() async { + for (var i = 0; i < 400 && fluidBackground!.outstanding > 0; i++) { + await Future.delayed(const Duration(milliseconds: 5)); + } +} + +void main() { + test( + 'modes worked out on the other isolate are the same, to the bit', + () async { + // A 9 × 9 square of cells, each with its neighbours inside. + const side = 9; + final neighbours = [ + for (var r = 0; r < side; r++) + for (var c = 0; c < side; c++) + [ + if (c + 1 < side) r * side + c + 1, + if (c > 0) r * side + c - 1, + if (r + 1 < side) (r + 1) * side + c, + if (r > 0) (r - 1) * side + c, + ], + ]; + final here = FreeSurface.solveModes(side * side, neighbours, 1e-6, 4); + (List, Float64List)? there; + fluidBackground!.solve( + side * side, + neighbours, + 1e-6, + 4, + (modes) => there = modes, + ); + await _settle(); + expect(there, isNotNull); + expect(there!.$2, here.$2); + for (var m = 0; m < here.$1.length; m++) { + expect(there!.$1[m], here.$1[m]); + } + }, + ); + + test('a meniscus worked out on the other isolate is the same', () async { + final here = TubeMeniscus( + medium: FluidMedium.water, + radius: 0.0075, + g: 9.81, + ); + TubeMeniscus? there; + fluidBackground!.meniscus( + FluidMedium.water, + 0.0075, + 9.81, + (m) => there = m, + ); + await _settle(); + expect(there!.apexCurvature, here.apexCurvature); + expect(there!.meanHeight, here.meanHeight); + expect(there!.wallRise, here.wallRise); + }); + + test( + 'a tube tipped to a new angle carries on, then takes its modes', + () async { + final world = FluidWorld(gravity: Vector3(0, -9.81, 0), background: true); + final tube = LiquidBody( + shape: RevolvedVessel([ + for (var i = 0; i <= 8; i++) + Vector2( + 0.0075 * math.sin(i * math.pi / 16), + 0.0075 - 0.0075 * math.cos(i * math.pi / 16), + ), + Vector2(0.0075, 0.1), + ]), + medium: FluidMedium.water, + volume: 3e-6, + modes: 4, + ); + world.bodies.add(tube); + void at(double tilt) { + tube.place( + Matrix3.rotationX(tilt), + Vector3.zero(), + time: world.time + world.step, + ); + world.advance(world.step); + } + + for (var i = 0; i < 10; i++) { + at(0.0); + } + // An angle no tube has been at here: its cross-section is new. + at(0.6123); + expect(tube.surface.waitingForModes, isTrue); + await _settle(); + at(0.6123); + expect(tube.surface.waitingForModes, isFalse); + // And the liquid is all there throughout. + expect(tube.volume, closeTo(3e-6, 1e-18)); + }, + ); +} diff --git a/site/content/core/liquids.md b/site/content/core/liquids.md index be42f1345..b482dc2d2 100644 --- a/site/content/core/liquids.md +++ b/site/content/core/liquids.md @@ -113,6 +113,13 @@ A body holds layers. Liquids that mix are one layer, keeping amounts of solutes, A body turning in the liquid is held back too, by Stokes's torque 8πμR³ω on the sphere of its volume, for the part of it that is under: a ball spun in glycerol slows by e in ρR²/15μ. +## Faster, where a run need not replay + +Two switches on `FluidWorld` trade the bit-for-bit replay for speed, and change nothing that happens otherwise. + +- `nativeKernels: true` runs the particles' pair loops and neighbour search in C, built by the package's own hook with the machine's C compiler and vectorised. Each kernel matches the Dart one to a part in 10¹². Where no compiler was found, and on the web, the Dart kernels run. +- `background: true` works out what would stop a frame, a cross-section's modes or a meniscus not met before, on another isolate. The vessel carries on as it was until the answer comes. On the web there are no isolates, and it is all worked out at once. + ## Being honest about it - The surface is linear, so it rocks harder where real water would break. diff --git a/site/content/quickstart.md b/site/content/quickstart.md index b2621122a..efcd5d301 100644 --- a/site/content/quickstart.md +++ b/site/content/quickstart.md @@ -91,7 +91,7 @@ tool/ci.sh # shaders, analyze, every test (cd packages/flutter3d_physics && dart test) # plain Dart, no Flutter needed ``` -There are 11371 tests across 43 packages and twelve applications, and only about thirty need a GPU: the Impeller half of the golden set. The other half renders through the software backend, so ninety scenes stay checkable in a headless run. +There are 11374 tests across 43 packages and twelve applications, and only about thirty need a GPU: the Impeller half of the golden set. The other half renders through the software backend, so ninety scenes stay checkable in a headless run. ## Your own application diff --git a/site/content/reference/testing.md b/site/content/reference/testing.md index ced8659a1..01c26e0ab 100644 --- a/site/content/reference/testing.md +++ b/site/content/reference/testing.md @@ -1,10 +1,10 @@ --- -description: Four independent golden sets, mutation-checking every new test, determinism and snapshots, and why only about thirty of 11371 tests need a GPU. +description: Four independent golden sets, mutation-checking every new test, determinism and snapshots, and why only about thirty of 11374 tests need a GPU. --- # Testing -11371 tests across 43 packages and nine applications, counted the same way the `the document says how many tests there are` rule does: a scan of every `test(`/`testWidgets(` call. The rule holds `ARCHITECTURE.md` §13, the README and this page to the answer. The README went on saying 1242 across thirteen packages for as long as nothing compared it with anything. About thirty need a GPU; the [architecture](/core/architecture/) is what keeps the number that low. +11374 tests across 43 packages and nine applications, counted the same way the `the document says how many tests there are` rule does: a scan of every `test(`/`testWidgets(` call. The rule holds `ARCHITECTURE.md` §13, the README and this page to the answer. The README went on saying 1242 across thirteen packages for as long as nothing compared it with anything. About thirty need a GPU; the [architecture](/core/architecture/) is what keeps the number that low. | Package | Tests | | Package | Tests | |---|---|---|---|---| @@ -23,7 +23,7 @@ description: Four independent golden sets, mutation-checking every new test, det | `flutter3d_cpu` | 380 | | `apps/flutter3d_demo_strategy` | 50 | | `apps/flutter3d_editor` | 234 | | `apps/flutter3d_demo_arcade` | 20 | | `apps/flutter3d_demo_racing` | 162 | | `pointer_lock` | 28 | -| `flutter3d_physics` | 298 | | `flutter3d_webgpu` | 193 | +| `flutter3d_physics` | 301 | | `flutter3d_webgpu` | 193 | | `flutter3d_game_strategy` | 133 | | `flutter3d_editor_mcp` | 36 | | `apps/flutter3d_demo_river` | 54 | | `flutter3d_testing` | 45 | | `flutter3d_editor_core` | 141 | | `flutter3d_editor_widgets` | 91 | @@ -40,7 +40,7 @@ description: Four independent golden sets, mutation-checking every new test, det | `flame_flutter3d` | 140 | | `apps/flutter3d_showcase` | 88 | | `flame_multiplayer` | 9 | | `flame_multiplayer_dashwire` | 3 | -The rows sum to 11344 rather than 11371: the remaining 26 live in `packages/*/example/test`, which the count includes and this table does not, among them the two seeds a new project starts from, `packages/flutter3d_app/example` and `packages/flutter3d_game/example`. +The rows sum to 11347 rather than 11374: the remaining 26 live in `packages/*/example/test`, which the count includes and this table does not, among them the two seeds a new project starts from, `packages/flutter3d_app/example` and `packages/flutter3d_game/example`. `flutter3d_samples` is not in the table and has no `test/` at all: it is test data with two path constants over it, and other packages' decoder tests are what exercise it. `flutter3d_conformance` is missing for a different reason: it is invoked as a script harness rather than through `flutter test`, so it does not surface in a grep of `test(` calls either. See below for what that cost once. From 8bfc8989f5fe5858072c91bae2e3a6b5e5d583b1 Mon Sep 17 00:00:00 2001 From: Dmitrii Zolotov Date: Sat, 3 Oct 2026 17:31:39 +0300 Subject: [PATCH 27/34] perf: Work out a surface's modes natively with the native kernels A world with nativeKernels: true now runs the heavy half of a cross-section's mode solve in C too: the banded Cholesky factor and the Lanczos steps with full reorthogonalisation, a millisecond where Dart takes three or four. The tridiagonal is finished in Dart from the same start vector. Native and Dart modes are cached apart, so a world that must replay never reads the other's, and the background isolate solves natively when asked to. --- ARCHITECTURE.md | 2 +- README.md | 2 +- packages/flutter3d_physics/hook/build.dart | 2 +- .../fluid/background/fluid_background_io.dart | 8 +- .../lib/src/fluid/fluid_world.dart | 3 +- .../lib/src/fluid/free_surface.dart | 134 +++++++++++++++--- .../lib/src/fluid/native/pbf_native.dart | 62 +++++++- .../lib/src/fluid/native/pbf_none.dart | 16 +++ packages/flutter3d_physics/src/pbf_kernels.c | 2 +- .../flutter3d_physics/src/surface_modes.c | 120 ++++++++++++++++ .../test/fluid/native_kernels_test.dart | 53 +++++++ site/content/quickstart.md | 2 +- site/content/reference/testing.md | 8 +- 13 files changed, 379 insertions(+), 35 deletions(-) create mode 100644 packages/flutter3d_physics/src/surface_modes.c diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index f8739baf6..f37be7259 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -2691,7 +2691,7 @@ storage. |---|---| | Style | `dart format` | | Analysis | `flutter analyze` clean across the workspace, no warnings | -| Unit tests | **11374 tests** across 43 packages and 10 applications | +| Unit tests | **11375 tests** across 43 packages and 10 applications | | Structure rules | 35, `dart run tool/structure.dart`, the first CI step | | CI | GitHub Actions over `tool/ci.sh`, on `ubuntu-latest`, with no graphics card | diff --git a/README.md b/README.md index ff737ebb5..b8090b2b6 100644 --- a/README.md +++ b/README.md @@ -158,7 +158,7 @@ Or one package at a time: (cd packages/flutter3d_physics && dart test) # plain Dart, no Flutter needed ``` -There are 11374 tests across forty-three packages and nine applications. The +There are 11375 tests across forty-three packages and nine applications. The only ones that need a GPU are the Impeller half of the golden set. The other half is rendered by the software backend, which is what makes 90 scenes checkable in a headless run. diff --git a/packages/flutter3d_physics/hook/build.dart b/packages/flutter3d_physics/hook/build.dart index f7f09f297..820b91e8a 100644 --- a/packages/flutter3d_physics/hook/build.dart +++ b/packages/flutter3d_physics/hook/build.dart @@ -28,7 +28,7 @@ void main(List arguments) async { final builder = CBuilder.library( name: 'flutter3d_physics_native', assetName: 'src/fluid/native/pbf_native.dart', - sources: ['src/pbf_kernels.c'], + sources: ['src/pbf_kernels.c', 'src/surface_modes.c'], flags: msvc ? const ['/O2'] : const ['-O3', '-fno-math-errno'], ); try { diff --git a/packages/flutter3d_physics/lib/src/fluid/background/fluid_background_io.dart b/packages/flutter3d_physics/lib/src/fluid/background/fluid_background_io.dart index 91bc6e556..519660e61 100644 --- a/packages/flutter3d_physics/lib/src/fluid/background/fluid_background_io.dart +++ b/packages/flutter3d_physics/lib/src/fluid/background/fluid_background_io.dart @@ -65,9 +65,10 @@ final class FluidBackground implements ModeSolver { List> neighbours, double cell2, int count, - void Function((List, Float64List) modes) done, - ) { - _post(['modes', _next++, n, neighbours, cell2, count], (reply) { + void Function((List, Float64List) modes) done, { + bool native = false, + }) { + _post(['modes', _next++, n, neighbours, cell2, count, native], (reply) { done(( [for (final m in reply[1]! as List) m! as Float64List], reply[2]! as Float64List, @@ -127,6 +128,7 @@ void _work(SendPort back) { (request[3]! as List).cast>(), request[4]! as double, request[5]! as int, + native: request[6]! as bool, ); back.send([id, modes, k2]); case 'meniscus': diff --git a/packages/flutter3d_physics/lib/src/fluid/fluid_world.dart b/packages/flutter3d_physics/lib/src/fluid/fluid_world.dart index f72946435..ee898f544 100644 --- a/packages/flutter3d_physics/lib/src/fluid/fluid_world.dart +++ b/packages/flutter3d_physics/lib/src/fluid/fluid_world.dart @@ -139,7 +139,8 @@ final class FluidWorld { for (final body in bodies) { body ..background = helper - ..surface.solver = helper; + ..surface.solver = helper + ..surface.nativeModes = nativeKernels; } for (final liquid in bodies) { var displaced = 0.0; diff --git a/packages/flutter3d_physics/lib/src/fluid/free_surface.dart b/packages/flutter3d_physics/lib/src/fluid/free_surface.dart index 674c48f4b..4be52efac 100644 --- a/packages/flutter3d_physics/lib/src/fluid/free_surface.dart +++ b/packages/flutter3d_physics/lib/src/fluid/free_surface.dart @@ -5,6 +5,7 @@ import 'package:vector_math/vector_math.dart'; import '../portable_math.dart'; import 'fluid_medium.dart'; +import 'native/pbf_backend.dart'; import 'vessel_shape.dart'; /// The waves on a liquid's free surface in a vessel of any shape: how far @@ -123,16 +124,17 @@ final class FreeSurface { old != null && _modes.isNotEmpty && grid.count >= 6 && - _cachedModes(grid, modeCount) == null) { + _cachedModes(grid, modeCount, nativeModes) == null) { _wanted = (shape: shape, up: up.clone(), height: height, grid: grid); final count = modeCount; + final native = nativeModes; // Asked once, however many steps go by before it comes. - final key = _keyOf(grid, count); + final key = _keyOf(grid, count, native); if (_asked.add(key)) { defer.solve(grid.count, grid.neighbours, grid.cell2, count, (modes) { _asked.remove(key); - _remember(grid, count, modes); - }); + _remember(grid, count, native, modes); + }, native: native); } _carryOn(old, up, height); return; @@ -149,7 +151,7 @@ final class FreeSurface { _rate = Float64List(0); return; } - final (shapes, k2) = _modesOf(grid, modeCount); + final (shapes, k2) = _modesOf(grid, modeCount, nativeModes); _modes = shapes; _k2 = k2; // The liquid stays: what stood off the old plane stands off the new one @@ -184,6 +186,11 @@ final class FreeSurface { _field = null; } + /// Whether its cross-sections' modes are worked out natively where that + /// was built; set by a world that may be stepped so + /// (`FluidWorld.nativeKernels`). + bool nativeModes = false; + /// Where cross-sections not yet worked out are worked out instead of /// waited for: another isolate, set by a world that may be stepped so /// (`FluidWorld.background`). Null, they are worked out at once. @@ -206,7 +213,8 @@ final class FreeSurface { _depth = depth; // The modes put off for have come: laid out now, as it would have been. final wanted = _wanted; - if (wanted != null && _cachedModes(wanted.grid, modeCount) != null) { + if (wanted != null && + _cachedModes(wanted.grid, modeCount, nativeModes) != null) { _wanted = null; layOut(wanted.shape, wanted.up, wanted.height); } @@ -502,27 +510,40 @@ final class FreeSurface { /// tube being poured into worked out its modes every other step, fifty /// milliseconds each, and that was most of a pour's cost. Read only, so /// shared between surfaces. - static (List, Float64List) _modesOf(_Grid grid, int count) { - final cached = _cachedModes(grid, count); + /// + /// Kept apart by [native]: a world that must replay to the bit never + /// reads modes the native solve worked out for another. + static (List, Float64List) _modesOf( + _Grid grid, + int count, + bool native, + ) { + final cached = _cachedModes(grid, count, native); if (cached != null) return cached; - final modes = _lowestModes(grid, count); - _remember(grid, count, modes); + final modes = _lowestModes(grid, count, native: native); + _remember(grid, count, native, modes); return modes; } - static int _keyOf(_Grid grid, int count) => Object.hash( + static int _keyOf(_Grid grid, int count, bool native) => Object.hash( count, + native, grid.columns, grid.rows, grid.cell, Object.hashAll(grid.index), ); - static (List, Float64List)? _cachedModes(_Grid grid, int count) { - final hits = _solved[_keyOf(grid, count)]; + static (List, Float64List)? _cachedModes( + _Grid grid, + int count, + bool native, + ) { + final hits = _solved[_keyOf(grid, count, native)]; if (hits == null) return null; for (final hit in hits) { if (hit.count == count && + hit.native == native && hit.columns == grid.columns && hit.rows == grid.rows && hit.cell == grid.cell && @@ -536,12 +557,14 @@ final class FreeSurface { static void _remember( _Grid grid, int count, + bool native, (List, Float64List) modes, ) { - if (_cachedModes(grid, count) != null) return; + if (_cachedModes(grid, count, native) != null) return; if (_solved.length >= 256) _solved.remove(_solved.keys.first); - (_solved[_keyOf(grid, count)] ??= []).add(( + (_solved[_keyOf(grid, count, native)] ??= []).add(( count: count, + native: native, columns: grid.columns, rows: grid.rows, cell: grid.cell, @@ -563,6 +586,7 @@ final class FreeSurface { List< ({ int count, + bool native, int columns, int rows, double cell, @@ -573,18 +597,31 @@ final class FreeSurface { > _solved = {}; - static (List, Float64List) _lowestModes(_Grid grid, int count) => - solveModes(grid.count, grid.neighbours, grid.cell2, count); + static (List, Float64List) _lowestModes( + _Grid grid, + int count, { + bool native = false, + }) => solveModes( + grid.count, + grid.neighbours, + grid.cell2, + count, + native: native, + ); /// The lowest [count] non-flat modes of the graph Laplacian of [n] cells /// [cell2] square metres each, with [neighbours] inside, and their k²: /// all the solve needs, so another isolate can do it from these alone. + /// + /// [native] runs the Lanczos steps in C where that was built: the same + /// steps, to within a tolerance rather than to the bit. static (List, Float64List) solveModes( int n, List> neighbours, double cell2, - int count, - ) { + int count, { + bool native = false, + }) { final inv = 1.0 / cell2; // The graph Laplacian: each cell against the neighbours it has inside. // A neighbour outside is the wall, and leaving it out is ∂φ/∂n = 0. @@ -664,6 +701,45 @@ final class FreeSurface { } _removeMean(q); _normalise(q); + if (native) { + final start = Int32List(n + 1); + for (var i = 0; i < n; i++) { + start[i + 1] = start[i] + neighbours[i].length; + } + final adjacent = Int32List(start[n]); + for (var i = 0; i < n; i++) { + adjacent.setAll(start[i], neighbours[i]); + } + final rows = Float64List(steps * n); + final a = Float64List(steps); + final bs = Float64List(steps); + final size = nativeSurfaceLanczos( + n, + start, + adjacent, + cell2, + band, + steps, + q, + rows, + a, + bs, + ); + if (size > 0) { + return _finishModes( + n, + cell2, + count, + sigma, + [ + for (var m = 0; m < size; m++) + Float64List.sublistView(rows, m * n, (m + 1) * n), + ], + [for (var m = 0; m < size; m++) a[m]], + [for (var m = 0; m < size - 1; m++) bs[m]], + ); + } + } var previous = Float64List(n); var b = 0.0; for (var m = 0; m < steps; m++) { @@ -697,6 +773,21 @@ final class FreeSurface { q[i] = w[i] / b; } } + return _finishModes(n, cell2, count, sigma, basis, alpha, beta); + } + + /// The modes from the Lanczos [basis] and its tridiagonal [alpha] and + /// [beta]: its eigenvectors, the highest of (L + σ)⁻¹ first, carried back + /// into the cells. + static (List, Float64List) _finishModes( + int n, + double cell2, + int count, + double sigma, + List basis, + List alpha, + List beta, + ) { final size = alpha.length; final (values, vectors) = _tridiagonalEigen(alpha, beta, size); // Highest of L⁻¹ first, which is lowest of L. @@ -1000,6 +1091,7 @@ abstract interface class ModeSolver { List> neighbours, double cell2, int count, - void Function((List, Float64List) modes) done, - ); + void Function((List, Float64List) modes) done, { + bool native = false, + }); } diff --git a/packages/flutter3d_physics/lib/src/fluid/native/pbf_native.dart b/packages/flutter3d_physics/lib/src/fluid/native/pbf_native.dart index 3ed4e41e7..4a90b529c 100644 --- a/packages/flutter3d_physics/lib/src/fluid/native/pbf_native.dart +++ b/packages/flutter3d_physics/lib/src/fluid/native/pbf_native.dart @@ -183,11 +183,71 @@ external int _within( Pointer out, ); +@Native< + Int32 Function( + Int32, + Pointer, + Pointer, + Double, + Int32, + Int32, + Pointer, + Pointer, + Pointer, + Pointer, + Pointer, + ) +>(symbol: 'f3d_surface_lanczos', isLeaf: true) +external int _surfaceLanczos( + int n, + Pointer start, + Pointer adjacent, + double cell2, + int band, + int steps, + Pointer q0, + Pointer basis, + Pointer alpha, + Pointer beta, + Pointer scratch, +); + +/// The Lanczos steps of `FreeSurface.solveModes` in C, into [basis], +/// [alpha] and [beta]: how many ran, or -1 where there is no native code. +int nativeSurfaceLanczos( + int n, + Int32List start, + Int32List adjacent, + double cell2, + int band, + int steps, + Float64List q0, + Float64List basis, + Float64List alpha, + Float64List beta, +) { + if (!nativePbfAvailable) return -1; + final scratch = Float64List(n * (band + 1) + 2 * n); + return _surfaceLanczos( + n, + start.address, + (adjacent.isEmpty ? Int32List(1) : adjacent).address, + cell2, + band, + steps, + q0.address, + basis.address, + alpha.address, + (beta.isEmpty ? Float64List(1) : beta).address, + scratch.address, + ); +} + /// Whether the native kernels were built and load: false where the build /// had no C compiler, and asked once. final bool nativePbfAvailable = () { try { - return _version() == 3; + return _version() == 4; } on Object { return false; } diff --git a/packages/flutter3d_physics/lib/src/fluid/native/pbf_none.dart b/packages/flutter3d_physics/lib/src/fluid/native/pbf_none.dart index 3f5c5b118..fc3ec39f6 100644 --- a/packages/flutter3d_physics/lib/src/fluid/native/pbf_none.dart +++ b/packages/flutter3d_physics/lib/src/fluid/native/pbf_none.dart @@ -1,4 +1,6 @@ // Where there is no `dart:ffi` (the web): no native kernels. +import 'dart:typed_data'; + import '../pbf_kernels.dart'; /// Always false here. @@ -6,3 +8,17 @@ const bool nativePbfAvailable = false; /// None here. PbfKernels? nativePbfKernels(PbfConstants k) => null; + +/// No native code here: -1. +int nativeSurfaceLanczos( + int n, + Int32List start, + Int32List adjacent, + double cell2, + int band, + int steps, + Float64List q0, + Float64List basis, + Float64List alpha, + Float64List beta, +) => -1; diff --git a/packages/flutter3d_physics/src/pbf_kernels.c b/packages/flutter3d_physics/src/pbf_kernels.c index fa3732f8d..342a0339e 100644 --- a/packages/flutter3d_physics/src/pbf_kernels.c +++ b/packages/flutter3d_physics/src/pbf_kernels.c @@ -76,7 +76,7 @@ static inline f3d_d2 poly6_2(const double* k, f3d_d2 r2) { } #endif -F3D_EXPORT int32_t f3d_pbf_version(void) { return 3; } +F3D_EXPORT int32_t f3d_pbf_version(void) { return 4; } // Of the rows [start] and [list], those within [radius] at [x], in order, // into [out_start] and [out] (room for as many as [list] has). diff --git a/packages/flutter3d_physics/src/surface_modes.c b/packages/flutter3d_physics/src/surface_modes.c new file mode 100644 index 000000000..d476e01d2 --- /dev/null +++ b/packages/flutter3d_physics/src/surface_modes.c @@ -0,0 +1,120 @@ +// The heavy half of `FreeSurface.solveModes`, in C: the banded Cholesky +// factor of the surface's graph Laplacian (shifted by σ) and the Lanczos +// steps on its inverse, with full reorthogonalisation. What comes back, the +// tridiagonal and its basis, is finished in Dart: the tridiagonal is at most +// a few dozen across. +// +// Step for step the Dart one; held to it within a tolerance, since the +// compiler may fuse a multiply and an add where Dart rounds twice. + +#include +#include +#include + +#if defined(_WIN32) +#define F3D_EXPORT __declspec(dllexport) +#else +#define F3D_EXPORT __attribute__((visibility("default"))) +#endif + +static double dot(const double* a, const double* b, int32_t n) { + double s = 0.0; + for (int32_t i = 0; i < n; i++) s += a[i] * b[i]; + return s; +} + +static void remove_mean(double* a, int32_t n) { + double mean = 0.0; + for (int32_t i = 0; i < n; i++) mean += a[i]; + mean /= n; + for (int32_t i = 0; i < n; i++) a[i] -= mean; +} + +// x = (L + σ)⁻¹ b on the flat-free part, by the factor's two sweeps. +static void solve(const double* factor, int32_t n, int32_t band, + const double* b, double* x) { + const int32_t w1 = band + 1; + memcpy(x, b, sizeof(double) * (size_t)n); + remove_mean(x, n); + for (int32_t i = 0; i < n; i++) { + double sum = x[i]; + const int32_t lo = i - band > 0 ? i - band : 0; + for (int32_t k = lo; k < i; k++) sum -= factor[i * w1 + (i - k)] * x[k]; + x[i] = sum / factor[i * w1]; + } + for (int32_t i = n - 1; i >= 0; i--) { + double sum = x[i]; + const int32_t hi = i + band < n - 1 ? i + band : n - 1; + for (int32_t k = i + 1; k <= hi; k++) { + sum -= factor[k * w1 + (k - i)] * x[k]; + } + x[i] = sum / factor[i * w1]; + } + remove_mean(x, n); +} + +// Lanczos on (L + σ)⁻¹ from [q0] for at most [steps] steps: [basis] (steps +// rows of n), [alpha] and [beta] (one fewer). Returns how many steps ran. +// [scratch] holds n·(band + 1) + 2·n doubles, the caller's own. +F3D_EXPORT int32_t f3d_surface_lanczos(int32_t n, const int32_t* start, + const int32_t* adjacent, double cell2, + int32_t band, int32_t steps, + const double* q0, double* basis, + double* alpha, double* beta, + double* scratch) { + const double inv = 1.0 / cell2; + const double sigma = 1e-6 * inv; + const int32_t w1 = band + 1; + double* factor = scratch; + double* w = scratch + (size_t)n * w1; + double* previous = w + n; + memset(factor, 0, sizeof(double) * (size_t)n * w1); + for (int32_t i = 0; i < n; i++) { + factor[i * w1] = (start[i + 1] - start[i]) * inv + sigma; + for (int32_t q = start[i]; q < start[i + 1]; q++) { + const int32_t k = adjacent[q]; + if (k < i) factor[i * w1 + (i - k)] = -inv; + } + } + for (int32_t i = 0; i < n; i++) { + const int32_t lo = i - band > 0 ? i - band : 0; + for (int32_t j = lo; j <= i; j++) { + double sum = factor[i * w1 + (i - j)]; + const int32_t from = lo > j - band ? lo : j - band; + for (int32_t k = from; k < j; k++) { + sum -= factor[i * w1 + (i - k)] * factor[j * w1 + (j - k)]; + } + factor[i * w1 + (i - j)] = + i == j ? sqrt(sum > 1e-300 ? sum : 1e-300) : sum / factor[j * w1]; + } + } + memset(previous, 0, sizeof(double) * (size_t)n); + memcpy(basis, q0, sizeof(double) * (size_t)n); + double b = 0.0; + int32_t size = 0; + for (int32_t m = 0; m < steps; m++) { + const double* q = basis + (size_t)m * n; + solve(factor, n, band, q, w); + for (int32_t i = 0; i < n; i++) w[i] -= b * previous[i]; + const double a = dot(w, q, n); + for (int32_t i = 0; i < n; i++) w[i] -= a * q[i]; + // Full reorthogonalisation, twice: Lanczos alone loses it. + for (int32_t pass = 0; pass < 2; pass++) { + for (int32_t v = 0; v <= m; v++) { + const double* row = basis + (size_t)v * n; + const double c = dot(w, row, n); + for (int32_t i = 0; i < n; i++) w[i] -= c * row[i]; + } + remove_mean(w, n); + } + alpha[m] = a; + size = m + 1; + b = sqrt(dot(w, w, n)); + if (b < 1e-12 * fabs(a) || m == steps - 1) break; + beta[m] = b; + memcpy(previous, q, sizeof(double) * (size_t)n); + double* next = basis + (size_t)(m + 1) * n; + for (int32_t i = 0; i < n; i++) next[i] = w[i] / b; + } + return size; +} diff --git a/packages/flutter3d_physics/test/fluid/native_kernels_test.dart b/packages/flutter3d_physics/test/fluid/native_kernels_test.dart index 7884ffbe1..1709fe253 100644 --- a/packages/flutter3d_physics/test/fluid/native_kernels_test.dart +++ b/packages/flutter3d_physics/test/fluid/native_kernels_test.dart @@ -171,4 +171,57 @@ void main() { expect((fast - reference).length, lessThan(0.001)); }, ); + + test('the native modes of a round cross-section are the Dart ones', () { + // A disc of cells twelve across its radius, as a test tube's surface. + const r = 12; + final index = {}; + for (var y = -r; y <= r; y++) { + for (var x = -r; x <= r; x++) { + if (x * x + y * y <= r * r) { + index[(y + r) * 100 + (x + r)] = index.length; + } + } + } + final neighbours = List>.generate(index.length, (_) => []); + index.forEach((key, i) { + for (final d in const [1, -1, 100, -100]) { + final j = index[key + d]; + if (j != null) neighbours[i].add(j); + } + }); + final n = index.length; + const cell2 = 0.0006 * 0.0006; + final dart = FreeSurface.solveModes(n, neighbours, cell2, 4); + final native = FreeSurface.solveModes( + n, + neighbours, + cell2, + 4, + native: true, + ); + for (var m = 0; m < 4; m++) { + expect(native.$2[m], closeTo(dart.$2[m], dart.$2[m] * 1e-9)); + } + // Each native mode lies in the span of the Dart modes of its own k²: + // a round section's come in pairs, and either turn of a pair is right. + double dot(Float64List a, Float64List b) { + var s = 0.0; + for (var i = 0; i < n; i++) { + s += a[i] * b[i]; + } + return s; + } + + for (var m = 0; m < 4; m++) { + final mode = native.$1[m]; + var projected = 0.0; + for (var d = 0; d < 4; d++) { + if ((dart.$2[d] - native.$2[m]).abs() > dart.$2[d] * 1e-6) continue; + final c = dot(mode, dart.$1[d]) / dot(dart.$1[d], dart.$1[d]); + projected += c * c * dot(dart.$1[d], dart.$1[d]); + } + expect(projected / dot(mode, mode), closeTo(1.0, 1e-9)); + } + }); } diff --git a/site/content/quickstart.md b/site/content/quickstart.md index efcd5d301..428a5e599 100644 --- a/site/content/quickstart.md +++ b/site/content/quickstart.md @@ -91,7 +91,7 @@ tool/ci.sh # shaders, analyze, every test (cd packages/flutter3d_physics && dart test) # plain Dart, no Flutter needed ``` -There are 11374 tests across 43 packages and twelve applications, and only about thirty need a GPU: the Impeller half of the golden set. The other half renders through the software backend, so ninety scenes stay checkable in a headless run. +There are 11375 tests across 43 packages and twelve applications, and only about thirty need a GPU: the Impeller half of the golden set. The other half renders through the software backend, so ninety scenes stay checkable in a headless run. ## Your own application diff --git a/site/content/reference/testing.md b/site/content/reference/testing.md index 01c26e0ab..cd40fa7db 100644 --- a/site/content/reference/testing.md +++ b/site/content/reference/testing.md @@ -1,10 +1,10 @@ --- -description: Four independent golden sets, mutation-checking every new test, determinism and snapshots, and why only about thirty of 11374 tests need a GPU. +description: Four independent golden sets, mutation-checking every new test, determinism and snapshots, and why only about thirty of 11375 tests need a GPU. --- # Testing -11374 tests across 43 packages and nine applications, counted the same way the `the document says how many tests there are` rule does: a scan of every `test(`/`testWidgets(` call. The rule holds `ARCHITECTURE.md` §13, the README and this page to the answer. The README went on saying 1242 across thirteen packages for as long as nothing compared it with anything. About thirty need a GPU; the [architecture](/core/architecture/) is what keeps the number that low. +11375 tests across 43 packages and nine applications, counted the same way the `the document says how many tests there are` rule does: a scan of every `test(`/`testWidgets(` call. The rule holds `ARCHITECTURE.md` §13, the README and this page to the answer. The README went on saying 1242 across thirteen packages for as long as nothing compared it with anything. About thirty need a GPU; the [architecture](/core/architecture/) is what keeps the number that low. | Package | Tests | | Package | Tests | |---|---|---|---|---| @@ -23,7 +23,7 @@ description: Four independent golden sets, mutation-checking every new test, det | `flutter3d_cpu` | 380 | | `apps/flutter3d_demo_strategy` | 50 | | `apps/flutter3d_editor` | 234 | | `apps/flutter3d_demo_arcade` | 20 | | `apps/flutter3d_demo_racing` | 162 | | `pointer_lock` | 28 | -| `flutter3d_physics` | 301 | | `flutter3d_webgpu` | 193 | +| `flutter3d_physics` | 302 | | `flutter3d_webgpu` | 193 | | `flutter3d_game_strategy` | 133 | | `flutter3d_editor_mcp` | 36 | | `apps/flutter3d_demo_river` | 54 | | `flutter3d_testing` | 45 | | `flutter3d_editor_core` | 141 | | `flutter3d_editor_widgets` | 91 | @@ -40,7 +40,7 @@ description: Four independent golden sets, mutation-checking every new test, det | `flame_flutter3d` | 140 | | `apps/flutter3d_showcase` | 88 | | `flame_multiplayer` | 9 | | `flame_multiplayer_dashwire` | 3 | -The rows sum to 11347 rather than 11374: the remaining 26 live in `packages/*/example/test`, which the count includes and this table does not, among them the two seeds a new project starts from, `packages/flutter3d_app/example` and `packages/flutter3d_game/example`. +The rows sum to 11348 rather than 11375: the remaining 26 live in `packages/*/example/test`, which the count includes and this table does not, among them the two seeds a new project starts from, `packages/flutter3d_app/example` and `packages/flutter3d_game/example`. `flutter3d_samples` is not in the table and has no `test/` at all: it is test data with two path constants over it, and other packages' decoder tests are what exercise it. `flutter3d_conformance` is missing for a different reason: it is invoked as a script harness rather than through `flutter test`, so it does not surface in a grep of `test(` calls either. See below for what that cost once. From 971a796ce10d7090024201b03550c65071c9dc21 Mon Sep 17 00:00:00 2001 From: Dmitrii Zolotov Date: Sat, 3 Oct 2026 17:34:40 +0300 Subject: [PATCH 28/34] perf: Solve menisci natively with the native kernels TubeMeniscus takes native: true and runs the same Illinois search over Runge-Kutta shots in C, on the platform's sine and cosine. It agrees with the Dart solve to about 1e-16 and takes 0.34 ms where Dart takes 0.56. A world with nativeKernels sets it on its vessels; native and Dart menisci are cached apart, and the background isolate solves the kind it is asked for. --- ARCHITECTURE.md | 2 +- README.md | 2 +- packages/flutter3d_physics/hook/build.dart | 2 +- .../fluid/background/fluid_background_io.dart | 7 +- .../background/fluid_background_none.dart | 5 +- .../lib/src/fluid/capillary.dart | 19 ++- .../lib/src/fluid/fluid_world.dart | 1 + .../lib/src/fluid/liquid_body.dart | 52 +++++-- .../lib/src/fluid/native/pbf_native.dart | 60 +++++++- .../lib/src/fluid/native/pbf_none.dart | 8 ++ packages/flutter3d_physics/src/meniscus.c | 135 ++++++++++++++++++ packages/flutter3d_physics/src/pbf_kernels.c | 2 +- .../test/fluid/native_kernels_test.dart | 26 ++++ site/content/quickstart.md | 2 +- site/content/reference/testing.md | 8 +- 15 files changed, 304 insertions(+), 27 deletions(-) create mode 100644 packages/flutter3d_physics/src/meniscus.c diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index f37be7259..7a58d2706 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -2691,7 +2691,7 @@ storage. |---|---| | Style | `dart format` | | Analysis | `flutter analyze` clean across the workspace, no warnings | -| Unit tests | **11375 tests** across 43 packages and 10 applications | +| Unit tests | **11376 tests** across 43 packages and 10 applications | | Structure rules | 35, `dart run tool/structure.dart`, the first CI step | | CI | GitHub Actions over `tool/ci.sh`, on `ubuntu-latest`, with no graphics card | diff --git a/README.md b/README.md index b8090b2b6..cf84ff860 100644 --- a/README.md +++ b/README.md @@ -158,7 +158,7 @@ Or one package at a time: (cd packages/flutter3d_physics && dart test) # plain Dart, no Flutter needed ``` -There are 11375 tests across forty-three packages and nine applications. The +There are 11376 tests across forty-three packages and nine applications. The only ones that need a GPU are the Impeller half of the golden set. The other half is rendered by the software backend, which is what makes 90 scenes checkable in a headless run. diff --git a/packages/flutter3d_physics/hook/build.dart b/packages/flutter3d_physics/hook/build.dart index 820b91e8a..73767f563 100644 --- a/packages/flutter3d_physics/hook/build.dart +++ b/packages/flutter3d_physics/hook/build.dart @@ -28,7 +28,7 @@ void main(List arguments) async { final builder = CBuilder.library( name: 'flutter3d_physics_native', assetName: 'src/fluid/native/pbf_native.dart', - sources: ['src/pbf_kernels.c', 'src/surface_modes.c'], + sources: ['src/pbf_kernels.c', 'src/surface_modes.c', 'src/meniscus.c'], flags: msvc ? const ['/O2'] : const ['-O3', '-fno-math-errno'], ); try { diff --git a/packages/flutter3d_physics/lib/src/fluid/background/fluid_background_io.dart b/packages/flutter3d_physics/lib/src/fluid/background/fluid_background_io.dart index 519660e61..0a64a511b 100644 --- a/packages/flutter3d_physics/lib/src/fluid/background/fluid_background_io.dart +++ b/packages/flutter3d_physics/lib/src/fluid/background/fluid_background_io.dart @@ -82,8 +82,9 @@ final class FluidBackground implements ModeSolver { FluidMedium medium, double radius, double g, - void Function(TubeMeniscus meniscus) done, - ) { + void Function(TubeMeniscus meniscus) done, { + bool native = false, + }) { _post( [ 'meniscus', @@ -95,6 +96,7 @@ final class FluidBackground implements ModeSolver { medium.contactAngle, radius, g, + native, ], (reply) { done( @@ -143,6 +145,7 @@ void _work(SendPort back) { medium: medium, radius: request[7]! as double, g: request[8]! as double, + native: request[9]! as bool, ).solution; back.send([id, m.apexCurvature, m.r, m.z]); } diff --git a/packages/flutter3d_physics/lib/src/fluid/background/fluid_background_none.dart b/packages/flutter3d_physics/lib/src/fluid/background/fluid_background_none.dart index b66d834f3..f39a3675c 100644 --- a/packages/flutter3d_physics/lib/src/fluid/background/fluid_background_none.dart +++ b/packages/flutter3d_physics/lib/src/fluid/background/fluid_background_none.dart @@ -14,8 +14,9 @@ abstract final class FluidBackground implements ModeSolver { FluidMedium medium, double radius, double g, - void Function(TubeMeniscus meniscus) done, - ); + void Function(TubeMeniscus meniscus) done, { + bool native = false, + }); } /// None here: what would be put off is worked out at once. diff --git a/packages/flutter3d_physics/lib/src/fluid/capillary.dart b/packages/flutter3d_physics/lib/src/fluid/capillary.dart index a7a5dc4f3..10f42d007 100644 --- a/packages/flutter3d_physics/lib/src/fluid/capillary.dart +++ b/packages/flutter3d_physics/lib/src/fluid/capillary.dart @@ -2,6 +2,7 @@ import 'dart:math' as math; import '../portable_math.dart'; import 'fluid_medium.dart'; +import 'native/pbf_backend.dart'; /// Surface tension at a wall: how high liquid climbs it, and the shape of /// the surface it leaves. @@ -38,8 +39,24 @@ final class TubeMeniscus { required this.radius, required this.g, this.samples = 64, + bool native = false, }) { - _solve(); + final solved = native + ? nativeMeniscus( + radius, + medium.density * g / medium.surfaceTension, + medium.contactAngle, + samples, + ) + : null; + if (solved == null) { + _solve(); + } else { + apexCurvature = solved.apexCurvature; + _r = solved.r; + _z = solved.z; + wallRise = _z.last; + } } /// A meniscus already solved, from what [solution] gave: for one worked diff --git a/packages/flutter3d_physics/lib/src/fluid/fluid_world.dart b/packages/flutter3d_physics/lib/src/fluid/fluid_world.dart index ee898f544..3ec968b37 100644 --- a/packages/flutter3d_physics/lib/src/fluid/fluid_world.dart +++ b/packages/flutter3d_physics/lib/src/fluid/fluid_world.dart @@ -140,6 +140,7 @@ final class FluidWorld { body ..background = helper ..surface.solver = helper + ..nativeMeniscus = nativeKernels ..surface.nativeModes = nativeKernels; } for (final liquid in bodies) { diff --git a/packages/flutter3d_physics/lib/src/fluid/liquid_body.dart b/packages/flutter3d_physics/lib/src/fluid/liquid_body.dart index f64da0d72..714374be1 100644 --- a/packages/flutter3d_physics/lib/src/fluid/liquid_body.dart +++ b/packages/flutter3d_physics/lib/src/fluid/liquid_body.dart @@ -575,21 +575,25 @@ final class LiquidBody implements JetReceiver { final radius = shape.radiusAt(height.clamp(shape.floor, shape.top)); if (radius <= 0.0) return null; if (!identical(_menisciMedium, medium) || - !((_menisciG - _g).abs() < 1e-3 * _g)) { + !((_menisciG - _g).abs() < 1e-3 * _g) || + _menisciNative != nativeMeniscus) { _menisci.clear(); _menisciMedium = medium; _menisciG = _g; + _menisciNative = nativeMeniscus; } + final native = nativeMeniscus; final key = (Portable.log(radius) / 0.01).round(); final have = _menisci[key]; if (have != null) return have; final bg = background; if (bg != null) { - final shared = _menisciShared[_meniscusId(medium, key, _menisciG)]; + final shared = + _menisciShared[_meniscusId(medium, key, _menisciG, native)]; if (shared != null) return _menisci[key] = shared; // **Asked of the background, not waited for**: until it comes, the // nearest radius's meniscus stands in, or none. - _askMeniscus(bg, medium, key, _menisciG); + _askMeniscus(bg, medium, key, _menisciG, native); TubeMeniscus? nearest; var gap = 1 << 30; _menisci.forEach((k, m) { @@ -600,25 +604,35 @@ final class LiquidBody implements JetReceiver { }); return nearest; } - return _menisci[key] = _sharedMeniscus(medium, key, _menisciG); + return _menisci[key] = _sharedMeniscus(medium, key, _menisciG, native); } + bool _menisciNative = false; + + /// Whether its menisci are solved natively where that was built: on the + /// platform's own sine, to within a tolerance of the Dart solve rather + /// than to the bit. Set by a world that may be stepped so + /// (`FluidWorld.nativeKernels`). + bool nativeMeniscus = false; + /// Where a meniscus not yet worked out is worked out instead of waited /// for; set by a world that may be stepped so (`FluidWorld.background`). FluidBackground? background; - static final Set<(double, double, double, double, int)> _menisciAsked = {}; + static final Set<_MeniscusId> _menisciAsked = {}; - static (double, double, double, double, int) _meniscusId( + static _MeniscusId _meniscusId( FluidMedium medium, int key, double g, + bool native, ) => ( medium.density, medium.surfaceTension, medium.contactAngle, (g * 1000).roundToDouble(), key, + native, ); static void _askMeniscus( @@ -626,31 +640,40 @@ final class LiquidBody implements JetReceiver { FluidMedium medium, int key, double g, + bool native, ) { - final id = _meniscusId(medium, key, g); + final id = _meniscusId(medium, key, g, native); if (!_menisciAsked.add(id)) return; bg.meniscus(medium, Portable.exp(key * 0.01), id.$4 / 1000, (m) { _menisciAsked.remove(id); _menisciShared[id] = m; - }); + }, native: native); } /// **One meniscus for every vessel of the liquid and gravity**: the /// shape depends on nothing else, and a bench's six tubes worked out the /// same ones six times over, seven at the first frame, a tenth of a /// second. - static final Map<(double, double, double, double, int), TubeMeniscus> - _menisciShared = {}; + /// + /// Kept apart by whether they were solved natively: a world that must + /// replay to the bit never reads one solved for another. + static final Map<_MeniscusId, TubeMeniscus> _menisciShared = {}; - static TubeMeniscus _sharedMeniscus(FluidMedium medium, int key, double g) { + static TubeMeniscus _sharedMeniscus( + FluidMedium medium, + int key, + double g, + bool native, + ) { // Gravity to a part in a thousand, as a vessel's own cache keeps it. - final id = _meniscusId(medium, key, g); + final id = _meniscusId(medium, key, g, native); final gKey = id.$4; if (_menisciShared.length > 4096) _menisciShared.clear(); return _menisciShared[id] ??= TubeMeniscus( medium: medium, radius: Portable.exp(key * 0.01), g: gKey / 1000, + native: native, ); } @@ -838,3 +861,8 @@ final class OutsideWalls implements JetObstacle { ); } } + +/// What a meniscus is kept by: the liquid's density, surface tension and +/// contact angle, gravity to a part in a thousand, the radius's key, and +/// whether it was solved natively. +typedef _MeniscusId = (double, double, double, double, int, bool); diff --git a/packages/flutter3d_physics/lib/src/fluid/native/pbf_native.dart b/packages/flutter3d_physics/lib/src/fluid/native/pbf_native.dart index 4a90b529c..7a23a382d 100644 --- a/packages/flutter3d_physics/lib/src/fluid/native/pbf_native.dart +++ b/packages/flutter3d_physics/lib/src/fluid/native/pbf_native.dart @@ -243,11 +243,69 @@ int nativeSurfaceLanczos( ); } +@Native< + Int32 Function( + Double, + Double, + Double, + Int32, + Pointer, + Pointer, + Int32, + Pointer, + ) +>(symbol: 'f3d_meniscus', isLeaf: true) +external int _meniscus( + double radius, + double bond, + double contactAngle, + int samples, + Pointer rs, + Pointer zs, + int capacity, + Pointer apex, +); + +/// `TubeMeniscus`'s solve in C: the apex curvature and the surface's +/// points, or null where there is no native code. +({double apexCurvature, List r, List z})? nativeMeniscus( + double radius, + double bond, + double contactAngle, + int samples, +) { + if (!nativePbfAvailable) return null; + var capacity = samples * 4; + final apex = Float64List(1); + while (true) { + final rs = Float64List(capacity); + final zs = Float64List(capacity); + final count = _meniscus( + radius, + bond, + contactAngle, + samples, + rs.address, + zs.address, + capacity, + apex.address, + ); + if (count <= capacity) { + return ( + apexCurvature: apex[0], + r: List.of(Float64List.sublistView(rs, 0, count)), + z: List.of(Float64List.sublistView(zs, 0, count)), + ); + } + capacity = count; + } +} + /// Whether the native kernels were built and load: false where the build /// had no C compiler, and asked once. final bool nativePbfAvailable = () { try { - return _version() == 4; + return _version() == 5; } on Object { return false; } diff --git a/packages/flutter3d_physics/lib/src/fluid/native/pbf_none.dart b/packages/flutter3d_physics/lib/src/fluid/native/pbf_none.dart index fc3ec39f6..b33c2b3a4 100644 --- a/packages/flutter3d_physics/lib/src/fluid/native/pbf_none.dart +++ b/packages/flutter3d_physics/lib/src/fluid/native/pbf_none.dart @@ -22,3 +22,11 @@ int nativeSurfaceLanczos( Float64List alpha, Float64List beta, ) => -1; + +/// No native code here: null. +({double apexCurvature, List r, List z})? nativeMeniscus( + double radius, + double bond, + double contactAngle, + int samples, +) => null; diff --git a/packages/flutter3d_physics/src/meniscus.c b/packages/flutter3d_physics/src/meniscus.c new file mode 100644 index 000000000..a4678ab7a --- /dev/null +++ b/packages/flutter3d_physics/src/meniscus.c @@ -0,0 +1,135 @@ +// `TubeMeniscus._solve` in C: the curvature at the surface's middle that +// meets the wall at the contact angle, by Illinois false position over shots +// of Runge–Kutta in arc length, and the surface it gives. +// +// On the platform's own sine and cosine, many times as quick as the Dart +// one's portable ones, and so held to it within a tolerance, not to the bit: +// for a world that need not replay (`FluidWorld.nativeKernels`). + +#include +#include + +#if defined(_WIN32) +#define F3D_EXPORT __declspec(dllexport) +#else +#define F3D_EXPORT __attribute__((visibility("default"))) +#endif + +#define F3D_PI 3.14159265358979323846 + +static double turn(double bond, double b, double r, double z, double phi) { + return bond * z + b - sin(phi) / (r > 1e-12 ? r : 1e-12); +} + +// One shot from the axis to the wall for apex curvature [b]: the angle it +// meets the wall at. Keeps its points in [rs] and [zs] when they are given, +// [count] of them. +static double shoot(double radius, double bond, double b, int32_t samples, + double* rs, double* zs, int32_t capacity, + int32_t* count) { + const double s0 = radius * 1e-4; + double r = s0; + double z = 0.5 * b * 0.5 * s0 * s0; + double phi = 0.5 * b * s0; + int32_t kept = 0; + if (rs && kept < capacity) { + rs[kept] = 0.0; + zs[kept] = 0.0; + } + kept++; + const double ds = radius / (samples * 2); + int32_t guard = 0; + while (r < radius && guard++ < samples * 400) { + const double k1r = cos(phi), k1z = sin(phi); + const double k1p = turn(bond, b, r, z, phi); + const double k2r = cos(phi + 0.5 * ds * k1p); + const double k2z = sin(phi + 0.5 * ds * k1p); + const double k2p = turn(bond, b, r + 0.5 * ds * k1r, z + 0.5 * ds * k1z, + phi + 0.5 * ds * k1p); + const double k3r = cos(phi + 0.5 * ds * k2p); + const double k3z = sin(phi + 0.5 * ds * k2p); + const double k3p = turn(bond, b, r + 0.5 * ds * k2r, z + 0.5 * ds * k2z, + phi + 0.5 * ds * k2p); + const double k4r = cos(phi + ds * k3p); + const double k4z = sin(phi + ds * k3p); + const double k4p = + turn(bond, b, r + ds * k3r, z + ds * k3z, phi + ds * k3p); + const double nr = r + ds / 6 * (k1r + 2 * k2r + 2 * k3r + k4r); + const double nz = z + ds / 6 * (k1z + 2 * k2z + 2 * k3z + k4z); + const double np = phi + ds / 6 * (k1p + 2 * k2p + 2 * k3p + k4p); + // A surface that turns back on itself before the wall has overshot. + if (nr <= r || fabs(np) > F3D_PI) { + if (count) *count = kept; + return (np > 0.0 ? 1.0 : (np < 0.0 ? -1.0 : 0.0)) * F3D_PI; + } + if (nr >= radius) { + const double t = (radius - r) / (nr - r); + z += (nz - z) * t; + phi += (np - phi) * t; + r = radius; + } else { + r = nr; + z = nz; + phi = np; + } + if (rs) { + if (kept < capacity) { + rs[kept] = r; + zs[kept] = z; + } + kept++; + } + } + if (count) *count = kept; + return phi; +} + +// The meniscus in a tube of [radius]: its apex curvature into [apex], its +// points into [rs] and [zs] (room for [capacity]); returns how many points +// there are, which, if more than [capacity], wants a call with that room. +F3D_EXPORT int32_t f3d_meniscus(double radius, double bond, + double contact_angle, int32_t samples, + double* rs, double* zs, int32_t capacity, + double* apex) { + const double target = F3D_PI / 2 - contact_angle; + double lo = -40.0 / radius, hi = 40.0 / radius; + double flo = shoot(radius, bond, lo, samples, 0, 0, 0, 0) - target; + double fhi = shoot(radius, bond, hi, samples, 0, 0, 0, 0) - target; + int32_t kept = 0; + const double tolerance = (hi - lo) * 8.673617379884035e-19; + for (int32_t i = 0; i < 200 && hi - lo > tolerance; i++) { + double mid = isfinite(flo) && isfinite(fhi) && fhi != flo + ? lo - flo * (hi - lo) / (fhi - flo) + : 0.5 * (lo + hi); + if (!(mid > lo && mid < hi)) mid = 0.5 * (lo + hi); + const double f = shoot(radius, bond, mid, samples, 0, 0, 0, 0) - target; + if (!isfinite(f)) { + if (isfinite(flo) && flo > 0.0) { + hi = mid; + } else { + lo = mid; + } + continue; + } + if (fabs(f) < 1e-15) { + lo = mid; + hi = mid; + break; + } + if (f < 0.0) { + lo = mid; + flo = f; + if (kept == 1) fhi *= 0.5; + kept = 1; + } else { + hi = mid; + fhi = f; + if (kept == -1) flo *= 0.5; + kept = -1; + } + } + *apex = 0.5 * (lo + hi); + int32_t count = 0; + shoot(radius, bond, *apex, samples, rs, zs, capacity, &count); + return count; +} diff --git a/packages/flutter3d_physics/src/pbf_kernels.c b/packages/flutter3d_physics/src/pbf_kernels.c index 342a0339e..7ead37e07 100644 --- a/packages/flutter3d_physics/src/pbf_kernels.c +++ b/packages/flutter3d_physics/src/pbf_kernels.c @@ -76,7 +76,7 @@ static inline f3d_d2 poly6_2(const double* k, f3d_d2 r2) { } #endif -F3D_EXPORT int32_t f3d_pbf_version(void) { return 4; } +F3D_EXPORT int32_t f3d_pbf_version(void) { return 5; } // Of the rows [start] and [list], those within [radius] at [x], in order, // into [out_start] and [out] (room for as many as [list] has). diff --git a/packages/flutter3d_physics/test/fluid/native_kernels_test.dart b/packages/flutter3d_physics/test/fluid/native_kernels_test.dart index 1709fe253..6b0726365 100644 --- a/packages/flutter3d_physics/test/fluid/native_kernels_test.dart +++ b/packages/flutter3d_physics/test/fluid/native_kernels_test.dart @@ -224,4 +224,30 @@ void main() { expect(projected / dot(mode, mode), closeTo(1.0, 1e-9)); } }); + + test('the native meniscus is the Dart one, to within a tolerance', () { + for (final medium in [ + FluidMedium.water, + FluidMedium.ethanol, + FluidMedium.mercury, + ]) { + for (final radius in [0.0005, 0.0075, 0.02]) { + final dart = TubeMeniscus(medium: medium, radius: radius, g: 9.81); + final native = TubeMeniscus( + medium: medium, + radius: radius, + g: 9.81, + native: true, + ); + final scale = dart.apexCurvature.abs() + 1.0 / radius * 1e-6; + expect( + native.apexCurvature, + closeTo(dart.apexCurvature, scale * 1e-9), + reason: '\${medium.name} in \$radius m', + ); + expect(native.wallRise, closeTo(dart.wallRise, radius * 1e-9)); + expect(native.meanHeight, closeTo(dart.meanHeight, radius * 1e-9)); + } + } + }); } diff --git a/site/content/quickstart.md b/site/content/quickstart.md index 428a5e599..5b291f7d6 100644 --- a/site/content/quickstart.md +++ b/site/content/quickstart.md @@ -91,7 +91,7 @@ tool/ci.sh # shaders, analyze, every test (cd packages/flutter3d_physics && dart test) # plain Dart, no Flutter needed ``` -There are 11375 tests across 43 packages and twelve applications, and only about thirty need a GPU: the Impeller half of the golden set. The other half renders through the software backend, so ninety scenes stay checkable in a headless run. +There are 11376 tests across 43 packages and twelve applications, and only about thirty need a GPU: the Impeller half of the golden set. The other half renders through the software backend, so ninety scenes stay checkable in a headless run. ## Your own application diff --git a/site/content/reference/testing.md b/site/content/reference/testing.md index cd40fa7db..a2a327466 100644 --- a/site/content/reference/testing.md +++ b/site/content/reference/testing.md @@ -1,10 +1,10 @@ --- -description: Four independent golden sets, mutation-checking every new test, determinism and snapshots, and why only about thirty of 11375 tests need a GPU. +description: Four independent golden sets, mutation-checking every new test, determinism and snapshots, and why only about thirty of 11376 tests need a GPU. --- # Testing -11375 tests across 43 packages and nine applications, counted the same way the `the document says how many tests there are` rule does: a scan of every `test(`/`testWidgets(` call. The rule holds `ARCHITECTURE.md` §13, the README and this page to the answer. The README went on saying 1242 across thirteen packages for as long as nothing compared it with anything. About thirty need a GPU; the [architecture](/core/architecture/) is what keeps the number that low. +11376 tests across 43 packages and nine applications, counted the same way the `the document says how many tests there are` rule does: a scan of every `test(`/`testWidgets(` call. The rule holds `ARCHITECTURE.md` §13, the README and this page to the answer. The README went on saying 1242 across thirteen packages for as long as nothing compared it with anything. About thirty need a GPU; the [architecture](/core/architecture/) is what keeps the number that low. | Package | Tests | | Package | Tests | |---|---|---|---|---| @@ -23,7 +23,7 @@ description: Four independent golden sets, mutation-checking every new test, det | `flutter3d_cpu` | 380 | | `apps/flutter3d_demo_strategy` | 50 | | `apps/flutter3d_editor` | 234 | | `apps/flutter3d_demo_arcade` | 20 | | `apps/flutter3d_demo_racing` | 162 | | `pointer_lock` | 28 | -| `flutter3d_physics` | 302 | | `flutter3d_webgpu` | 193 | +| `flutter3d_physics` | 303 | | `flutter3d_webgpu` | 193 | | `flutter3d_game_strategy` | 133 | | `flutter3d_editor_mcp` | 36 | | `apps/flutter3d_demo_river` | 54 | | `flutter3d_testing` | 45 | | `flutter3d_editor_core` | 141 | | `flutter3d_editor_widgets` | 91 | @@ -40,7 +40,7 @@ description: Four independent golden sets, mutation-checking every new test, det | `flame_flutter3d` | 140 | | `apps/flutter3d_showcase` | 88 | | `flame_multiplayer` | 9 | | `flame_multiplayer_dashwire` | 3 | -The rows sum to 11348 rather than 11375: the remaining 26 live in `packages/*/example/test`, which the count includes and this table does not, among them the two seeds a new project starts from, `packages/flutter3d_app/example` and `packages/flutter3d_game/example`. +The rows sum to 11349 rather than 11376: the remaining 26 live in `packages/*/example/test`, which the count includes and this table does not, among them the two seeds a new project starts from, `packages/flutter3d_app/example` and `packages/flutter3d_game/example`. `flutter3d_samples` is not in the table and has no `test/` at all: it is test data with two path constants over it, and other packages' decoder tests are what exercise it. `flutter3d_conformance` is missing for a different reason: it is invoked as a script harness rather than through `flutter test`, so it does not surface in a grep of `test(` calls either. See below for what that cost once. From 239016ddb685a0aaccd240aaf6149c3a9faf4026 Mon Sep 17 00:00:00 2001 From: Dmitrii Zolotov Date: Sat, 3 Oct 2026 17:39:01 +0300 Subject: [PATCH 29/34] perf: Read neighbour candidates in cell order in the native search The native neighbour search read each candidate's position through its index, nearly always a cache miss, and with one search per cell. It now copies the positions out in sorted order and finds each row of three cells with one search. Rows and their order are unchanged. On 576 particles on a pane the search takes half the time it did, and a step 4.3 ms instead of 5.4. --- packages/flutter3d_physics/src/pbf_kernels.c | 55 ++++++++++++++------ 1 file changed, 39 insertions(+), 16 deletions(-) diff --git a/packages/flutter3d_physics/src/pbf_kernels.c b/packages/flutter3d_physics/src/pbf_kernels.c index 7ead37e07..016840163 100644 --- a/packages/flutter3d_physics/src/pbf_kernels.c +++ b/packages/flutter3d_physics/src/pbf_kernels.c @@ -127,48 +127,71 @@ static int compare_entries(const void* a, const void* b) { // are: called again with room for that when it is more. [scratch] holds // 5·n int64s, the caller's own: nothing here is shared between calls, so // two isolates may step two fluids at once. +// +// **Read in the cells' order, not the particles'.** Of the 27 cells' worth +// of candidates around a particle only one in six or seven is within h, +// and each was read through its index from wherever it lay in [x]: nearly +// every read missed the cache, and the search cost twice all the loops +// over pairs together. The positions are copied out in the sorted order, +// so a cell's candidates are read one after the other. F3D_EXPORT int32_t f3d_pbf_neighbours(const double* x, int32_t n, double radius, int32_t* start, int32_t* list, int32_t capacity, int64_t* scratch) { const double h = radius; const double reach2 = h * h; - int64_t* cx = scratch; - int64_t* cy = scratch + n; - int64_t* cz = scratch + 2 * n; - // Two words an entry, in the scratch's last 2·n. - f3d_cell_entry* entries = (f3d_cell_entry*)(scratch + 3 * n); + // Two words an entry in the scratch's first 2·n, the positions in sorted + // order in its last 3·n. + f3d_cell_entry* entries = (f3d_cell_entry*)scratch; + double* sorted = (double*)(scratch + 2 * n); for (int32_t i = 0; i < n; i++) { - cx[i] = (int64_t)floor(x[3 * i] / h); - cy[i] = (int64_t)floor(x[3 * i + 1] / h); - cz[i] = (int64_t)floor(x[3 * i + 2] / h); - entries[i].key = pack_cell(cx[i], cy[i], cz[i]); + entries[i].key = pack_cell((int64_t)floor(x[3 * i] / h), + (int64_t)floor(x[3 * i + 1] / h), + (int64_t)floor(x[3 * i + 2] / h)); entries[i].index = i; } qsort(entries, (size_t)n, sizeof(f3d_cell_entry), compare_entries); + for (int32_t q = 0; q < n; q++) { + const int64_t j = entries[q].index; + sorted[3 * q] = x[3 * j]; + sorted[3 * q + 1] = x[3 * j + 1]; + sorted[3 * q + 2] = x[3 * j + 2]; + } int32_t count = 0; start[0] = 0; for (int32_t i = 0; i < n; i++) { const double xi = x[3 * i], yi = x[3 * i + 1], zi = x[3 * i + 2]; + const int64_t cx = (int64_t)floor(xi / h), cy = (int64_t)floor(yi / h), + cz = (int64_t)floor(zi / h); for (int64_t dx = -1; dx <= 1; dx++) { for (int64_t dy = -1; dy <= 1; dy++) { - for (int64_t dz = -1; dz <= 1; dz++) { - const int64_t key = pack_cell(cx[i] + dx, cy[i] + dy, cz[i] + dz); + // The three cells from z − 1 to z + 1 are three keys in a row, z + // being the key's last part: one search finds the first, and the + // rest follow it in the sorted entries, in the order three searches + // gave. Where z wraps round they are not in a row, and each is + // searched for. + const int64_t first = pack_cell(cx + dx, cy + dy, cz - 1); + const int64_t last = pack_cell(cx + dx, cy + dy, cz + 1); + const int32_t runs = last == first + 2 ? 1 : 3; + for (int32_t run = 0; run < runs; run++) { + const int64_t from = + runs == 1 ? first : pack_cell(cx + dx, cy + dy, cz - 1 + run); + const int64_t to = runs == 1 ? last : from; int32_t lo = 0, hi = n; while (lo < hi) { const int32_t mid = (lo + hi) >> 1; - if (entries[mid].key < key) { + if (entries[mid].key < from) { lo = mid + 1; } else { hi = mid; } } - for (int32_t q = lo; q < n && entries[q].key == key; q++) { + for (int32_t q = lo; q < n && entries[q].key <= to; q++) { + const double ex = sorted[3 * q] - xi, ey = sorted[3 * q + 1] - yi, + ez = sorted[3 * q + 2] - zi; + if (ex * ex + ey * ey + ez * ez >= reach2) continue; const int32_t j = (int32_t)entries[q].index; if (j == i) continue; - const double ex = x[3 * j] - xi, ey = x[3 * j + 1] - yi, - ez = x[3 * j + 2] - zi; - if (ex * ex + ey * ey + ez * ez >= reach2) continue; if (count < capacity) list[count] = j; count++; } From c8290463f92af3faeb3b7cee293802187255b0e2 Mon Sep 17 00:00:00 2001 From: Dmitrii Zolotov Date: Sat, 3 Oct 2026 17:44:22 +0300 Subject: [PATCH 30/34] perf: Find drops and neighbours in fewer steps on the Dart path Finding which particles make one drop walked each union-find chain to its end, and blocks of particles on a wall made chains hundreds long. The three copies of it are now one helper that halves the path on the way; roots, and so every result, are the same. The Dart neighbour search reads candidates in cell order and finds each row of three cells with one search, as the native one does, with the same rows. A pour replays bit for bit against the previous code. On 576 particles on a pane a Dart step takes 7.3 ms instead of 8.3, a native one 3.4 instead of 4.3. --- .../lib/src/fluid/particle_fluid.dart | 102 ++++++++---------- .../lib/src/fluid/pbf_kernels.dart | 36 +++++-- 2 files changed, 73 insertions(+), 65 deletions(-) diff --git a/packages/flutter3d_physics/lib/src/fluid/particle_fluid.dart b/packages/flutter3d_physics/lib/src/fluid/particle_fluid.dart index 035252794..4955e906c 100644 --- a/packages/flutter3d_physics/lib/src/fluid/particle_fluid.dart +++ b/packages/flutter3d_physics/lib/src/fluid/particle_fluid.dart @@ -600,21 +600,26 @@ final class ParticleFluid { d.volume = kept; } - /// Particles gathered into a drop, a spacing and a half apart at most, - /// that touch no wall, become that drop: one body again, in flight. - void _clustersToDrops(List walls) { + /// For each particle, the drop it is in, by the particle that stands for + /// the drop: particles nearer each other than a spacing and a half are + /// one, through any chain of them. + /// + /// **Each step on the way halved.** Which particle stands for a drop is + /// set by the joins alone, so shortcuts taken on the way change none; + /// walked to the end each time, a block of five hundred on a pane made + /// chains hundreds long, and finding the drops was a sixth of a step. + Int32List _dropRoots(Int32List start, Int32List list) { final n = _x.length; - if (n == 0 || medium.surfaceTension <= 0.0) return; - final parent = List.generate(n, (i) => i); + final parent = Int32List.fromList([for (var i = 0; i < n; i++) i]); int root(int i) { var r = i; while (parent[r] != r) { + parent[r] = parent[parent[r]]; r = parent[r]; } - return parent[i] = r; + return r; } - final (start, list) = _rows(_x); final close = 2.25 * spacing * spacing; for (var i = 0; i < n; i++) { for (var q = start[i]; q < start[i + 1]; q++) { @@ -622,11 +627,21 @@ final class ParticleFluid { if (_x[i].distance2(_x[j]) < close) parent[root(i)] = root(j); } } + return Int32List.fromList([for (var i = 0; i < n; i++) root(i)]); + } + + /// Particles gathered into a drop, a spacing and a half apart at most, + /// that touch no wall, become that drop: one body again, in flight. + void _clustersToDrops(List walls) { + final n = _x.length; + if (n == 0 || medium.surfaceTension <= 0.0) return; + final (start, list) = _rows(_x); + final roots = _dropRoots(start, list); final volume = {}; final speed = {}; final onWall = {}; for (var i = 0; i < n; i++) { - final r = root(i); + final r = roots[i]; volume[r] = (volume[r] ?? 0.0) + _vol[i]; (speed[r] ??= _V(0, 0, 0)).addScaled(_v[i], _vol[i]); final near = obstaclesNear(walls, _x[i].toVector3(), spacing); @@ -642,7 +657,7 @@ final class ParticleFluid { } if (into.isEmpty) return; for (var i = n - 1; i >= 0; i--) { - final d = into[root(i)]; + final d = into[roots[i]]; if (d == null) continue; final w = _vol[i]; final total = d.volume + w; @@ -744,27 +759,12 @@ final class ParticleFluid { /// particles by their share, what is dissolved in them left behind. void _measureDrops(double dt, Atmosphere air) { final n = _x.length; - final parent = List.generate(n, (i) => i); - int root(int i) { - var r = i; - while (parent[r] != r) { - r = parent[r]; - } - return parent[i] = r; - } - final (start, list) = _rows(_x); - final touching = 2.25 * spacing * spacing; - for (var i = 0; i < n; i++) { - for (var q = start[i]; q < start[i + 1]; q++) { - final j = list[q]; - if (_x[i].distance2(_x[j]) < touching) parent[root(i)] = root(j); - } - } + final roots = _dropRoots(start, list); final volume = {}; final speed = {}; for (var i = 0; i < n; i++) { - final r = root(i); + final r = roots[i]; volume[r] = (volume[r] ?? 0.0) + _vol[i]; (speed[r] ??= _V(0, 0, 0)).addScaled(_v[i], _vol[i]); } @@ -788,7 +788,7 @@ final class ParticleFluid { volume[r] = diameter; } for (var i = 0; i < n; i++) { - final r = root(i); + final r = roots[i]; _drop[i] = volume[r]!; final share = lost[r]; if (share != null && share > 0.0) { @@ -1011,36 +1011,26 @@ final class ParticleFluid { final n = _x.length; final out = List.filled(n, false); if (n == 0 || medium.surfaceTension <= 0.0) return out; - final parent = List.generate(n, (i) => i); - int root(int i) { - var r = i; - while (parent[r] != r) { - r = parent[r]; - } - return parent[i] = r; - } - - // One drop: particles nearer each other than a spacing and a half. - final close = 2.25 * spacing * spacing; - for (var i = 0; i < n; i++) { - for (var q = start[i]; q < start[i + 1]; q++) { - final j = list[q]; - if (_x[i].distance2(_x[j]) < close) parent[root(i)] = root(j); - } - } - final volume = {}; - final normal = {}; - final solid = {}; + final dropOf = _dropRoots(start, list); + // By root, in arrays: summed in the particles' order, as before. + final volume = Float64List(n); + final normal = Float64List(3 * n); + final solid = List.filled(n, null); for (var i = 0; i < n; i++) { - final r = root(i); - volume[r] = (volume[r] ?? 0.0) + _vol[i]; + final r = dropOf[i]; + volume[r] += _vol[i]; final t = touching[i]; if (t == null) continue; - (normal[r] ??= _V(0, 0, 0)).add(t.normal); + normal[3 * r] += t.normal.x; + normal[3 * r + 1] += t.normal.y; + normal[3 * r + 2] += t.normal.z; solid[r] ??= t.wall.solid; } - final holds = {}; - for (final MapEntry(key: r, value: sum) in normal.entries) { + final holds = List.filled(n, false); + for (var r = 0; r < n; r++) { + final surface = solid[r]; + if (surface == null) continue; + final sum = _V(normal[3 * r], normal[3 * r + 1], normal[3 * r + 2]); final length = sum.length; if (length <= 0.0) continue; final nx = sum.x / length; @@ -1050,13 +1040,13 @@ final class ParticleFluid { final g = at == null ? gravity : _V(at.x, at.y, at.z); final into = g.x * nx + g.y * ny + g.z * nz; final along = math.sqrt(math.max(g.length2 - into * into, 0.0)); - final v = volume[r]!; + final v = volume[r]; final weight = medium.density * v * along; - final width = 2.0 * solid[r]!.baseRadius(medium, v); - if (weight <= solid[r]!.retention(medium, width)) holds.add(r); + final width = 2.0 * surface.baseRadius(medium, v); + if (weight <= surface.retention(medium, width)) holds[r] = true; } for (var i = 0; i < n; i++) { - out[i] = holds.contains(root(i)); + out[i] = holds[dropOf[i]]; } return out; } diff --git a/packages/flutter3d_physics/lib/src/fluid/pbf_kernels.dart b/packages/flutter3d_physics/lib/src/fluid/pbf_kernels.dart index b08c399c8..df0e6d5b6 100644 --- a/packages/flutter3d_physics/lib/src/fluid/pbf_kernels.dart +++ b/packages/flutter3d_physics/lib/src/fluid/pbf_kernels.dart @@ -227,8 +227,15 @@ final class DartPbfKernels implements PbfKernels { return c != 0 ? c : a - b; }); final sorted = Float64List(n); + // The positions in the same order: a cell's candidates are then read + // one after another, not from wherever each lies in [x]. + final at = Float64List(3 * n); for (var q = 0; q < n; q++) { - sorted[q] = keys[order[q]]; + final j = order[q]; + sorted[q] = keys[j]; + at[3 * q] = x[3 * j]; + at[3 * q + 1] = x[3 * j + 1]; + at[3 * q + 2] = x[3 * j + 2]; } int first(double key) { var lo = 0; @@ -254,16 +261,27 @@ final class DartPbfKernels implements PbfKernels { final zi = x[3 * i + 2]; for (var dx = -1; dx <= 1; dx++) { for (var dy = -1; dy <= 1; dy++) { - for (var dz = -1; dz <= 1; dz++) { - final key = _pack(cx[i] + dx, cy[i] + dy, cz[i] + dz); - for (var q = first(key); q < n && sorted[q] == key; q++) { - final j = order[q]; - if (j == i) continue; - final ex = x[3 * j] - xi; - final ey = x[3 * j + 1] - yi; - final ez = x[3 * j + 2] - zi; + // **The three cells from z − 1 to z + 1 are three keys in a + // row**, z being the key's last part: one search finds the first + // and the rest follow it in the sorted keys, in the order three + // searches gave. Where z wraps round they are not in a row, and + // each is searched for. + final from = _pack(cx[i] + dx, cy[i] + dy, cz[i] - 1); + final to = _pack(cx[i] + dx, cy[i] + dy, cz[i] + 1); + final runs = to == from + 2 ? 1 : 3; + for (var run = 0; run < runs; run++) { + final lo = runs == 1 + ? from + : _pack(cx[i] + dx, cy[i] + dy, cz[i] - 1 + run); + final hi = runs == 1 ? to : lo; + for (var q = first(lo); q < n && sorted[q] <= hi; q++) { + final ex = at[3 * q] - xi; + final ey = at[3 * q + 1] - yi; + final ez = at[3 * q + 2] - zi; // As `_V.distance2` reads it: the other point less this one. if (ex * ex + ey * ey + ez * ez >= reach2) continue; + final j = order[q]; + if (j == i) continue; if (count == list.length) { list = Int32List(list.length * 2)..setAll(0, list); } From 3bff51396a30055cfab41f358b000b71a12fce98 Mon Sep 17 00:00:00 2001 From: Dmitrii Zolotov Date: Sat, 3 Oct 2026 17:45:41 +0300 Subject: [PATCH 31/34] docs: Say what else the native kernels switch moves into C The liquids page now says that nativeKernels also runs the surface mode solve and the meniscus solve natively. --- site/content/core/liquids.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/content/core/liquids.md b/site/content/core/liquids.md index b482dc2d2..5c1cc92f5 100644 --- a/site/content/core/liquids.md +++ b/site/content/core/liquids.md @@ -117,7 +117,7 @@ A body turning in the liquid is held back too, by Stokes's torque 8πμR³ω on Two switches on `FluidWorld` trade the bit-for-bit replay for speed, and change nothing that happens otherwise. -- `nativeKernels: true` runs the particles' pair loops and neighbour search in C, built by the package's own hook with the machine's C compiler and vectorised. Each kernel matches the Dart one to a part in 10¹². Where no compiler was found, and on the web, the Dart kernels run. +- `nativeKernels: true` runs the particles' pair loops and neighbour search in C, built by the package's own hook with the machine's C compiler and vectorised. Each kernel matches the Dart one to a part in 10¹². The same switch moves the heavy half of a surface's mode solve (a millisecond against three or four in Dart) and the meniscus solve into C. Where no compiler was found, and on the web, the Dart code runs. - `background: true` works out what would stop a frame, a cross-section's modes or a meniscus not met before, on another isolate. The vessel carries on as it was until the answer comes. On the web there are no isolates, and it is all worked out at once. ## Being honest about it From 84904beb30297caf20c7ba3b2f5d6a39fca6ec18 Mon Sep 17 00:00:00 2001 From: Dmitrii Zolotov Date: Sat, 3 Oct 2026 17:52:58 +0300 Subject: [PATCH 32/34] perf: Pick the SIMD width of the running processor for the native loops All six native pair loops now come from one source, pbf_lanes.h, built at two, four and eight lanes. Which one runs is chosen on first use by what the processor reports: AVX-512F takes eight, AVX2 four, SSE2 and NEON two. The hook builds on the machine that builds the app, so the wider widths are compiled with a target attribute and only called where cpuid allows; nothing is built for the build machine's own processor. No fused multiply-adds, so each lane rounds as the scalar loop does. Every width agrees with the scalar loop to about 1e-15, checked on arm64 and on x86-64 under Rosetta with AVX2. A new CI job builds the check with gcc and clang on an x86-64 runner and times each width there. On arm64, where two lanes measured fastest, a PBF step on 576 particles takes 3.1 ms instead of 3.4. --- .github/workflows/ci.yml | 24 ++ ARCHITECTURE.md | 2 +- README.md | 2 +- .../lib/src/fluid/native/pbf_native.dart | 18 +- .../lib/src/fluid/native/pbf_none.dart | 6 + packages/flutter3d_physics/src/pbf_kernels.c | 237 +++++++++++-- packages/flutter3d_physics/src/pbf_lanes.h | 322 ++++++++++++++++++ .../test/fluid/native_kernels_test.dart | 123 ++++--- .../test/native/lanes_check.c | 68 ++++ site/content/quickstart.md | 2 +- site/content/reference/testing.md | 8 +- 11 files changed, 718 insertions(+), 94 deletions(-) create mode 100644 packages/flutter3d_physics/src/pbf_lanes.h create mode 100644 packages/flutter3d_physics/test/native/lanes_check.c diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d471d1665..417b4248d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -195,6 +195,30 @@ jobs: sdk: '3.13.0' - run: tool/flat_dart_check.sh + # **The native pair loops at every width this processor has** — x86-64, so + # the AVX2 and AVX-512 widths, which `src/pbf_kernels.c` picks at run time + # by what the processor says, are real here and on no developer's arm64 + # machine. Each width is held to the scalar loop, and timed: which width a + # processor should take by default is a measurement, and this is where it + # can be made. Built with gcc and with clang, which reach the wider widths + # through different pragmas. Seconds; no Dart, no Flutter. + native-lanes: + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - uses: actions/checkout@v7 + - run: grep -o -m1 -w -E 'avx512f|avx2|sse2' /proc/cpuinfo | sort -u + - name: gcc + working-directory: packages/flutter3d_physics + run: | + gcc -O3 -fno-math-errno -Wall -Werror -Isrc src/pbf_kernels.c test/native/lanes_check.c -lm -o lanes-gcc + ./lanes-gcc + - name: clang + working-directory: packages/flutter3d_physics + run: | + clang -O3 -fno-math-errno -Wall -Werror -Isrc src/pbf_kernels.c test/native/lanes_check.c -lm -o lanes-clang + ./lanes-clang + # **A second engine opens the files this one writes, which nothing here had # ever checked.** The design plan's line is "the exported file opens in Godot # and Unity", and K2 closed on 2026-09-09 with: headless Godot in CI — diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 7a58d2706..436b2ec71 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -2691,7 +2691,7 @@ storage. |---|---| | Style | `dart format` | | Analysis | `flutter analyze` clean across the workspace, no warnings | -| Unit tests | **11376 tests** across 43 packages and 10 applications | +| Unit tests | **11377 tests** across 43 packages and 10 applications | | Structure rules | 35, `dart run tool/structure.dart`, the first CI step | | CI | GitHub Actions over `tool/ci.sh`, on `ubuntu-latest`, with no graphics card | diff --git a/README.md b/README.md index cf84ff860..1ed2106c4 100644 --- a/README.md +++ b/README.md @@ -158,7 +158,7 @@ Or one package at a time: (cd packages/flutter3d_physics && dart test) # plain Dart, no Flutter needed ``` -There are 11376 tests across forty-three packages and nine applications. The +There are 11377 tests across forty-three packages and nine applications. The only ones that need a GPU are the Impeller half of the golden set. The other half is rendered by the software backend, which is what makes 90 scenes checkable in a headless run. diff --git a/packages/flutter3d_physics/lib/src/fluid/native/pbf_native.dart b/packages/flutter3d_physics/lib/src/fluid/native/pbf_native.dart index 7a23a382d..ae71469f9 100644 --- a/packages/flutter3d_physics/lib/src/fluid/native/pbf_native.dart +++ b/packages/flutter3d_physics/lib/src/fluid/native/pbf_native.dart @@ -301,11 +301,27 @@ external int _meniscus( } } +@Native(symbol: 'f3d_pbf_lanes', isLeaf: true) +external int _lanes(); + +@Native(symbol: 'f3d_pbf_set_lanes', isLeaf: true) +external int _setLanes(int lanes); + +/// How many neighbours the native pair loops take at a time: chosen by the +/// running processor (eight with AVX-512F, four with AVX2, two with SSE2 or +/// NEON), or 0 where there is no native code. +int get nativePbfLanes => nativePbfAvailable ? _lanes() : 0; + +/// Sets [nativePbfLanes] to [lanes] where the processor has them, 0 for its +/// own choice, and returns what is now in use: for a test to hold each +/// width to the Dart kernels. One setting for the whole process. +int setNativePbfLanes(int lanes) => nativePbfAvailable ? _setLanes(lanes) : 0; + /// Whether the native kernels were built and load: false where the build /// had no C compiler, and asked once. final bool nativePbfAvailable = () { try { - return _version() == 5; + return _version() == 6; } on Object { return false; } diff --git a/packages/flutter3d_physics/lib/src/fluid/native/pbf_none.dart b/packages/flutter3d_physics/lib/src/fluid/native/pbf_none.dart index b33c2b3a4..ee6938d1b 100644 --- a/packages/flutter3d_physics/lib/src/fluid/native/pbf_none.dart +++ b/packages/flutter3d_physics/lib/src/fluid/native/pbf_none.dart @@ -30,3 +30,9 @@ int nativeSurfaceLanczos( double contactAngle, int samples, ) => null; + +/// No native code here: 0. +int get nativePbfLanes => 0; + +/// No native code here: 0. +int setNativePbfLanes(int lanes) => 0; diff --git a/packages/flutter3d_physics/src/pbf_kernels.c b/packages/flutter3d_physics/src/pbf_kernels.c index 016840163..a98d2378e 100644 --- a/packages/flutter3d_physics/src/pbf_kernels.c +++ b/packages/flutter3d_physics/src/pbf_kernels.c @@ -3,11 +3,20 @@ // `NativePbfKernels` to call through `@Native`. // // **Held to the Dart reference within a tolerance, not to the bit.** The -// neighbours of a particle are summed two at a time where the compiler has -// vector extensions (clang and gcc, on NEON and SSE2 alike), which adds in -// another order than Dart's one at a time; a run is the same run to about a -// part in 10¹², not exactly. Where the world must replay to the bit, the -// Dart kernels are the ones to step it with. +// neighbours of a particle are summed several at a time where the compiler +// has vector extensions (clang and gcc), which adds in another order than +// Dart's one at a time; a run is the same run to about a part in 10¹², not +// exactly. Where the world must replay to the bit, the Dart kernels are the +// ones to step it with. +// +// **How many at a time is the running processor's, chosen when first +// asked**, not the building machine's: the hook builds on whatever machine +// builds the app, and code for its processor would stop on an older one +// with an illegal instruction. Two lanes everywhere (SSE2 and NEON are +// in every x86-64 and arm64); on x86-64 also four, built for AVX2, and +// eight, built for AVX-512F, each taken only where the processor says it +// has them. Without fused multiply-adds, so that each lane rounds as the +// scalar loop does. // // The constants come as one array, in this order: // 0 h, 1 h², 2 ρ₀, 3 m, 4 norm, 5 γ, 6 rest stiffness, @@ -19,11 +28,21 @@ #if defined(__clang__) || defined(__GNUC__) #define F3D_VECTOR 1 -typedef double f3d_d2 __attribute__((vector_size(16))); #else #define F3D_VECTOR 0 #endif +#if F3D_VECTOR && (defined(__x86_64__) || defined(_M_X64)) +#define F3D_X86 1 +#else +#define F3D_X86 0 +#endif + +// The lanes arm64 takes unless a test sets others: what measured fastest. +#ifndef F3D_ARM_LANES +#define F3D_ARM_LANES 2 +#endif + #if defined(_WIN32) #define F3D_EXPORT __declspec(dllexport) #else @@ -65,18 +84,7 @@ static inline double cohesion(const double* k, double r) { return k[K_COHESION] * (2.0 * a - k[K_H6] / 64.0); } -#if F3D_VECTOR -// The kernel weight of two squared distances at once, a lane each. -static inline f3d_d2 poly6_2(const double* k, f3d_d2 r2) { - const f3d_d2 h2 = {k[K_H2], k[K_H2]}; - f3d_d2 d = h2 - r2; - d = (f3d_d2){d[0] > 0.0 ? d[0] : 0.0, d[1] > 0.0 ? d[1] : 0.0}; - const f3d_d2 c = {k[K_POLY6], k[K_POLY6]}; - return c * d * d * d; -} -#endif - -F3D_EXPORT int32_t f3d_pbf_version(void) { return 5; } +F3D_EXPORT int32_t f3d_pbf_version(void) { return 6; } // Of the rows [start] and [list], those within [radius] at [x], in order, // into [out_start] and [out] (room for as many as [list] has). @@ -203,7 +211,7 @@ F3D_EXPORT int32_t f3d_pbf_neighbours(const double* x, int32_t n, return count; } -F3D_EXPORT void f3d_pbf_densities(const double* x, const int32_t* start, +static void scalar_densities(const double* x, const int32_t* start, const int32_t* list, int32_t n, const double* k, double* density) { const double self = poly6(k, 0.0); @@ -212,17 +220,6 @@ F3D_EXPORT void f3d_pbf_densities(const double* x, const int32_t* start, int32_t q = start[i]; const int32_t end = start[i + 1]; double w = self; -#if F3D_VECTOR - f3d_d2 acc = {0.0, 0.0}; - for (; q + 2 <= end; q += 2) { - const int32_t a = list[q], b = list[q + 1]; - const f3d_d2 dx = {xi - x[3 * a], xi - x[3 * b]}; - const f3d_d2 dy = {yi - x[3 * a + 1], yi - x[3 * b + 1]}; - const f3d_d2 dz = {zi - x[3 * a + 2], zi - x[3 * b + 2]}; - acc += poly6_2(k, dx * dx + dy * dy + dz * dz); - } - w += acc[0] + acc[1]; -#endif for (; q < end; q++) { const int32_t j = list[q]; const double dx = xi - x[3 * j], dy = yi - x[3 * j + 1], @@ -233,7 +230,7 @@ F3D_EXPORT void f3d_pbf_densities(const double* x, const int32_t* start, } } -F3D_EXPORT void f3d_pbf_normals(const double* x, const int32_t* start, +static void scalar_normals(const double* x, const int32_t* start, const int32_t* list, int32_t n, const double* k, const double* density, double* normal) { @@ -256,7 +253,7 @@ F3D_EXPORT void f3d_pbf_normals(const double* x, const int32_t* start, } } -F3D_EXPORT void f3d_pbf_forces(const double* x, const int32_t* start, +static void scalar_forces(const double* x, const int32_t* start, const int32_t* list, int32_t n, const double* k, const double* density, const double* normal, const double* before, @@ -287,7 +284,7 @@ F3D_EXPORT void f3d_pbf_forces(const double* x, const int32_t* start, } } -F3D_EXPORT void f3d_pbf_lambdas(const double* p, const int32_t* start, +static void scalar_lambdas(const double* p, const int32_t* start, const int32_t* list, int32_t n, const double* k, double* lambda) { const double norm = k[K_NORM]; @@ -314,7 +311,7 @@ F3D_EXPORT void f3d_pbf_lambdas(const double* p, const int32_t* start, } } -F3D_EXPORT void f3d_pbf_deltas(const double* p, const int32_t* start, +static void scalar_deltas(const double* p, const int32_t* start, const int32_t* list, int32_t n, const double* k, const double* lambda, double* delta) { @@ -342,7 +339,7 @@ F3D_EXPORT void f3d_pbf_deltas(const double* p, const int32_t* start, } } -F3D_EXPORT void f3d_pbf_viscosity(const double* p, const double* v, +static void scalar_viscosity(const double* p, const double* v, const int32_t* start, const int32_t* list, int32_t n, const double* k, double share, double* smoothed) { @@ -365,3 +362,173 @@ F3D_EXPORT void f3d_pbf_viscosity(const double* p, const double* v, smoothed[3 * i + 2] = sz; } } + +// ------------------------------------------------------------ the widths + +#if F3D_VECTOR +#define F3D_W 2 +#define F3D_NAME(name) name##_w2 +#include "pbf_lanes.h" +#undef F3D_W +#undef F3D_NAME + +#if F3D_X86 +#if defined(__clang__) +#pragma clang attribute push(__attribute__((target("avx2"))), apply_to = function) +#else +#pragma GCC push_options +#pragma GCC target("avx2") +#endif +#define F3D_W 4 +#define F3D_NAME(name) name##_w4 +#include "pbf_lanes.h" +#undef F3D_W +#undef F3D_NAME +#if defined(__clang__) +#pragma clang attribute pop +#else +#pragma GCC pop_options +#endif + +#if defined(__clang__) +#pragma clang attribute push(__attribute__((target("avx512f"))), apply_to = function) +#else +#pragma GCC push_options +#pragma GCC target("avx512f") +#endif +#define F3D_W 8 +#define F3D_NAME(name) name##_w8 +#include "pbf_lanes.h" +#undef F3D_W +#undef F3D_NAME +#if defined(__clang__) +#pragma clang attribute pop +#else +#pragma GCC pop_options +#endif +#else +// Off x86-64 the wider widths are built for the baseline: four lanes are +// two NEON registers an operation, eight are four. Built so that a test +// can hold them to the Dart kernels on any machine; which one runs by +// default is [f3d_pbf_lanes]'s choice. +#define F3D_W 4 +#define F3D_NAME(name) name##_w4 +#include "pbf_lanes.h" +#undef F3D_W +#undef F3D_NAME +#define F3D_W 8 +#define F3D_NAME(name) name##_w8 +#include "pbf_lanes.h" +#undef F3D_W +#undef F3D_NAME +#endif +#endif + +// The widest the running processor can take: 1 without vector extensions. +static int32_t f3d_widest(void) { +#if !F3D_VECTOR + return 1; +#elif F3D_X86 + __builtin_cpu_init(); + if (__builtin_cpu_supports("avx512f")) return 8; + if (__builtin_cpu_supports("avx2")) return 4; + return 2; +#else + return 8; +#endif +} + +// The lanes in use: 0 until first asked. Written once with the same value +// by whichever isolate asks first, or set by a test. +static int32_t f3d_lanes = 0; + +static int32_t f3d_default_lanes(void) { +#if F3D_X86 + return f3d_widest(); +#elif F3D_VECTOR + return F3D_ARM_LANES; +#else + return 1; +#endif +} + +// How many neighbours each pair loop takes at a time: 1, 2, 4 or 8. +F3D_EXPORT int32_t f3d_pbf_lanes(void) { + if (f3d_lanes == 0) f3d_lanes = f3d_default_lanes(); + return f3d_lanes; +} + +// Sets the lanes to [lanes] where the processor has them, and returns the +// lanes now in use: for a test to hold each width to the Dart kernels. +// 0 goes back to the running processor's default. +F3D_EXPORT int32_t f3d_pbf_set_lanes(int32_t lanes) { + if (lanes == 0) { + f3d_lanes = f3d_default_lanes(); + } else if ((lanes == 1 || lanes == 2 || lanes == 4 || lanes == 8) && + lanes <= f3d_widest()) { + f3d_lanes = lanes; + } + return f3d_pbf_lanes(); +} + +#if F3D_VECTOR +#define F3D_DISPATCH(name, ...) \ + switch (f3d_pbf_lanes()) { \ + case 8: \ + name##_w8(__VA_ARGS__); \ + return; \ + case 4: \ + name##_w4(__VA_ARGS__); \ + return; \ + case 2: \ + name##_w2(__VA_ARGS__); \ + return; \ + default: \ + scalar_##name(__VA_ARGS__); \ + return; \ + } +#else +#define F3D_DISPATCH(name, ...) scalar_##name(__VA_ARGS__); +#endif + +F3D_EXPORT void f3d_pbf_densities(const double* x, const int32_t* start, + const int32_t* list, int32_t n, + const double* k, double* density) { + F3D_DISPATCH(densities, x, start, list, n, k, density) +} + +F3D_EXPORT void f3d_pbf_normals(const double* x, const int32_t* start, + const int32_t* list, int32_t n, + const double* k, const double* density, + double* normal) { + F3D_DISPATCH(normals, x, start, list, n, k, density, normal) +} + +F3D_EXPORT void f3d_pbf_forces(const double* x, const int32_t* start, + const int32_t* list, int32_t n, + const double* k, const double* density, + const double* normal, const double* before, + const double* after, double* v, double dt) { + F3D_DISPATCH(forces, x, start, list, n, k, density, normal, before, after, + v, dt) +} + +F3D_EXPORT void f3d_pbf_lambdas(const double* p, const int32_t* start, + const int32_t* list, int32_t n, + const double* k, double* lambda) { + F3D_DISPATCH(lambdas, p, start, list, n, k, lambda) +} + +F3D_EXPORT void f3d_pbf_deltas(const double* p, const int32_t* start, + const int32_t* list, int32_t n, + const double* k, const double* lambda, + double* delta) { + F3D_DISPATCH(deltas, p, start, list, n, k, lambda, delta) +} + +F3D_EXPORT void f3d_pbf_viscosity(const double* p, const double* v, + const int32_t* start, const int32_t* list, + int32_t n, const double* k, double share, + double* smoothed) { + F3D_DISPATCH(viscosity, p, v, start, list, n, k, share, smoothed) +} diff --git a/packages/flutter3d_physics/src/pbf_lanes.h b/packages/flutter3d_physics/src/pbf_lanes.h new file mode 100644 index 000000000..a84e25104 --- /dev/null +++ b/packages/flutter3d_physics/src/pbf_lanes.h @@ -0,0 +1,322 @@ +// The pair loops of `pbf_kernels.c`, F3D_W neighbours at a time: included +// once for each width, with F3D_W and F3D_NAME(name) set by the includer +// (and, for the AVX2 width on x86-64, inside a target that allows it). +// +// Each loop takes the neighbours F3D_W at a time, a lane each, and the last +// few one at a time as the scalar loop does; the lanes are summed at the end +// in order. The sums so come out in another order than the scalar loop's, +// and so differ from it, and from Dart, in the last few bits. +// +// Branches become masks: a lane a kernel is nil for (past h, or at the same +// point) is computed anyway, inf or NaN as may be, and then cleared by +// and-ing its bits with the mask. + +typedef double F3D_NAME(vd) __attribute__((vector_size(F3D_W * 8))); +typedef long long F3D_NAME(vi) __attribute__((vector_size(F3D_W * 8))); +#define VD F3D_NAME(vd) +#define VI F3D_NAME(vi) +// Lanes of [a] where [m] is set, nil elsewhere; [a] where set, [b] where not. +#define KEEP(m, a) ((VD)((VI)(a) & (m))) +#define PICK(m, a, b) ((VD)(((VI)(a) & (m)) | ((VI)(b) & ~(m)))) + +// Component [c] of the points [list] names from [q] on, a lane each. +static inline VD F3D_NAME(gather3)(const double* a, const int32_t* list, + int32_t q, int c) { + VD r; + for (int l = 0; l < F3D_W; l++) r[l] = a[3 * list[q + l] + c]; + return r; +} + +static inline VD F3D_NAME(gather1)(const double* a, const int32_t* list, + int32_t q) { + VD r; + for (int l = 0; l < F3D_W; l++) r[l] = a[list[q + l]]; + return r; +} + +static inline VD F3D_NAME(root)(VD r2) { + VD r; + for (int l = 0; l < F3D_W; l++) r[l] = sqrt(r2[l]); + return r; +} + +static inline double F3D_NAME(sum)(VD v) { + double s = 0.0; + for (int l = 0; l < F3D_W; l++) s += v[l]; + return s; +} + +static inline VD F3D_NAME(poly6)(const double* k, VD r2) { + const VD d = k[K_H2] - r2; + return KEEP((VI)(d > 0.0), k[K_POLY6] * d * d * d); +} + +static inline VD F3D_NAME(spiky)(const double* k, VD r) { + const VD hr = k[K_H] - r; + const VI live = (VI)(r > 1e-12) & (VI)(r < k[K_H]); + return KEEP(live, k[K_SPIKY] * hr * hr / r); +} + +static inline VD F3D_NAME(cohesion)(const double* k, VD r) { + const double h = k[K_H]; + const VD hr = h - r; + const VD a = hr * hr * hr * r * r * r; + const VI live = (VI)(r < h) & (VI)(r > 0.0); + const VI far = (VI)(2.0 * r > h); + const VD value = + PICK(far, k[K_COHESION] * a, k[K_COHESION] * (2.0 * a - k[K_H6] / 64.0)); + return KEEP(live, value); +} + +static void F3D_NAME(densities)(const double* x, const int32_t* start, + const int32_t* list, int32_t n, + const double* k, double* density) { + const double self = poly6(k, 0.0); + for (int32_t i = 0; i < n; i++) { + const double xi = x[3 * i], yi = x[3 * i + 1], zi = x[3 * i + 2]; + int32_t q = start[i]; + const int32_t end = start[i + 1]; + VD acc = {0.0}; + for (; q + F3D_W <= end; q += F3D_W) { + const VD dx = xi - F3D_NAME(gather3)(x, list, q, 0); + const VD dy = yi - F3D_NAME(gather3)(x, list, q, 1); + const VD dz = zi - F3D_NAME(gather3)(x, list, q, 2); + acc += F3D_NAME(poly6)(k, dx * dx + dy * dy + dz * dz); + } + double w = self + F3D_NAME(sum)(acc); + for (; q < end; q++) { + const int32_t j = list[q]; + const double dx = xi - x[3 * j], dy = yi - x[3 * j + 1], + dz = zi - x[3 * j + 2]; + w += poly6(k, dx * dx + dy * dy + dz * dz); + } + density[i] = k[K_RHO0] * w * k[K_NORM]; + } +} + +static void F3D_NAME(normals)(const double* x, const int32_t* start, + const int32_t* list, int32_t n, + const double* k, const double* density, + double* normal) { + const double hm = k[K_H] * k[K_MASS]; + for (int32_t i = 0; i < n; i++) { + const double xi = x[3 * i], yi = x[3 * i + 1], zi = x[3 * i + 2]; + int32_t q = start[i]; + const int32_t end = start[i + 1]; + VD ax = {0.0}, ay = {0.0}, az = {0.0}; + for (; q + F3D_W <= end; q += F3D_W) { + const VD dx = xi - F3D_NAME(gather3)(x, list, q, 0); + const VD dy = yi - F3D_NAME(gather3)(x, list, q, 1); + const VD dz = zi - F3D_NAME(gather3)(x, list, q, 2); + const VD r = F3D_NAME(root)(dx * dx + dy * dy + dz * dz); + const VD f = F3D_NAME(spiky)(k, r) * hm / + F3D_NAME(gather1)(density, list, q); + ax += dx * f; + ay += dy * f; + az += dz * f; + } + double nx = F3D_NAME(sum)(ax), ny = F3D_NAME(sum)(ay), + nz = F3D_NAME(sum)(az); + for (; q < end; q++) { + const int32_t j = list[q]; + const double dx = xi - x[3 * j], dy = yi - x[3 * j + 1], + dz = zi - x[3 * j + 2]; + const double f = spiky_scale(k, sqrt(dx * dx + dy * dy + dz * dz)) * + k[K_H] * k[K_MASS] / density[j]; + nx += dx * f; + ny += dy * f; + nz += dz * f; + } + normal[3 * i] = nx; + normal[3 * i + 1] = ny; + normal[3 * i + 2] = nz; + } +} + +static void F3D_NAME(forces)(const double* x, const int32_t* start, + const int32_t* list, int32_t n, const double* k, + const double* density, const double* normal, + const double* before, const double* after, + double* v, double dt) { + const double rho0 = k[K_RHO0]; + const double gm = k[K_GAMMA] * k[K_MASS]; + for (int32_t i = 0; i < n; i++) { + const double xi = x[3 * i], yi = x[3 * i + 1], zi = x[3 * i + 2]; + const double di = density[i]; + const double nxi = normal[3 * i], nyi = normal[3 * i + 1], + nzi = normal[3 * i + 2]; + int32_t q = start[i]; + const int32_t end = start[i + 1]; + VD sx = {0.0}, sy = {0.0}, sz = {0.0}; + for (; q + F3D_W <= end; q += F3D_W) { + const VD dx = xi - F3D_NAME(gather3)(x, list, q, 0); + const VD dy = yi - F3D_NAME(gather3)(x, list, q, 1); + const VD dz = zi - F3D_NAME(gather3)(x, list, q, 2); + const VD r = F3D_NAME(root)(dx * dx + dy * dy + dz * dz); + const VI apart = (VI)(r >= 1e-12); + const VD kk = 2.0 * rho0 / (di + F3D_NAME(gather1)(density, list, q)); + const VD c = -kk * gm * F3D_NAME(cohesion)(k, r) / r; + const VD t = -kk * k[K_GAMMA]; + sx += KEEP(apart, + dx * c + (nxi - F3D_NAME(gather3)(normal, list, q, 0)) * t); + sy += KEEP(apart, + dy * c + (nyi - F3D_NAME(gather3)(normal, list, q, 1)) * t); + sz += KEEP(apart, + dz * c + (nzi - F3D_NAME(gather3)(normal, list, q, 2)) * t); + } + double ax = before[3 * i] + F3D_NAME(sum)(sx); + double ay = before[3 * i + 1] + F3D_NAME(sum)(sy); + double az = before[3 * i + 2] + F3D_NAME(sum)(sz); + for (; q < end; q++) { + const int32_t j = list[q]; + const double dx = xi - x[3 * j], dy = yi - x[3 * j + 1], + dz = zi - x[3 * j + 2]; + const double r = sqrt(dx * dx + dy * dy + dz * dz); + if (r < 1e-12) continue; + const double kk = 2.0 * rho0 / (di + density[j]); + const double c = -kk * gm * cohesion(k, r) / r; + const double t = -kk * k[K_GAMMA]; + ax += dx * c + (nxi - normal[3 * j]) * t; + ay += dy * c + (nyi - normal[3 * j + 1]) * t; + az += dz * c + (nzi - normal[3 * j + 2]) * t; + } + ax += after[3 * i]; + ay += after[3 * i + 1]; + az += after[3 * i + 2]; + v[3 * i] += ax * dt; + v[3 * i + 1] += ay * dt; + v[3 * i + 2] += az * dt; + } +} + +static void F3D_NAME(lambdas)(const double* p, const int32_t* start, + const int32_t* list, int32_t n, + const double* k, double* lambda) { + const double norm = k[K_NORM]; + const double self = poly6(k, 0.0); + for (int32_t i = 0; i < n; i++) { + const double xi = p[3 * i], yi = p[3 * i + 1], zi = p[3 * i + 2]; + int32_t q = start[i]; + const int32_t end = start[i + 1]; + VD vw = {0.0}, vs = {0.0}, vx = {0.0}, vy = {0.0}, vz = {0.0}; + for (; q + F3D_W <= end; q += F3D_W) { + const VD dx = xi - F3D_NAME(gather3)(p, list, q, 0); + const VD dy = yi - F3D_NAME(gather3)(p, list, q, 1); + const VD dz = zi - F3D_NAME(gather3)(p, list, q, 2); + const VD r2 = dx * dx + dy * dy + dz * dz; + vw += F3D_NAME(poly6)(k, r2); + const VD f = F3D_NAME(spiky)(k, F3D_NAME(root)(r2)) * norm; + vs += r2 * f * f; + vx += dx * f; + vy += dy * f; + vz += dz * f; + } + double w = self + F3D_NAME(sum)(vw), sum2 = F3D_NAME(sum)(vs); + double gx = F3D_NAME(sum)(vx), gy = F3D_NAME(sum)(vy), + gz = F3D_NAME(sum)(vz); + for (; q < end; q++) { + const int32_t j = list[q]; + const double dx = xi - p[3 * j], dy = yi - p[3 * j + 1], + dz = zi - p[3 * j + 2]; + const double r2 = dx * dx + dy * dy + dz * dz; + w += poly6(k, r2); + const double f = spiky_scale(k, sqrt(r2)) * norm; + sum2 += r2 * f * f; + gx += dx * f; + gy += dy * f; + gz += dz * f; + } + sum2 += gx * gx + gy * gy + gz * gz; + double c = w * norm - 1.0; + if (c < 0.0) c = 0.0; + lambda[i] = -c / (sum2 + 1e-6 * norm * norm / (k[K_H] * k[K_H])); + } +} + +static void F3D_NAME(deltas)(const double* p, const int32_t* start, + const int32_t* list, int32_t n, const double* k, + const double* lambda, double* delta) { + const double norm = k[K_NORM]; + const double corr_scale = -0.02 / k[K_REST_STIFFNESS]; + for (int32_t i = 0; i < n; i++) { + const double xi = p[3 * i], yi = p[3 * i + 1], zi = p[3 * i + 2]; + const double li = lambda[i]; + int32_t q = start[i]; + const int32_t end = start[i + 1]; + VD vx = {0.0}, vy = {0.0}, vz = {0.0}; + for (; q + F3D_W <= end; q += F3D_W) { + const VD dx = xi - F3D_NAME(gather3)(p, list, q, 0); + const VD dy = yi - F3D_NAME(gather3)(p, list, q, 1); + const VD dz = zi - F3D_NAME(gather3)(p, list, q, 2); + const VD r2 = dx * dx + dy * dy + dz * dz; + const VD ratio = F3D_NAME(poly6)(k, r2) / k[K_WQ]; + const VD corr = ratio * ratio * ratio * ratio * corr_scale; + const VD f = F3D_NAME(spiky)(k, F3D_NAME(root)(r2)) * + (li + F3D_NAME(gather1)(lambda, list, q) + corr) * norm; + vx += dx * f; + vy += dy * f; + vz += dz * f; + } + double sx = F3D_NAME(sum)(vx), sy = F3D_NAME(sum)(vy), + sz = F3D_NAME(sum)(vz); + for (; q < end; q++) { + const int32_t j = list[q]; + const double dx = xi - p[3 * j], dy = yi - p[3 * j + 1], + dz = zi - p[3 * j + 2]; + const double r2 = dx * dx + dy * dy + dz * dz; + const double ratio = poly6(k, r2) / k[K_WQ]; + const double corr = + -0.02 * ratio * ratio * ratio * ratio / k[K_REST_STIFFNESS]; + const double f = + spiky_scale(k, sqrt(r2)) * (li + lambda[j] + corr) * norm; + sx += dx * f; + sy += dy * f; + sz += dz * f; + } + delta[3 * i] = sx; + delta[3 * i + 1] = sy; + delta[3 * i + 2] = sz; + } +} + +static void F3D_NAME(viscosity)(const double* p, const double* v, + const int32_t* start, const int32_t* list, + int32_t n, const double* k, double share, + double* smoothed) { + const double scale = k[K_NORM] * share; + for (int32_t i = 0; i < n; i++) { + const double xi = p[3 * i], yi = p[3 * i + 1], zi = p[3 * i + 2]; + const double vxi = v[3 * i], vyi = v[3 * i + 1], vzi = v[3 * i + 2]; + int32_t q = start[i]; + const int32_t end = start[i + 1]; + VD ax = {0.0}, ay = {0.0}, az = {0.0}; + for (; q + F3D_W <= end; q += F3D_W) { + const VD dx = xi - F3D_NAME(gather3)(p, list, q, 0); + const VD dy = yi - F3D_NAME(gather3)(p, list, q, 1); + const VD dz = zi - F3D_NAME(gather3)(p, list, q, 2); + const VD w = F3D_NAME(poly6)(k, dx * dx + dy * dy + dz * dz) * scale; + ax += (F3D_NAME(gather3)(v, list, q, 0) - vxi) * w; + ay += (F3D_NAME(gather3)(v, list, q, 1) - vyi) * w; + az += (F3D_NAME(gather3)(v, list, q, 2) - vzi) * w; + } + double sx = vxi + F3D_NAME(sum)(ax), sy = vyi + F3D_NAME(sum)(ay), + sz = vzi + F3D_NAME(sum)(az); + for (; q < end; q++) { + const int32_t j = list[q]; + const double dx = xi - p[3 * j], dy = yi - p[3 * j + 1], + dz = zi - p[3 * j + 2]; + const double w = poly6(k, dx * dx + dy * dy + dz * dz) * scale; + sx += (v[3 * j] - vxi) * w; + sy += (v[3 * j + 1] - vyi) * w; + sz += (v[3 * j + 2] - vzi) * w; + } + smoothed[3 * i] = sx; + smoothed[3 * i + 1] = sy; + smoothed[3 * i + 2] = sz; + } +} + +#undef VD +#undef VI +#undef KEEP +#undef PICK diff --git a/packages/flutter3d_physics/test/fluid/native_kernels_test.dart b/packages/flutter3d_physics/test/fluid/native_kernels_test.dart index 6b0726365..0af034b39 100644 --- a/packages/flutter3d_physics/test/fluid/native_kernels_test.dart +++ b/packages/flutter3d_physics/test/fluid/native_kernels_test.dart @@ -2,6 +2,8 @@ import 'dart:math' as math; import 'dart:typed_data'; import 'package:flutter3d_physics/flutter3d_physics.dart'; +import 'package:flutter3d_physics/src/fluid/native/pbf_backend.dart' + show nativePbfLanes, setNativePbfLanes; import 'package:test/test.dart'; import 'package:vector_math/vector_math.dart'; @@ -52,57 +54,22 @@ void main() { expect(nativePbfAvailable, isTrue); }); - test('each native kernel matches the Dart one to a part in 10¹²', () { - final fluid = ParticleFluid(medium: FluidMedium.water, spacing: 0.001); - final native = ParticleFluid( - medium: FluidMedium.water, - spacing: 0.001, - native: true, - ); - final dart = fluid.kernels; - final c = native.kernels; - expect(c, isNot(isA())); - const n = 200; - final (x, start, list) = _cloud(n, fluid.h); - expect(list.length, greaterThan(n)); - - final d1 = Float64List(n); - final d2 = Float64List(n); - dart.densities(x, start, list, n, d1); - c.densities(x, start, list, n, d2); - _close(d1, d2); - - final n1 = Float64List(3 * n); - final n2 = Float64List(3 * n); - dart.normals(x, start, list, n, d1, n1); - c.normals(x, start, list, n, d1, n2); - _close(n1, n2); - - final before = Float64List(3 * n)..fillRange(0, 3 * n, -9.81); - final after = Float64List(3 * n)..fillRange(0, 3 * n, 0.1); - final v1 = Float64List(3 * n); - final v2 = Float64List(3 * n); - dart.forces(x, start, list, n, d1, n1, before, after, v1, 1e-4); - c.forces(x, start, list, n, d1, n1, before, after, v2, 1e-4); - _close(v1, v2); - - final l1 = Float64List(n); - final l2 = Float64List(n); - dart.lambdas(x, start, list, n, l1); - c.lambdas(x, start, list, n, l2); - _close(l1, l2); - - final p1 = Float64List(3 * n); - final p2 = Float64List(3 * n); - dart.deltas(x, start, list, n, l1, p1); - c.deltas(x, start, list, n, l1, p2); - _close(p1, p2); - - final s1 = Float64List(3 * n); - final s2 = Float64List(3 * n); - dart.viscosity(x, v1, start, list, n, 0.05, s1); - c.viscosity(x, v1, start, list, n, 0.05, s2); - _close(s1, s2); + for (final lanes in const [1, 2, 4, 8]) { + test('each native kernel matches the Dart one to a part in 10¹², ' + '\$lanes at a time', () { + // Each width this processor has: the wider are only the running + // processor's (AVX2, AVX-512F) on x86-64, and all of them on arm64. + if (setNativePbfLanes(lanes) != lanes) { + markTestSkipped('not on this processor'); + return; + } + addTearDown(() => setNativePbfLanes(0)); + _matches(); + }); + } + + test('the processor chooses how many at a time', () { + expect(const [2, 4, 8], contains(nativePbfLanes)); }); test('both find the same neighbours, in the same order', () { @@ -251,3 +218,57 @@ void main() { } }); } + +/// Each native kernel against the Dart one, at the width set. +void _matches() { + final fluid = ParticleFluid(medium: FluidMedium.water, spacing: 0.001); + final native = ParticleFluid( + medium: FluidMedium.water, + spacing: 0.001, + native: true, + ); + final dart = fluid.kernels; + final c = native.kernels; + expect(c, isNot(isA())); + const n = 200; + final (x, start, list) = _cloud(n, fluid.h); + expect(list.length, greaterThan(n)); + + final d1 = Float64List(n); + final d2 = Float64List(n); + dart.densities(x, start, list, n, d1); + c.densities(x, start, list, n, d2); + _close(d1, d2); + + final n1 = Float64List(3 * n); + final n2 = Float64List(3 * n); + dart.normals(x, start, list, n, d1, n1); + c.normals(x, start, list, n, d1, n2); + _close(n1, n2); + + final before = Float64List(3 * n)..fillRange(0, 3 * n, -9.81); + final after = Float64List(3 * n)..fillRange(0, 3 * n, 0.1); + final v1 = Float64List(3 * n); + final v2 = Float64List(3 * n); + dart.forces(x, start, list, n, d1, n1, before, after, v1, 1e-4); + c.forces(x, start, list, n, d1, n1, before, after, v2, 1e-4); + _close(v1, v2); + + final l1 = Float64List(n); + final l2 = Float64List(n); + dart.lambdas(x, start, list, n, l1); + c.lambdas(x, start, list, n, l2); + _close(l1, l2); + + final p1 = Float64List(3 * n); + final p2 = Float64List(3 * n); + dart.deltas(x, start, list, n, l1, p1); + c.deltas(x, start, list, n, l1, p2); + _close(p1, p2); + + final s1 = Float64List(3 * n); + final s2 = Float64List(3 * n); + dart.viscosity(x, v1, start, list, n, 0.05, s1); + c.viscosity(x, v1, start, list, n, 0.05, s2); + _close(s1, s2); +} diff --git a/packages/flutter3d_physics/test/native/lanes_check.c b/packages/flutter3d_physics/test/native/lanes_check.c new file mode 100644 index 000000000..563af039f --- /dev/null +++ b/packages/flutter3d_physics/test/native/lanes_check.c @@ -0,0 +1,68 @@ +// Each width of the native pair loops (`src/pbf_lanes.h`) held to the +// scalar loop, on whatever processor runs it, and timed: for CI's x86-64, +// where the AVX2 and AVX-512 widths are real, which no arm64 machine can +// say. Built and run by the `native-lanes` job: +// +// cc -O3 -fno-math-errno -Isrc src/pbf_kernels.c test/native/lanes_check.c -lm +// +// Exits 1 when a width differs from the scalar loop by more than a part in +// 10¹² of the largest value, which is summing in another order and nothing +// else. +#include +#include +#include +#include +#include +int32_t f3d_pbf_lanes(void); int32_t f3d_pbf_set_lanes(int32_t); +int32_t f3d_pbf_neighbours(const double*, int32_t, double, int32_t*, int32_t*, int32_t, int64_t*); +void f3d_pbf_densities(const double*, const int32_t*, const int32_t*, int32_t, const double*, double*); +void f3d_pbf_normals(const double*, const int32_t*, const int32_t*, int32_t, const double*, const double*, double*); +void f3d_pbf_forces(const double*, const int32_t*, const int32_t*, int32_t, const double*, const double*, const double*, const double*, const double*, double*, double); +void f3d_pbf_lambdas(const double*, const int32_t*, const int32_t*, int32_t, const double*, double*); +void f3d_pbf_deltas(const double*, const int32_t*, const int32_t*, int32_t, const double*, const double*, double*); +void f3d_pbf_viscosity(const double*, const double*, const int32_t*, const int32_t*, int32_t, const double*, double, double*); +#define N 2000 +static double x[3*N], v[3*N], k[12], bef[3*N], aft[3*N]; +static int32_t st[N+1], lst[N*200]; static int64_t scr[5*N]; +typedef struct { double d[N], n[3*N], f[3*N], l[N], dl[3*N], vs[3*N]; } out_t; +static out_t o[9]; +static void run(out_t* r) { + f3d_pbf_densities(x, st, lst, N, k, r->d); + f3d_pbf_normals(x, st, lst, N, k, r->d, r->n); + for (int i=0;i<3*N;i++) r->f[i]=v[i]; + f3d_pbf_forces(x, st, lst, N, k, r->d, r->n, bef, aft, r->f, 1e-3); + f3d_pbf_lambdas(x, st, lst, N, k, r->l); + f3d_pbf_deltas(x, st, lst, N, k, r->l, r->dl); + f3d_pbf_viscosity(x, v, st, lst, N, k, 0.1, r->vs); +} +static double rel(const double* a, const double* b, int n) { + double m=0, s=0; for (int i=0;im)m=e; if(fabs(b[i])>s)s=fabs(b[i]); } return s>0? m/s : m; +} +int main(void) { + int failed = 0; + srand(7); const double sp=0.001, h=2*sp; + // A jittered block, with a few particles on top of each other. + for (int i=0;id,b->d,N); + double e[5] = {rel(a->n,b->n,3*N), rel(a->f,b->f,3*N), rel(a->l,b->l,N), rel(a->dl,b->dl,3*N), rel(a->vs,b->vs,3*N)}; + for (int q=0;q<5;q++) if (e[q]>worst) worst=e[q]; + if (worst > 1e-12) failed = 1; + printf("lanes %d: %.3f ms; against scalar: density %.1e normals %.1e forces %.1e lambda %.1e delta %.1e viscosity %.1e\n", widths[w], ms, + rel(a->d,b->d,N), rel(a->n,b->n,3*N), rel(a->f,b->f,3*N), rel(a->l,b->l,N), rel(a->dl,b->dl,3*N), rel(a->vs,b->vs,3*N)); + } + if (failed) printf("a width differs from the scalar loop\n"); + return failed; +} diff --git a/site/content/quickstart.md b/site/content/quickstart.md index 5b291f7d6..fe869b70e 100644 --- a/site/content/quickstart.md +++ b/site/content/quickstart.md @@ -91,7 +91,7 @@ tool/ci.sh # shaders, analyze, every test (cd packages/flutter3d_physics && dart test) # plain Dart, no Flutter needed ``` -There are 11376 tests across 43 packages and twelve applications, and only about thirty need a GPU: the Impeller half of the golden set. The other half renders through the software backend, so ninety scenes stay checkable in a headless run. +There are 11377 tests across 43 packages and twelve applications, and only about thirty need a GPU: the Impeller half of the golden set. The other half renders through the software backend, so ninety scenes stay checkable in a headless run. ## Your own application diff --git a/site/content/reference/testing.md b/site/content/reference/testing.md index a2a327466..e0aea063a 100644 --- a/site/content/reference/testing.md +++ b/site/content/reference/testing.md @@ -1,10 +1,10 @@ --- -description: Four independent golden sets, mutation-checking every new test, determinism and snapshots, and why only about thirty of 11376 tests need a GPU. +description: Four independent golden sets, mutation-checking every new test, determinism and snapshots, and why only about thirty of 11377 tests need a GPU. --- # Testing -11376 tests across 43 packages and nine applications, counted the same way the `the document says how many tests there are` rule does: a scan of every `test(`/`testWidgets(` call. The rule holds `ARCHITECTURE.md` §13, the README and this page to the answer. The README went on saying 1242 across thirteen packages for as long as nothing compared it with anything. About thirty need a GPU; the [architecture](/core/architecture/) is what keeps the number that low. +11377 tests across 43 packages and nine applications, counted the same way the `the document says how many tests there are` rule does: a scan of every `test(`/`testWidgets(` call. The rule holds `ARCHITECTURE.md` §13, the README and this page to the answer. The README went on saying 1242 across thirteen packages for as long as nothing compared it with anything. About thirty need a GPU; the [architecture](/core/architecture/) is what keeps the number that low. | Package | Tests | | Package | Tests | |---|---|---|---|---| @@ -23,7 +23,7 @@ description: Four independent golden sets, mutation-checking every new test, det | `flutter3d_cpu` | 380 | | `apps/flutter3d_demo_strategy` | 50 | | `apps/flutter3d_editor` | 234 | | `apps/flutter3d_demo_arcade` | 20 | | `apps/flutter3d_demo_racing` | 162 | | `pointer_lock` | 28 | -| `flutter3d_physics` | 303 | | `flutter3d_webgpu` | 193 | +| `flutter3d_physics` | 304 | | `flutter3d_webgpu` | 193 | | `flutter3d_game_strategy` | 133 | | `flutter3d_editor_mcp` | 36 | | `apps/flutter3d_demo_river` | 54 | | `flutter3d_testing` | 45 | | `flutter3d_editor_core` | 141 | | `flutter3d_editor_widgets` | 91 | @@ -40,7 +40,7 @@ description: Four independent golden sets, mutation-checking every new test, det | `flame_flutter3d` | 140 | | `apps/flutter3d_showcase` | 88 | | `flame_multiplayer` | 9 | | `flame_multiplayer_dashwire` | 3 | -The rows sum to 11349 rather than 11376: the remaining 26 live in `packages/*/example/test`, which the count includes and this table does not, among them the two seeds a new project starts from, `packages/flutter3d_app/example` and `packages/flutter3d_game/example`. +The rows sum to 11350 rather than 11377: the remaining 26 live in `packages/*/example/test`, which the count includes and this table does not, among them the two seeds a new project starts from, `packages/flutter3d_app/example` and `packages/flutter3d_game/example`. `flutter3d_samples` is not in the table and has no `test/` at all: it is test data with two path constants over it, and other packages' decoder tests are what exercise it. `flutter3d_conformance` is missing for a different reason: it is invoked as a script harness rather than through `flutter test`, so it does not surface in a grep of `test(` calls either. See below for what that cost once. From a770c0010b9ca7e2857ecf9b8e1f6de28e07b319 Mon Sep 17 00:00:00 2001 From: Dmitrii Zolotov Date: Sat, 3 Oct 2026 18:00:01 +0300 Subject: [PATCH 33/34] perf: Take AVX2's four lanes on x86-64 even where AVX-512 is there The CI runner, which has AVX-512F, measured eight lanes as fast as four with gcc and slower with clang: the native loops wait on gathering each neighbour's numbers, not on arithmetic. Four lanes stay the default wherever AVX2 is; eight remain for a test to ask for. --- .../lib/src/fluid/native/pbf_native.dart | 4 ++-- packages/flutter3d_physics/src/pbf_kernels.c | 12 +++++++++--- .../test/fluid/native_kernels_test.dart | 2 +- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/packages/flutter3d_physics/lib/src/fluid/native/pbf_native.dart b/packages/flutter3d_physics/lib/src/fluid/native/pbf_native.dart index ae71469f9..e8c53a242 100644 --- a/packages/flutter3d_physics/lib/src/fluid/native/pbf_native.dart +++ b/packages/flutter3d_physics/lib/src/fluid/native/pbf_native.dart @@ -308,8 +308,8 @@ external int _lanes(); external int _setLanes(int lanes); /// How many neighbours the native pair loops take at a time: chosen by the -/// running processor (eight with AVX-512F, four with AVX2, two with SSE2 or -/// NEON), or 0 where there is no native code. +/// running processor (four with AVX2, which measured as fast as AVX-512F's +/// eight; two with SSE2 or NEON), or 0 where there is no native code. int get nativePbfLanes => nativePbfAvailable ? _lanes() : 0; /// Sets [nativePbfLanes] to [lanes] where the processor has them, 0 for its diff --git a/packages/flutter3d_physics/src/pbf_kernels.c b/packages/flutter3d_physics/src/pbf_kernels.c index a98d2378e..04371d3d9 100644 --- a/packages/flutter3d_physics/src/pbf_kernels.c +++ b/packages/flutter3d_physics/src/pbf_kernels.c @@ -15,8 +15,9 @@ // with an illegal instruction. Two lanes everywhere (SSE2 and NEON are // in every x86-64 and arm64); on x86-64 also four, built for AVX2, and // eight, built for AVX-512F, each taken only where the processor says it -// has them. Without fused multiply-adds, so that each lane rounds as the -// scalar loop does. +// has them, eight being there for a test to ask for: four is the default +// (see [f3d_default_lanes]). Without fused multiply-adds, so that each lane +// rounds as the scalar loop does. // // The constants come as one array, in this order: // 0 h, 1 h², 2 ρ₀, 3 m, 4 norm, 5 γ, 6 rest stiffness, @@ -442,9 +443,14 @@ static int32_t f3d_widest(void) { // by whichever isolate asks first, or set by a test. static int32_t f3d_lanes = 0; +// **Four on x86-64 where there is AVX2, not the widest there is.** On a +// CI runner with AVX-512F, eight lanes were as fast as four built with gcc +// and slower built with clang (0.67 and 0.77 ms against 0.70 and 0.65): the +// loops wait on gathering each neighbour's numbers, not on arithmetic. +// Four against two was 1.5 times as fast. static int32_t f3d_default_lanes(void) { #if F3D_X86 - return f3d_widest(); + return f3d_widest() >= 4 ? 4 : 2; #elif F3D_VECTOR return F3D_ARM_LANES; #else diff --git a/packages/flutter3d_physics/test/fluid/native_kernels_test.dart b/packages/flutter3d_physics/test/fluid/native_kernels_test.dart index 0af034b39..5630ed79a 100644 --- a/packages/flutter3d_physics/test/fluid/native_kernels_test.dart +++ b/packages/flutter3d_physics/test/fluid/native_kernels_test.dart @@ -69,7 +69,7 @@ void main() { } test('the processor chooses how many at a time', () { - expect(const [2, 4, 8], contains(nativePbfLanes)); + expect(const [2, 4], contains(nativePbfLanes)); }); test('both find the same neighbours, in the same order', () { From b13b5af93bf415987f514a1f72cc1168993c0118 Mon Sep 17 00:00:00 2001 From: Dmitrii Zolotov Date: Sat, 3 Oct 2026 20:09:53 +0300 Subject: [PATCH 34/34] test: Run the native and background tests on the VM only On the web there is neither dart:ffi nor a second isolate, and the code rightly works everything out in Dart at once there; the tests that check the native kernels and the background isolate now say @TestOn('vm'). The width test's name now carries the width instead of a literal $lanes. --- packages/flutter3d_physics/test/fluid/background_test.dart | 5 +++++ .../flutter3d_physics/test/fluid/native_kernels_test.dart | 7 ++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/packages/flutter3d_physics/test/fluid/background_test.dart b/packages/flutter3d_physics/test/fluid/background_test.dart index 049eb761a..8bedcf10b 100644 --- a/packages/flutter3d_physics/test/fluid/background_test.dart +++ b/packages/flutter3d_physics/test/fluid/background_test.dart @@ -1,3 +1,8 @@ +// The background is another isolate, which the web has not: there what +// would be put off is worked out at once, and nothing here applies. +@TestOn('vm') +library; + import 'dart:math' as math; import 'dart:typed_data'; diff --git a/packages/flutter3d_physics/test/fluid/native_kernels_test.dart b/packages/flutter3d_physics/test/fluid/native_kernels_test.dart index 5630ed79a..2ce3bbde9 100644 --- a/packages/flutter3d_physics/test/fluid/native_kernels_test.dart +++ b/packages/flutter3d_physics/test/fluid/native_kernels_test.dart @@ -1,3 +1,8 @@ +// The native kernels are reached through dart:ffi, which the web has not: +// there the Dart kernels run, and nothing here applies. +@TestOn('vm') +library; + import 'dart:math' as math; import 'dart:typed_data'; @@ -56,7 +61,7 @@ void main() { for (final lanes in const [1, 2, 4, 8]) { test('each native kernel matches the Dart one to a part in 10¹², ' - '\$lanes at a time', () { + '$lanes at a time', () { // Each width this processor has: the wider are only the running // processor's (AVX2, AVX-512F) on x86-64, and all of them on arm64. if (setNativePbfLanes(lanes) != lanes) {