Hi Hzzzln, thanks for giving it a try. I also wish there was more but a lot of my ideas came far too late and I just needed to close the game loop as short as it was.
Someone else asked in the comments so I'm going to copy/paste my response from that:
Since my game mostly takes place on the X axis I have a global shader value for that position and another global shader for an edge thickness. I check the world position of the current pixel and if within the edge value I blend between grass and snow while applying a noise texture and TIME for some randomness
I'll throw the fragment part of the shader in since that's the only part doing anything.
vec3 p = (INV_VIEW_MATRIX * vec4(VERTEX, 1.0)).rgb; bool in_danger = thaw_position >= p.x; float noise = mod(texture(noise_texture, UV * (uv_scale / 2.0)).r + (TIME / 2.0), 1.0); float dist = (p.x - thaw_position) + noise; if (dist >= 0.0 && dist <= edge_thickness) { vec3 ground = texture(ground_texture, UV * uv_scale).rgb; vec3 snow = texture(snow_texture, UV * uv_scale).rgb; float blend = mod((dist / edge_thickness), 1.0); ALBEDO = mix(ground, snow, dist); NORMAL_MAP = texture(snow_normal, UV * uv_scale).rgb; } else { // Danger if (in_danger) { ALBEDO = texture(ground_texture, UV * uv_scale).rgb; NORMAL_MAP = texture(ground_normal, UV * uv_scale).rgb; } // Snow else { ALBEDO = texture(snow_texture, UV * uv_scale).rgb; NORMAL_MAP = texture(snow_normal, UV * uv_scale).rgb; } }
As I try to point out in the post this is a very slapped together shader so none of the code is well thought out it simply looked "good enough" haha.