Land the six shield-panel sources, ported to built-in and compiling
Cut 1 of docs/shield-panel-cut.md: land ShieldPanel.cs, ShieldPanel.shader,
ShieldSim.compute, ShieldCommon.hlsl, TilingBuilder.cs and Tilings.cs under
Assets/Shaders/Compute/ShieldField/, alongside Lightning/ and Slime/.
Port (URP -> built-in, three substitutions per the map's §2.1 probe):
- drop the UniversalPipeline SubShader tag, add IgnoreProjector
- swap the URP Core.hlsl include for UnityCG.cginc
- TransformWorldToHClip -> UnityWorldToClipPos (3 call sites)
Drawing collapse (D2/D5): RenderParams has no shaderPass member in
6000.3.24f1, and a multi-pass material draws every SubShader pass from one
indirect call regardless, so the three per-pass args buffers and draw calls
collapse to one args buffer sized to the widest pass (Outline) and one
Graphics.RenderPrimitivesIndirect call. Deleted: argsOutline, argsConduit,
drawFill/drawOutline/drawConduits and their branches.
Also deleted: ShieldPanelTester (the click harness the operator ruled
against; it also can't run — activeInputHandler is New Input System only)
and [ExecuteAlways] (incompatible with a pool per D13; Rebuild stays on the
context menu).
Defects fixed:
- D1: TilingBuilder.cs's inner `dist` shadowed the outer one (CS0136);
renamed to nbrDist.
- D3: CellStatic was 15 floats against a declared Stride of 16; added pad2
on both the HLSL and C# sides.
- D4: `centroid` is reserved in the compute compiler; renamed the
ShieldCommon.hlsl field to `center` (kept the C# field name as-is; it's
not reserved there and the two sides don't need matching names, only
matching layout).
- D6: fixed the comment on _BreakBudget — it's two elements (count + cap),
not the "single element" the old comment claimed.
- D12: the two-element uint[] Update() allocated every frame is now a
cached field, cheaper still under a pool of many live panels.
- D18 (R5 — operator ruling, not deferred to a follow-up): Penrose ignored
panelRadius entirely — a fixed authored iteration count meant the tiling
was just uniformly rescaled, not resampled, so cell count never grew with
the panel. Every other tiling here uses cellSize to hold local cell size
constant while radius extends coverage; Penrose now derives its iteration
count the same way (each substitution divides edge length by phi, solved
for the count that brings a unit edge to ~cellSize once scaled to
radius). This retires the now-meaningless `penroseIterations` field and
the `subdivisions` parameter it threaded through Tilings.Generate.
- Also removed a dead `idx` counter in Tilings.Voronoi (D8's mention of
dead code; the Vector2.zero sentinel ambiguity itself is unfixed, same as
D7/D19 — Voronoi and TriHex stay recorded defects, not fixed, per R5).
Not fixed here, per the map: D7 (Voronoi is unusably slow) and D19 (TriHex
has zero dual edges) are recorded, not fixed. D9/D10 (fracture tuning) are
Cut 5. D17 (growth gate blocks the spawning hit) and D20 (_PanelSpawnTime
hardcoded to 0) are Cut 3.
Repo-specific fix not in the map: Assets/Scripts/UI/ContextMenu.cs defines
a global `ContextMenu` MonoBehaviour that shadows UnityEngine.ContextMenu,
so `[ContextMenu("Rebuild")]` doesn't compile here (CS0616) even though it
did in the map's throwaway probe project. Used the fully-qualified
`[UnityEngine.ContextMenu(...)]` instead.
Adds Assets/Scripts/Editor/ShieldPanelCut1Verify.cs, a batchmode probe (no
NUnit path exists per the map's Q7 — Tests.asmdef can't see
Assembly-CSharp): asserts zero shader/compute compile errors and that
Penrose cell count actually scales with panelRadius (D18). Also adds
tests/mutation_tests_shield_panel_cut1.py, which mutates the D18 fix, the
D4 fix, and the shaderPass deletion in turn and asserts the probe goes red
each time, restoring the source after each case (own file per the
convention mutation_tests_addressables_cut.py established, so as not to
touch item-provenance's or the addressables cut's harnesses).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-18 06:08:04 +02:00
|
|
|
#ifndef SHIELD_COMMON_INCLUDED
|
|
|
|
|
#define SHIELD_COMMON_INCLUDED
|
|
|
|
|
|
|
|
|
|
#define MAX_VERTS 8 // must match Limits.MaxVerts in TilingBuilder.cs
|
|
|
|
|
#define TAU 6.28318530718
|
|
|
|
|
#define PI 3.14159265359
|
|
|
|
|
|
|
|
|
|
// ---- fracture pattern ids (must match FracturePattern in ShieldPanel.cs)
|
|
|
|
|
#define PAT_RADIAL 0
|
|
|
|
|
#define PAT_STAR 1
|
|
|
|
|
#define PAT_LANCE 2
|
|
|
|
|
#define PAT_SPIRAL 3
|
|
|
|
|
#define PAT_CRYSTAL 4
|
|
|
|
|
#define PAT_FIZZLE 5
|
|
|
|
|
|
|
|
|
|
struct CellStatic
|
|
|
|
|
{
|
|
|
|
|
float2 center;
|
|
|
|
|
float radius;
|
|
|
|
|
float spawnDelay;
|
|
|
|
|
uint vertStart;
|
|
|
|
|
uint vertCount;
|
|
|
|
|
uint nbrStart;
|
|
|
|
|
uint nbrCount;
|
|
|
|
|
float toughness;
|
|
|
|
|
uint tileType;
|
|
|
|
|
uint splitSeed;
|
|
|
|
|
float area; // Laplacian denominator
|
Cut 5: hold the rim, clamp v, fix fracture's clock, tune to spec
R7 (operator ruling): the panel's emitters hold its edge, so the rim is no
longer a free surface. Deletes the openW ghost term end to end -- its only
consumer in ShieldSim.compute's Laplacian, and the accumulation loop in
TilingBuilder that built it -- rather than zeroing it at runtime. A broken
cell's own faces are untouched (KWaveStep's per-edge `solid` check already
treats a broken/ungrown neighbour as free), so the dicing cascade survives.
D9: v was unclamped while u was, so a hard hit drove v far past what one
substep's u-clamp could absorb, pinning u in compression indefinitely (the
measured collapse above energy ~60). Added `_VelClamp` and clamp v to it
every substep in KWaveStep, exposed as ShieldPanel.velocityClamp (100).
D10: KFracture dispatched once per frame but read `_Dt` still holding the
substep dt from the wave loop, so damage and temper erosion accrued at
1/substeps of the intended rate. Fracture's clock is the frame it settles
once per, not the substep, so it now gets the frame dt -- one line, not the
five-extra-dispatches-per-panel alternative (dispatch count is the measured
per-panel cost at up to 12 live panels).
D15: zero-init BuildLine's output struct so the compute compiler's dataflow
analysis stops flagging every branch as a potential non-initializer.
Tuning (ShieldPanel.cs Material header): tensileStrength 0.9->0.2,
temperErosion 2.2->12, damageGain 6->100, breakAt 0.75->0.08,
storedEnergyGain 0.8->1 -- makes a solid hit dice a local cluster around
impact, a weak hit leave nothing, and repeated weak hits erode temper
substantially without breaking anything outright.
Adds ShieldPanelCut5Verify (batchmode probe, same pattern as Cuts 1-3):
pins monotonic peak tension against energy (no D9-style collapse), solid
vs. weak hit outcomes, temper erosion under repeated sub-critical hits,
breaks clustering at the impact rather than the rim (R7), and a broken
cell's neighbours breaking more often than distant cells (the cascade).
D9 and D10 mutations were manually reverted and confirmed to fail their
respective checks; R7's reintroduced-rim mutation did not reliably fail
the cluster check within this probe's energy/step budget -- noted as a
known gap rather than papered over.
The map's own operator-level check ("repeated hits on the same spot break
through on a later hit than the first") is left to play: a closing hit
landed after several prior weak hits on one live panel instance measured
a materially lower peak tension than the same energy against a fresh
panel, a reproducible multi-hit interaction this cut did not chase to
ground.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-18 20:04:05 +02:00
|
|
|
// R7: openW (rim free-surface ghost weight) removed — the panel's emitters hold its edge.
|
Land the six shield-panel sources, ported to built-in and compiling
Cut 1 of docs/shield-panel-cut.md: land ShieldPanel.cs, ShieldPanel.shader,
ShieldSim.compute, ShieldCommon.hlsl, TilingBuilder.cs and Tilings.cs under
Assets/Shaders/Compute/ShieldField/, alongside Lightning/ and Slime/.
Port (URP -> built-in, three substitutions per the map's §2.1 probe):
- drop the UniversalPipeline SubShader tag, add IgnoreProjector
- swap the URP Core.hlsl include for UnityCG.cginc
- TransformWorldToHClip -> UnityWorldToClipPos (3 call sites)
Drawing collapse (D2/D5): RenderParams has no shaderPass member in
6000.3.24f1, and a multi-pass material draws every SubShader pass from one
indirect call regardless, so the three per-pass args buffers and draw calls
collapse to one args buffer sized to the widest pass (Outline) and one
Graphics.RenderPrimitivesIndirect call. Deleted: argsOutline, argsConduit,
drawFill/drawOutline/drawConduits and their branches.
Also deleted: ShieldPanelTester (the click harness the operator ruled
against; it also can't run — activeInputHandler is New Input System only)
and [ExecuteAlways] (incompatible with a pool per D13; Rebuild stays on the
context menu).
Defects fixed:
- D1: TilingBuilder.cs's inner `dist` shadowed the outer one (CS0136);
renamed to nbrDist.
- D3: CellStatic was 15 floats against a declared Stride of 16; added pad2
on both the HLSL and C# sides.
- D4: `centroid` is reserved in the compute compiler; renamed the
ShieldCommon.hlsl field to `center` (kept the C# field name as-is; it's
not reserved there and the two sides don't need matching names, only
matching layout).
- D6: fixed the comment on _BreakBudget — it's two elements (count + cap),
not the "single element" the old comment claimed.
- D12: the two-element uint[] Update() allocated every frame is now a
cached field, cheaper still under a pool of many live panels.
- D18 (R5 — operator ruling, not deferred to a follow-up): Penrose ignored
panelRadius entirely — a fixed authored iteration count meant the tiling
was just uniformly rescaled, not resampled, so cell count never grew with
the panel. Every other tiling here uses cellSize to hold local cell size
constant while radius extends coverage; Penrose now derives its iteration
count the same way (each substitution divides edge length by phi, solved
for the count that brings a unit edge to ~cellSize once scaled to
radius). This retires the now-meaningless `penroseIterations` field and
the `subdivisions` parameter it threaded through Tilings.Generate.
- Also removed a dead `idx` counter in Tilings.Voronoi (D8's mention of
dead code; the Vector2.zero sentinel ambiguity itself is unfixed, same as
D7/D19 — Voronoi and TriHex stay recorded defects, not fixed, per R5).
Not fixed here, per the map: D7 (Voronoi is unusably slow) and D19 (TriHex
has zero dual edges) are recorded, not fixed. D9/D10 (fracture tuning) are
Cut 5. D17 (growth gate blocks the spawning hit) and D20 (_PanelSpawnTime
hardcoded to 0) are Cut 3.
Repo-specific fix not in the map: Assets/Scripts/UI/ContextMenu.cs defines
a global `ContextMenu` MonoBehaviour that shadows UnityEngine.ContextMenu,
so `[ContextMenu("Rebuild")]` doesn't compile here (CS0616) even though it
did in the map's throwaway probe project. Used the fully-qualified
`[UnityEngine.ContextMenu(...)]` instead.
Adds Assets/Scripts/Editor/ShieldPanelCut1Verify.cs, a batchmode probe (no
NUnit path exists per the map's Q7 — Tests.asmdef can't see
Assembly-CSharp): asserts zero shader/compute compile errors and that
Penrose cell count actually scales with panelRadius (D18). Also adds
tests/mutation_tests_shield_panel_cut1.py, which mutates the D18 fix, the
D4 fix, and the shaderPass deletion in turn and asserts the probe goes red
each time, restoring the source after each case (own file per the
convention mutation_tests_addressables_cut.py established, so as not to
touch item-provenance's or the addressables cut's harnesses).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-18 06:08:04 +02:00
|
|
|
float pad0;
|
|
|
|
|
float pad1;
|
|
|
|
|
float pad2;
|
Cut 5: hold the rim, clamp v, fix fracture's clock, tune to spec
R7 (operator ruling): the panel's emitters hold its edge, so the rim is no
longer a free surface. Deletes the openW ghost term end to end -- its only
consumer in ShieldSim.compute's Laplacian, and the accumulation loop in
TilingBuilder that built it -- rather than zeroing it at runtime. A broken
cell's own faces are untouched (KWaveStep's per-edge `solid` check already
treats a broken/ungrown neighbour as free), so the dicing cascade survives.
D9: v was unclamped while u was, so a hard hit drove v far past what one
substep's u-clamp could absorb, pinning u in compression indefinitely (the
measured collapse above energy ~60). Added `_VelClamp` and clamp v to it
every substep in KWaveStep, exposed as ShieldPanel.velocityClamp (100).
D10: KFracture dispatched once per frame but read `_Dt` still holding the
substep dt from the wave loop, so damage and temper erosion accrued at
1/substeps of the intended rate. Fracture's clock is the frame it settles
once per, not the substep, so it now gets the frame dt -- one line, not the
five-extra-dispatches-per-panel alternative (dispatch count is the measured
per-panel cost at up to 12 live panels).
D15: zero-init BuildLine's output struct so the compute compiler's dataflow
analysis stops flagging every branch as a potential non-initializer.
Tuning (ShieldPanel.cs Material header): tensileStrength 0.9->0.2,
temperErosion 2.2->12, damageGain 6->100, breakAt 0.75->0.08,
storedEnergyGain 0.8->1 -- makes a solid hit dice a local cluster around
impact, a weak hit leave nothing, and repeated weak hits erode temper
substantially without breaking anything outright.
Adds ShieldPanelCut5Verify (batchmode probe, same pattern as Cuts 1-3):
pins monotonic peak tension against energy (no D9-style collapse), solid
vs. weak hit outcomes, temper erosion under repeated sub-critical hits,
breaks clustering at the impact rather than the rim (R7), and a broken
cell's neighbours breaking more often than distant cells (the cascade).
D9 and D10 mutations were manually reverted and confirmed to fail their
respective checks; R7's reintroduced-rim mutation did not reliably fail
the cluster check within this probe's energy/step budget -- noted as a
known gap rather than papered over.
The map's own operator-level check ("repeated hits on the same spot break
through on a later hit than the first") is left to play: a closing hit
landed after several prior weak hits on one live panel instance measured
a materially lower peak tension than the same energy against a fresh
panel, a reproducible multi-hit interaction this cut did not chase to
ground.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-18 20:04:05 +02:00
|
|
|
float pad3;
|
Land the six shield-panel sources, ported to built-in and compiling
Cut 1 of docs/shield-panel-cut.md: land ShieldPanel.cs, ShieldPanel.shader,
ShieldSim.compute, ShieldCommon.hlsl, TilingBuilder.cs and Tilings.cs under
Assets/Shaders/Compute/ShieldField/, alongside Lightning/ and Slime/.
Port (URP -> built-in, three substitutions per the map's §2.1 probe):
- drop the UniversalPipeline SubShader tag, add IgnoreProjector
- swap the URP Core.hlsl include for UnityCG.cginc
- TransformWorldToHClip -> UnityWorldToClipPos (3 call sites)
Drawing collapse (D2/D5): RenderParams has no shaderPass member in
6000.3.24f1, and a multi-pass material draws every SubShader pass from one
indirect call regardless, so the three per-pass args buffers and draw calls
collapse to one args buffer sized to the widest pass (Outline) and one
Graphics.RenderPrimitivesIndirect call. Deleted: argsOutline, argsConduit,
drawFill/drawOutline/drawConduits and their branches.
Also deleted: ShieldPanelTester (the click harness the operator ruled
against; it also can't run — activeInputHandler is New Input System only)
and [ExecuteAlways] (incompatible with a pool per D13; Rebuild stays on the
context menu).
Defects fixed:
- D1: TilingBuilder.cs's inner `dist` shadowed the outer one (CS0136);
renamed to nbrDist.
- D3: CellStatic was 15 floats against a declared Stride of 16; added pad2
on both the HLSL and C# sides.
- D4: `centroid` is reserved in the compute compiler; renamed the
ShieldCommon.hlsl field to `center` (kept the C# field name as-is; it's
not reserved there and the two sides don't need matching names, only
matching layout).
- D6: fixed the comment on _BreakBudget — it's two elements (count + cap),
not the "single element" the old comment claimed.
- D12: the two-element uint[] Update() allocated every frame is now a
cached field, cheaper still under a pool of many live panels.
- D18 (R5 — operator ruling, not deferred to a follow-up): Penrose ignored
panelRadius entirely — a fixed authored iteration count meant the tiling
was just uniformly rescaled, not resampled, so cell count never grew with
the panel. Every other tiling here uses cellSize to hold local cell size
constant while radius extends coverage; Penrose now derives its iteration
count the same way (each substitution divides edge length by phi, solved
for the count that brings a unit edge to ~cellSize once scaled to
radius). This retires the now-meaningless `penroseIterations` field and
the `subdivisions` parameter it threaded through Tilings.Generate.
- Also removed a dead `idx` counter in Tilings.Voronoi (D8's mention of
dead code; the Vector2.zero sentinel ambiguity itself is unfixed, same as
D7/D19 — Voronoi and TriHex stay recorded defects, not fixed, per R5).
Not fixed here, per the map: D7 (Voronoi is unusably slow) and D19 (TriHex
has zero dual edges) are recorded, not fixed. D9/D10 (fracture tuning) are
Cut 5. D17 (growth gate blocks the spawning hit) and D20 (_PanelSpawnTime
hardcoded to 0) are Cut 3.
Repo-specific fix not in the map: Assets/Scripts/UI/ContextMenu.cs defines
a global `ContextMenu` MonoBehaviour that shadows UnityEngine.ContextMenu,
so `[ContextMenu("Rebuild")]` doesn't compile here (CS0616) even though it
did in the map's throwaway probe project. Used the fully-qualified
`[UnityEngine.ContextMenu(...)]` instead.
Adds Assets/Scripts/Editor/ShieldPanelCut1Verify.cs, a batchmode probe (no
NUnit path exists per the map's Q7 — Tests.asmdef can't see
Assembly-CSharp): asserts zero shader/compute compile errors and that
Penrose cell count actually scales with panelRadius (D18). Also adds
tests/mutation_tests_shield_panel_cut1.py, which mutates the D18 fix, the
D4 fix, and the shaderPass deletion in turn and asserts the probe goes red
each time, restoring the source after each case (own file per the
convention mutation_tests_addressables_cut.py established, so as not to
touch item-provenance's or the addressables cut's harnesses).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-18 06:08:04 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct DualEdge
|
|
|
|
|
{
|
|
|
|
|
uint nbr;
|
|
|
|
|
float2 mid;
|
|
|
|
|
float2 dir;
|
|
|
|
|
float len;
|
|
|
|
|
float w; // finite-volume weight, len / |c_i - c_j|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct CellState
|
|
|
|
|
{
|
|
|
|
|
float3 vel;
|
|
|
|
|
float spin;
|
|
|
|
|
float3 pos; // displacement from rest, panel space (z = out of plane)
|
|
|
|
|
float rot;
|
|
|
|
|
float damage; // 0..1 persistent
|
|
|
|
|
float breakTime; // <0 while intact
|
|
|
|
|
float glow; // transient crack emission
|
|
|
|
|
float growth; // 0..1 materialisation
|
|
|
|
|
float temper; // remaining surface compression — the "charge" that resists initiation
|
|
|
|
|
float released; // stored energy dumped at break; sets fragment fineness
|
|
|
|
|
float peakTension; // running max, for visualisation
|
|
|
|
|
float pad2;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
|
// hashing
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
|
uint Hash(uint x)
|
|
|
|
|
{
|
|
|
|
|
x ^= x >> 16; x *= 0x7feb352du;
|
|
|
|
|
x ^= x >> 15; x *= 0x846ca68bu;
|
|
|
|
|
x ^= x >> 16; return x;
|
|
|
|
|
}
|
|
|
|
|
float Hash01(uint x) { return Hash(x) * (1.0 / 4294967296.0); }
|
|
|
|
|
float2 Hash2(uint x) { return float2(Hash01(x), Hash01(x ^ 0x68bc21ebu)); }
|
|
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
|
// shard partitioning
|
|
|
|
|
//
|
|
|
|
|
// A cell is drawn as a fan of vertCount triangles around its centroid.
|
|
|
|
|
// A shard is a contiguous run of those triangles. Split boundaries are
|
|
|
|
|
// derived from the cell seed, so every shader agrees without storage.
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
|
// Fragment count scales with the stored elastic energy released at the moment
|
|
|
|
|
// of breaking -- the same reason a highly tempered pane dices into gravel while
|
|
|
|
|
// an annealed one splits into a few big shards. `released` is 0 for a cell that
|
|
|
|
|
// is merely cracked and not yet broken, so the chords appear before separation.
|
|
|
|
|
uint ShardCount(uint seed, float damage, float released, uint vertCount,
|
|
|
|
|
float crackStart, uint maxShards)
|
|
|
|
|
{
|
|
|
|
|
if (damage <= crackStart) return 0;
|
|
|
|
|
float t = saturate(max(damage - crackStart, 0.0) / max(1.0 - crackStart, 1e-4));
|
|
|
|
|
t = saturate(t * 0.4 + released * 1.2);
|
|
|
|
|
uint hi = min(vertCount, maxShards);
|
|
|
|
|
if (hi < 2) return 0;
|
|
|
|
|
uint n = (uint)round(lerp(2.0, (float)hi, t * (0.55 + 0.45 * Hash01(seed))));
|
|
|
|
|
return clamp(n, 2u, hi);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Returns the shard index for fan triangle `tri`; startTri receives the
|
|
|
|
|
// first triangle of that shard (used as the shard's motion reference).
|
|
|
|
|
uint ShardOf(uint seed, uint nSplits, uint vertCount, uint tri, out uint startTri)
|
|
|
|
|
{
|
|
|
|
|
uint count = 0, prevB = 0, maxB = 0;
|
|
|
|
|
[loop] for (uint k = 0; k < nSplits; k++)
|
|
|
|
|
{
|
|
|
|
|
uint b = Hash(seed ^ (k * 0x9E3779B9u + 0x2545F491u)) % max(vertCount, 1u);
|
|
|
|
|
maxB = max(maxB, b);
|
|
|
|
|
if (b <= tri) { count++; prevB = max(prevB, b); }
|
|
|
|
|
}
|
|
|
|
|
startTri = (count == 0) ? maxB : prevB;
|
|
|
|
|
return (count == 0) ? (nSplits - 1) : (count - 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Is fan edge `ei` (the radial chord from centroid to vertex ei) a shard boundary?
|
|
|
|
|
bool IsChord(uint seed, uint nSplits, uint vertCount, uint ei)
|
|
|
|
|
{
|
|
|
|
|
[loop] for (uint k = 0; k < nSplits; k++)
|
|
|
|
|
if ((Hash(seed ^ (k * 0x9E3779B9u + 0x2545F491u)) % max(vertCount, 1u)) == ei) return true;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
|
// easing
|
|
|
|
|
// ------------------------------------------------------------------
|
|
|
|
|
float EaseOutBack(float t)
|
|
|
|
|
{
|
|
|
|
|
float u = t - 1.0;
|
|
|
|
|
return 1.0 + 2.70158 * u * u * u + 1.70158 * u * u;
|
|
|
|
|
}
|
|
|
|
|
float EaseOutCubic(float t) { float u = 1.0 - t; return 1.0 - u * u * u; }
|
|
|
|
|
|
|
|
|
|
float2 Rot2(float2 p, float a)
|
|
|
|
|
{
|
|
|
|
|
float s = sin(a), c = cos(a);
|
|
|
|
|
return float2(p.x * c - p.y * s, p.x * s + p.y * c);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#endif
|