Files

78 lines
3.3 KiB
Plaintext

// Original Blender tuft. Opaque blades avoid alpha overdraw and sorting.
shader_type spatial;
render_mode skip_vertex_transform, cull_disabled, specular_disabled;
#include "foliage_trail.gdshaderinc"
const int MAX_INTERACTORS = 8;
uniform vec2 wind_direction = vec2(1.0, 0.7);
uniform vec3 base_color : source_color = vec3(0.23, 0.40, 0.22);
uniform vec3 tip_color : source_color = vec3(0.53, 0.67, 0.35);
uniform float wind_amount : hint_range(0.0, 1.0) = 0.24;
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.1;
uniform float interaction_strength : hint_range(0.0, 2.0) = 0.55;
uniform int clearing_count = 0;
uniform vec4 clearing_segments[4];
uniform vec4 clearing_half_widths = vec4(0.0);
varying float blade_height;
varying float shade_variation;
varying float pressed_weight;
void vertex() {
blade_height = UV.y;
float tip_weight = blade_height * blade_height;
vec3 anchor = MODEL_MATRIX[3].xyz;
float clearing_scale = 1.0;
for (int index = 0; index < 4; index++) {
if (index >= clearing_count) { break; }
vec2 start = clearing_segments[index].xy;
vec2 line = clearing_segments[index].zw - start;
float along = clamp(dot(anchor.xz - start, line) / max(dot(line, line), 0.001), 0.0, 1.0);
float distance_to_path = length(anchor.xz - start - line * along);
clearing_scale *= smoothstep(clearing_half_widths[index], clearing_half_widths[index] + 0.20, distance_to_path);
}
VERTEX *= clearing_scale;
tip_weight *= clearing_scale;
vec3 world_vertex = (MODEL_MATRIX * vec4(VERTEX, 1.0)).xyz;
float phase = dot(anchor.xz, vec2(0.38, 0.29));
float gust = sin(TIME * 1.15 + phase) * 0.65 + sin(TIME * 0.58 + phase * 0.42) * 0.35;
vec3 trail = sample_foliage_trail(anchor);
world_vertex.xz += normalize(wind_direction) * gust * wind_amount * tip_weight * (1.0 - trail.z * 0.75);
vec2 contact_bend = trail.xy * 0.72;
float pressure = trail.z;
shade_variation = sin(anchor.x * 0.30 + anchor.z * 0.21) * 0.5 + 0.5;
pressed_weight = 0.0;
for (int index = 0; index < MAX_INTERACTORS; index++) {
if (index >= interactor_count) { break; }
vec2 offset = anchor.xz - interactor_positions[index].xz;
float distance_to_actor = length(offset);
float influence = 1.0 - smoothstep(0.25, interaction_radius, distance_to_actor);
influence *= 1.0 - smoothstep(0.55, 1.35, abs(anchor.y - interactor_positions[index].y));
vec2 away = offset / max(distance_to_actor, 0.08);
if (influence > pressure) {
contact_bend = away * influence * interaction_strength;
pressure = influence;
}
}
world_vertex.xz += contact_bend * tip_weight;
// Lower relative to the blade's own root so short tufts stay above the ground.
world_vertex.y -= max(world_vertex.y - anchor.y, 0.0) * pressure * 0.78 * blade_height;
pressed_weight = pressure;
VERTEX = (VIEW_MATRIX * vec4(world_vertex, 1.0)).xyz;
NORMAL = normalize((VIEW_MATRIX * vec4(0.0, 1.0, 0.0, 0.0)).xyz);
}
void fragment() {
vec3 color = mix(base_color, tip_color, smoothstep(0.05, 1.0, blade_height) * 0.78);
color *= mix(0.90, 1.09, shade_variation);
ALBEDO = mix(color, base_color, pressed_weight * 0.15);
ROUGHNESS = 1.0;
}
void light() {
float band = smoothstep(0.05, 0.16, dot(NORMAL, LIGHT));
DIFFUSE_LIGHT += mix(vec3(0.46, 0.60, 0.52), vec3(1.0, 0.98, 0.85), band) * LIGHT_COLOR * ATTENUATION / PI;
}