// BVLE Voxels - Toping Vertex Shader (Phase 4.2) // Instanced vertex pulling: reads mesh vertices from t4, instance positions from t5. // Push constants carry per-draw-group offsets. #include "voxelCommon.hlsli" // Toping mesh vertex (must match C++ TopingVertex, 24 bytes) struct TopingVtx { float3 position; // local to voxel [0,1]^3 float3 normal; }; // Toping instance (just the world position, 12 bytes) struct TopingInst { float3 worldPos; }; StructuredBuffer topingVertices : register(t4); StructuredBuffer topingInstances : register(t5); // Push constants — repurposed fields for toping draws: // chunkIndex → vertexOffset (into t4) // quadOffset → instanceOffset (into t5) // flags → materialID struct TopingPush { uint vertexOffset; uint instanceOffset; uint materialID; uint pad0, pad1, pad2, pad3, pad4, pad5, pad6, pad7, pad8; }; [[vk::push_constant]] ConstantBuffer push : register(b999); struct VSOutput { float4 position : SV_POSITION; float3 worldPos : WORLDPOS; float3 normal : NORMAL; float localHeight : LOCALHEIGHT; // height above voxel face (0=base, 1=tip) nointerpolation uint materialID : MATERIALID; }; [RootSignature(VOXEL_ROOTSIG)] VSOutput main(uint vertexID : SV_VertexID, uint instanceID : SV_InstanceID) { TopingVtx vtx = topingVertices[push.vertexOffset + vertexID]; TopingInst inst = topingInstances[push.instanceOffset + 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; float amplitude = 2.0; float frequency = 1.4; if (localHeight > 0.0) { float heightFactor = localHeight * localHeight; // quadratic float phase = worldPos.x * 1.8 + worldPos.z * 1.3 + windTime * 3.5 * frequency; float phase2 = worldPos.x * 0.7 - worldPos.z * 2.1 + windTime * 2.7 * frequency; float swayX = sin(phase) * 0.11 * heightFactor * amplitude; float swayZ = cos(phase2) * 0.08 * heightFactor * amplitude; float swayY = -abs(sin(phase * 0.7)) * 0.02 * heightFactor * amplitude; // slight droop worldPos.x += swayX; worldPos.y += swayY; worldPos.z += swayZ; } } VSOutput output; output.position = mul(viewProjection, float4(worldPos, 1.0)); output.worldPos = worldPos; output.normal = vtx.normal; output.localHeight = saturate((vtx.position.y - 1.0) * 5.0); // normalized: 0=base, 1=tip (blades ~0.06-0.24 tall) output.materialID = push.materialID; return output; }