Files
gamedev-the-steward/world/jajce/materials/cozy_grass.gdshader
T
2026-07-16 23:51:08 +02:00

71 lines
2.8 KiB
Plaintext

// Adapted for The Steward from the bundled Terrain3D particle-grass example.
shader_type spatial;
render_mode skip_vertex_transform, cull_disabled, blend_mix;
const int MAX_INTERACTORS = 8;
uniform vec2 wind_direction = vec2(1.0, 0.7);
uniform vec3 base_color : source_color = vec3(0.16, 0.31, 0.08);
uniform vec3 tip_color : source_color = vec3(0.54, 0.68, 0.24);
uniform float wind_amount : hint_range(0.0, 1.0) = 0.34;
uniform int interactor_count : hint_range(0, 8) = 0;
uniform vec3 interactor_positions[MAX_INTERACTORS];
uniform float interaction_radius : hint_range(0.25, 4.0) = 1.8;
uniform float interaction_strength : hint_range(0.0, 2.0) = 0.75;
varying vec4 grass_data;
varying float pressed_weight;
void vertex() {
grass_data[2] = VERTEX.y + 0.55;
grass_data[2] *= grass_data[2];
VERTEX.xz *= 1.0 - grass_data[2];
COLOR = mix(COLOR, vec4(1.0), smoothstep(0.9, 1.0, grass_data[2]));
COLOR *= INSTANCE_CUSTOM[3] < 0.35 ? 1.0 : mix(1.0, 0.75, smoothstep(0.35, 0.0, grass_data[2]));
grass_data.rg = INSTANCE_CUSTOM.rg;
vec3 world_vertex = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz;
float scale = pow(INSTANCE_CUSTOM[3] * INSTANCE_CUSTOM[3], 0.707);
float force = INSTANCE_CUSTOM[2] * grass_data[2] * scale * wind_amount;
force -= fract(force * 256.0) * force * 0.05;
force = pow(max(force, 0.0), 0.707);
float lateral_wobble = sin(TIME * 2.0 * (1.0 + grass_data.r + grass_data.g)) * 0.2 * (1.0 - INSTANCE_CUSTOM[2]);
vec2 direction = normalize(wind_direction);
world_vertex.xz -= (vec2(-direction.y, direction.x) * lateral_wobble + direction) * force;
world_vertex.y -= INSTANCE_CUSTOM[2] * force * grass_data[2];
grass_data[3] = force;
pressed_weight = 0.0;
for (int index = 0; index < MAX_INTERACTORS; index++) {
if (index >= interactor_count) {
break;
}
vec2 offset = world_vertex.xz - interactor_positions[index].xz;
float distance_to_actor = length(offset);
float influence = 1.0 - smoothstep(0.25, interaction_radius, distance_to_actor);
vec2 away = offset / max(distance_to_actor, 0.08);
world_vertex.xz += away * influence * interaction_strength * grass_data[2];
world_vertex.y -= influence * 0.28 * grass_data[2];
pressed_weight = max(pressed_weight, influence);
}
VERTEX = (VIEW_MATRIX * vec4(world_vertex, 1.0)).xyz;
NORMAL = MODELVIEW_NORMAL_MATRIX * NORMAL;
BINORMAL = MODELVIEW_NORMAL_MATRIX * BINORMAL;
TANGENT = MODELVIEW_NORMAL_MATRIX * TANGENT;
}
void fragment() {
vec3 color = mix(base_color, tip_color, grass_data[2] * 0.62);
color.rg *= grass_data.rg * 0.18 + 0.91;
color *= pow(COLOR.rgb, vec3(2.2));
ALBEDO = mix(color, base_color * 0.72, pressed_weight * 0.42);
float specular_roughness = clamp(max(grass_data[2], grass_data[3]), 0.0, 1.0);
ROUGHNESS = 1.0 - specular_roughness * 0.22;
SPECULAR = clamp(specular_roughness * 0.2, 0.0, 0.12);
BACKLIGHT = tip_color * 0.24;
}