mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-07-19 05:29:17 +02:00
Merge remote-tracking branch 'remotes/origin/opengl-instancing'
This commit is contained in:
@@ -27,8 +27,8 @@ float metalic = 0.0;
|
||||
// = sharper terminator (more contrast between
|
||||
// lit and shaded faces of the same surface).
|
||||
// ---------------------------------------------------------------------
|
||||
const float AMBIENT_SCALE = 0.65;
|
||||
const float SUN_DIFFUSE_SCALE = 2.5;
|
||||
const float AMBIENT_SCALE = 0.3;
|
||||
const float SUN_DIFFUSE_SCALE = 0.4;
|
||||
const float SUN_NDOTL_SHARPNESS = 1.25;
|
||||
|
||||
float length2(vec3 v)
|
||||
@@ -230,6 +230,32 @@ vec2 calc_headlights(light_s light, vec3 fragnormal)
|
||||
return part * atten * lightintensity;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Split-sum environment BRDF (Karis / UE4 analytic approximation).
|
||||
//
|
||||
// This is the missing piece that made matte specgloss surfaces "shine like
|
||||
// crazy": previously the env reflection was added at full strength
|
||||
// (envcolor * fresnel * reflectivity) and roughness only blurred the mip,
|
||||
// never dimmed the energy. A rough surface therefore mirrored the bright
|
||||
// sky just as strongly as a polished one.
|
||||
//
|
||||
// EnvBRDFApprox returns the pre-integrated specular scale (the "DFG" term)
|
||||
// for a given F0, roughness and view angle. For rough surfaces it collapses
|
||||
// toward ~0, so low-glossiness materials reflect almost nothing — matching
|
||||
// what Substance 3D Painter shows. Polished surfaces keep their full
|
||||
// reflection, and the grazing-angle Fresnel edge is preserved.
|
||||
// roughness 1.0 (matte) -> scale ~0.015 (virtually no reflection)
|
||||
// roughness 0.0 (mirror) -> scale ~F0..1 (full reflection + Fresnel rim)
|
||||
vec3 EnvBRDFApprox(vec3 F0, float roughness, float NoV)
|
||||
{
|
||||
const vec4 c0 = vec4(-1.0, -0.0275, -0.572, 0.022);
|
||||
const vec4 c1 = vec4( 1.0, 0.0425, 1.040, -0.040);
|
||||
vec4 r = roughness * c0 + c1;
|
||||
float a004 = min(r.x * r.x, exp2(-9.28 * NoV)) * r.x + r.y;
|
||||
vec2 AB = vec2(-1.04, 1.04) * a004 + r.zw;
|
||||
return F0 * AB.x + AB.y;
|
||||
}
|
||||
|
||||
// [0] - diffuse, [1] - specular
|
||||
// do magic here
|
||||
vec3 apply_lights(vec3 fragcolor, vec3 fragnormal, vec3 texturecolor, float reflectivity, float specularity, float shadowtone)
|
||||
@@ -251,15 +277,25 @@ vec3 apply_lights(vec3 fragcolor, vec3 fragnormal, vec3 texturecolor, float refl
|
||||
float env_roughness = 1.0 - clamp(glossiness / max(abs(param[1].w), 1.0), 0.0, 1.0);
|
||||
vec3 envcolor = envmap_color_lod(fragnormal, env_roughness * MAX_REFLECTION_LOD);
|
||||
|
||||
// Tint texture toward fully-saturated under strong env, weighted by fresnel
|
||||
// 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 * fresnel.r);
|
||||
texturecolor = mix(texturecolor, texturecolorfullv, envyuv.r * reflectivity * env_spec_w);
|
||||
|
||||
if (lights_count == 0U)
|
||||
return (fragcolor + emissioncolor) * texturecolor
|
||||
+ envcolor * fresnel * reflectivity;
|
||||
// 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)
|
||||
+ emissioncolor * texturecolor
|
||||
+ envcolor * env_spec * reflectivity;
|
||||
|
||||
vec2 sunlight = calc_dir_light(lights[0], fragnormal);
|
||||
// Sharpen sun N.L falloff so the lit-to-shaded terminator on cab
|
||||
@@ -289,20 +325,29 @@ vec3 apply_lights(vec3 fragcolor, vec3 fragnormal, vec3 texturecolor, float refl
|
||||
if (shadowtone < 1.0)
|
||||
specularamount *= clamp(1.0 - shadow1, 0.0, 1.0);
|
||||
|
||||
fragcolor += emissioncolor;
|
||||
vec3 specularcolor = specularamount * lights[0].color;
|
||||
|
||||
// Env reflection tracked separately — must NOT go through the albedo multiply below
|
||||
vec3 env_reflection = envcolor * fresnel * reflectivity * (1.0 - shadow1 * 0.5);
|
||||
// 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);
|
||||
|
||||
// Diffuse + specular: albedo tints diffuse, metals also tint specular
|
||||
vec3 result = mix(
|
||||
(fragcolor + specularcolor) * texturecolor,
|
||||
fragcolor * texturecolor + specularcolor,
|
||||
metalic);
|
||||
// --- 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);
|
||||
|
||||
// Env added after albedo multiply: raw for dielectrics, albedo-tinted for metals
|
||||
result += mix(env_reflection, env_reflection * texturecolor, metalic);
|
||||
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;
|
||||
}
|
||||
@@ -52,14 +52,20 @@ vec3 apply_lights_sunless(vec3 fragcolor, vec3 fragnormal, vec3 texturecolor, fl
|
||||
float env_roughness = 1.0 - clamp(glossiness / max(abs(param[1].w), 1.0), 0.0, 1.0);
|
||||
vec3 envcolor = envmap_color_lod(fragnormal, env_roughness * MAX_REFLECTION_LOD);
|
||||
|
||||
// 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 * fresnel.r);
|
||||
texturecolor = mix(texturecolor, texturecolorfullv, envyuv.r * reflectivity * env_spec_w);
|
||||
|
||||
if (lights_count == 0U)
|
||||
return (fragcolor + emissioncolor) * texturecolor
|
||||
+ envcolor * fresnel * reflectivity;
|
||||
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
|
||||
@@ -83,18 +89,21 @@ vec3 apply_lights_sunless(vec3 fragcolor, vec3 fragnormal, vec3 texturecolor, fl
|
||||
fragcolor = mix(fragcolor, fragcolor * shadowtone, clamp(diffuseamount * shadow, 0.0, 1.0));
|
||||
}
|
||||
|
||||
fragcolor += emissioncolor;
|
||||
vec3 specularcolor = specularamount * lights[0].color;
|
||||
|
||||
// Env reflection separate from albedo multiply — same fix as apply_lights
|
||||
vec3 env_reflection = envcolor * fresnel * reflectivity;
|
||||
// Env reflection gated by env BRDF (roughness-attenuated, F0-tinted).
|
||||
vec3 env_reflection = envcolor * env_spec * reflectivity;
|
||||
|
||||
vec3 result = mix(
|
||||
(fragcolor + specularcolor) * texturecolor,
|
||||
fragcolor * texturecolor + specularcolor,
|
||||
metalic);
|
||||
// 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);
|
||||
|
||||
result += mix(env_reflection, env_reflection * texturecolor, metalic);
|
||||
vec3 result = fragcolor * diffuse_albedo
|
||||
+ specularcolor * spec_tint
|
||||
+ emissioncolor * texturecolor
|
||||
+ env_reflection; // env_spec already F0-tinted for metals
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -40,23 +40,116 @@ vec3 filmic(vec3 x)
|
||||
return filmicF(x) / filmicF(vec3(11.2f));
|
||||
}
|
||||
|
||||
|
||||
// AgX tonemapping based on nxrighthere / Missing Deadlines implementation.
|
||||
// 0: Default, 1: Golden, 2: Punchy
|
||||
#ifndef AGX_LOOK
|
||||
#define AGX_LOOK 2
|
||||
#endif
|
||||
|
||||
vec3 AgxDefaultContrastApprox(vec3 x)
|
||||
{
|
||||
vec3 x2 = x * x;
|
||||
vec3 x4 = x2 * x2;
|
||||
|
||||
return 15.5 * x4 * x2
|
||||
- 40.14 * x4 * x
|
||||
+ 31.96 * x4
|
||||
- 6.868 * x2 * x
|
||||
+ 0.4298 * x2
|
||||
+ 0.1191 * x
|
||||
- 0.00232;
|
||||
}
|
||||
|
||||
vec3 Agx(vec3 val)
|
||||
{
|
||||
mat3 agx_mat = mat3(
|
||||
0.842479062253094, 0.0784335999999992, 0.0792237451477643,
|
||||
0.0423282422610123, 0.878468636469772, 0.0791661274605434,
|
||||
0.0423756549057051, 0.0784336, 0.879142973793104
|
||||
);
|
||||
|
||||
// DEFAULT_LOG2_MIN = -10.0
|
||||
// DEFAULT_LOG2_MAX = +6.5
|
||||
// MIDDLE_GRAY = 0.18
|
||||
// log2(pow(2, VALUE) * MIDDLE_GRAY)
|
||||
const float min_ev = -12.47393;
|
||||
const float max_ev = 0.526069;
|
||||
const float agx_eps = 1e-6;
|
||||
|
||||
// Input transform (inset)
|
||||
val = agx_mat * val;
|
||||
|
||||
// Log2 space encoding. max() avoids -INF/NaN for zero/negative inputs.
|
||||
val = clamp(log2(max(val, vec3(agx_eps))), min_ev, max_ev);
|
||||
val = (val - min_ev) / (max_ev - min_ev);
|
||||
|
||||
// Apply sigmoid function approximation.
|
||||
return AgxDefaultContrastApprox(val);
|
||||
}
|
||||
|
||||
vec3 AgxEotf(vec3 val)
|
||||
{
|
||||
mat3 agx_mat_inv = mat3(
|
||||
1.19687900512017, -0.0980208811401368, -0.0990297440797205,
|
||||
-0.0528968517574562, 1.15190312990417, -0.0989611768448433,
|
||||
-0.0529716355144438, -0.0980434501171241, 1.15107367264116
|
||||
);
|
||||
|
||||
// Inverse input transform (outset)
|
||||
val = agx_mat_inv * val;
|
||||
|
||||
// sRGB IEC 61966-2-1 2.2 Exponent Reference EOTF Display.
|
||||
// If your render target already applies sRGB conversion, replace this with:
|
||||
// return max(val, vec3(0.0));
|
||||
return pow(max(val, vec3(0.0)), vec3(2.2));
|
||||
}
|
||||
|
||||
vec3 AgxLook(vec3 val)
|
||||
{
|
||||
vec3 lw = vec3(0.2126, 0.7152, 0.0722);
|
||||
float luma = dot(val, lw);
|
||||
|
||||
vec3 offset = vec3(0.0);
|
||||
vec3 slope = vec3(1.0);
|
||||
vec3 power = vec3(1.0);
|
||||
float sat = 1.0;
|
||||
|
||||
#if AGX_LOOK == 1
|
||||
// Golden
|
||||
slope = vec3(1.0, 0.9, 0.5);
|
||||
power = vec3(0.8);
|
||||
sat = 0.8;
|
||||
#elif AGX_LOOK == 2
|
||||
// Punchy
|
||||
slope = vec3(1.0);
|
||||
power = vec3(1.35);
|
||||
sat = 1.4;
|
||||
#endif
|
||||
|
||||
// ASC CDL
|
||||
val = pow(max(val * slope + offset, vec3(0.0)), power);
|
||||
return vec3(luma) + sat * (val - vec3(luma));
|
||||
}
|
||||
|
||||
vec3 ApplyAgX(vec3 linearColorRec709)
|
||||
{
|
||||
linearColorRec709 = Agx(linearColorRec709);
|
||||
linearColorRec709 = AgxLook(linearColorRec709);
|
||||
linearColorRec709 = AgxEotf(linearColorRec709);
|
||||
return linearColorRec709;
|
||||
}
|
||||
|
||||
vec4 tonemap(vec4 x)
|
||||
{
|
||||
// Use ACES Filmic by default. Reinhard above kept for reference, but
|
||||
// with pureWhite=1.0 it collapses to identity (L*(1+L)/(1+L) = L) and
|
||||
// just clips HDR>1.0 at the framebuffer -> washed-out / burnt look.
|
||||
// ACES gives a smooth highlight shoulder + slight toe contrast.
|
||||
// Use AgX by default. Reinhard and ACES above are kept for reference.
|
||||
|
||||
// Last-line-of-defense sanitize. ACESFilm has the form
|
||||
// (x*(a*x+b)) / (x*(c*x+d)+e)
|
||||
// which maps NaN -> NaN and +Inf -> NaN (Inf/Inf). Either turns the
|
||||
// pixel black after framebuffer clamp. A negative HDR input feeds a
|
||||
// negative numerator/denominator and can produce non-physical output
|
||||
// that also looks like a black flash. Clamp to a sensible range
|
||||
// before the curve so a single bad upstream pixel can't escape.
|
||||
// Last-line-of-defense sanitize so NaN/Inf/negative HDR values do not
|
||||
// escape into log2()/pow() and produce black flashes or invalid output.
|
||||
vec3 hdr = x.rgb;
|
||||
hdr = mix(hdr, vec3(0.0), vec3(any(isnan(hdr)) || any(isinf(hdr))));
|
||||
hdr = max(hdr, vec3(0.0));
|
||||
return FBOUT(vec4(ACESFilm(hdr), x.a));
|
||||
return FBOUT(vec4(ApplyAgX(hdr), x.a));
|
||||
//return FBOUT(vec4(ACESFilm(hdr), x.a));
|
||||
//return FBOUT(vec4(reinhard(x.rgb), x.a));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user