feat(art): add storybook meadow and woodland villagers
This commit is contained in:
@@ -1,70 +1,66 @@
|
||||
// Adapted for The Steward from the bundled Terrain3D particle-grass example.
|
||||
// Original Blender tuft. Opaque blades avoid alpha overdraw and sorting.
|
||||
shader_type spatial;
|
||||
|
||||
render_mode skip_vertex_transform, cull_disabled, blend_mix;
|
||||
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.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 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.75;
|
||||
|
||||
varying vec4 grass_data;
|
||||
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() {
|
||||
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;
|
||||
|
||||
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 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;
|
||||
|
||||
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 = world_vertex.xz - interactor_positions[index].xz;
|
||||
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 * grass_data[2];
|
||||
world_vertex.y -= influence * 0.28 * grass_data[2];
|
||||
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 = MODELVIEW_NORMAL_MATRIX * NORMAL;
|
||||
BINORMAL = MODELVIEW_NORMAL_MATRIX * BINORMAL;
|
||||
TANGENT = MODELVIEW_NORMAL_MATRIX * TANGENT;
|
||||
NORMAL = normalize((VIEW_MATRIX * vec4(0.0, 1.0, 0.0, 0.0)).xyz);
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user