struct ShadowUniforms {
light_view_projection: mat4x4<f32>,
cascade_index: u32,
time: f32,
wind_strength: f32,
wind_frequency: f32,
wind_direction: vec2<f32>,
_padding: vec2<f32>,
}
struct GrassInstance {
position: vec3<f32>,
rotation: f32,
height: f32,
width: f32,
species_index: u32,
lod: u32,
base_color: vec4<f32>,
tip_color: vec4<f32>,
bend: vec2<f32>,
}
struct VertexInput {
@builtin(vertex_index) vertex_index: u32,
@builtin(instance_index) instance_index: u32,
}
struct VertexOutput {
@builtin(position) position: vec4<f32>,
}
@group(0) @binding(0) var<uniform> shadow_uniforms: ShadowUniforms;
@group(0) @binding(1) var<storage, read> instances: array<GrassInstance>;
@group(0) @binding(2) var<storage, read> visible_indices: array<u32>;
fn blade_vertex_position(vertex_index: u32, height: f32, width: f32) -> vec3<f32> {
let segment = vertex_index / 2u;
let side = f32(vertex_index % 2u) * 2.0 - 1.0;
let t = f32(segment) / 3.0;
let curvature = 0.3;
let curve_offset = curvature * t * t;
let segment_width = width * (1.0 - t * 0.8);
var position: vec3<f32>;
position.x = side * segment_width * 0.5;
position.y = t * height;
position.z = curve_offset;
if vertex_index == 6u {
position.x = 0.0;
position.y = height;
position.z = curvature;
}
return position;
}
fn rotation_matrix_y(angle: f32) -> mat3x3<f32> {
let c = cos(angle);
let s = sin(angle);
return mat3x3<f32>(
vec3<f32>(c, 0.0, s),
vec3<f32>(0.0, 1.0, 0.0),
vec3<f32>(-s, 0.0, c)
);
}
fn wind_displacement(world_pos: vec3<f32>, height_factor: f32) -> vec3<f32> {
let base_freq = shadow_uniforms.wind_frequency * 0.5;
let gust_freq = shadow_uniforms.wind_frequency * 2.0;
let time = shadow_uniforms.time;
let strength = shadow_uniforms.wind_strength;
let direction = shadow_uniforms.wind_direction;
let wave1 = sin(world_pos.x * base_freq + time * 1.5) * 0.5 + 0.5;
let wave2 = sin(world_pos.z * base_freq * 0.7 + time * 1.2) * 0.5 + 0.5;
let wave3 = sin((world_pos.x + world_pos.z) * gust_freq + time * 3.0) * 0.3;
let combined_wave = (wave1 * wave2 + wave3) * strength * height_factor * height_factor;
var displacement: vec3<f32>;
displacement.x = direction.x * combined_wave;
displacement.y = -combined_wave * 0.1;
displacement.z = direction.y * combined_wave;
return displacement;
}
@vertex
fn vs_main(input: VertexInput) -> VertexOutput {
var output: VertexOutput;
let visible_index = visible_indices[input.instance_index];
let instance = instances[visible_index];
var local_pos = blade_vertex_position(input.vertex_index, instance.height, instance.width);
let height_factor = local_pos.y / instance.height;
let rot = rotation_matrix_y(instance.rotation);
local_pos = rot * local_pos;
let wind_disp = wind_displacement(instance.position, height_factor);
let world_pos = instance.position + local_pos + wind_disp;
output.position = shadow_uniforms.light_view_projection * vec4<f32>(world_pos, 1.0);
return output;
}
@fragment
fn fs_main() {
}