experiment: LivingPlane repeatable + standalone UE runtime module (L164)
Readback barrier fix (GL_TEXTURE_UPDATE_BARRIER_BIT before glGetTexImage); check_repeatability.py compares full-field checksums across query/capture settings - Intel GPU PASS (3b9d45905c7aafff), llvmpipe PASS, mismatch control fails. New runtime module VoxelForgeLivingPlane (separate from generation): RDG global shader (Shaders/LivingPlane.usf), ping-pong RGBA32F render targets, actor with WPO plane and object inputs, no CPU readback. Compiles in Linux UE 5.7. Windows build: Source/VoxelForgeLivingPlane/*, Shaders/LivingPlane.usf, VoxelForge.uplugin. Setup: UE-SETUP.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016dhxM43dnWvUu2B5Ph1iG1
This commit is contained in:
1 parent
e1d87eed26
commit
3b71d35eba
13 files changed
+868
-8
No files matched your search
@@ -0,0 +1,85 @@
|
||||
Texture2D<float4> SourceState;
|
||||
RWTexture2D<float4> TargetState;
|
||||
|
||||
int2 GridSize;
|
||||
float Dt;
|
||||
float Dx;
|
||||
float PlaneLength;
|
||||
float WaveSpeed;
|
||||
float Damping;
|
||||
float FoundationStiffness;
|
||||
float TimeSeconds;
|
||||
float2 BreathingSettings;
|
||||
float4 ImprintSettings;
|
||||
float4 ObjectPositionRadius[2];
|
||||
float4 ObjectVelocityPush[2];
|
||||
|
||||
[numthreads(8, 8, 1)]
|
||||
void MainCS(uint3 DispatchThreadId : SV_DispatchThreadID)
|
||||
{
|
||||
int2 Pixel = int2(DispatchThreadId.xy);
|
||||
if (Pixel.x >= GridSize.x || Pixel.y >= GridSize.y)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int2 Lo = int2(0, 0);
|
||||
int2 Hi = GridSize - 1;
|
||||
float4 State = SourceState.Load(int3(Pixel, 0));
|
||||
float Height = State.r;
|
||||
float Velocity = State.g;
|
||||
float Imprint = State.b;
|
||||
float Left = SourceState.Load(int3(max(Pixel + int2(-1, 0), Lo), 0)).r;
|
||||
float Right = SourceState.Load(int3(min(Pixel + int2(1, 0), Hi), 0)).r;
|
||||
float Down = SourceState.Load(int3(max(Pixel + int2(0, -1), Lo), 0)).r;
|
||||
float Up = SourceState.Load(int3(min(Pixel + int2(0, 1), Hi), 0)).r;
|
||||
float Laplacian = (Left + Right + Down + Up - 4.0 * Height) / max(Dx * Dx, 1.0e-8);
|
||||
float2 World = (float2(Pixel) + 0.5) * Dx - PlaneLength * 0.5;
|
||||
|
||||
float Interaction = 0.0;
|
||||
float Contact = 0.0;
|
||||
for (int ObjectIndex = 0; ObjectIndex < 2; ++ObjectIndex)
|
||||
{
|
||||
float4 PositionRadius = ObjectPositionRadius[ObjectIndex];
|
||||
if (PositionRadius.w <= 0.0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
float4 VelocityPush = ObjectVelocityPush[ObjectIndex];
|
||||
float Radius = PositionRadius.w;
|
||||
float Sigma = max(Radius * (0.58 / 0.43), Dx);
|
||||
float2 Offset = World - PositionRadius.xy;
|
||||
float Weight = exp(-dot(Offset, Offset) / max(2.0 * Sigma * Sigma, 1.0e-8));
|
||||
float HeightAboveContact = max(PositionRadius.z - Radius, 0.0);
|
||||
float ContactHeight = 1.0 - smoothstep(0.0, max(Radius, Dx), HeightAboveContact);
|
||||
float ImpactSpeed = length(VelocityPush.xy) * 0.25 + max(-VelocityPush.z, 0.0) * 0.5;
|
||||
float Push = max(VelocityPush.w, 0.0) + ImpactSpeed;
|
||||
Interaction -= Push * Weight * ContactHeight;
|
||||
if (Push > 0.0)
|
||||
{
|
||||
Contact = max(Contact, Weight * ContactHeight);
|
||||
}
|
||||
}
|
||||
|
||||
float Breathing = 0.0;
|
||||
if (BreathingSettings.x != 0.0)
|
||||
{
|
||||
float Swell = sin(World.x * 0.48 - TimeSeconds * 0.22)
|
||||
* cos(World.y * 0.42 + TimeSeconds * 0.16);
|
||||
Breathing = BreathingSettings.y * Swell * sin(TimeSeconds * 0.48);
|
||||
}
|
||||
|
||||
float NextImprint = Imprint;
|
||||
if (ImprintSettings.x != 0.0)
|
||||
{
|
||||
NextImprint = clamp(Imprint * exp(-Dt / max(ImprintSettings.z, 1.0e-4))
|
||||
- Contact * ImprintSettings.y * Dt, -ImprintSettings.w, 0.0);
|
||||
}
|
||||
float FoundationTarget = ImprintSettings.x != 0.0 ? Imprint : 0.0;
|
||||
float Acceleration = WaveSpeed * WaveSpeed * Laplacian
|
||||
- FoundationStiffness * (Height - FoundationTarget) + Interaction + Breathing;
|
||||
float NextVelocity = (Velocity + Acceleration * Dt) * exp(-Damping * Dt);
|
||||
float NextHeight = Height + NextVelocity * Dt;
|
||||
TargetState[Pixel] = float4(NextHeight, NextVelocity, NextImprint, 0.0);
|
||||
}
|
||||
Reference in new issue
Block a user