Lower portable power pulse field splats

This commit is contained in:
Meta Vens 2026-07-15 22:42:05 +01:00
commit 441471949a
4 changed files with 62 additions and 5 deletions

View file

@ -12,7 +12,7 @@ namespace GameCult.Eve.UnityScene.Fields
public const string ViewportToClipPropertyName = "_EveFieldsViewportToClip";
public const string ChannelFilterPropertyName = "_EveFieldsChannelFilter";
private const int SplatStrideBytes = 80;
private const int SplatStrideBytes = 96;
private EveFieldsGpuSplat[] splats = Array.Empty<EveFieldsGpuSplat>();
private GraphicsBuffer buffer;
private int capacity;
@ -54,6 +54,7 @@ namespace GameCult.Eve.UnityScene.Fields
RotationChannelFalloff = new Vector4((float)Read(source.RotationCos, index, 1), (float)Read(source.RotationSin, index, 0), channel, Read(source.Falloff, index, EveFieldsSplatFalloffs.Smooth)),
LayerSource = new Vector4(layer, Read(source.SourceKind, index, EveFieldsSplatSourceKinds.Constant), (float)Read(source.AnimationSpeed, index, 0), (float)Read(source.SourceFlags, index, 0)),
SourceFrequencyPhase = new Vector4((float)Read(source.FrequencyX, index, 1), (float)Read(source.FrequencyY, index, 1), (float)Read(source.PhaseX, index, 0), (float)Read(source.PhaseY, index, 0)),
FalloffParameters = new Vector4((float)Read(source.FalloffScale, index, 1), (float)Read(source.FalloffExponent, index, 1), 0, 0),
Value = new Vector4((float)Read(source.ValueR, index, 0), (float)Read(source.ValueG, index, 0), (float)Read(source.ValueB, index, 0), (float)Read(source.ValueA, index, 1))
};
}
@ -99,6 +100,7 @@ namespace GameCult.Eve.UnityScene.Fields
public Vector4 RotationChannelFalloff;
public Vector4 LayerSource;
public Vector4 SourceFrequencyPhase;
public Vector4 FalloffParameters;
public Vector4 Value;
}
}

View file

@ -7,6 +7,7 @@ struct EveFieldsSplat
float4 rotationChannelFalloff;
float4 layerSource;
float4 sourceFrequencyPhase;
float4 falloffParameters;
float4 value;
};
@ -58,12 +59,17 @@ Varyings Vert(uint vertexId : SV_VertexID, uint instanceId : SV_InstanceID)
return output;
}
float ResolveFalloff(float2 localUv, int falloff)
float ResolveFalloff(float2 localUv, int falloff, float scale, float exponent)
{
float distance01 = saturate(length(localUv));
if (falloff == 0) return 1;
if (falloff == 1) return saturate(1 - distance01);
if (falloff == 3) return smoothstep(0, 1, distance01);
if (falloff == 4)
{
float pulseDistance = distance01 * max(0, scale);
return pow(saturate(1 - pulseDistance * pulseDistance), max(0.0001, exponent));
}
return 1 - smoothstep(0, 1, distance01);
}
@ -72,7 +78,11 @@ float4 Frag(Varyings input) : SV_Target
EveFieldsSplat splat = _EveFieldsSplats[input.instanceId];
int channel = (int)round(splat.rotationChannelFalloff.z);
if (_EveFieldsChannelFilter >= 0 && channel != _EveFieldsChannelFilter) discard;
float alpha = ResolveFalloff(input.localUv, (int)round(splat.rotationChannelFalloff.w));
float alpha = ResolveFalloff(
input.localUv,
(int)round(splat.rotationChannelFalloff.w),
splat.falloffParameters.x,
splat.falloffParameters.y);
clip(alpha - 0.0001);
int sourceKind = (int)round(splat.layerSource.y);
float source = 1;

View file

@ -131,6 +131,49 @@ namespace GameCult.Eve.UnityScene.Tests
UnityEngine.Object.DestroyImmediate(host);
}
[Test]
public void RasterizerLowersPortablePowerPulseParameters()
{
var document = new EveFieldsSplatsDocument
{
Viewport = new EveFieldsViewport { MinX = -1, MinY = -1, MaxX = 1, MaxY = 1 },
Splats = new EveFieldsSplatSoa
{
Count = 1,
CenterX = new[] { 0d },
CenterY = new[] { 0d },
HalfExtentX = new[] { 1d },
HalfExtentY = new[] { 1d },
RotationCos = new[] { 1d },
RotationSin = new[] { 0d },
Channel = new[] { 0 },
Falloff = new[] { EveFieldsSplatFalloffs.PowerPulse },
FalloffScale = new[] { 2d },
FalloffExponent = new[] { 1d },
ValueR = new[] { 1d },
ValueA = new[] { 1d },
LayerIndex = new[] { 0 },
SourceKind = new[] { EveFieldsSplatSourceKinds.Constant }
}
};
var host = new GameObject("eve-fields-power-pulse");
var rasterizer = host.AddComponent<EveFieldsSplatRasterizer>();
var output = rasterizer.Render(document, 128, 128);
var previous = RenderTexture.active;
RenderTexture.active = output;
var readback = new Texture2D(128, 128, TextureFormat.RGBAFloat, false, true);
readback.ReadPixels(new Rect(0, 0, 128, 128), 0, 0);
readback.Apply();
RenderTexture.active = previous;
Assert.That(readback.GetPixel(64, 64).r, Is.GreaterThan(0.95f));
Assert.That(readback.GetPixel(80, 64).r, Is.InRange(0.65f, 0.85f));
Assert.That(readback.GetPixel(96, 64).r, Is.LessThan(0.02f));
UnityEngine.Object.DestroyImmediate(readback);
UnityEngine.Object.DestroyImmediate(host);
}
private sealed class CaptureDocument : IEveFieldsSplatsDocument
{
public string Schema => EveFieldsSchemas.Splats;
@ -188,6 +231,8 @@ namespace GameCult.Eve.UnityScene.Tests
public IReadOnlyList<double> PhaseY => Zero;
public IReadOnlyList<double> AnimationSpeed => Zero;
public IReadOnlyList<double> SourceFlags => Zero;
public IReadOnlyList<double> FalloffScale => One;
public IReadOnlyList<double> FalloffExponent => One;
}
}
}

View file

@ -1,12 +1,12 @@
{
"name": "org.gamecult.eve.unity-scene",
"displayName": "Eve Unity Scene Lowering",
"version": "0.3.41",
"version": "0.3.42",
"unity": "2021.3",
"description": "Provider-agnostic Unity scene shell for gamecult.eve.surface.v1 interactive world surfaces.",
"dependencies": {
"org.gamecult.cultlib": "1.0.13",
"org.gamecult.eve.plugin-fields": "0.2.0",
"org.gamecult.eve.plugin-fields": "0.2.1",
"org.gamecult.eve.surface": "0.2.2",
"com.unity.mathematics": "1.3.2",
"com.unity.modules.particlesystem": "1.0.0"