67 lines
2.9 KiB
Plaintext
67 lines
2.9 KiB
Plaintext
// Original Blender tuft. Opaque blades avoid alpha overdraw and sorting.
|
|
shader_type spatial;
|
|
render_mode skip_vertex_transform, cull_disabled, specular_disabled;
|
|
|
|
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.8;
|
|
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;
|
|
world_vertex.xz += normalize(wind_direction) * gust * wind_amount * tip_weight;
|
|
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);
|
|
vec2 away = offset / max(distance_to_actor, 0.08);
|
|
world_vertex.xz += away * influence * interaction_strength * tip_weight;
|
|
world_vertex.y -= influence * 0.18 * tip_weight;
|
|
pressed_weight = max(pressed_weight, influence);
|
|
}
|
|
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;
|
|
}
|