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,114 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "GameFramework/Actor.h"
|
||||
#include "VoxelForgeLivingPlaneActor.generated.h"
|
||||
|
||||
class UMaterialInterface;
|
||||
class UMaterialInstanceDynamic;
|
||||
class UStaticMeshComponent;
|
||||
class UTextureRenderTarget2D;
|
||||
|
||||
USTRUCT(BlueprintType)
|
||||
struct FVFLivingPlaneObjectInput
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Living Plane|Object")
|
||||
FVector WorldPositionCm = FVector(0.0, 0.0, 43.0);
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Living Plane|Object")
|
||||
FVector WorldVelocityCmPerSecond = FVector::ZeroVector;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Living Plane|Object", meta=(ClampMin="0.1"))
|
||||
float RadiusCm = 43.0f;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Living Plane|Object", meta=(ClampMin="0.0"))
|
||||
float PushAccelerationMetersPerSecondSquared = 36.0f;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Living Plane|Object")
|
||||
bool bActive = false;
|
||||
};
|
||||
|
||||
/** A render-only, GPU-stepped heightfield plane. Object state is uploaded; the field is never read back. */
|
||||
UCLASS(BlueprintType, Blueprintable)
|
||||
class VOXELFORGELIVINGPLANE_API AVoxelForgeLivingPlaneActor : public AActor
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
AVoxelForgeLivingPlaneActor();
|
||||
|
||||
virtual void BeginPlay() override;
|
||||
virtual void Tick(float DeltaSeconds) override;
|
||||
virtual void OnConstruction(const FTransform& Transform) override;
|
||||
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category="Living Plane|Object")
|
||||
void SetObjectState(int32 ObjectIndex, const FVFLivingPlaneObjectInput& State);
|
||||
|
||||
UFUNCTION(BlueprintCallable, Category="Living Plane")
|
||||
void ResetSimulation();
|
||||
|
||||
UFUNCTION(BlueprintPure, Category="Living Plane")
|
||||
int64 GetSimulationStepCount() const { return SimulationStepCount; }
|
||||
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Living Plane")
|
||||
TObjectPtr<UStaticMeshComponent> PlaneMesh;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category="Living Plane|Rendering")
|
||||
TObjectPtr<UMaterialInterface> PlaneMaterial;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Living Plane|Simulation", meta=(ClampMin="16", ClampMax="2048"))
|
||||
int32 GridSize = 256;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Living Plane|Simulation", meta=(ClampMin="1.0", ClampMax="100.0"))
|
||||
float PlaneLengthMeters = 12.0f;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Living Plane|Simulation", meta=(ClampMin="0.0"))
|
||||
float WaveSpeedMetersPerSecond = 4.5f;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Living Plane|Simulation", meta=(ClampMin="0.0"))
|
||||
float DampingPerSecond = 1.35f;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Living Plane|Simulation", meta=(ClampMin="0.0"))
|
||||
float FoundationStiffnessPerSecondSquared = 28.0f;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Living Plane|Simulation")
|
||||
bool bEnableBreathing = true;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Living Plane|Simulation", meta=(ClampMin="0.0", ClampMax="30.0"))
|
||||
float BreathingStrengthMetersPerSecondSquared = 4.8f;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Living Plane|Imprint")
|
||||
bool bEnableImprint = true;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Living Plane|Imprint", meta=(ClampMin="0.0", ClampMax="1.0"))
|
||||
float ImprintCaptureMetersPerSecond = 0.15f;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Living Plane|Imprint", meta=(ClampMin="0.1", ClampMax="60.0"))
|
||||
float ImprintRecoverySeconds = 6.0f;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Living Plane|Imprint", meta=(ClampMin="0.0", ClampMax="1.0"))
|
||||
float ImprintMaxDepthMeters = 0.34f;
|
||||
|
||||
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Living Plane|Object")
|
||||
TArray<FVFLivingPlaneObjectInput> ObjectInputs;
|
||||
|
||||
private:
|
||||
void CreateFieldTargets();
|
||||
void EnqueueSimulationSteps(int32 NumSteps);
|
||||
void UpdateMaterialField();
|
||||
float GetStableStepSeconds() const;
|
||||
|
||||
UPROPERTY(Transient)
|
||||
TObjectPtr<UTextureRenderTarget2D> FieldTargets[2];
|
||||
|
||||
UPROPERTY(Transient)
|
||||
TObjectPtr<UMaterialInstanceDynamic> DynamicPlaneMaterial;
|
||||
|
||||
int32 CurrentFieldIndex = 0;
|
||||
int64 SimulationStepCount = 0;
|
||||
double SimulationAccumulatorSeconds = 0.0;
|
||||
double FixedStepSeconds = 0.0;
|
||||
};
|
||||
Reference in new issue
Block a user