OverviewFilesCommitsIssuesDocsReleasesPeers

hyper-tps / shaders / terrain_material.gdshaderinc

80 lines · gdshaderinc ref:
// Terrain surface materials, shared by the map's colour shader and the density
// preview probe.
//
// MOVED HERE, NOT COPIED. The probe exists to judge how the terrain will look
// before the shading is wired into a map; a probe that colours with its own
// private copy of the ramp is judging something the game does not render. One
// definition, two consumers.

float sstep2(float a, float b, float x) {
	float t = clamp((x - a) / (b - a), 0.0, 1.0);
	return t * t * (3.0 - 2.0 * t);
}

// terrain-lookdev/index.html computeAlbedo(), transcribed. THREE attributes:
// altitude t, slope, and curvature k (0 crease .. 1 ridge). Concave ground
// collects water and grows things; convex ground sheds both and shows rock.
vec3 lookdev_material(float t, float slope, float k) {
	const vec3 GRASS  = vec3(0.20, 0.30, 0.13);
	const vec3 MEADOW = vec3(0.33, 0.40, 0.17);
	const vec3 DRY    = vec3(0.47, 0.43, 0.26);
	const vec3 SCREE  = vec3(0.44, 0.40, 0.36);
	const vec3 ROCK   = vec3(0.34, 0.31, 0.30);
	const vec3 ROCK_L = vec3(0.52, 0.49, 0.46);
	const vec3 SNOW   = vec3(0.95, 0.96, 0.98);
	const vec3 WET    = vec3(0.16, 0.19, 0.15);

	float rock = sstep2(0.30, 0.85, slope);
	// snow lies later on steep ground and later in creases where it is shaded
	float snowline = 0.58 + 0.22 * rock;
	float snow = sstep2(snowline, snowline + 0.16, t) * (1.0 - 0.7 * rock);
	// creases are wet: darker, greener, and they hold vegetation higher
	float wet = sstep2(0.55, 0.10, k);

	vec3 veg = t < 0.5 ? mix(GRASS, MEADOW, sstep2(0.0, 0.5, t))
	                   : mix(MEADOW, DRY,   sstep2(0.5, 0.85, t));
	veg = mix(veg, WET, 0.55 * wet);
	vec3 rk = mix(ROCK, ROCK_L, sstep2(0.45, 1.0, k));
	rk = mix(rk, SCREE, sstep2(0.75, 0.35, k) * 0.5);

	vec3 a = mix(veg, rk, rock);
	vec3 b = mix(a, SNOW, snow);
	float ao = 0.72 + 0.28 * sstep2(0.15, 0.85, k);   // creases in their own shadow
	return b * ao;
}

const int LAND_N = 7;
const int SEA_N = 6;

vec3 hypso_ramp(float y) {
	// Land, above sea level.
	float le[7] = float[](0.0, 300.0, 800.0, 1600.0, 2600.0, 3600.0, 6500.0);
	vec3  lc[7] = vec3[](vec3(0.29, 0.48, 0.25), vec3(0.49, 0.60, 0.29),
	                     vec3(0.72, 0.63, 0.35), vec3(0.66, 0.46, 0.25),
	                     vec3(0.55, 0.44, 0.38), vec3(0.91, 0.91, 0.94),
	                     vec3(1.00, 1.00, 1.00));
	// Sea, below it, on its OWN scale so it gets the full range.
	float se[6] = float[](0.0, -200.0, -1000.0, -2500.0, -4500.0, -9000.0);
	vec3  sc[6] = vec3[](vec3(0.47, 0.68, 0.74), vec3(0.31, 0.53, 0.63),
	                     vec3(0.19, 0.37, 0.52), vec3(0.11, 0.24, 0.38),
	                     vec3(0.05, 0.13, 0.24), vec3(0.02, 0.06, 0.14));
	if (y > 0.0) {
		if (y >= le[LAND_N - 1]) { return lc[LAND_N - 1]; }
		for (int i = 0; i < LAND_N - 1; i++) {
			if (y < le[i + 1]) {
				float t = (y - le[i]) / max(le[i + 1] - le[i], 0.001);
				return mix(lc[i], lc[i + 1], t);
			}
		}
		return lc[0];
	}
	if (y <= se[SEA_N - 1]) { return sc[SEA_N - 1]; }
	for (int i = 0; i < SEA_N - 1; i++) {
		if (y > se[i + 1]) {
			float t = (y - se[i]) / min(se[i + 1] - se[i], -0.001);
			return mix(sc[i], sc[i + 1], t);
		}
	}
	return sc[0];
}