Bliss-Shader/shaders/lib/specular.glsl
Xonk 25a2284a60 LOTS of fixes, changes, improvements. changes made is bloated because of a skill issue.
FIXED AND IMPROVED translucent rendering. FIXED random stuff from rendering over the hand. FIXED hand shading. FIXED blue horses. FIXED translucent lighting on the hand. FIXED translucent lighting on entities. IMPROVED colored shadows. IMPROVED SSAO application to the scene. IMPROVED subsurface scattering and give it more settings. IMPROVED bloom. ADD AgX tonemap and make it default.
2024-05-04 21:08:24 -04:00

285 lines
9.9 KiB
GLSL

uniform int framemod8;
const vec2[8] offsets = vec2[8](vec2(1./8.,-3./8.),
vec2(-1.,3.)/8.,
vec2(5.0,1.)/8.,
vec2(-3,-5.)/8.,
vec2(-5.,5.)/8.,
vec2(-7.,-1.)/8.,
vec2(3,7.)/8.,
vec2(7.,-7.)/8.);
vec3 lerp(vec3 X, vec3 Y, float A){
return X * (1.0 - A) + Y * A;
}
float lerp(float X, float Y, float A){
return X * (1.0 - A) + Y * A;
}
float square(float x){
return x*x;
}
vec3 toClipSpace3(vec3 viewSpacePosition) {
return projMAD(gbufferProjection, viewSpacePosition) / -viewSpacePosition.z * 0.5 + 0.5;
}
float invLinZ (float lindepth){
return -((2.0*near/lindepth)-far-near)/(far-near);
}
float linZ(float depth) {
return (2.0 * near) / (far + near - depth * (far - near));
// l = (2*n)/(f+n-d(f-n))
// f+n-d(f-n) = 2n/l
// -d(f-n) = ((2n/l)-f-n)
// d = -((2n/l)-f-n)/(f-n)
}
void frisvad(in vec3 n, out vec3 f, out vec3 r){
if(n.z < -0.9) {
f = vec3(0.,-1,0);
r = vec3(-1, 0, 0);
} else {
float a = 1./(1.+n.z);
float b = -n.x*n.y*a;
f = vec3(1. - n.x*n.x*a, b, -n.x) ;
r = vec3(b, 1. - n.y*n.y*a , -n.y);
}
}
mat3 CoordBase(vec3 n){
vec3 x,y;
frisvad(n,x,y);
return mat3(x,y,n);
}
vec2 R2_Sample(int n){
vec2 alpha = vec2(0.75487765, 0.56984026);
return fract(alpha * n);
}
vec3 rayTraceSpeculars(vec3 dir, vec3 position, float dither, float quality, bool hand, inout float reflectLength){
vec3 clipPosition = toClipSpace3(position);
float rayLength = ((position.z + dir.z * far*sqrt(3.)) > -near) ?
(-near -position.z) / dir.z : far*sqrt(3.);
vec3 direction = normalize(toClipSpace3(position+dir*rayLength)-clipPosition); //convert to clip space
direction.xy = normalize(direction.xy);
//get at which length the ray intersects with the edge of the screen
vec3 maxLengths = (step(0.0,direction)-clipPosition) / direction;
float mult = min(min(maxLengths.x,maxLengths.y),maxLengths.z);
vec3 stepv = direction * mult / quality*vec3(RENDER_SCALE,1.0);
vec3 spos = clipPosition*vec3(RENDER_SCALE,1.0) + stepv*dither;
float minZ = spos.z;
float maxZ = spos.z;
spos.xy += TAA_Offset*texelSize*0.5/RENDER_SCALE;
float depthcancleoffset = pow(1.0-(quality/reflection_quality),1.0);
float dist = 1.0 + clamp(position.z*position.z/50.0,0.0,2.0); // shrink sample size as distance increases
for (int i = 0; i <= int(quality); i++) {
float sp = invLinZ(sqrt(texelFetch2D(colortex4,ivec2(spos.xy/texelSize/4.0),0).a/65000.0));
if(sp <= max(maxZ,minZ) && sp >= min(maxZ,minZ) ) return vec3(spos.xy/RENDER_SCALE,sp);
spos += stepv;
//small bias
float biasamount = (0.0002 + 0.0015*pow(depthcancleoffset,5) ) / dist;
if(hand) biasamount = 0.00035;
minZ = maxZ-biasamount / ld(spos.z);
maxZ += stepv.z;
reflectLength += 1.0 / quality; // for shit
}
return vec3(1.1);
}
float fma(float a,float b,float c){
return a * b + c;
}
//// thank you Zombye | the paper: https://ggx-research.github.io/publication/2023/06/09/publication-ggx.html
vec3 SampleVNDFGGX(
vec3 viewerDirection, // Direction pointing towards the viewer, oriented such that +Z corresponds to the surface normal
vec2 alpha, // Roughness parameter along X and Y of the distribution
float xy // Pair of uniformly distributed numbers in [0, 1)
) {
// alpha *= alpha;
// Transform viewer direction to the hemisphere configuration
viewerDirection = normalize(vec3(alpha * viewerDirection.xy, viewerDirection.z));
// Sample a reflection direction off the hemisphere
const float tau = 6.2831853; // 2 * pi
float phi = tau * xy;
float cosTheta = fma(1.0 - xy, 1.0 + viewerDirection.z, -viewerDirection.z) ;
float sinTheta = sqrt(clamp(1.0 - cosTheta * cosTheta, 0.0, 1.0));
// xonk note, i dont know what im doing but this kinda does what i want so whatever
float attemptTailClamp = clamp(sinTheta,max(cosTheta-0.25,0), cosTheta);
float attemptTailClamp2 = clamp(cosTheta,max(sinTheta-0.25,0), sinTheta);
vec3 reflected = vec3(vec2(cos(phi), sin(phi)) * attemptTailClamp2, attemptTailClamp);
// vec3 reflected = vec3(vec2(cos(phi), sin(phi)) * sinTheta, cosTheta);
// Evaluate halfway direction
// This gives the normal on the hemisphere
vec3 halfway = reflected + viewerDirection;
// Transform the halfway direction back to hemiellispoid configuation
// This gives the final sampled normal
return normalize(vec3(alpha * halfway.xy, halfway.z));
}
float GGX(vec3 n, vec3 v, vec3 l, float r, float f0) {
r = max(pow(r,2.5), 0.0001);
vec3 h = l + v;
float hn = inversesqrt(dot(h, h));
float dotLH = clamp(dot(h,l)*hn,0.,1.);
float dotNH = clamp(dot(h,n)*hn,0.,1.) ;
float dotNL = clamp(dot(n,l),0.,1.);
float dotNHsq = dotNH*dotNH;
float denom = dotNHsq * r - dotNHsq + 1.;
float D = r / (3.141592653589793 * denom * denom);
float F = f0 + (1. - f0) * exp2((-5.55473*dotLH-6.98316)*dotLH);
float k2 = .25 * r;
return dotNL * D * F / (dotLH*dotLH*(1.0-k2)+k2);
}
void DoSpecularReflections(
inout vec3 Output,
vec3 FragPos, // toScreenspace(vec3(screenUV, depth)
vec3 WorldPos,
vec3 LightPos, // should be in world space
vec2 Noise, // x = bluenoise z = interleaved gradient noise
vec3 Normal, // normals in world space
float Roughness, // red channel of specular texture _S
float F0, // green channel of specular texture _S
vec3 Albedo,
vec3 Diffuse, // should contain the light color and NdotL. and maybe shadows.
float Lightmap, // in anything other than world0, this should be 1.0;
bool Hand // mask for the hand
){
vec3 Final_Reflection = Output;
vec3 Background_Reflection = Output;
vec3 Lightsource_Reflection = vec3(0.0);
vec4 SS_Reflections = vec4(0.0);
Lightmap = clamp((Lightmap-0.8)*7.0, 0.0,1.0);
Roughness = 1.0 - Roughness; Roughness *= Roughness;
F0 = F0 == 0.0 ? 0.02 : F0;
// Roughness = 0.1;
// F0 = 0.9;
mat3 Basis = CoordBase(Normal);
vec3 ViewDir = -WorldPos*Basis;
#ifdef Rough_reflections
vec3 SamplePoints = SampleVNDFGGX(ViewDir, vec2(Roughness), Noise.x);
if(Hand) SamplePoints = vec3(0.0,0.0,1.0);
#else
vec3 SamplePoints = vec3(0.0,0.0,1.0);
#endif
vec3 Ln = reflect(-ViewDir, SamplePoints);
vec3 L = Basis * Ln;
float Fresnel = pow(clamp(1.0 + dot(-Ln, SamplePoints),0.0,1.0), 5.0); // Schlick's approximation
float RayContribution = lerp(F0, 1.0, Fresnel); // ensure that when the angle is 0 that the correct F0 is used.
#ifdef Rough_reflections
if(Hand) RayContribution = RayContribution * pow(1.0-Roughness,F0 > 229.5/255.0 ? 1.0 : 3.0);
#else
RayContribution = RayContribution * pow(1.0-Roughness,3.0);
#endif
bool hasReflections = Roughness_Threshold == 1.0 ? true : F0 * (1.0 - Roughness * Roughness_Threshold) > 0.01;
// mulitply all reflections by the albedo if it is a metal.
// vec3 Metals = F0 > 229.5/255.0 ? lerp(normalize(Albedo+1e-7) * (dot(Albedo,vec3(0.21, 0.72, 0.07)) * 0.7 + 0.3), vec3(1.0), Fresnel * pow(1.0-Roughness,25.0)) : vec3(1.0);
vec3 Metals = F0 > 229.5/255.0 ? normalize(Albedo+1e-7) * (dot(Albedo,vec3(0.21, 0.72, 0.07)) * 0.7 + 0.3) : vec3(1.0);
// vec3 Metals = F0 > 229.5/255.0 ? Albedo : vec3(1.0);
// --------------- BACKGROUND REFLECTIONS
// apply background reflections to the final color. make sure it does not exist based on the lightmap
#ifdef Sky_reflection
#ifdef OVERWORLD_SHADER
if(hasReflections) Background_Reflection = (skyCloudsFromTexLOD(L, colortex4, sqrt(Roughness) * 9.0).rgb / 30.0) * Metals;
#else
if(hasReflections) Background_Reflection = (skyCloudsFromTexLOD2(L, colortex4, sqrt(Roughness) * 6.0).rgb / 30.0) * Metals;
#endif
// take fresnel and lightmap levels into account and write to the final color
Final_Reflection = lerp(Output, Background_Reflection, Lightmap * RayContribution);
#endif
// --------------- SCREENSPACE REFLECTIONS
// apply screenspace reflections to the final color and mask out background reflections.
#ifdef Screen_Space_Reflections
if(hasReflections){
#ifdef Dynamic_SSR_quality
float SSR_Quality = lerp(reflection_quality, 6.0, RayContribution); // Scale quality with ray contribution
#else
float SSR_Quality = reflection_quality;
#endif
float reflectLength = 0.0;
vec3 RaytracePos = rayTraceSpeculars(mat3(gbufferModelView) * L, FragPos, Noise.y, float(SSR_Quality), Hand, reflectLength);
float LOD = clamp(pow(reflectLength, pow(1.0-sqrt(Roughness),5.0) * 3.0) * 6.0, 0.0, 6.0); // use higher LOD as the reflection goes on, to blur it. this helps denoise a little.
if(Roughness <= 0.0) LOD = 0.0;
if (RaytracePos.z < 1.0){
vec3 previousPosition = mat3(gbufferModelViewInverse) * toScreenSpace(RaytracePos) + gbufferModelViewInverse[3].xyz + cameraPosition-previousCameraPosition;
previousPosition = mat3(gbufferPreviousModelView) * previousPosition + gbufferPreviousModelView[3].xyz;
previousPosition.xy = projMAD(gbufferPreviousProjection, previousPosition).xy / -previousPosition.z * 0.5 + 0.5;
if (previousPosition.x > 0.0 && previousPosition.y > 0.0 && previousPosition.x < 1.0 && previousPosition.x < 1.0) {
SS_Reflections.a = 1.0;
SS_Reflections.rgb = texture2DLod(colortex5, previousPosition.xy, LOD).rgb * Metals;
}
}
// make sure it takes the fresnel into account for SSR.
SS_Reflections.rgb = lerp(Output, SS_Reflections.rgb, RayContribution);
// occlude the background with the SSR and write to the final color.
Final_Reflection = lerp(Final_Reflection, SS_Reflections.rgb, SS_Reflections.a);
}
#endif
// Final_Reflection = mix(mix(Output,Background_Reflection,Lightmap), SS_Reflections.rgb, SS_Reflections.a) * RayContribution;
// --------------- LIGHTSOURCE REFLECTIONS
// slap the main lightsource reflections to the final color.
#ifdef LIGHTSOURCE_REFLECTION
Lightsource_Reflection = Diffuse * GGX(Normal, -WorldPos, LightPos, Roughness, F0) * Metals;
Final_Reflection += Lightsource_Reflection * Sun_specular_Strength ;
#endif
Output = Final_Reflection;
}