Solara-Shaders/shaders/lib/surface/materialHandling/material.glsl

698 lines
21 KiB
GLSL

#if !defined INCLUDE_MISC_MATERIAL
#define INCLUDE_MISC_MATERIAL
const float air_n = 1.000293; // for 0°C and 1 atm
const float water_n = 1.333; // for 20°C
struct Material {
vec3 albedo;
vec3 emission;
vec3 f0;
vec3 f82; // hardcoded metals only
float roughness;
float sss_amount;
float sheen_amount; // SSS "sheen" for tall grass
float porosity;
float ssr_multiplier;
float normal_multiplier; // normal map multiplier for generated normals
bool is_metal;
bool is_hardcoded_metal;
};
const Material water_material = Material(vec3(0.0), vec3(0.0), vec3(0.02), vec3(0.0), 0.002, 1.0, 0.0, 0.0, 1.0, 1.0, false, false);
#if TEXTURE_FORMAT == TEXTURE_FORMAT_LAB
void decode_specular_map(vec4 specular_map, inout Material material) {
// f0 and f82 values for hardcoded metals from Jessie LC (https://github.com/Jessie-LC)
const vec3[] metal_f0 = vec3[](
vec3(0.78, 0.77, 0.74), // Iron
vec3(1.00, 0.90, 0.61), // Gold
vec3(1.00, 0.98, 1.00), // Aluminum
vec3(0.77, 0.80, 0.79), // Chrome
vec3(1.00, 0.89, 0.73), // Copper
vec3(0.79, 0.87, 0.85), // Lead
vec3(0.92, 0.90, 0.83), // Platinum
vec3(1.00, 1.00, 0.91) // Silver
);
const vec3[] metal_f82 = vec3[](
vec3(0.74, 0.76, 0.76),
vec3(1.00, 0.93, 0.73),
vec3(0.96, 0.97, 0.98),
vec3(0.74, 0.79, 0.78),
vec3(1.00, 0.90, 0.80),
vec3(0.83, 0.80, 0.83),
vec3(0.89, 0.87, 0.81),
vec3(1.00, 1.00, 0.95)
);
material.roughness = sqr(1.0 - specular_map.r);
material.emission = max(material.emission, material.albedo * specular_map.a * float(specular_map.a != 1.0));
if (specular_map.g < 229.5 / 255.0) {
#ifdef F0_FALLBACK
if (specular_map.g < 0.5 / 255.0) specular_map.g = 0.04;
#endif
// Dielectrics
material.f0 = max(material.f0, specular_map.g);
float has_sss = step(64.5 / 255.0, specular_map.b);
material.sss_amount = max(material.sss_amount, linear_step(64.0 / 255.0, 1.0, specular_map.b * has_sss));
material.porosity = linear_step(0.0, 64.0 / 255.0, max0(specular_map.b - specular_map.b * has_sss));
} else if (specular_map.g < 237.5 / 255.0) {
// Hardcoded metals
uint metal_id = clamp(uint(255.0 * specular_map.g) - 230u, 0u, 7u);
material.f0 = metal_f0[metal_id];
material.f82 = metal_f82[metal_id];
material.is_metal = true;
material.is_hardcoded_metal = true;
} else {
// Albedo metal
material.f0 = material.albedo;
material.is_metal = true;
}
material.ssr_multiplier = step(0.01, (material.f0.x - material.f0.x * material.roughness * SSR_ROUGHNESS_THRESHOLD)); // based on Kneemund's method
}
#elif TEXTURE_FORMAT == TEXTURE_FORMAT_OLD
void decode_specular_map(vec4 specular_map, inout Material material) {
material.roughness = sqr(1.0 - specular_map.r);
material.is_metal = specular_map.g > 0.5;
material.f0 = material.is_metal ? material.albedo : material.f0;
material.emission = max(material.emission, material.albedo * specular_map.b);
material.ssr_multiplier = step(0.01, (material.f0.x - material.f0.x * material.roughness * SSR_ROUGHNESS_THRESHOLD)); // based on Kneemund's method
}
#endif
void decode_specular_map(vec4 specular_map, inout Material material, out bool parallax_shadow) {
#if defined POM && defined POM_SHADOW
// Specular map alpha >= 0.5 => parallax shadow
parallax_shadow = specular_map.a >= 0.5;
specular_map.a = fract(specular_map.a * 2.0);
#endif
decode_specular_map(specular_map, material);
}
Material material_from(vec3 albedo_srgb, uint material_mask, vec3 world_pos, vec3 normal, inout vec2 light_levels) {
vec3 block_pos = fract(world_pos);
// Create material with default values
Material material;
material.albedo = srgb_eotf_inv(albedo_srgb) * rec709_to_rec2020;
material.emission = vec3(0.0);
material.f0 = vec3(0.0);
material.f82 = vec3(0.0);
material.roughness = 1.0;
material.sss_amount = 0.0;
material.sheen_amount = 0.0;
material.porosity = 0.0;
material.ssr_multiplier = 0.0;
material.normal_multiplier = 1.0;
material.is_metal = false;
material.is_hardcoded_metal = false;
// Hardcoded materials for specific blocks
// Using binary split search to minimise branches per fragment (TODO: measure impact)
vec3 hsl = rgb_to_hsl(albedo_srgb);
vec3 albedo_sqrt = sqrt(material.albedo);
if (material_mask < 32u) { // 0-32
if (material_mask < 16u) { // 0-16
if (material_mask < 8u) { // 0-8
if (material_mask < 4u) { // 0-4
if (material_mask >= 2u) { // 2-4
if (material_mask == 2u) { // 2
#ifdef HARDCODED_SSS
// Small plants
material.sss_amount = 0.5;
material.sheen_amount = 0.5;
#endif
} else { // 3
#ifdef HARDCODED_SSS
// Tall plants (lower half)
material.sss_amount = 0.5;
material.sheen_amount = 0.5;
#endif
}
}
} else { // 4-8
if (material_mask < 6u) { // 4-6
if (material_mask == 4u) { // 4
#ifdef HARDCODED_SSS
// Tall plants (upper half)
material.sss_amount = 0.5;
material.sheen_amount = 0.5;
#endif
} else { // 5
// Leaves
#ifdef HARDCODED_SPECULAR
float smoothness = 0.5 * smoothstep(0.16, 0.5, hsl.z);
material.roughness = sqr(1.0 - smoothness);
material.f0 = vec3(0.02);
material.sheen_amount = 0.5;
#endif
#ifdef HARDCODED_SSS
material.sss_amount = 1.0;
#endif
}
} else { // 6-8
if (material_mask == 6u) { // 6
#ifdef HARDCODED_SPECULAR
// Grass, stone, spruce and dark oak planks
float smoothness = 0.33 * smoothstep(0.2, 0.6, hsl.z);
material.roughness = sqr(1.0 - smoothness);
material.f0 = vec3(0.02);
#endif
#ifdef HARDCODED_POROSITY
material.porosity = 0.2;
#endif
} else { // 7
// Sand
#ifdef HARDCODED_SPECULAR
float smoothness = 0.8 * linear_step(0.81, 0.96, hsl.z);
material.roughness = sqr(1.0 - smoothness);
material.f0 = vec3(0.02);
#endif
#ifdef HARDCODED_POROSITY
material.porosity = 1.35;
#endif
}
}
}
} else { // 8-16
if (material_mask < 12u) { // 8-12
if (material_mask < 10u) { // 8-10
if (material_mask == 8u) { // 8
// Ice
#ifdef HARDCODED_SPECULAR
float smoothness = pow4(linear_step(0.4, 0.8, hsl.z)) * 0.6;
material.roughness = sqr(1.0 - smoothness);
material.f0 = vec3(0.02);
material.ssr_multiplier = 1.0;
#endif
#ifdef HARDCODED_SSS
// Strong SSS
material.sss_amount = 0.75;
#endif
#ifdef HARDCODED_POROSITY
material.porosity = 0.2;
#endif
} else { // 9
// Red sand, birch planks
#ifdef HARDCODED_SPECULAR
float smoothness = 0.4 * linear_step(0.61, 0.85, hsl.z);
material.roughness = sqr(1.0 - smoothness);
material.f0 = vec3(0.02);
#endif
#ifdef HARDCODED_POROSITY
material.porosity = 0.5;
#endif
}
} else { // 10-12
if (material_mask == 10u) { // 10
// Oak, jungle and acacia planks, granite and diorite
#ifdef HARDCODED_SPECULAR
float smoothness = 0.5 * linear_step(0.4, 0.8, hsl.z);
material.roughness = sqr(1.0 - smoothness);
material.f0 = vec3(0.02);
#endif
#ifdef HARDCODED_POROSITY
material.porosity = 0.2;
#endif
} else { // 11
// Obsidian, nether bricks
#ifdef HARDCODED_SPECULAR
float smoothness = linear_step(0.02, 0.4, hsl.z);
material.roughness = sqr(1.0 - smoothness);
material.f0 = vec3(0.02);
material.ssr_multiplier = 1.0;
#endif
}
}
} else { // 12-16
if (material_mask < 14u) { // 12-14
if (material_mask == 12u) { // 12
// Metals
#ifdef HARDCODED_SPECULAR
float smoothness = sqrt(linear_step(0.1, 0.9, hsl.z));
material.roughness = max(sqr(1.0 - smoothness), 0.04);
material.f0 = material.albedo;
material.is_metal = true;
material.ssr_multiplier = 1.0;
#endif
} else { // 13
// Gems
#ifdef HARDCODED_SPECULAR
float smoothness = sqrt(linear_step(0.1, 0.9, hsl.z));
material.roughness = max(sqr(1.0 - smoothness), 0.04);
material.f0 = vec3(0.25);
material.ssr_multiplier = 1.0;
#endif
}
} else { // 14-16
if (material_mask == 14u) { // 14
#ifdef HARDCODED_SSS
// Strong SSS
material.sss_amount = 0.6;
#endif
#ifdef HARDCODED_POROSITY
material.porosity = 0.5;
#endif
} else { // 15
#ifdef HARDCODED_SSS
// Weak SSS
material.sss_amount = 0.1;
#endif
#ifdef HARDCODED_POROSITY
material.porosity = 0.25;
#endif
}
}
}
}
} else { // 16-32
if (material_mask < 24u) { // 16-24
if (material_mask < 20u) { // 16-20
if (material_mask < 18u) { // 16-18
if (material_mask == 16u) { // 16
#ifdef HARDCODED_EMISSION
// Chorus plant
material.emission = 0.25 * albedo_sqrt * pow4(hsl.z);
#endif
} else { // 17
#ifdef HARDCODED_SPECULAR
// End stone
float smoothness = 0.4 * linear_step(0.61, 0.85, hsl.z);
material.roughness = sqr(1.0 - smoothness);
material.f0 = vec3(0.02);
material.ssr_multiplier = 1.0;
#endif
}
} else { // 18-20
if (material_mask == 18u) { // 18
// Metals
#ifdef HARDCODED_SPECULAR
float smoothness = sqrt(linear_step(0.1, 0.9, hsl.z));
material.roughness = max(sqr(1.0 - smoothness), 0.04);
material.f0 = material.albedo;
material.is_metal = true;
material.ssr_multiplier = 1.0;
#endif
} else { // 19
// Warped stem
#ifdef HARDCODED_EMISSION
float emission_amount = mix(
1.0,
float(any(lessThan(
vec4(block_pos.yz, 1.0 - block_pos.yz),
vec4(rcp(16.0) - 1e-3)
))),
step(0.5, abs(normal.x))
);
float blue = isolate_hue(hsl, 200.0, 60.0);
material.emission = albedo_sqrt * hsl.y * blue * emission_amount;
#endif
}
}
} else { // 20-24
if (material_mask < 22u) { // 20-22
if (material_mask == 20u) { // 20
// Warped stem
#ifdef HARDCODED_EMISSION
float emission_amount = mix(
1.0,
float(any(lessThan(
vec4(block_pos.xz, 1.0 - block_pos.xz),
vec4(rcp(16.0) - 1e-3)
))),
step(0.5, abs(normal.y))
);
float blue = isolate_hue(hsl, 200.0, 60.0);
material.emission = albedo_sqrt * hsl.y * blue * emission_amount;
#endif
} else { // 21
// Warped stem
#ifdef HARDCODED_EMISSION
float emission_amount = mix(
1.0,
float(any(lessThan(
vec4(block_pos.xy, 1.0 - block_pos.xy),
vec4(rcp(16.0) - 1e-3)
))),
step(0.5, abs(normal.z))
);
float blue = isolate_hue(hsl, 200.0, 60.0);
material.emission = albedo_sqrt * hsl.y * blue * emission_amount;
#endif
}
} else { // 22-24
if (material_mask == 22u) { // 22
// Warped hyphae
#ifdef HARDCODED_EMISSION
float blue = isolate_hue(hsl, 200.0, 60.0);
material.emission = albedo_sqrt * hsl.y * blue;
#endif
} else { // 23
// Crimson stem
#ifdef HARDCODED_EMISSION
float emission_amount = mix(
1.0,
float(any(lessThan(
vec4(block_pos.yz, 1.0 - block_pos.yz),
vec4(rcp(16.0) - 1e-3)
))),
step(0.5, abs(normal.x))
);
material.emission = albedo_sqrt * linear_step(0.33, 0.5, hsl.z) * emission_amount;
#endif
}
}
}
} else { // 24-32
if (material_mask < 28u) { // 24-28
if (material_mask < 26u) { // 24-26
if (material_mask == 24u) { // 24
// Crimson stem
#ifdef HARDCODED_EMISSION
float emission_amount = mix(
1.0,
float(any(lessThan(
vec4(block_pos.xz, 1.0 - block_pos.xz),
vec4(rcp(16.0) - 1e-3)
))),
step(0.5, abs(normal.y))
);
material.emission = albedo_sqrt * linear_step(0.33, 0.5, hsl.z) * emission_amount;
#endif
} else { // 25
// Crimson stem
#ifdef HARDCODED_EMISSION
float emission_amount = mix(
1.0,
float(any(lessThan(
vec4(block_pos.xy, 1.0 - block_pos.xy),
vec4(rcp(16.0) - 1e-3)
))),
step(0.5, abs(normal.z))
);
material.emission = albedo_sqrt * linear_step(0.33, 0.5, hsl.z) * emission_amount;
#endif
}
} else { // 26-28
if (material_mask == 26u) { // 26
// Crimson hyphae
#ifdef HARDCODED_EMISSION
material.emission = albedo_sqrt * linear_step(0.33, 0.5, hsl.z);
#endif
} else { // 27
}
}
} else { // 28-32
if (material_mask < 30) { // 28-30
if (material_mask == 28u) { // 28
} else { // 29
}
} else { // 30-32
if (material_mask == 30u) { // 30
} else { // 31
}
}
}
}
}
} else if (material_mask < 64u) { // 32-64
if (material_mask < 48u) { // 32-48
if (material_mask < 40u) { // 32-40
if (material_mask < 36u) { // 32-36
if (material_mask < 34u) { // 32-34
if (material_mask == 32u) { // 32
#ifdef HARDCODED_EMISSION
// Strong white light
material.emission = 1.00 * albedo_sqrt * (0.1 + 0.9 * cube(hsl.z));
#endif
} else { // 33
#ifdef HARDCODED_EMISSION
// Medium white light
material.emission = 0.66 * albedo_sqrt * linear_step(0.75, 0.9, hsl.z);
#endif
}
} else { // 34-36
if (material_mask == 34u) { // 34
#ifdef HARDCODED_EMISSION
// Weak white light
material.emission = 0.2 * albedo_sqrt * (0.1 + 0.9 * pow4(hsl.z));
#endif
} else { // 35
#ifdef HARDCODED_EMISSION
// Strong golden light
material.emission = 0.85 * albedo_sqrt * linear_step(0.4, 0.6, 0.2 * hsl.y + 0.55 * hsl.z);
#endif
}
}
} else { // 36-40
if (material_mask < 38u) { // 36-38
if (material_mask == 36u) { // 36
#ifdef HARDCODED_EMISSION
// Medium golden light
material.emission = 0.85 * albedo_sqrt * linear_step(0.78, 0.85, hsl.z);
#endif
} else { // 37
#ifdef HARDCODED_EMISSION
// Weak golden light
float blue = isolate_hue(hsl, 200.0, 30.0);
material.emission = 0.8 * albedo_sqrt * linear_step(0.47, 0.50, 0.2 * hsl.y + 0.5 * hsl.z + 0.1 * blue);
#endif
}
} else { // 38-40
if (material_mask == 38u) { // 38
#ifdef HARDCODED_EMISSION
// Redstone components
vec3 ap1 = material.albedo * rec2020_to_ap1_unlit;
float l = 0.5 * (min_of(ap1) + max_of(ap1));
float redness = ap1.r * rcp(ap1.g + ap1.b);
material.emission = 0.33 * material.albedo * step(0.45, redness * l);
#endif
} else { // 39
#ifdef HARDCODED_EMISSION
// Lava
material.emission = 4.0 * albedo_sqrt * (0.2 + 0.8 * isolate_hue(hsl, 30.0, 15.0)) * step(0.4, hsl.y);
#endif
}
}
}
} else { // 40-48
if (material_mask < 44u) { // 40-44
if (material_mask < 42u) { // 40-42
if (material_mask == 40u) { // 40
#ifdef HARDCODED_EMISSION
// Medium orange emissives
material.emission = 0.60 * albedo_sqrt * (0.1 + 0.9 * cube(hsl.z));
#endif
} else { // 41
#ifdef HARDCODED_EMISSION
// Brewing stand
material.emission = 0.85 * albedo_sqrt * linear_step(0.77, 0.85, hsl.z);
#endif
}
} else { // 42-44
if (material_mask == 42u) { // 42
#ifdef HARDCODED_EMISSION
// Jack o' Lantern
material.emission = 0.80 * albedo_sqrt * step(0.73, 0.1 * hsl.y + 0.7 * hsl.z);
#endif
} else { // 43
#ifdef HARDCODED_EMISSION
// Soul lights
float blue = isolate_hue(hsl, 200.0, 30.0);
material.emission = 0.66 * albedo_sqrt * linear_step(0.8, 1.0, blue + hsl.z);
#endif
}
}
} else { // 44-48
if (material_mask < 46u) { // 44-46
if (material_mask == 44u) { // 44
#ifdef HARDCODED_EMISSION
// Beacon
material.emission = step(0.2, hsl.z) * albedo_sqrt * step(max_of(abs(block_pos - 0.5)), 0.4);
#endif
} else { // 45
#ifdef HARDCODED_EMISSION
// End portal frame
material.emission = 0.33 * material.albedo * isolate_hue(hsl, 120.0, 50.0);
#endif
}
} else { // 46-48
if (material_mask == 46u) { // 46
#ifdef HARDCODED_EMISSION
// Sculk
material.emission = 0.2 * material.albedo * isolate_hue(hsl, 200.0, 40.0) * smoothstep(0.5, 0.7, hsl.z) * (1.0 - linear_step(0.0, 20.0, distance(world_pos, cameraPosition)));
#endif
} else { // 47
#ifdef HARDCODED_EMISSION
// Pink glow
material.emission = vec3(0.75) * isolate_hue(hsl, 310.0, 50.0);
#endif
}
}
}
}
} else { // 48-64
if (material_mask < 56u) { // 48-56
if (material_mask < 52u) { // 48-52
if (material_mask < 50u) { // 48-50
if (material_mask == 48u) { // 48
material.emission = 0.5 * albedo_sqrt * linear_step(0.5, 0.6, hsl.z);
} else { // 49
#ifdef HARDCODED_EMISSION
// Jack o' Lantern + nether mushrooms
material.emission = 0.80 * albedo_sqrt * step(0.73, 0.1 * hsl.y + 0.7 * hsl.z);
#endif
}
} else { // 50-52
if (material_mask == 50u) { // 50
#ifdef HARDCODED_EMISSION
// Candles
material.emission = vec3(0.2) * pow4(clamp01(block_pos.y * 2.0));
#endif
} else { // 51
#ifdef HARDCODED_EMISSION
// Ochre froglight
material.emission = 0.40 * albedo_sqrt * (0.1 + 0.9 * cube(hsl.z));
#endif
}
}
} else { // 52-56
if (material_mask < 54u) { // 52-54
if (material_mask == 52u) { // 52
#ifdef HARDCODED_EMISSION
// Verdant froglight
material.emission = 0.40 * albedo_sqrt * (0.1 + 0.9 * cube(hsl.z));
#endif
} else { // 53
#ifdef HARDCODED_EMISSION
// Pearlescent froglight
material.emission = 0.40 * albedo_sqrt * (0.1 + 0.9 * cube(hsl.z));
#endif
}
} else { // 54-56
if (material_mask == 54u) { // 54
} else { // 55
#ifdef HARDCODED_EMISSION
// Amethyst cluster
material.emission = vec3(0.20) * (0.1 + 0.9 * hsl.z);
#endif
}
}
}
} else { // 56-64
if (material_mask < 60u) { // 56-60
if (material_mask < 58u) { // 56-58
if (material_mask == 56u) { // 56
#ifdef HARDCODED_EMISSION
// Calibrated sculk sensor
material.emission = 0.2 * material.albedo * isolate_hue(hsl, 200.0, 40.0) * smoothstep(0.5, 0.7, hsl.z) * (1.0 - linear_step(0.0, 20.0, distance(world_pos, cameraPosition)));
material.emission += vec3(0.20) * (0.1 + 0.9 * hsl.z) * step(0.5, isolate_hue(hsl, 270.0, 50.0) + 0.55 * hsl.z);
#endif
} else { // 57
#ifdef HARDCODED_EMISSION
// Active sculk sensor
material.emission = vec3(0.20) * (0.1 + 0.9 * hsl.z);
#endif
}
} else { // 58-60
if (material_mask == 58u) { // 58
#ifdef HARDCODED_EMISSION
// Redstone block
material.emission = 0.33 * albedo_sqrt;
#endif
} else { // 59
#ifdef HARDCODED_EMISSION
// Emerald block
material.emission = 0.1 * albedo_sqrt;
#endif
}
}
} else { // 60-64
if (material_mask < 62u) { // 60-62
if (material_mask == 60u) { // 60
#ifdef HARDCODED_EMISSION
// Lapis block
material.emission = 0.33 * albedo_sqrt;
#endif
} else { // 61
}
} else { // 62-64
if (material_mask == 62u) { // 62
// Nether portal
material.emission = vec3(1.0);
} else { // 63
// End portal
material.emission = vec3(1.0);
}
}
}
}
}
} else if (material_mask < 264u) { // 64 - 264
if(material_mask == 80) { // 80
// Powered lightning rod
material.emission = vec3(1.0);
} /*else {
}*/
} else if (material_mask < 331u) { // 264 - 331
// Colored Candles
material.emission = vec3(0.2) * pow4(clamp01(block_pos.y * 2.0));
} /*else if (material_mask == PHYSICS_MOD_SNOW_ID) {
#ifdef HARDCODED_SPECULAR
material.f0 = vec3(0.02);
material.roughness = 0.5;
#endif
#ifdef HARDCODED_SSS
material.sss_amount = 1.0;
material.sheen_amount = 1.0;
#endif
}*/
if (164u <= material_mask && material_mask < 180u) {
// Stained glass, honey and slime
#ifdef HARDCODED_SPECULAR
material.f0 = vec3(0.04);
material.roughness = 0.1;
material.ssr_multiplier = 1.0;
#endif
#ifdef HARDCODED_SSS
material.sss_amount = 0.5;
#endif
}
return material;
}
#endif // INCLUDE_MISC_MATERIAL