mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-10-22 12:03:20 +02:00
Make the material shaders physically based
This commit is contained in:
@@ -20,7 +20,7 @@ layout(location = 1) out vec4 out_motion;
|
||||
void main()
|
||||
{
|
||||
vec3 fragnormal = normalize(f_normal);
|
||||
glossiness = 6.0;
|
||||
glossiness = phong_glossiness(6.0);
|
||||
metalic = 0.0;
|
||||
vec3 fragcolor = apply_lights(ambient, fragnormal, f_albedo, 0.0, 0.2, shadow_tone);
|
||||
|
||||
|
||||
@@ -216,13 +216,81 @@ float G_SchlickGGX(float NdotX, float roughness)
|
||||
return NdotX / (NdotX * (1.0 - k) + k);
|
||||
}
|
||||
|
||||
// Height-correlated Smith geometry term
|
||||
// Separable Smith geometry term (not height-correlated)
|
||||
// G(N,V,L) = G_SchlickGGX(NdotV) · G_SchlickGGX(NdotL)
|
||||
float G_Smith(float NdotV, float NdotL, float roughness)
|
||||
{
|
||||
return G_SchlickGGX(NdotV, roughness) * G_SchlickGGX(NdotL, roughness);
|
||||
}
|
||||
|
||||
const float BRDF_PI = 3.14159265359;
|
||||
// the smoothest surface the lights are reflected by: a mirror would make a highlight smaller than a pixel
|
||||
const float MIN_ROUGHNESS = 0.045;
|
||||
// cap of the brdf for the lamps and headlights (see specular_light()): a tiny light next to a polished surface
|
||||
const float LOCAL_LIGHT_BRDF_LIMIT = 16.0;
|
||||
// no cap for the sun
|
||||
const float SUN_BRDF_LIMIT = 1.0e6;
|
||||
|
||||
// the specular reflectance at normal incidence and the perceptual roughness the lights are reflected with, worked out by
|
||||
// apply_lights() for the fragment before it adds the lamps (add_local_lights())
|
||||
vec3 spec_f0 = vec3(0.04);
|
||||
float spec_roughness = 0.5;
|
||||
|
||||
// light of a light from Light_dir reflected by the surface, in the units of the diffuse shading (a white lambertian surface
|
||||
// facing the light reflects 1 of it): pi times the cook-torrance brdf with schlick's fresnel of F0, times n.l. Limit caps the
|
||||
// brdf without the n.l
|
||||
vec3 specular_light(vec3 light_dir, vec3 fragnormal, vec3 f0, float roughness, float limit)
|
||||
{
|
||||
float NdotL = dot(fragnormal, light_dir);
|
||||
if (NdotL <= 0.0)
|
||||
return vec3(0.0);
|
||||
vec3 V = normalize(-f_pos.xyz);
|
||||
vec3 H = normalize(light_dir + V);
|
||||
float NdotV = max(dot(fragnormal, V), 1e-4);
|
||||
float NdotH = max(dot(fragnormal, H), 0.0);
|
||||
float VdotH = max(dot(V, H), 0.0);
|
||||
float brdf = D_GGX(NdotH, roughness) * G_Smith(NdotV, NdotL, roughness) / (4.0 * NdotL * NdotV);
|
||||
vec3 fresnel = f0 + (1.0 - f0) * pow(1.0 - VdotH, 5.0);
|
||||
return fresnel * (min(brdf, limit) * NdotL * BRDF_PI);
|
||||
}
|
||||
|
||||
// perceptual roughness raised where the normal changes much from a pixel to the next (normal maps, tight curves), so the
|
||||
// highlight of a detail smaller than a pixel spreads over the pixel instead of flickering. Kaplanyan, Tokuyoshi, "Improved
|
||||
// geometric specular antialiasing", 2019
|
||||
float specular_antialiasing(vec3 fragnormal, float roughness)
|
||||
{
|
||||
vec3 dndx = dFdx(fragnormal);
|
||||
vec3 dndy = dFdy(fragnormal);
|
||||
float variance = 0.25 * (dot(dndx, dndx) + dot(dndy, dndy));
|
||||
float kernel = min(2.0 * variance, 0.18);
|
||||
float a2 = roughness * roughness * roughness * roughness;
|
||||
return sqrt(sqrt(clamp(a2 + kernel, 0.0, 1.0)));
|
||||
}
|
||||
|
||||
// the materials without a specgloss map give glossiness: (param[1].w, 10 by default) as the exponent of the blinn-phong
|
||||
// highlight of the old renderer. a lobe of exponent n is about a ggx one of alpha sqrt(2 / (n + 2))
|
||||
float phong_roughness(float exponent)
|
||||
{
|
||||
return sqrt(sqrt(2.0 / (max(exponent, 0.0) + 2.0)));
|
||||
}
|
||||
|
||||
// glossiness which apply_lights() turns into the roughness of a blinn-phong exponent (it takes 1 - glossiness / param[1].w)
|
||||
float phong_glossiness(float exponent)
|
||||
{
|
||||
return (1.0 - phong_roughness(exponent)) * max(abs(param[1].w), 1.0);
|
||||
}
|
||||
|
||||
// the reflection of the surroundings of a material without a specgloss map is a smooth varnish over the rough surface: the
|
||||
// old renderer showed it as a sharp reflection, as much of it as reflection: (and the masks of the material) asked for
|
||||
bool legacy_coat = false;
|
||||
|
||||
// set up the gloss of a material without a specgloss map, before apply_lights()
|
||||
void legacy_gloss()
|
||||
{
|
||||
glossiness = phong_glossiness(abs(param[1].w));
|
||||
legacy_coat = true;
|
||||
}
|
||||
|
||||
// Returns vec2(diffuse, specular) for a single punctual light.
|
||||
//
|
||||
// diffuse – Lambert N·L (Fresnel-weighted diffuse is handled per-material
|
||||
@@ -380,7 +448,8 @@ vec2 calc_headlights(light_s light, vec3 fragnormal, vec3 dpdx, vec3 dpdy)
|
||||
if ((contact_shadow_budget > 0) && (lightintensity > 0.0) && (part.x > 0.0))
|
||||
lightintensity *= 1.0 - contact_shadow_lamp(light_dir, distance,
|
||||
part.x * atten * lightintensity * light.intensity * max(light.color.r, max(light.color.g, light.color.b)));
|
||||
return part * atten * lightintensity;
|
||||
// x the diffuse light, y the light the specular reflection takes (specular_light() brings its own n.l)
|
||||
return vec2(part.x, 1.0) * (atten * lightintensity);
|
||||
}
|
||||
|
||||
// closest distance (squared) the light of a lamp is computed for: nearer the inverse square would grow without a limit
|
||||
@@ -436,7 +505,7 @@ float local_light_shadow(light_s light, vec3 fragnormal)
|
||||
}
|
||||
|
||||
// light of a lamp (point or spot light: the lamps of models and vehicles, the cab lamp) reaching the fragment, x the diffuse
|
||||
// and y the specular part. it falls off with the square of the distance, and smoothly to nothing at the range of the light,
|
||||
// part and y the light the specular reflection takes (specular_light() brings its own n.l). it falls off with the square of the distance, and smoothly to nothing at the range of the light,
|
||||
// 1 / sqrt(quadratic), past which the culling of the clusters does not take it. a spot light fades from its inner cone to the
|
||||
// outer one. a lamp with a shadow map is held back by what is between it and the fragment
|
||||
vec2 calc_local_light(light_s light, vec3 fragnormal)
|
||||
@@ -455,9 +524,7 @@ vec2 calc_local_light(light_s light, vec3 fragnormal)
|
||||
atten * max(dot(fragnormal, light_dir), 0.0) * light.intensity * max(light.color.r, max(light.color.g, light.color.b)));
|
||||
if (atten <= 0.0)
|
||||
return vec2(0.0);
|
||||
vec2 part = calc_light(light_dir, fragnormal);
|
||||
// the highlight of a tiny light on a polished surface is kept within what the image can take
|
||||
return vec2(part.x, min(part.y, 16.0) * part.x) * atten;
|
||||
return vec2(max(dot(fragnormal, light_dir), 0.0), 1.0) * atten;
|
||||
}
|
||||
|
||||
// index of the light cluster the fragment is in, see gl/cluster_grid.h: its screen tile and slice of depth. the depth is the clip
|
||||
@@ -471,10 +538,21 @@ uint fragment_cluster()
|
||||
return uint(tile.x + CLUSTER_GRID_X * (tile.y + CLUSTER_GRID_Y * slice));
|
||||
}
|
||||
|
||||
// adds the light of the headlights and lamps which reach the fragment to its colour. these are the ones in the list of its cluster
|
||||
// when the lights are clustered (the sun is not on the list, the callers take care of it), and the first lights_count - 1 of
|
||||
// lights[] otherwise, which are headlights only
|
||||
vec3 add_headlights(vec3 fragcolor, vec3 fragnormal)
|
||||
// adds the light of a headlight or lamp to the diffuse and the specular light of the fragment
|
||||
void add_local_light(light_s light, vec2 part, vec3 fragnormal, inout vec3 diffuse, inout vec3 specular)
|
||||
{
|
||||
if (part.y <= 0.0)
|
||||
return;
|
||||
vec3 color = light.color * light.intensity;
|
||||
diffuse += color * part.x;
|
||||
specular += color * (part.y * param[1].y) * specular_light(normalize(light.pos - f_pos.xyz), fragnormal, spec_f0, spec_roughness, LOCAL_LIGHT_BRDF_LIMIT);
|
||||
}
|
||||
|
||||
// adds the light of the headlights and lamps which reach the fragment to its diffuse and specular light. these are the ones in
|
||||
// the list of its cluster when the lights are clustered (the sun is not on the list, the callers take care of it), and the
|
||||
// first lights_count - 1 of lights[] otherwise, which are headlights only. the specular light is reflected with spec_f0 and
|
||||
// spec_roughness, and is already coloured by the fresnel term
|
||||
void add_local_lights(vec3 fragnormal, inout vec3 diffuse, inout vec3 specular)
|
||||
{
|
||||
// worked out before the loops, which the fragments of a quad do not leave together
|
||||
vec3 dpdx = dFdx(f_pos.xyz);
|
||||
@@ -488,7 +566,7 @@ vec3 add_headlights(vec3 fragcolor, vec3 fragnormal)
|
||||
{
|
||||
light_s light = lights[cluster_light_indices[range.offset + i]];
|
||||
vec2 part = (light.type == LIGHT_HEADLIGHTS) ? calc_headlights(light, fragnormal, dpdx, dpdy) : calc_local_light(light, fragnormal);
|
||||
fragcolor += light.color * (part.x + part.y * param[1].y) * light.intensity;
|
||||
add_local_light(light, part, fragnormal, diffuse, specular);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -496,11 +574,19 @@ vec3 add_headlights(vec3 fragcolor, vec3 fragnormal)
|
||||
for (uint i = 1U; i < lights_count; i++)
|
||||
{
|
||||
light_s light = lights[i];
|
||||
vec2 part = calc_headlights(light, fragnormal, dpdx, dpdy);
|
||||
fragcolor += light.color * (part.x + part.y * param[1].y) * light.intensity;
|
||||
add_local_light(light, calc_headlights(light, fragnormal, dpdx, dpdy), fragnormal, diffuse, specular);
|
||||
}
|
||||
}
|
||||
return fragcolor;
|
||||
}
|
||||
|
||||
// the light of the headlights and lamps added to Fragcolor, diffuse and specular together (for shaders which don't tell
|
||||
// the albedo from the reflection)
|
||||
vec3 add_headlights(vec3 fragcolor, vec3 fragnormal)
|
||||
{
|
||||
vec3 diffuse = vec3(0.0);
|
||||
vec3 specular = vec3(0.0);
|
||||
add_local_lights(fragnormal, diffuse, specular);
|
||||
return fragcolor + diffuse + specular;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
@@ -565,110 +651,140 @@ vec3 add_sky_ambient(vec3 basecolor, vec3 fragnormal)
|
||||
return max(basecolor + sky_ambient_directional(worldnormal) * (sky_ambient_factor * share), vec3(0.0));
|
||||
}
|
||||
|
||||
// [0] - diffuse, [1] - specular
|
||||
// do magic here
|
||||
vec3 apply_lights(vec3 fragcolor, vec3 fragnormal, vec3 texturecolor, float reflectivity, float specularity, float shadowtone)
|
||||
// lights the surface: the ambient light, the sun (the moon), the headlights and lamps and the reflection of the surroundings.
|
||||
// the units are the ones of the ambient light, the irradiance over pi: a white lambertian surface lit by 1 of it shows 1.
|
||||
// Texturecolor is the albedo (the base colour of a metal), Specularity the specular level of a dielectric (0.5 is the
|
||||
// reflectance of 4% at normal incidence), Reflectivity how much of the reflected surroundings is the cubemap rather than the
|
||||
// ambient light, Shadowtone the share of the sun left in its shadow (1 for the materials which take no shadows).
|
||||
// a Sunless surface (the interior of a cab) gets no light of the sun, its shadow only darkens the ambient light
|
||||
vec3 shade_surface(vec3 fragcolor, vec3 fragnormal, vec3 texturecolor, float reflectivity, float specularity, float shadowtone, bool sunless)
|
||||
{
|
||||
// Diffuse colour is applied once, to the albedo; the light terms below are not scaled by it again
|
||||
texturecolor *= material_diffuse();
|
||||
// the sky lights the faces turned up and towards the bright part of the sky more than the ones turned to the ground
|
||||
fragcolor = add_sky_ambient(fragcolor, fragnormal);
|
||||
float weathered = (param[2].w > 0.0 ? clamp(param[2].w * UserData.x, 0.0, 1.0) : 0.0);
|
||||
float tinted = (param[2].w < 0.0 ? clamp(-param[2].w * UserData.x, 0.0, 1.0) : 0.0);
|
||||
// a tint only scales the colour of the texture, the steel keeps its own polish
|
||||
float polished = weathered * smoothstep(0.03, 0.12, dot(texturecolor, vec3(0.2126, 0.7152, 0.0722)));
|
||||
float weatheredluma = min(dot(texturecolor, vec3(0.2126, 0.7152, 0.0722)), 0.05);
|
||||
vec3 unused = texturecolor * (weatheredluma / max(dot(texturecolor, vec3(0.2126, 0.7152, 0.0722)), 1e-4));
|
||||
unused = mix(unused, vec3(1.0, 0.82, 0.74) * (weatheredluma / 0.8525), 0.5);
|
||||
texturecolor = mix(texturecolor, unused, smoothstep(0.0, 0.4, weathered));
|
||||
texturecolor = (tinted > 0.0 ? texturecolor * mix(vec3(1.0), param[2].rgb, tinted) : texturecolor);
|
||||
specularity = mix(specularity, min(specularity, 0.03), smoothstep(0.0, 0.4, polished));
|
||||
metalic = mix(metalic, 0.0, polished);
|
||||
glossiness = mix(glossiness, min(glossiness, 0.06 * abs(param[1].w)), polished);
|
||||
reflectivity = mix(reflectivity, min(reflectivity, 0.08 * param[1].z), smoothstep(0.0, 0.4, polished));
|
||||
// Scale ambient before it gets tinted by the texture.
|
||||
// Sun, headlights and emission are added afterwards so they are NOT
|
||||
// attenuated by AMBIENT_SCALE - this only dims the indirect term.
|
||||
fragcolor *= AMBIENT_SCALE;
|
||||
float polished = 0.0;
|
||||
if (sunless)
|
||||
{
|
||||
// Cab interior: dim ambient less than the exterior path - ambient
|
||||
// is the dominant indoor illumination, but it was still too bright.
|
||||
fragcolor *= 0.80;
|
||||
}
|
||||
else
|
||||
{
|
||||
// the sky lights the faces turned up and towards the bright part of the sky more than the ones turned to the ground
|
||||
fragcolor = add_sky_ambient(fragcolor, fragnormal);
|
||||
#ifndef NO_WEATHERING
|
||||
float weathered = (param[2].w > 0.0 ? clamp(param[2].w * UserData.x, 0.0, 1.0) : 0.0);
|
||||
float tinted = (param[2].w < 0.0 ? clamp(-param[2].w * UserData.x, 0.0, 1.0) : 0.0);
|
||||
// a tint only scales the colour of the texture, the steel keeps its own polish
|
||||
polished = weathered * smoothstep(0.03, 0.12, dot(texturecolor, vec3(0.2126, 0.7152, 0.0722)));
|
||||
float weatheredluma = min(dot(texturecolor, vec3(0.2126, 0.7152, 0.0722)), 0.05);
|
||||
vec3 unused = texturecolor * (weatheredluma / max(dot(texturecolor, vec3(0.2126, 0.7152, 0.0722)), 1e-4));
|
||||
unused = mix(unused, vec3(1.0, 0.82, 0.74) * (weatheredluma / 0.8525), 0.5);
|
||||
texturecolor = mix(texturecolor, unused, smoothstep(0.0, 0.4, weathered));
|
||||
texturecolor = (tinted > 0.0 ? texturecolor * mix(vec3(1.0), param[2].rgb, tinted) : texturecolor);
|
||||
specularity = mix(specularity, min(specularity, 0.03), smoothstep(0.0, 0.4, polished));
|
||||
metalic = mix(metalic, 0.0, polished);
|
||||
glossiness = mix(glossiness, min(glossiness, 0.06 * abs(param[1].w)), polished);
|
||||
reflectivity = mix(reflectivity, min(reflectivity, 0.08 * param[1].z), smoothstep(0.0, 0.4, polished));
|
||||
#endif
|
||||
// Scale ambient before it gets tinted by the texture.
|
||||
// Sun, headlights and emission are added afterwards so they are NOT
|
||||
// attenuated by AMBIENT_SCALE - this only dims the indirect term.
|
||||
fragcolor *= AMBIENT_SCALE;
|
||||
}
|
||||
|
||||
vec3 emissioncolor = vec3(emission);
|
||||
|
||||
vec3 view_dir = normalize(-f_pos.xyz);
|
||||
float NdotV = max(dot(fragnormal, view_dir), 0.0);
|
||||
vec3 F0 = mix(vec3(0.04), texturecolor, metalic);
|
||||
vec3 fresnel = F0 + (1.0 - F0) * pow(1.0 - NdotV, 5.0);
|
||||
float NdotV = max(dot(fragnormal, view_dir), 1e-4);
|
||||
|
||||
float env_roughness = 1.0 - clamp(glossiness / max(abs(param[1].w), 1.0), 0.0, 1.0);
|
||||
// glossiness == param[1].w -> mirror, glossiness == 0 -> fully rough
|
||||
float roughness = clamp(1.0 - glossiness / max(abs(param[1].w), 1.0), 0.0, 1.0);
|
||||
roughness = max(specular_antialiasing(fragnormal, roughness), MIN_ROUGHNESS);
|
||||
// metals reflect with their base colour, dielectrics with the specular level (0.5 -> 0.04)
|
||||
vec3 f0 = mix(vec3(0.08 * specularity), texturecolor, metalic);
|
||||
spec_f0 = f0;
|
||||
spec_roughness = roughness;
|
||||
|
||||
// Pre-integrated env BRDF: how much of the surroundings the surface reflects, for its F0, roughness and the view angle.
|
||||
// the surroundings are the cubemap where the material asks for it (reflectivity) and the ambient light elsewhere, so a
|
||||
// surface reflects them always, the rough one barely
|
||||
vec3 env_spec = EnvBRDFApprox(f0, roughness, NdotV);
|
||||
float env_roughness = roughness;
|
||||
vec3 cubemap_spec = env_spec;
|
||||
float cubemap_share = max(reflectivity, 0.0);
|
||||
float ambient_share = clamp(1.0 - reflectivity, 0.0, 1.0);
|
||||
// what the diffuse layer is left with
|
||||
vec3 diffuse_albedo = texturecolor * (1.0 - metalic) * (1.0 - env_spec);
|
||||
if (legacy_coat)
|
||||
{
|
||||
// the varnish: a smooth dielectric layer reflecting the cubemap, worn off where the material is weathered
|
||||
env_roughness = specular_antialiasing(fragnormal, roughness * smoothstep(0.0, 0.4, polished));
|
||||
cubemap_spec = EnvBRDFApprox(mix(vec3(0.04), texturecolor, metalic), env_roughness, NdotV);
|
||||
ambient_share = 1.0;
|
||||
diffuse_albedo *= 1.0 - cubemap_spec * min(cubemap_share, 1.0);
|
||||
}
|
||||
vec3 envcolor = envmap_color_rough(fragnormal, env_roughness);
|
||||
|
||||
// Pre-integrated env BRDF: roughness/F0/view-dependent specular scale.
|
||||
// Replaces the old raw `fresnel` weighting so matte surfaces stop
|
||||
// mirroring the sky. `env_spec` is the colour to multiply the cubemap by.
|
||||
vec3 env_spec = EnvBRDFApprox(F0, env_roughness, NdotV);
|
||||
float env_spec_w = max(env_spec.r, max(env_spec.g, env_spec.b));
|
||||
|
||||
// Tint texture toward fully-saturated under strong env, weighted by the
|
||||
// env BRDF (so a rough/matte surface no longer gets washed toward env hue)
|
||||
vec3 texturecoloryuv = rgb2yuv(texturecolor);
|
||||
vec3 texturecolorfullv = yuv2rgb(vec3(0.2176, texturecoloryuv.gb));
|
||||
vec3 envyuv = rgb2yuv(envcolor);
|
||||
texturecolor = mix(texturecolor, texturecolorfullv, envyuv.r * reflectivity * env_spec_w);
|
||||
|
||||
if (lights_count == 0U)
|
||||
// Metals carry no diffuse term; env reflection is gated by the env BRDF
|
||||
// (F0-tinted, roughness-attenuated) so matte surfaces barely reflect.
|
||||
return fragcolor * texturecolor * (1.0 - metalic)
|
||||
return fragcolor * diffuse_albedo
|
||||
+ emissioncolor * texturecolor
|
||||
+ envcolor * env_spec * reflectivity;
|
||||
+ fragcolor * env_spec * ambient_share
|
||||
+ envcolor * cubemap_spec * cubemap_share;
|
||||
|
||||
vec2 sunlight = calc_dir_light(lights[0], fragnormal);
|
||||
vec3 light_dir = normalize(-lights[0].dir);
|
||||
float NdotL = max(dot(fragnormal, light_dir), 0.0);
|
||||
// Sharpen sun N.L falloff so the lit-to-shaded terminator on cab
|
||||
// panels, vehicle bodies and terrain reads as a clear edge rather
|
||||
// than a soft Lambertian ramp. Tunable via SUN_NDOTL_SHARPNESS.
|
||||
float sun_NdotL = pow(sunlight.x, SUN_NDOTL_SHARPNESS);
|
||||
float sun_NdotL = pow(NdotL, SUN_NDOTL_SHARPNESS);
|
||||
// the clouds hold back the sun (the moon at night) where their shadow falls
|
||||
float cloudsun = cloud_shadow(mat3(inv_view) * f_pos.xyz);
|
||||
float diffuseamount = sun_NdotL * lights[0].intensity * cloudsun;
|
||||
// Sun HDR scale -> SUN_DIFFUSE_SCALE, the same for the diffuse and the specular light
|
||||
vec3 sunlight = lights[0].color * (SUN_DIFFUSE_SCALE * lights[0].intensity * cloudsun);
|
||||
|
||||
float shadow1 = 0.0;
|
||||
float shadow = 0.0;
|
||||
if (shadowtone < 1.0)
|
||||
shadow1 = (1.0 - shadowtone) * clamp(calc_shadow(), 0.0, 1.0);
|
||||
shadow = clamp(calc_shadow(), 0.0, 1.0);
|
||||
|
||||
// Sun HDR scale -> SUN_DIFFUSE_SCALE (default 2.5). Controls how
|
||||
// bright sun-lit (unshaded) faces get. Lower this if surfaces in
|
||||
// direct sun read as too hot/burnt; raise it for more punch.
|
||||
fragcolor += lights[0].color * SUN_DIFFUSE_SCALE * (1.0 - shadow1) * diffuseamount;
|
||||
// the cubemap knows nothing of what shades the fragment: it is dimmed a little in the shadow of the sun
|
||||
float cubemap_shadow = 1.0;
|
||||
if (sunless)
|
||||
{
|
||||
// the sun adds no light in the cab, where it would fall its shadow darkens the ambient light
|
||||
float diffuseamount = sun_NdotL * lights[0].intensity;
|
||||
float darkness = (shadowtone < 1.0 ? max(shadow, 1.0 - cloudsun) : 0.0);
|
||||
fragcolor = mix(fragcolor, fragcolor * shadowtone, clamp(diffuseamount * darkness, 0.0, 1.0));
|
||||
}
|
||||
else
|
||||
cubemap_shadow = 1.0 - (1.0 - shadowtone) * shadow * 0.5;
|
||||
|
||||
fragcolor = add_headlights(fragcolor, fragnormal);
|
||||
// the reflection of the surroundings, before the light of the sun and the lamps joins the ambient light
|
||||
vec3 env_reflection = fragcolor * env_spec * ambient_share
|
||||
+ envcolor * cubemap_spec * (cubemap_share * cubemap_shadow);
|
||||
|
||||
float specularamount = sunlight.y * param[1].y * specularity * lights[0].intensity * cloudsun
|
||||
* clamp(1.0 - shadowtone, 0.0, 1.0);
|
||||
if (shadowtone < 1.0)
|
||||
specularamount *= clamp(1.0 - shadow1, 0.0, 1.0);
|
||||
// the shadow leaves the share of the sun Shadowtone tells (the old shadow colour of the scenery) to the diffuse light,
|
||||
// nothing to the highlight
|
||||
if (!sunless)
|
||||
fragcolor += sunlight * (sun_NdotL * (1.0 - (1.0 - shadowtone) * shadow));
|
||||
vec3 specular = sunlight * specular_light(light_dir, fragnormal, f0, roughness, SUN_BRDF_LIMIT) * (1.0 - shadow);
|
||||
|
||||
vec3 specularcolor = specularamount * lights[0].color;
|
||||
vec3 lampspecular = vec3(0.0);
|
||||
add_local_lights(fragnormal, fragcolor, lampspecular);
|
||||
|
||||
// Env reflection tracked separately — must NOT go through the albedo multiply
|
||||
// below. Gated by the pre-integrated env BRDF (env_spec) so reflection energy
|
||||
// falls off with roughness; F0 inside env_spec already tints metals by albedo.
|
||||
vec3 env_reflection = envcolor * env_spec * reflectivity * (1.0 - shadow1 * 0.5);
|
||||
return fragcolor * diffuse_albedo // ambient, sun and lamps on the diffuse layer
|
||||
+ specular * param[1].y // highlight of the sun, fresnel coloured (metals take their base colour)
|
||||
+ lampspecular // highlights of the lamps, param[1].y already applied
|
||||
+ emissioncolor * texturecolor
|
||||
+ env_reflection;
|
||||
}
|
||||
|
||||
// --- Physically-based metal/rough combine (Substance 3D Painter parity) ---
|
||||
// Dielectrics: keep the full diffuse albedo; the direct sun highlight stays
|
||||
// light-coloured because dielectric F0 is achromatic (~0.04) and
|
||||
// must NOT be tinted by the base colour.
|
||||
// Metals: drop the diffuse term entirely and tint the direct highlight
|
||||
// with the albedo (metal F0 == base colour).
|
||||
// The highlight *strength* (specularamount) is deliberately left untouched so
|
||||
// existing material tuning is preserved — only the colour/energy split that
|
||||
// was previously inverted gets corrected.
|
||||
vec3 diffuse_albedo = texturecolor * (1.0 - metalic);
|
||||
vec3 spec_tint = mix(vec3(1.0), texturecolor, metalic);
|
||||
vec3 apply_lights(vec3 fragcolor, vec3 fragnormal, vec3 texturecolor, float reflectivity, float specularity, float shadowtone)
|
||||
{
|
||||
return shade_surface(fragcolor, fragnormal, texturecolor, reflectivity, specularity, shadowtone, false);
|
||||
}
|
||||
|
||||
vec3 result = fragcolor * diffuse_albedo // sun + ambient + headlight diffuse
|
||||
+ specularcolor * spec_tint // direct sun highlight
|
||||
+ emissioncolor * texturecolor // emissive glow (albedo-tinted, unchanged)
|
||||
+ env_reflection; // env reflection (env_spec already F0-tinted)
|
||||
|
||||
return result;
|
||||
}
|
||||
// the interior of a cab: no light of the sun, its shadow darkens the ambient light
|
||||
vec3 apply_lights_sunless(vec3 fragcolor, vec3 fragnormal, vec3 texturecolor, float reflectivity, float specularity, float shadowtone)
|
||||
{
|
||||
return shade_surface(fragcolor, fragnormal, texturecolor, reflectivity, specularity, shadowtone, true);
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ void main()
|
||||
vec3 fragnormal = normalize(f_normal);
|
||||
float reflectivity = param[1].z;
|
||||
float specularity = dot(pow(param[0].rgb, vec3(2.2)), vec3(0.5));
|
||||
glossiness = abs(param[1].w);
|
||||
legacy_gloss();
|
||||
|
||||
fragcolor = apply_lights(fragcolor, fragnormal, tex_color.rgb, reflectivity, specularity, shadow_tone);
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ void main()
|
||||
vec3 fragnormal = normalize(f_normal);
|
||||
float reflectivity = param[1].z;
|
||||
//float specularity = (tex_color.r + tex_color.g + tex_color.b) * 0.5;
|
||||
glossiness = abs(param[1].w);
|
||||
legacy_gloss();
|
||||
|
||||
fragcolor = apply_lights(fragcolor, fragnormal, tex_color.rgb, reflectivity, 0.0, shadow_tone);
|
||||
vec4 color = vec4(apply_fog(fragcolor), tex_color.a * alpha_mult);
|
||||
|
||||
@@ -49,7 +49,7 @@ void main()
|
||||
vec3 fragnormal = normalize(f_tbn * normalize(normal.xyz));
|
||||
float reflectivity = param[1].z;
|
||||
float specularity = (tex_color.r + tex_color.g + tex_color.b) * 0.5;
|
||||
glossiness = abs(param[1].w);
|
||||
legacy_gloss();
|
||||
|
||||
fragcolor = apply_lights(fragcolor, fragnormal, tex_color.rgb, reflectivity, specularity, shadow_tone);
|
||||
vec4 color = vec4(apply_fog(fragcolor), tex_color.a * alpha_mult);
|
||||
|
||||
@@ -62,6 +62,7 @@ void main()
|
||||
float reflblend = (normal_map.a + detailnormal_map.a);
|
||||
float reflectivity = reflblend > 1.0 ? param[1].z * 1.0 : param[1].z * reflblend;
|
||||
float specularity = (tex_color.r + tex_color.g + tex_color.b) * 0.5;
|
||||
legacy_gloss();
|
||||
|
||||
fragcolor = apply_lights(fragcolor, fragnormal, tex_color.rgb, reflectivity, specularity, shadow_tone);
|
||||
vec4 color = vec4(apply_fog(fragcolor), tex_color.a * alpha_mult);
|
||||
|
||||
@@ -34,6 +34,8 @@ uniform sampler2D normalmap;
|
||||
uniform sampler2D detailnormalmap;
|
||||
|
||||
#define PARALLAX
|
||||
// param[2].w is the height offset, not the weathering
|
||||
#define NO_WEATHERING
|
||||
#include <light_common.glsl>
|
||||
#include <apply_fog.glsl>
|
||||
#include <tonemapping.glsl>
|
||||
@@ -68,7 +70,8 @@ void main()
|
||||
|
||||
vec3 fragnormal = normalize(f_tbn * normalize(vec3(normal.xy + normaldetail.xy, normal.z)));
|
||||
float reflectivity = param[1].z * normal_map.a;
|
||||
float specularity = (tex_color.r + tex_color.g + tex_color.b) * 0.5;
|
||||
float specularity = (tex_color.r + tex_color.g + tex_color.b) * 0.5;
|
||||
legacy_gloss();
|
||||
|
||||
fragcolor = apply_lights(fragcolor, fragnormal, tex_color.rgb, reflectivity, specularity, shadow_tone);
|
||||
|
||||
@@ -91,36 +94,41 @@ void main()
|
||||
vec2 ParallaxMapping(vec2 f_coord, vec3 viewDir)
|
||||
{
|
||||
float pos_len = length(f_pos.xyz);
|
||||
// gradients of the coordinates taken here: inside the loop the fragments of a quad don't go the same way
|
||||
vec2 dcoorddx = dFdx(f_coord);
|
||||
vec2 dcoorddy = dFdy(f_coord);
|
||||
|
||||
if (pos_len > 100.0) {
|
||||
return f_coord;
|
||||
}
|
||||
// the shift fades out before the distance it stops at, so it doesn't switch off at once there
|
||||
float fade = 1.0 - smoothstep(80.0, 100.0, pos_len);
|
||||
|
||||
#if EXTRAEFFECTS_ENABLED
|
||||
const float minLayers = 8.0;
|
||||
const float maxLayers = 32.0;
|
||||
float LayersWeight = pos_len / 20.0;
|
||||
vec2 currentTexCoords = f_coord;
|
||||
float currentDepthMapValue = texture(normalmap, currentTexCoords).b;
|
||||
float currentDepthMapValue = textureGrad(normalmap, currentTexCoords, dcoorddx, dcoorddy).b;
|
||||
LayersWeight = min(abs(dot(vec3(0.0, 0.0, 1.0), viewDir)),LayersWeight);
|
||||
float numLayers = mix(maxLayers, minLayers, clamp(LayersWeight, 0.0, 1.0)); // number of depth layers
|
||||
float layerDepth = 1.0 / numLayers; // calculate the size of each layer
|
||||
float currentLayerDepth = 0.0; // depth of current layer
|
||||
vec2 P = viewDir.xy * param[2].z; // the amount to shift the texture coordinates per layer (from vector P)
|
||||
vec2 P = viewDir.xy * param[2].z * fade; // the amount to shift the texture coordinates per layer (from vector P)
|
||||
vec2 deltaTexCoords = P / numLayers;
|
||||
|
||||
|
||||
while(currentLayerDepth < currentDepthMapValue)
|
||||
{
|
||||
currentTexCoords -= deltaTexCoords; // shift texture coordinates along direction of P
|
||||
currentDepthMapValue = texture(normalmap, currentTexCoords).b; // get depthmap value at current texture coordinates
|
||||
currentDepthMapValue = textureGrad(normalmap, currentTexCoords, dcoorddx, dcoorddy).b; // get depthmap value at current texture coordinates
|
||||
currentLayerDepth += layerDepth; // get depth of next layer
|
||||
}
|
||||
|
||||
vec2 prevTexCoords = currentTexCoords + deltaTexCoords; // get texture coordinates before collision (reverse operations)
|
||||
|
||||
float afterDepth = currentDepthMapValue - currentLayerDepth; // get depth after and before collision for linear interpolation
|
||||
float beforeDepth = texture(normalmap, prevTexCoords).b - currentLayerDepth + layerDepth;
|
||||
float beforeDepth = textureGrad(normalmap, prevTexCoords, dcoorddx, dcoorddy).b - currentLayerDepth + layerDepth;
|
||||
|
||||
float weight = afterDepth / (afterDepth - beforeDepth); // interpolation of texture coordinates
|
||||
vec2 finalTexCoords = prevTexCoords * weight + currentTexCoords * (1.0 - weight);
|
||||
@@ -128,7 +136,7 @@ vec2 ParallaxMapping(vec2 f_coord, vec3 viewDir)
|
||||
return finalTexCoords;
|
||||
#else
|
||||
float height = texture(normalmap, f_coord).b;
|
||||
vec2 p = viewDir.xy / viewDir.z * (height * (param[2].z - param[2].w) * 0.2);
|
||||
vec2 p = viewDir.xy / viewDir.z * (height * (param[2].z - param[2].w) * 0.2) * fade;
|
||||
return f_coord - p;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -38,6 +38,8 @@ uniform sampler2D detailnormalmap;
|
||||
|
||||
|
||||
#define PARALLAX
|
||||
// param[2].w is the height offset, not the weathering
|
||||
#define NO_WEATHERING
|
||||
#include <light_common.glsl>
|
||||
#include <apply_fog.glsl>
|
||||
#include <tonemapping.glsl>
|
||||
@@ -98,36 +100,41 @@ vec2 ParallaxMapping(vec2 f_coord, vec3 viewDir)
|
||||
{
|
||||
|
||||
float pos_len = length(f_pos.xyz);
|
||||
// gradients of the coordinates taken here: inside the loop the fragments of a quad don't go the same way
|
||||
vec2 dcoorddx = dFdx(f_coord);
|
||||
vec2 dcoorddy = dFdy(f_coord);
|
||||
|
||||
if (pos_len > 100.0) {
|
||||
return f_coord;
|
||||
}
|
||||
// the shift fades out before the distance it stops at, so it doesn't switch off at once there
|
||||
float fade = 1.0 - smoothstep(80.0, 100.0, pos_len);
|
||||
|
||||
#if EXTRAEFFECTS_ENABLED
|
||||
const float minLayers = 8.0;
|
||||
const float maxLayers = 32.0;
|
||||
float LayersWeight = pos_len / 20.0;
|
||||
vec2 currentTexCoords = f_coord;
|
||||
float currentDepthMapValue = texture(normalmap, currentTexCoords).b;
|
||||
float currentDepthMapValue = textureGrad(normalmap, currentTexCoords, dcoorddx, dcoorddy).b;
|
||||
LayersWeight = min(abs(dot(vec3(0.0, 0.0, 1.0), viewDir)),LayersWeight);
|
||||
float numLayers = mix(maxLayers, minLayers, clamp(LayersWeight, 0.0, 1.0)); // number of depth layers
|
||||
float layerDepth = 1.0 / numLayers; // calculate the size of each layer
|
||||
float currentLayerDepth = 0.0; // depth of current layer
|
||||
vec2 P = viewDir.xy * param[2].z; // the amount to shift the texture coordinates per layer (from vector P)
|
||||
vec2 P = viewDir.xy * param[2].z * fade; // the amount to shift the texture coordinates per layer (from vector P)
|
||||
vec2 deltaTexCoords = P / numLayers;
|
||||
|
||||
|
||||
while(currentLayerDepth < currentDepthMapValue)
|
||||
{
|
||||
currentTexCoords -= deltaTexCoords; // shift texture coordinates along direction of P
|
||||
currentDepthMapValue = texture(normalmap, currentTexCoords).b; // get depthmap value at current texture coordinates
|
||||
currentDepthMapValue = textureGrad(normalmap, currentTexCoords, dcoorddx, dcoorddy).b; // get depthmap value at current texture coordinates
|
||||
currentLayerDepth += layerDepth; // get depth of next layer
|
||||
}
|
||||
|
||||
vec2 prevTexCoords = currentTexCoords + deltaTexCoords; // get texture coordinates before collision (reverse operations)
|
||||
|
||||
float afterDepth = currentDepthMapValue - currentLayerDepth; // get depth after and before collision for linear interpolation
|
||||
float beforeDepth = texture(normalmap, prevTexCoords).b - currentLayerDepth + layerDepth;
|
||||
float beforeDepth = textureGrad(normalmap, prevTexCoords, dcoorddx, dcoorddy).b - currentLayerDepth + layerDepth;
|
||||
|
||||
float weight = afterDepth / (afterDepth - beforeDepth); // interpolation of texture coordinates
|
||||
vec2 finalTexCoords = prevTexCoords * weight + currentTexCoords * (1.0 - weight);
|
||||
@@ -135,7 +142,7 @@ vec2 ParallaxMapping(vec2 f_coord, vec3 viewDir)
|
||||
return finalTexCoords;
|
||||
#else
|
||||
float height = texture(normalmap, f_coord).b;
|
||||
vec2 p = viewDir.xy / viewDir.z * (height * (param[2].z - param[2].w) * 0.2);
|
||||
vec2 p = viewDir.xy / viewDir.z * (height * (param[2].z - param[2].w) * 0.2) * fade;
|
||||
return f_coord - p;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -48,6 +48,7 @@ void main()
|
||||
vec3 fragnormal = normalize(f_tbn * normalize(normal.xyz));
|
||||
float reflectivity = param[1].z * texture(normalmap, f_coord).a;
|
||||
float specularity = (tex_color.r + tex_color.g + tex_color.b) * 0.5;
|
||||
legacy_gloss();
|
||||
|
||||
fragcolor = apply_lights(fragcolor, fragnormal, tex_color.rgb, reflectivity, specularity, shadow_tone);
|
||||
|
||||
|
||||
@@ -55,7 +55,8 @@ void main()
|
||||
normal.z = sqrt(1.0 - clamp((dot(normal.xy, normal.xy)), 0.0, 1.0));
|
||||
vec3 fragnormal = normalize(f_tbn * normalize(normal.xyz));
|
||||
float reflectivity = param[1].z * texture(normalmap, f_coord_p).a;
|
||||
float specularity = (tex_color.r + tex_color.g + tex_color.b) * 0.5;
|
||||
float specularity = (tex_color.r + tex_color.g + tex_color.b) * 0.5;
|
||||
legacy_gloss();
|
||||
|
||||
fragcolor = apply_lights(fragcolor, fragnormal, tex_color.rgb, reflectivity, specularity, shadow_tone);
|
||||
|
||||
@@ -78,36 +79,41 @@ void main()
|
||||
vec2 ParallaxMapping(vec2 f_coord, vec3 viewDir)
|
||||
{
|
||||
float pos_len = length(f_pos.xyz);
|
||||
// gradients of the coordinates taken here: inside the loop the fragments of a quad don't go the same way
|
||||
vec2 dcoorddx = dFdx(f_coord);
|
||||
vec2 dcoorddy = dFdy(f_coord);
|
||||
|
||||
if (pos_len > 100.0) {
|
||||
return f_coord;
|
||||
}
|
||||
// the shift fades out before the distance it stops at, so it doesn't switch off at once there
|
||||
float fade = 1.0 - smoothstep(80.0, 100.0, pos_len);
|
||||
|
||||
#if EXTRAEFFECTS_ENABLED
|
||||
const float minLayers = 8.0;
|
||||
const float maxLayers = 32.0;
|
||||
float LayersWeight = pos_len / 20.0;
|
||||
vec2 currentTexCoords = f_coord;
|
||||
float currentDepthMapValue = texture(normalmap, currentTexCoords).b;
|
||||
float currentDepthMapValue = textureGrad(normalmap, currentTexCoords, dcoorddx, dcoorddy).b;
|
||||
LayersWeight = min(abs(dot(vec3(0.0, 0.0, 1.0), viewDir)),LayersWeight);
|
||||
float numLayers = mix(maxLayers, minLayers, clamp(LayersWeight, 0.0, 1.0)); // number of depth layers
|
||||
float layerDepth = 1.0 / numLayers; // calculate the size of each layer
|
||||
float currentLayerDepth = 0.0; // depth of current layer
|
||||
vec2 P = viewDir.xy * param[2].y; // the amount to shift the texture coordinates per layer (from vector P)
|
||||
vec2 P = viewDir.xy * param[2].y * fade; // the amount to shift the texture coordinates per layer (from vector P)
|
||||
vec2 deltaTexCoords = P / numLayers;
|
||||
|
||||
|
||||
while(currentLayerDepth < currentDepthMapValue)
|
||||
{
|
||||
currentTexCoords -= deltaTexCoords; // shift texture coordinates along direction of P
|
||||
currentDepthMapValue = texture(normalmap, currentTexCoords).b; // get depthmap value at current texture coordinates
|
||||
currentDepthMapValue = textureGrad(normalmap, currentTexCoords, dcoorddx, dcoorddy).b; // get depthmap value at current texture coordinates
|
||||
currentLayerDepth += layerDepth; // get depth of next layer
|
||||
}
|
||||
|
||||
vec2 prevTexCoords = currentTexCoords + deltaTexCoords; // get texture coordinates before collision (reverse operations)
|
||||
|
||||
float afterDepth = currentDepthMapValue - currentLayerDepth; // get depth after and before collision for linear interpolation
|
||||
float beforeDepth = texture(normalmap, prevTexCoords).b - currentLayerDepth + layerDepth;
|
||||
float beforeDepth = textureGrad(normalmap, prevTexCoords, dcoorddx, dcoorddy).b - currentLayerDepth + layerDepth;
|
||||
|
||||
float weight = afterDepth / (afterDepth - beforeDepth); // interpolation of texture coordinates
|
||||
vec2 finalTexCoords = prevTexCoords * weight + currentTexCoords * (1.0 - weight);
|
||||
@@ -115,7 +121,7 @@ vec2 ParallaxMapping(vec2 f_coord, vec3 viewDir)
|
||||
return finalTexCoords;
|
||||
#else
|
||||
float height = texture(normalmap, f_coord).b;
|
||||
vec2 p = viewDir.xy / viewDir.z * (height * (param[2].y - param[2].z) * 0.2);
|
||||
vec2 p = viewDir.xy / viewDir.z * (height * (param[2].y - param[2].z) * 0.2) * fade;
|
||||
return f_coord - p;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -84,36 +84,41 @@ void main()
|
||||
vec2 ParallaxMapping(vec2 f_coord, vec3 viewDir)
|
||||
{
|
||||
float pos_len = length(f_pos.xyz);
|
||||
// gradients of the coordinates taken here: inside the loop the fragments of a quad don't go the same way
|
||||
vec2 dcoorddx = dFdx(f_coord);
|
||||
vec2 dcoorddy = dFdy(f_coord);
|
||||
|
||||
if (pos_len > 100.0) {
|
||||
return f_coord;
|
||||
}
|
||||
// the shift fades out before the distance it stops at, so it doesn't switch off at once there
|
||||
float fade = 1.0 - smoothstep(80.0, 100.0, pos_len);
|
||||
|
||||
#if EXTRAEFFECTS_ENABLED
|
||||
const float minLayers = 8.0;
|
||||
const float maxLayers = 32.0;
|
||||
float LayersWeight = pos_len / 20.0;
|
||||
vec2 currentTexCoords = f_coord;
|
||||
float currentDepthMapValue = texture(normalmap, currentTexCoords).b;
|
||||
float currentDepthMapValue = textureGrad(normalmap, currentTexCoords, dcoorddx, dcoorddy).b;
|
||||
LayersWeight = min(abs(dot(vec3(0.0, 0.0, 1.0), viewDir)),LayersWeight);
|
||||
float numLayers = mix(maxLayers, minLayers, clamp(LayersWeight, 0.0, 1.0)); // number of depth layers
|
||||
float layerDepth = 1.0 / numLayers; // calculate the size of each layer
|
||||
float currentLayerDepth = 0.0; // depth of current layer
|
||||
vec2 P = viewDir.xy * param[2].y; // the amount to shift the texture coordinates per layer (from vector P)
|
||||
vec2 P = viewDir.xy * param[2].y * fade; // the amount to shift the texture coordinates per layer (from vector P)
|
||||
vec2 deltaTexCoords = P / numLayers;
|
||||
|
||||
|
||||
while(currentLayerDepth < currentDepthMapValue)
|
||||
{
|
||||
currentTexCoords -= deltaTexCoords; // shift texture coordinates along direction of P
|
||||
currentDepthMapValue = texture(normalmap, currentTexCoords).b; // get depthmap value at current texture coordinates
|
||||
currentDepthMapValue = textureGrad(normalmap, currentTexCoords, dcoorddx, dcoorddy).b; // get depthmap value at current texture coordinates
|
||||
currentLayerDepth += layerDepth; // get depth of next layer
|
||||
}
|
||||
|
||||
vec2 prevTexCoords = currentTexCoords + deltaTexCoords; // get texture coordinates before collision (reverse operations)
|
||||
|
||||
float afterDepth = currentDepthMapValue - currentLayerDepth; // get depth after and before collision for linear interpolation
|
||||
float beforeDepth = texture(normalmap, prevTexCoords).b - currentLayerDepth + layerDepth;
|
||||
float beforeDepth = textureGrad(normalmap, prevTexCoords, dcoorddx, dcoorddy).b - currentLayerDepth + layerDepth;
|
||||
|
||||
float weight = afterDepth / (afterDepth - beforeDepth); // interpolation of texture coordinates
|
||||
vec2 finalTexCoords = prevTexCoords * weight + currentTexCoords * (1.0 - weight);
|
||||
@@ -121,7 +126,7 @@ vec2 ParallaxMapping(vec2 f_coord, vec3 viewDir)
|
||||
return finalTexCoords;
|
||||
#else
|
||||
float height = texture(normalmap, f_coord).b;
|
||||
vec2 p = viewDir.xy / viewDir.z * (height * (param[2].y - param[2].z) * 0.2);
|
||||
vec2 p = viewDir.xy / viewDir.z * (height * (param[2].y - param[2].z) * 0.2) * fade;
|
||||
return f_coord - p;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -158,7 +158,7 @@ void main() {
|
||||
vec3 fragnormal = normalize(f_normal);
|
||||
float reflectivity = param[1].z;
|
||||
float specularity = (tex_color.r + tex_color.g + tex_color.b) * 0.5;
|
||||
glossiness = abs(param[1].w);
|
||||
legacy_gloss();
|
||||
|
||||
fragcolor = apply_lights(fragcolor, fragnormal, tex_color.rgb, reflectivity, specularity, shadow_tone);
|
||||
vec4 color = vec4(fragcolor, tex_color.a * alpha_mult);
|
||||
|
||||
@@ -42,7 +42,7 @@ void main()
|
||||
vec3 fragnormal = normalize(f_normal);
|
||||
float reflectivity = param[1].z * texture(reflmap, f_coord).a;
|
||||
float specularity = (tex_color.r + tex_color.g + tex_color.b) * 0.5;
|
||||
glossiness = abs(param[1].w);
|
||||
legacy_gloss();
|
||||
|
||||
fragcolor = apply_lights(fragcolor, fragnormal, tex_color.rgb, reflectivity, 0.0, shadow_tone);
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ void main()
|
||||
vec3 fragnormal = normalize(f_tbn * normalize(normal.xyz));
|
||||
float reflectivity = param[1].z * texture(normalmap, f_coord).a;
|
||||
float specularity = (tex_color.r + tex_color.g + tex_color.b) * 0.5;
|
||||
glossiness = abs(param[1].w);
|
||||
legacy_gloss();
|
||||
|
||||
fragcolor = apply_lights(fragcolor, fragnormal, tex_color.rgb, reflectivity, specularity, 1.0);
|
||||
vec4 color = vec4(apply_fog(fragcolor), tex_color.a * alpha_mult);
|
||||
|
||||
@@ -30,58 +30,6 @@ uniform sampler2D normalmap;
|
||||
#include <apply_fog.glsl>
|
||||
#include <tonemapping.glsl>
|
||||
|
||||
vec3 apply_lights_sunless(vec3 fragcolor, vec3 fragnormal, vec3 texturecolor, float reflectivity, float specularity, float shadowtone)
|
||||
{
|
||||
// diffuse colour applied once, to the albedo (see material_diffuse() in light_common.glsl)
|
||||
texturecolor *= material_diffuse();
|
||||
|
||||
// Cab interior: dim ambient less than the exterior path because
|
||||
// ambient is the dominant indoor illumination. 0.80 trims the
|
||||
// brightest faces without making the cab feel under-lit.
|
||||
fragcolor *= 0.80;
|
||||
|
||||
vec3 emissioncolor = vec3(emission);
|
||||
vec3 envcolor = envmap_color(fragnormal);
|
||||
|
||||
// yuv path
|
||||
vec3 texturecoloryuv = rgb2yuv(texturecolor);
|
||||
vec3 texturecolorfullv = yuv2rgb(vec3(0.2176, texturecoloryuv.gb));
|
||||
// hsl path
|
||||
// vec3 texturecolorhsl = rgb2hsl(texturecolor);
|
||||
// vec3 texturecolorfullv = hsl2rgb(vec3(texturecolorhsl.rg, 0.5));
|
||||
|
||||
vec3 envyuv = rgb2yuv(envcolor);
|
||||
texturecolor = mix(texturecolor, texturecolorfullv, envyuv.r * reflectivity);
|
||||
|
||||
if(lights_count == 0U)
|
||||
return (fragcolor + emissioncolor + envcolor * reflectivity) * texturecolor;
|
||||
|
||||
vec2 sunlight = calc_dir_light(lights[0], fragnormal);
|
||||
|
||||
// Sharpen N.L for stronger contrast between lit and shaded cab
|
||||
// surfaces (uses SUN_NDOTL_SHARPNESS from light_common.glsl).
|
||||
float sun_NdotL = pow(sunlight.x, SUN_NDOTL_SHARPNESS);
|
||||
float diffuseamount = sun_NdotL * lights[0].intensity;
|
||||
// the clouds hold back the sun where their shadow falls, as the shadow map does
|
||||
float cloudsun = cloud_shadow(mat3(inv_view) * f_pos.xyz);
|
||||
fragcolor += envcolor * reflectivity;
|
||||
float specularamount = (sunlight.y * param[1].y * specularity) * lights[0].intensity * cloudsun;
|
||||
glossiness = abs(param[1].w);
|
||||
|
||||
fragcolor = add_headlights(fragcolor, fragnormal);
|
||||
|
||||
if (shadowtone < 1.0)
|
||||
{
|
||||
float shadow = max(calc_shadow(), 1.0 - cloudsun);
|
||||
specularamount *= clamp(1.0 - shadow, 0.0, 1.0);
|
||||
fragcolor = mix(fragcolor, fragcolor * shadowtone, clamp(diffuseamount * shadow + specularamount, 0.0, 1.0));
|
||||
}
|
||||
fragcolor += emissioncolor;
|
||||
fragcolor *= texturecolor;
|
||||
|
||||
return fragcolor;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 tex_color = texture(diffuse, f_coord);
|
||||
@@ -100,6 +48,7 @@ void main()
|
||||
vec3 fragnormal = normalize(f_tbn * normalize(normal.xyz));
|
||||
float reflectivity = param[1].z * texture(normalmap, f_coord).a;
|
||||
float specularity = (tex_color.r + tex_color.g + tex_color.b) * 0.5;
|
||||
legacy_gloss();
|
||||
|
||||
fragcolor = apply_lights_sunless(fragcolor, fragnormal, tex_color.rgb, reflectivity, specularity, shadow_tone);
|
||||
vec4 color = vec4(apply_fog(fragcolor), tex_color.a * alpha_mult);
|
||||
|
||||
@@ -34,77 +34,6 @@ uniform sampler2D specgloss;
|
||||
#include <apply_fog.glsl>
|
||||
#include <tonemapping.glsl>
|
||||
|
||||
vec3 apply_lights_sunless(vec3 fragcolor, vec3 fragnormal, vec3 texturecolor, float reflectivity, float specularity, float shadowtone)
|
||||
{
|
||||
// diffuse colour applied once, to the albedo (see material_diffuse() in light_common.glsl)
|
||||
texturecolor *= material_diffuse();
|
||||
// Cab interior: dim ambient less than the exterior path - ambient
|
||||
// is the dominant indoor illumination, but it was still too bright.
|
||||
fragcolor *= 0.80;
|
||||
|
||||
vec3 emissioncolor = vec3(emission);
|
||||
|
||||
vec3 view_dir = normalize(-f_pos.xyz);
|
||||
float NdotV = max(dot(fragnormal, view_dir), 0.0);
|
||||
vec3 F0 = mix(vec3(0.04), texturecolor, metalic);
|
||||
vec3 fresnel = F0 + (1.0 - F0) * pow(1.0 - NdotV, 5.0);
|
||||
|
||||
float env_roughness = 1.0 - clamp(glossiness / max(abs(param[1].w), 1.0), 0.0, 1.0);
|
||||
vec3 envcolor = envmap_color_rough(fragnormal, env_roughness);
|
||||
|
||||
// Pre-integrated env BRDF (matches apply_lights): roughness-attenuated
|
||||
// reflection so matte cab surfaces no longer mirror the environment.
|
||||
vec3 env_spec = EnvBRDFApprox(F0, env_roughness, NdotV);
|
||||
float env_spec_w = max(env_spec.r, max(env_spec.g, env_spec.b));
|
||||
|
||||
vec3 texturecoloryuv = rgb2yuv(texturecolor);
|
||||
vec3 texturecolorfullv = yuv2rgb(vec3(0.2176, texturecoloryuv.gb));
|
||||
vec3 envyuv = rgb2yuv(envcolor);
|
||||
texturecolor = mix(texturecolor, texturecolorfullv, envyuv.r * reflectivity * env_spec_w);
|
||||
|
||||
if (lights_count == 0U)
|
||||
return fragcolor * texturecolor * (1.0 - metalic)
|
||||
+ emissioncolor * texturecolor
|
||||
+ envcolor * env_spec * reflectivity;
|
||||
|
||||
vec2 sunlight = calc_dir_light(lights[0], fragnormal);
|
||||
// Sharpen N.L for stronger contrast between lit and shaded cab
|
||||
// surfaces (uses SUN_NDOTL_SHARPNESS from light_common.glsl).
|
||||
float sun_NdotL = pow(sunlight.x, SUN_NDOTL_SHARPNESS);
|
||||
float diffuseamount = sun_NdotL * lights[0].intensity;
|
||||
// the clouds hold back the sun where their shadow falls, as the shadow map does
|
||||
float cloudsun = cloud_shadow(mat3(inv_view) * f_pos.xyz);
|
||||
|
||||
float specularamount = sunlight.y * param[1].y * specularity * lights[0].intensity * cloudsun;
|
||||
|
||||
fragcolor = add_headlights(fragcolor, fragnormal);
|
||||
|
||||
if (shadowtone < 1.0)
|
||||
{
|
||||
float shadow = max(calc_shadow(), 1.0 - cloudsun);
|
||||
specularamount *= clamp(1.0 - shadow, 0.0, 1.0);
|
||||
fragcolor = mix(fragcolor, fragcolor * shadowtone, clamp(diffuseamount * shadow, 0.0, 1.0));
|
||||
}
|
||||
|
||||
vec3 specularcolor = specularamount * lights[0].color;
|
||||
|
||||
// Env reflection gated by env BRDF (roughness-attenuated, F0-tinted).
|
||||
vec3 env_reflection = envcolor * env_spec * reflectivity;
|
||||
|
||||
// Physically-based metal/rough combine (matches apply_lights / Substance):
|
||||
// dielectric -> light-coloured highlight + full diffuse; metal -> albedo-tinted
|
||||
// highlight, no diffuse term. Highlight strength left unchanged.
|
||||
vec3 diffuse_albedo = texturecolor * (1.0 - metalic);
|
||||
vec3 spec_tint = mix(vec3(1.0), texturecolor, metalic);
|
||||
|
||||
vec3 result = fragcolor * diffuse_albedo
|
||||
+ specularcolor * spec_tint
|
||||
+ emissioncolor * texturecolor
|
||||
+ env_reflection; // env_spec already F0-tinted for metals
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 tex_color = texture(diffuse, f_coord);
|
||||
|
||||
@@ -43,6 +43,8 @@ uniform highp sampler2DArray layerspecgloss;
|
||||
uniform highp sampler2D layertable;
|
||||
|
||||
#define NORMALMAP
|
||||
// param[2] holds the placement of the chunk, not the weathering
|
||||
#define NO_WEATHERING
|
||||
#include <light_common.glsl>
|
||||
#include <apply_fog.glsl>
|
||||
#include <tonemapping.glsl>
|
||||
@@ -111,7 +113,9 @@ void main()
|
||||
}
|
||||
else
|
||||
{
|
||||
gloss += weight;
|
||||
// a layer without a specgloss map: a dielectric of the glossiness: of the material (a blinn-phong exponent)
|
||||
specularity += 0.5 * weight;
|
||||
gloss += (1.0 - phong_roughness(abs(param[1].w))) * weight;
|
||||
}
|
||||
reflectivity += layerreflection * weight;
|
||||
total += weight;
|
||||
|
||||
@@ -58,7 +58,8 @@ void main()
|
||||
normal.z = sqrt(1.0 - clamp((dot(normal.xy, normal.xy)), 0.0, 1.0));
|
||||
vec3 fragnormal = normalize(f_tbn * normalize(normal.xyz));
|
||||
float reflectivity = param[1].z * texture(normalmap, texture_coords ).a;
|
||||
float specularity = 1.0;
|
||||
// water reflects 2% at normal incidence
|
||||
float specularity = 0.25;
|
||||
glossiness = abs(param[1].w);
|
||||
|
||||
fragcolor = apply_lights(fragcolor, fragnormal, tex_color.rgb, reflectivity, specularity, shadow_tone);
|
||||
@@ -70,10 +71,10 @@ void main()
|
||||
|
||||
// fresnel effect
|
||||
vec3 view_dir = normalize(vec3(0.0f, 0.0f, 0.0f) - f_pos.xyz);
|
||||
float fresnel = pow ( dot (f_normal, view_dir), 0.2 );
|
||||
float fresnel = pow(max(dot(normalize(f_normal), view_dir), 0.0), 0.2);
|
||||
float fresnel_inv = ((fresnel - 1.0 ) * -1.0 );
|
||||
|
||||
vec4 color = vec4(apply_fog(clamp(fragcolor, 0.0, 1.0)), clamp((fresnel_inv + param[0].a), 0.0, 1.0));
|
||||
vec4 color = vec4(apply_fog(fragcolor), clamp((fresnel_inv + param[0].a), 0.0, 1.0));
|
||||
#if POSTFX_ENABLED
|
||||
out_color = color;
|
||||
#else
|
||||
|
||||
@@ -62,9 +62,10 @@ void main()
|
||||
normal.z = sqrt(1.0 - clamp((dot(normal.xy, normal.xy)), 0.0, 1.0));
|
||||
vec3 fragnormal = normalize(f_tbn * normalize(normal.xyz));
|
||||
float reflectivity = param[1].z * texture(normalmap, texture_coords ).a;
|
||||
float specularity = texture(specgloss, f_coord).r;
|
||||
glossiness = texture(specgloss, f_coord).g * abs(param[1].w);
|
||||
float metalic = texture(specgloss, f_coord).b;
|
||||
vec4 specgloss_map = texture(specgloss, texture_coords);
|
||||
float specularity = specgloss_map.r;
|
||||
glossiness = specgloss_map.g * abs(param[1].w);
|
||||
metalic = specgloss_map.b;
|
||||
|
||||
fragcolor = apply_lights(fragcolor, fragnormal, tex_color.rgb, reflectivity, specularity, shadow_tone);
|
||||
|
||||
@@ -75,10 +76,10 @@ void main()
|
||||
|
||||
// fresnel effect
|
||||
vec3 view_dir = normalize(vec3(0.0f, 0.0f, 0.0f) - f_pos.xyz);
|
||||
float fresnel = pow ( dot (f_normal, view_dir), 0.2 );
|
||||
float fresnel = pow(max(dot(normalize(f_normal), view_dir), 0.0), 0.2);
|
||||
float fresnel_inv = ((fresnel - 1.0 ) * -1.0 );
|
||||
|
||||
vec4 color = vec4(apply_fog(clamp(fragcolor, 0.0, 1.0)), clamp((fresnel_inv + param[0].a), 0.0, 1.0));
|
||||
vec4 color = vec4(apply_fog(fragcolor), clamp((fresnel_inv + param[0].a), 0.0, 1.0));
|
||||
#if POSTFX_ENABLED
|
||||
out_color = color;
|
||||
#else
|
||||
|
||||
@@ -38,9 +38,11 @@ void main()
|
||||
gl_Position = f_clip_pos;
|
||||
gl_PointSize = param[1].x;
|
||||
|
||||
vec3 T = normalize(mvn * v_tangent.xyz);
|
||||
vec3 N = f_normal;
|
||||
vec3 B = normalize(cross(N, T));
|
||||
vec3 T = mvn * v_tangent.xyz;
|
||||
T = normalize(T - N * dot(N, T));
|
||||
// w is -1 where the texture is mirrored (calculate_tangents()), the bitangent turns with it
|
||||
vec3 B = cross(N, T) * (v_tangent.w < 0.0 ? -1.0 : 1.0);
|
||||
f_tbn = mat3(T, B, N);
|
||||
|
||||
mat3 TBN = transpose(f_tbn);
|
||||
|
||||
Reference in New Issue
Block a user