diff --git a/shaders/voxelCommon.hlsli b/shaders/voxelCommon.hlsli index 0f26816..55ff410 100644 --- a/shaders/voxelCommon.hlsli +++ b/shaders/voxelCommon.hlsli @@ -50,7 +50,7 @@ cbuffer VoxelCB : register(b0) { uint chunkCount; uint bleedMask; // bit N set = material N can bleed onto neighbors uint resistBleedMask; // bit N set = material N resists bleed from neighbors - uint _cullPad2; + float windTime; // elapsed time for wind animation (seconds) }; // ── Indirect draw args (must match C++ IndirectDrawArgs, 20 bytes) ── diff --git a/shaders/voxelTopingVS.hlsl b/shaders/voxelTopingVS.hlsl index a28b524..b824bfb 100644 --- a/shaders/voxelTopingVS.hlsl +++ b/shaders/voxelTopingVS.hlsl @@ -44,6 +44,24 @@ VSOutput main(uint vertexID : SV_VertexID, uint instanceID : SV_InstanceID) { float3 worldPos = inst.worldPos + vtx.position; + // ── Wind animation (vegetation only) ──────────────────────── + // Height above the voxel face (y=1 in local space) drives amplitude. + // Quadratic scaling: base stays anchored, tips sway the most. + if (push.materialID != 3u) { // not stone + float localHeight = vtx.position.y - 1.0; + if (localHeight > 0.0) { + float heightFactor = localHeight * localHeight; // quadratic + float phase = worldPos.x * 1.8 + worldPos.z * 1.3 + windTime * 3.5; + float phase2 = worldPos.x * 0.7 - worldPos.z * 2.1 + windTime * 2.7; + float swayX = sin(phase) * 0.11 * heightFactor; + float swayZ = cos(phase2) * 0.08 * heightFactor; + float swayY = -abs(sin(phase * 0.7)) * 0.02 * heightFactor; // slight droop + worldPos.x += swayX; + worldPos.y += swayY; + worldPos.z += swayZ; + } + } + VSOutput output; output.position = mul(viewProjection, float4(worldPos, 1.0)); output.worldPos = worldPos; diff --git a/src/voxel/TopingSystem.cpp b/src/voxel/TopingSystem.cpp index 7973835..ac91780 100644 --- a/src/voxel/TopingSystem.cpp +++ b/src/voxel/TopingSystem.cpp @@ -399,7 +399,7 @@ void TopingSystem::generateGrassVariant(TopingDef& def, uint8_t bitmask) { angle += (h1 - 0.5f) * 20.0f; // Height: per-blade × per-tuft - float bladeHeight = (0.06f + h2 * 0.28f) * tuftHeightScale; + float bladeHeight = (0.09f + h2 * 0.42f) * tuftHeightScale; // +50% height float baseWidth = 0.030f + h3 * 0.030f; float lean = (0.03f + h4 * 0.12f) * tuftLeanScale; @@ -457,7 +457,7 @@ void TopingSystem::generateGrassVariant(TopingDef& def, uint8_t bitmask) { float angle = (fanT - 0.5f) * 2.0f * 70.0f; angle += (h1 - 0.5f) * 15.0f; - float height = (0.10f + h2 * 0.22f) * cornerHeightScale; + float height = (0.15f + h2 * 0.33f) * cornerHeightScale; // +50% height float baseWidth = 0.030f + h3 * 0.025f; float lean = (0.04f + h4 * 0.10f) * cornerLeanScale; float midLean = 0.10f + h5 * 0.30f; diff --git a/src/voxel/VoxelRenderer.cpp b/src/voxel/VoxelRenderer.cpp index 65f29c3..6d1b82b 100644 --- a/src/voxel/VoxelRenderer.cpp +++ b/src/voxel/VoxelRenderer.cpp @@ -714,7 +714,7 @@ void VoxelRenderer::render( // Material IDs: 1=Grass, 2=Dirt, 3=Stone, 4=Sand, 5=Snow cb.bleedMask = (1u << 1) | (1u << 2) | (1u << 4) | (1u << 5); // Grass, Dirt, Sand, Snow can bleed (NOT Stone) cb.resistBleedMask = (1u << 1); // Grass resists bleed (she bleeds onto others, not the reverse) - cb._cullPad2 = 0; + cb.windTime = windTime_; dev->UpdateBuffer(&constantBuffer_, &cb, cmd, sizeof(cb)); // Render pass @@ -801,7 +801,7 @@ void VoxelRenderer::render( cb.debugBlend = 0.0f; cb.bleedMask = 0; cb.resistBleedMask = 0; - cb._cullPad2 = 0; + cb.windTime = windTime_; cb.chunkCount = chunkCount_; extractFrustumPlanes(vpMatrix, cb.frustumPlanes); dev->UpdateBuffer(&constantBuffer_, &cb, cmd, sizeof(cb)); @@ -1466,6 +1466,8 @@ void VoxelRenderPath::Update(float dt) { float instantFps = (dt > 0.0f) ? (1.0f / dt) : 0.0f; smoothFps_ = smoothFps_ * 0.95f + instantFps * 0.05f; if (camera) handleInput(dt); + windTime_ += dt; + renderer.windTime_ = windTime_; // Animated terrain: regenerate at 60 Hz with time-shifted noise // Fused: regenerate + pack voxel data in the same parallel pass diff --git a/src/voxel/VoxelRenderer.h b/src/voxel/VoxelRenderer.h index 8bee61a..3b93daa 100644 --- a/src/voxel/VoxelRenderer.h +++ b/src/voxel/VoxelRenderer.h @@ -60,6 +60,7 @@ public: bool debugFaceColors_ = false; bool debugBlend_ = false; + float windTime_ = 0.0f; // set by VoxelRenderPath::Update each frame private: void createPipeline(); @@ -137,7 +138,7 @@ private: uint32_t chunkCount; uint32_t bleedMask; // bit N set = material N can bleed onto neighbors uint32_t resistBleedMask; // bit N set = material N resists bleed from neighbors - uint32_t _cullPad2; + float windTime; }; wi::graphics::GPUBuffer constantBuffer_; @@ -236,6 +237,9 @@ private: mutable float lastDt_ = 0.016f; mutable float smoothFps_ = 60.0f; + // Wind animation (continuous, always running) + float windTime_ = 0.0f; + // Animated terrain (wave effect at 60 Hz, toggled with F3) bool animatedTerrain_ = false; float animTime_ = 0.0f;