1059 lines
28 KiB
GLSL
Executable File
1059 lines
28 KiB
GLSL
Executable File
|
|
#version 300 es
|
|
|
|
precision highp float;
|
|
|
|
#ifndef NORMAL_MAP
|
|
#define NORMAL_MAP 0
|
|
#endif
|
|
|
|
#ifndef PARALLAX
|
|
#define PARALLAX 0
|
|
#endif
|
|
|
|
in vec3 position;
|
|
in vec2 textcoord;
|
|
|
|
in vec3 normal;
|
|
in vec3 tangent;
|
|
in vec3 bitangent;
|
|
|
|
uniform mat4 world;
|
|
uniform mat4 view;
|
|
uniform mat4 viewProjection;
|
|
uniform mat4 worldInverseTranspose;
|
|
uniform float normals;
|
|
|
|
|
|
|
|
|
|
out vec2 v_textcoord;
|
|
|
|
out vec4 v_normal;
|
|
out vec4 v_tangent;
|
|
out vec4 v_binormal;
|
|
out vec2 v_offset;
|
|
out vec4 v_worldposition;
|
|
out vec4 v_position;
|
|
|
|
out float v_depth;
|
|
|
|
out vec3 v_view;
|
|
|
|
|
|
|
|
//mat3 transpose(mat3 matrix) {
|
|
//
|
|
// return mat3( matrix[0].x, matrix[1].x, matrix[2].x,
|
|
// matrix[0].y, matrix[1].y, matrix[2].y,
|
|
// matrix[0].z, matrix[1].z, matrix[2].z );
|
|
//
|
|
//}
|
|
|
|
void main(void) {
|
|
|
|
v_textcoord = textcoord;
|
|
|
|
v_normal = normalize(worldInverseTranspose * vec4(normal, 0.0));
|
|
|
|
|
|
#if NORMAL_MAP == 1
|
|
|
|
v_tangent = normalize(worldInverseTranspose * vec4(tangent, 0.0) );
|
|
v_binormal = normalize(worldInverseTranspose * vec4(bitangent, 0.0) );
|
|
//v_binormal = vec4(cross(v_normal.xyz, v_tangent.xyz), 0.0);
|
|
|
|
#endif
|
|
|
|
|
|
#if PARALLAX == 1
|
|
|
|
const float height_map_range = 0.32;
|
|
|
|
vec3 vs_normal = ( view * v_normal ).xyz;
|
|
vec3 vs_tangent = ( view * v_tangent ).xyz;
|
|
vec3 vs_bitangent = ( view * vec4(v_binormal, 0.0) ).xyz;
|
|
//vec3 vs_bitangent = bitangent;
|
|
|
|
|
|
vec4 a = view * vec4(position, 1.0);
|
|
|
|
v_view = a.xyz;
|
|
|
|
mat3 tbn = mat3( normalize(vs_tangent), normalize(vs_bitangent), normalize(vs_normal) );
|
|
mat3 vs_to_ts = transpose( tbn );
|
|
|
|
vec3 ts_view = vs_to_ts * v_view;
|
|
|
|
v_offset = (ts_view.xy / ts_view.z) * height_map_range;
|
|
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
v_worldposition = world * vec4(position, 1.0);
|
|
v_position = viewProjection * vec4(position, 1.0);
|
|
v_depth = v_position.z;
|
|
|
|
gl_Position = v_position;
|
|
|
|
}
|
|
|
|
|
|
|
|
// #keplerEngine - Split
|
|
|
|
#version 300 es
|
|
|
|
precision highp float;
|
|
|
|
#define PI 3.14159265358979323846
|
|
|
|
|
|
|
|
|
|
|
|
|
|
layout(location = 0) out vec4 deferred_diffuse_roughness;
|
|
layout(location = 1) out vec4 deferred_normal_depth;
|
|
layout(location = 2) out vec4 deferred_position_material_ID;
|
|
layout(location = 3) out vec4 tangent;
|
|
|
|
//layout(location = 3) out vec4 deferred_material_1;
|
|
|
|
|
|
in vec2 v_textcoord;
|
|
in vec4 v_normal;
|
|
in vec4 v_tangent;
|
|
in vec4 v_binormal;
|
|
|
|
in vec4 v_worldposition;
|
|
in vec4 v_position;
|
|
|
|
in float v_depth;
|
|
|
|
in vec2 v_offset;
|
|
in vec3 v_view;
|
|
|
|
|
|
const float gamma = 2.2;
|
|
|
|
//pbr
|
|
uniform samplerCube reflectionSampler;
|
|
|
|
uniform vec3 cameraPosition;
|
|
uniform vec3 lightGeometry;
|
|
uniform float clearCoat;
|
|
uniform vec3 clearCoatColor;
|
|
uniform float clearCoatThickness;
|
|
uniform float clearCoatRoughness;
|
|
|
|
uniform float clearCoatIOR;
|
|
uniform float anisotropy;
|
|
|
|
uniform vec3 lightDirection;
|
|
uniform vec3 lightColor;
|
|
uniform float lightIntensity;
|
|
uniform float environmentLuminance;
|
|
uniform float v_metallic;
|
|
uniform float v_reflectance;
|
|
uniform float lightType;
|
|
uniform vec3 lightPosition;
|
|
|
|
#define ANISOTROPY 0
|
|
#define USE_IES_PROFILE 0
|
|
#define TRANSPARENT_MATERIAL 0
|
|
#define TRANSLUCENT_MATERIAL 0
|
|
#define CUBEMAP_EDGE_FIXUP 0
|
|
|
|
struct PixelParams {
|
|
vec3 diffuseColor;
|
|
vec3 f0;
|
|
float roughness;
|
|
float clearCoatRoughness;
|
|
float ao;
|
|
float eta;
|
|
float refracted_NoV;
|
|
};
|
|
|
|
const float PackUpscale = 256. / 255.; // fraction -> 0..1 (including 1)
|
|
const float UnpackDownscale = 255. / 256.; // 0..1 -> fraction (excluding 1)
|
|
|
|
const vec3 PackFactors = vec3( 256. * 256. * 256., 256. * 256., 256. );
|
|
const vec4 UnpackFactors = UnpackDownscale / vec4( PackFactors, 1. );
|
|
|
|
const float ShiftRight8 = 1. / 256.;
|
|
|
|
vec4 packDepthToRGBA( const in float v ) {
|
|
vec4 r = vec4( fract( v * PackFactors ), v );
|
|
r.yzw -= r.xyz * ShiftRight8; // tidy overflow
|
|
return r * PackUpscale;
|
|
}
|
|
|
|
float unpackRGBAToDepth( const in vec4 v ) {
|
|
return dot( v, UnpackFactors );
|
|
}
|
|
|
|
float D_GGX(float NoH, float a) {
|
|
float a2 = a * a;
|
|
float f = (NoH * a2 - NoH) * NoH + 1.0;
|
|
return a2 / (PI * f * f);
|
|
}
|
|
|
|
float D_GGX_Anisotropy(float NoH, vec3 h, vec3 x, vec3 y, float ax, float ay) {
|
|
float XoH = dot(x, h);
|
|
float YoH = dot(y, h);
|
|
float d = XoH * XoH * (ax * ax) + YoH * YoH * (ay * ay) + NoH * NoH;
|
|
return (ax * ay) / (PI * d * d);
|
|
}
|
|
|
|
vec3 F_Schlick(float VoH, vec3 f0, float f90) {
|
|
return f0 + (vec3(f90) - f0) * pow(1.0 - VoH, 5.0);
|
|
}
|
|
|
|
// Smith-GGX correlated for microfacets height
|
|
float V_SmithGGXCorrelated(float NoV, float NoL, float a) {
|
|
float a2 = a * a;
|
|
float GGXL = NoV * sqrt((-NoL * a2 + NoL) * NoL + a2);
|
|
float GGXV = NoL * sqrt((-NoV * a2 + NoV) * NoV + a2);
|
|
// approximation
|
|
// float GGXL = NoV * (NoL * (1.0 - a) + a);
|
|
// float GGXV = NoL * (NoV * (1.0 - a) + a);
|
|
return 0.5 / (GGXV + GGXL);
|
|
}
|
|
|
|
float Fd_Lambert() {
|
|
return 1.0 / PI;
|
|
}
|
|
|
|
float F_Schlick_Scalar(float VoH, float f0, float f90) {
|
|
return f0 + (f90 - f0) * pow(1.0 - VoH, 5.0);
|
|
}
|
|
|
|
float square(float v) {
|
|
return v * v;
|
|
}
|
|
|
|
vec3 irradianceSH(vec3 n) {
|
|
//vec3 sphericalHarmonics[8] =
|
|
// return
|
|
// sphericalHarmonics[0]
|
|
// + sphericalHarmonics[1] * (n.y)
|
|
// + sphericalHarmonics[2] * (n.z)
|
|
// + sphericalHarmonics[3] * (n.x)
|
|
// + sphericalHarmonics[4] * (n.y * n.x)
|
|
// + sphericalHarmonics[5] * (n.y * n.z)
|
|
// + sphericalHarmonics[6] * (3.0 * n.z * n.z - 1.0)
|
|
/// + sphericalHarmonics[7] * (n.z * n.x)
|
|
// + sphericalHarmonics[8] * (n.x * n.x - n.y * n.y);
|
|
|
|
return
|
|
vec3(0.754553530212464, 0.748541695286661, 0.790922541330174)
|
|
+ vec3(-0.083855089181764, 0.092536341322488, 0.322767327275582) * (n.y)
|
|
+ vec3(0.308154551673257, 0.366799355358085, 0.466705760819624) * (n.z)
|
|
+ vec3(-0.188887618191928, -0.277403749518126, -0.377844811540716) * (n.x)
|
|
|
|
+ vec3(-0.252782448589491, -0.316051613736677, -0.396141020484574) * (n.y * n.x)
|
|
+ vec3(0.071362454444021, 0.159789075773366, 0.29059362717571) * (n.y * n.z)
|
|
+ vec3(-0.031040420617065, -0.031141089772695, -0.031044001883204) * (3.0 * n.z * n.z - 1.0)
|
|
+ vec3(-0.161001896026477, -0.203649521035777, -0.246641086569566) * (n.z * n.x)
|
|
+ vec3(0.045710934605387, 0.048121779682969, 0.046326375668417) * (n.x * n.x - n.y * n.y);
|
|
}
|
|
|
|
vec2 prefilteredDFGKaris(float NoV, float roughness) {
|
|
// see https://www.unrealengine.com/blog/physically-based-shading-on-mobile
|
|
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;
|
|
return vec2(-1.04, 1.04) * a004 + r.zw;
|
|
}
|
|
|
|
|
|
|
|
float sRGBtoLinear(float c) {
|
|
return (c <= 0.04045) ? c / 12.92 : pow((c + 0.055) / 1.055, 2.4);
|
|
}
|
|
|
|
vec3 sRGBtoLinear(vec3 c) {
|
|
return vec3(sRGBtoLinear(c.r), sRGBtoLinear(c.g), sRGBtoLinear(c.b));
|
|
}
|
|
|
|
|
|
vec3 decodeEnvironmentMap(vec4 c) {
|
|
return c.rgb;
|
|
return sRGBtoLinear(c.rgb);
|
|
|
|
|
|
//;sRGBtoLinear(c.rgb) ;
|
|
}
|
|
|
|
|
|
//#if TEXTURED_MATERIAL == 1
|
|
//float getMaterialAmbientOcclusion() {
|
|
// return texture(aoMap, outUV).r;
|
|
//}
|
|
//#else
|
|
float getMaterialAmbientOcclusion() {
|
|
return 1.0;
|
|
}
|
|
//#endif
|
|
|
|
float getSquareFalloffAttenuation(float distanceSquare) {
|
|
float factor = distanceSquare * lightGeometry.x;
|
|
float smoothFactor = max(1.0 - factor * factor, 0.0);
|
|
// we would normally divide by the square distance here
|
|
// but we do it at the call site
|
|
return smoothFactor * smoothFactor;
|
|
}
|
|
|
|
//#if USE_IES_PROFILE == 1
|
|
//float getPhotometricAttenuation(vec3 lightToPos, vec3 lightDir) {
|
|
// float cosTheta = dot(lightToPos, lightDir);
|
|
// float angle = acos(cosTheta) * (1.0 / PI);
|
|
// return textureLodEXT(reflectionSampler, vec2(angle, 0.0), 0.0).r;
|
|
//}
|
|
//#else
|
|
float getPhotometricAttenuation(vec3 lightToPos, vec3 lightDir) {
|
|
return 1.0;
|
|
}
|
|
//#endif
|
|
|
|
float getAngleAttenuation(vec3 l, vec3 lightDir) {
|
|
float cd = dot(lightDir, l);
|
|
float attenuation = clamp(cd * lightGeometry.y + lightGeometry.z, 0.0, 1.0);
|
|
return attenuation * attenuation;
|
|
}
|
|
|
|
vec3 beerLambert(float NoV, float NoL, vec3 alpha, float d) {
|
|
return exp(alpha * -(d * ((NoL + NoV) / max(NoL * NoV, 1e-3))));
|
|
}
|
|
|
|
vec3 evaluateLight(vec3 n, vec3 v, PixelParams params, vec3 outWorldPosition, vec3 outWorldTangent, float shadow) {
|
|
vec3 l;
|
|
float NoL;
|
|
float energy;
|
|
float attenuation;
|
|
|
|
vec3 lightDir = normalize(lightDirection);
|
|
float linearRoughness = params.roughness * params.roughness;
|
|
|
|
vec3 r = reflect(-v, n);
|
|
|
|
if (lightType == 1.0) {
|
|
|
|
l = -lightDir;
|
|
|
|
// Disc area light
|
|
vec3 sunDir = -lightDir;
|
|
float e = sin(radians(0.53));
|
|
float d = cos(radians(0.53));
|
|
float DoR = dot(sunDir, r);
|
|
vec3 s = r - DoR * sunDir;
|
|
l = DoR < d ? normalize(d * sunDir + normalize(s) * e) : r;
|
|
|
|
NoL = dot(n, l);
|
|
energy = 1.0;
|
|
attenuation = 1.0;
|
|
|
|
|
|
} else if (lightType == 0.0) {
|
|
|
|
vec3 posToLight = lightPosition - outWorldPosition;
|
|
float distanceSquare = dot(posToLight, posToLight);
|
|
l = normalize(posToLight);
|
|
NoL = dot(n, l);
|
|
energy = 50.0;
|
|
attenuation = getSquareFalloffAttenuation(distanceSquare);
|
|
attenuation *= 1.0 / max(distanceSquare, 1e-4);
|
|
attenuation *= getPhotometricAttenuation(-l, lightDir);
|
|
// if (lightGeometry.w >= 1.0) {
|
|
// attenuation *= getAngleAttenuation(l, -lightDir);
|
|
// }
|
|
}
|
|
|
|
|
|
vec3 h = normalize(v + l);
|
|
|
|
NoL = clamp(NoL, 0.0, 1.0);
|
|
float NoV = abs(dot(n, v)) + 1e-5;
|
|
float NoH = clamp(dot(n, h), 0.0, 1.0);
|
|
float LoH = clamp(dot(l, h), 0.0, 1.0);
|
|
|
|
// specular BRDF
|
|
#if ANISOTROPY == 1
|
|
vec3 t = normalize(v_tangent.xyz);
|
|
vec3 b = normalize(cross(t, n));
|
|
|
|
float aspect = inversesqrt(1.0 - anisotropy * 0.9);
|
|
float ax = 1.0 / (linearRoughness * aspect);
|
|
float ay = aspect / linearRoughness;
|
|
|
|
float D = D_GGX_Anisotropy(NoH, h, t, b, ax, ay);
|
|
#else
|
|
float D = D_GGX(NoH, linearRoughness);
|
|
#endif
|
|
vec3 F = F_Schlick(LoH, params.f0, clamp(dot(params.f0, vec3(50.0 * 0.33)), 0.0, 1.0));
|
|
float V = V_SmithGGXCorrelated(NoV, NoL, linearRoughness);
|
|
vec3 Fr = (D * V) * F;
|
|
|
|
// diffuse BRDF
|
|
vec3 Fd = params.diffuseColor * Fd_Lambert();// * 3.6
|
|
|
|
// clear coat
|
|
float linearClearCoatRoughness = params.clearCoatRoughness * params.clearCoatRoughness;
|
|
float Dcc = D_GGX(NoH, linearClearCoatRoughness);
|
|
float Fcc = F_Schlick_Scalar(LoH, 0.04, 1.0) * clearCoat;
|
|
float Vcc = V_SmithGGXCorrelated(NoV, NoL, linearClearCoatRoughness);
|
|
float FrCC = Dcc * Vcc * Fcc;
|
|
|
|
vec3 refracted_l = -refract(l, n, params.eta);
|
|
float refracted_NoL = clamp(dot(n, refracted_l), 0.0, 1.0);
|
|
vec3 clearCoatAbsorption = mix(vec3(1.0),
|
|
beerLambert(params.refracted_NoV, refracted_NoL, clearCoatColor, clearCoatThickness),
|
|
clearCoat);
|
|
|
|
// direct contribution
|
|
vec3 color = (attenuation * NoL) * lightColor * lightIntensity * energy *
|
|
((Fd + Fr) * (1.0 - Fcc) * clearCoatAbsorption + FrCC);
|
|
|
|
#if TRANSLUCENT_MATERIAL == 1
|
|
vec3 tL = l + n * translucencyDistortion;
|
|
float tD = exp2(clamp(dot(v, -tL), 0.0, 1.0) * translucencyPower - translucencyPower) * translucencyScale;
|
|
vec3 tT = attenuation * lightIntensity * (tD + translucencyAmbient) * texture(translucencyThicknessMap, outUV).r;
|
|
color.rgb += Fd * lightColor * tT;
|
|
#endif
|
|
|
|
// micro-shadowing
|
|
float aperture = 2.0 * params.ao * params.ao * shadow;
|
|
float microShadow = clamp(abs(dot(l, n)) + aperture - 1.0, 0.0, 1.0);
|
|
color.rgb *= microShadow;
|
|
|
|
return color;
|
|
}
|
|
|
|
|
|
vec3 fixCubemapLookup(vec3 v, float lod) {
|
|
vec3 r = abs(v);
|
|
float M = max(max(v.x, v.y), v.z);
|
|
float scale = 1.0 - exp2(lod) * (1.0 / 256.0);
|
|
if (v.x != M) v.x *= scale;
|
|
if (v.y != M) v.y *= scale;
|
|
if (v.z != M) v.z *= scale;
|
|
return v;
|
|
}
|
|
|
|
|
|
vec3 evaluateSpecularIBL(vec3 r, float roughness) {
|
|
float lod = 5.0 * roughness;
|
|
|
|
r = fixCubemapLookup(r, lod);
|
|
|
|
return decodeEnvironmentMap( texture(reflectionSampler, r, lod) ); //, lod
|
|
}
|
|
|
|
float computeSpecularAO(float NoV, float ao, float roughness) {
|
|
return clamp(pow(NoV + ao, exp2(-16.0 * roughness - 1.0)) - 1.0 + ao, 0.0, 1.0);
|
|
}
|
|
|
|
vec3 getSpecularDominantDirection(vec3 n, vec3 r, float roughness) {
|
|
float s = 1.0 - roughness;
|
|
return mix(n, r, s * (sqrt(s) + roughness));
|
|
}
|
|
|
|
|
|
vec3 evaluateIBL(vec3 n, vec3 v, PixelParams params) {
|
|
float NoV = max(dot(n, v), 0.0);
|
|
|
|
#if ANISOTROPY == 1
|
|
vec3 t = normalize(v_tangent.xyz);
|
|
vec3 b = normalize(cross(t, n));
|
|
|
|
vec3 anisotropicTangent = cross(-v, b);
|
|
vec3 anisotropicNormal = cross(anisotropicTangent, b);
|
|
vec3 bentNormal = normalize(mix(n, anisotropicNormal, anisotropy));
|
|
|
|
vec3 r = reflect(v, bentNormal);
|
|
#else
|
|
vec3 r = reflect(-v, n);// vec3 r = reflect(-v, n);
|
|
r = getSpecularDominantDirection(n, r, params.roughness * params.roughness);
|
|
#endif
|
|
|
|
float NoR = max(dot(r, n), 0.0);
|
|
|
|
// specular indirect
|
|
vec3 indirectSpecular = evaluateSpecularIBL(reflect(v, n), params.roughness);
|
|
|
|
// horizon occlusion, can be removed for performance
|
|
float horizon = min(1.0 + NoR, 1.0);
|
|
indirectSpecular *= horizon * horizon;
|
|
|
|
vec2 env = prefilteredDFGKaris(NoV, params.roughness);
|
|
// we should multiply env.y by f90 for more accurate results
|
|
vec3 specularColor = params.f0 * env.x + env.y * (1.0 - clearCoat) *
|
|
clamp(dot(params.f0, vec3(50.0 * 0.33)), 0.0, 1.0);
|
|
|
|
// diffuse indirect
|
|
vec3 indirectDiffuse = max(irradianceSH(n), 0.0) * Fd_Lambert();
|
|
// ambient occlusion
|
|
float aoFade = clamp(dot(normalize(n), v), 0.0, 1.0);
|
|
float ao = mix(1.0, params.ao, aoFade);
|
|
indirectDiffuse *= ao;
|
|
//indirectDiffuse *= 4.0;
|
|
// TODO: Not really useful without SSAO/HBAO/etc.
|
|
indirectSpecular *= computeSpecularAO(NoV, ao, params.roughness);
|
|
|
|
// clear coat
|
|
float Fcc = F_Schlick_Scalar(NoV, 0.04, 1.0) * 0.2;
|
|
#if ANISOTROPY == 1
|
|
// We used the bent normal for the base layer
|
|
r = reflect(-v, n);
|
|
#endif
|
|
|
|
|
|
vec3 indirectClearCoatSpecular = evaluateSpecularIBL(reflect(v, n), params.clearCoatRoughness);
|
|
|
|
|
|
vec3 clearCoatAbsorption = mix(vec3(1.0),
|
|
beerLambert(params.refracted_NoV, params.refracted_NoV, clearCoatColor, clearCoatThickness),
|
|
clearCoat);
|
|
|
|
// indirect contribution
|
|
vec3 color =
|
|
(params.diffuseColor * indirectDiffuse + indirectSpecular * specularColor)//kaj params.diffuseColor * indirectDiffuse
|
|
* (1.0 - Fcc) * clearCoatAbsorption +
|
|
indirectClearCoatSpecular * Fcc;
|
|
|
|
#if TRANSLUCENT_MATERIAL == 1
|
|
indirectDiffuse = max(irradianceSH(-v), 0.0) * Fd_Lambert();
|
|
vec3 tL = -v + n * translucencyDistortion;
|
|
float tD = pow(clamp(dot(v, -tL), 0.0, 1.0), translucencyPower) * translucencyScale;
|
|
vec3 tT = (tD + translucencyAmbient) * texture(translucencyThicknessMap, outUV).r;
|
|
color.rgb += params.diffuseColor * indirectDiffuse * tT;
|
|
#endif
|
|
|
|
return color;
|
|
}
|
|
|
|
|
|
vec3 getNormal(vec3 n) {
|
|
|
|
return normalize(n);
|
|
|
|
}
|
|
|
|
|
|
|
|
vec4 surfaceShading(vec3 baseColor, vec3 outWorldNormal, vec3 outWorldPosition, float metallic, float roughness, float reflectance, float ambientOcclusion, vec3 tangent, float shadow) {
|
|
|
|
vec3 diffuseColor = (1.0 - metallic) * baseColor.rgb;
|
|
|
|
// Geometric AA
|
|
vec3 wn = normalize(outWorldNormal);
|
|
vec3 ndFdx = dFdx(wn);
|
|
vec3 ndFdy = dFdy(wn);
|
|
float geometricRoughness = pow(max(dot(ndFdx, ndFdx), dot(ndFdy, ndFdy)), 0.333);
|
|
float effectiveRoughness = max(roughness, geometricRoughness);
|
|
|
|
// Fresnel specular reflectance at normal incidence
|
|
vec3 f0 = 0.16 * reflectance * reflectance * (1.0 - metallic) +
|
|
baseColor.rgb * metallic;
|
|
|
|
float alpha = 1.0;
|
|
#if TRANSPARENT_MATERIAL == 1
|
|
// float reflectivity = max(max(f0.r, f0.g), f0.b);
|
|
// alpha = reflectivity + baseColor.a * (1.0 - reflectivity);
|
|
// diffuseColor *= baseColor.a;
|
|
#endif
|
|
|
|
vec3 v = normalize(cameraPosition - outWorldPosition);
|
|
vec3 n = getNormal(outWorldNormal);
|
|
|
|
PixelParams params;
|
|
params.diffuseColor = diffuseColor;
|
|
params.f0 = f0;
|
|
params.roughness = effectiveRoughness;
|
|
params.clearCoatRoughness = max(mix(0.089, 0.6, clearCoatRoughness), geometricRoughness); //max(mix(0.089, 0.6, clearCoatRoughness), geometricRoughness);
|
|
params.ao = ambientOcclusion;
|
|
params.eta = 1.0 / clearCoatIOR;
|
|
|
|
vec3 refracted_v = -refract(v, n, params.eta);
|
|
params.refracted_NoV = clamp(dot(n, refracted_v), 0.0, 1.0);
|
|
|
|
// indirect lighting
|
|
vec3 color = evaluateIBL(n, v, params);
|
|
color *= environmentLuminance;
|
|
|
|
// direct lighting
|
|
color += evaluateLight(n, v, params, outWorldPosition, tangent, shadow);
|
|
return vec4(color, alpha);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#ifndef NORMAL_MAP
|
|
#define NORMAL_MAP 0
|
|
#endif
|
|
|
|
#ifndef TEXTURE
|
|
#define TEXTURE 0
|
|
#endif
|
|
|
|
#ifndef ROUGHNESS_MAP
|
|
#define ROUGHNESS_MAP 0
|
|
#endif
|
|
|
|
#ifndef PARALLAX
|
|
#define PARALLAX 0
|
|
#endif
|
|
|
|
precision highp float;
|
|
|
|
uniform sampler2D diffuseSampler;
|
|
uniform sampler2D normalSampler;
|
|
uniform sampler2D roughnessSampler;
|
|
uniform sampler2D heightSampler;
|
|
uniform sampler2D shadowNoiseSampler;
|
|
uniform sampler2D shadowDepthSampler;
|
|
|
|
uniform float normals;
|
|
uniform float far;
|
|
uniform float roughness;
|
|
uniform float metallic;
|
|
uniform float alpha;
|
|
uniform float shadingModelID;
|
|
|
|
uniform vec3 diffuseColor;
|
|
|
|
|
|
uniform float attenuation;
|
|
|
|
uniform float SourceRadius;
|
|
uniform float SourceLength;
|
|
uniform float specular;
|
|
uniform float mode;
|
|
uniform float uvMultiplier;
|
|
uniform float render_type;
|
|
uniform float shadowBias;
|
|
|
|
uniform mat4 lightViewProjection;
|
|
uniform vec2 screenSize;
|
|
|
|
//reflect(v, n)
|
|
vec3 sampleReflection( vec3 r ) {
|
|
return texture(reflectionSampler, r).xyz;
|
|
}
|
|
vec3 lumaBasedReinhardToneMapping(vec3 color)
|
|
{
|
|
float gamma = 2.2;
|
|
float luma = dot(color, vec3(0.2126, 0.7152, 0.0722));
|
|
float toneMappedLuma = luma / (1.0 + luma);
|
|
|
|
color *= toneMappedLuma / luma;
|
|
color = pow(color, vec3(1. / gamma));
|
|
|
|
return color;
|
|
}
|
|
|
|
vec3 HDR_ACES(const vec3 x) {
|
|
// Narkowicz 2015, "ACES Filmic Tone Mapping Curve"
|
|
const float a = 2.51;
|
|
const float b = 0.03;
|
|
const float c = 2.43;
|
|
const float d = 0.59;
|
|
const float e = 0.14;
|
|
return (x * (a * x + b)) / (x * (c * x + d) + e);
|
|
}
|
|
vec3 tonemap(const vec3 x) {
|
|
return HDR_ACES(x);
|
|
}
|
|
|
|
float linearToSRGB(float c) {
|
|
return (c <= 0.0031308) ? c * 12.92 : (pow(abs(c), 1.0 / 2.4) * 1.055) - 0.055;
|
|
}
|
|
|
|
vec3 linearToSRGB(vec3 c) {
|
|
return vec3(linearToSRGB(c.r), linearToSRGB(c.g), linearToSRGB(c.b));
|
|
}
|
|
|
|
|
|
float DecodeFloatRGBA( vec4 rgba ) {
|
|
return (rgba).x;
|
|
|
|
//return dot( rgba, vec4(1.0, 1.0 / 255.0, 1.0 / 65025.0, 1.0 / 160581375.0) );
|
|
}
|
|
|
|
float shadow_sample(sampler2D depthMap, vec2 coord)
|
|
{
|
|
return texture(depthMap, coord).x;//DecodeFloatRGBA() ;
|
|
}
|
|
|
|
vec2 DoubleSampleRotated(sampler2D depthMap, vec4 p, vec4 rotMatr, vec4 kernel) {
|
|
|
|
vec4 rotatedOff;
|
|
|
|
rotatedOff = rotMatr.xyzw * kernel.xxww +
|
|
rotMatr.zwxy * kernel.yyzz;
|
|
|
|
vec4 fetchPos = p.xyxy + rotatedOff;// + rotatedOff
|
|
|
|
vec2 result;
|
|
|
|
result.x = shadow_sample(depthMap, fetchPos.xy);
|
|
result.y = shadow_sample(depthMap, fetchPos.zw);
|
|
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
|
|
float PCF(sampler2D depthMap, vec4 p, vec2 randDirTC, float depth)
|
|
{
|
|
|
|
vec2 kernelRadius = vec2(4.0);
|
|
|
|
vec4 irreg_kernel_2d[8];
|
|
irreg_kernel_2d[0] = vec4(-0.556641,-0.037109,-0.654297, 0.111328);
|
|
irreg_kernel_2d[1] = vec4(0.173828,0.111328,0.064453, -0.359375);
|
|
irreg_kernel_2d[2] = vec4(0.001953,0.082031,-0.060547, 0.078125);
|
|
irreg_kernel_2d[3] = vec4(0.220703,-0.359375,-0.062500, 0.001953);
|
|
irreg_kernel_2d[4] = vec4(0.242188,0.126953,-0.250000, -0.140625);
|
|
irreg_kernel_2d[5] = vec4(0.070313,-0.025391,0.148438, 0.082031);
|
|
irreg_kernel_2d[6] = vec4(-0.078125,0.013672,-0.314453, 0.013672);
|
|
irreg_kernel_2d[7] = vec4(0.117188,-0.140625,-0.199219, 0.117188);
|
|
|
|
vec2 vInvShadowMapWH = vec2(1.0 / 2048.0);
|
|
|
|
const int kernelSize = 8;
|
|
|
|
mediump float P_Z = depth; // p.z;
|
|
|
|
vec4 p0 = vec4(p.xyz, 1.0);
|
|
|
|
|
|
mediump vec2 rotScale = vec2(kernelRadius.y * 2.0);
|
|
|
|
float shadowTest = 0.0;
|
|
|
|
#define KERNEL_STEP_SIZE 2
|
|
|
|
vec2 rotSample = 2.0 * texture(shadowDepthSampler, randDirTC.xy).xy - 1.0;
|
|
rotSample.xy = normalize(rotSample.xy);
|
|
rotSample.xy *= (kernelRadius.xy * vInvShadowMapWH.xy);
|
|
|
|
vec4 rot = vec4(rotSample.x, -rotSample.y, rotSample.y, rotSample.x);
|
|
|
|
const int kernelOffset = 0;
|
|
|
|
for(int i=kernelOffset; i<kernelSize; i+=KERNEL_STEP_SIZE) // Loop over taps
|
|
{
|
|
|
|
mediump vec4 sampleDepth = vec4(0.0);
|
|
vec4 irr = irreg_kernel_2d[i+0];
|
|
sampleDepth.xy = DoubleSampleRotated(depthMap, p0, rot, irr);
|
|
sampleDepth.zw = DoubleSampleRotated(depthMap, p0, rot, irreg_kernel_2d[i+1]);
|
|
|
|
mediump vec4 InShadow;
|
|
InShadow.x = ( P_Z < sampleDepth.x + shadowBias ) ? 1. : 0.0;
|
|
InShadow.y = ( P_Z < sampleDepth.y + shadowBias ) ? 1. : 0.0;
|
|
InShadow.z = ( P_Z < sampleDepth.z + shadowBias ) ? 1. : 0.0;
|
|
InShadow.w = ( P_Z < sampleDepth.w + shadowBias ) ? 1. : 0.0;
|
|
|
|
|
|
const mediump float quality = 8.0; // 8 == high
|
|
const mediump float fInvSamplNum = (1.0 / quality);
|
|
|
|
shadowTest += dot(InShadow, vec4(fInvSamplNum));
|
|
}
|
|
|
|
return shadowTest;
|
|
}
|
|
float poissonPCFmultitap(vec4 projCoords, float shadowDepth, vec2 uv)
|
|
{
|
|
const mediump float step = 1.0 - 1.0 / 8.0;
|
|
const mediump float fScale = 0.025; // 0.025
|
|
|
|
mediump float n = 0.0;
|
|
|
|
mediump vec3 directions[8];
|
|
float vSampleScale = 1.0 / 2048.0;
|
|
|
|
|
|
directions[0] = normalize(vec3( 1.0, 1.0, 1.0))*fScale*(n+=step);
|
|
directions[1] = normalize(vec3(-1.0,-1.0,-1.0))*fScale*(n+=step);
|
|
directions[2] = normalize(vec3(-1.0,-1.0, 1.0))*fScale*(n+=step);
|
|
directions[3] = normalize(vec3(-1.0, 1.0,-1.0))*fScale*(n+=step);
|
|
directions[4] = normalize(vec3(-1.0, 1.0 ,1.0))*fScale*(n+=step);
|
|
directions[5] = normalize(vec3( 1.0,-1.0,-1.0))*fScale*(n+=step);
|
|
directions[6] = normalize(vec3( 1.0,-1.0, 1.0))*fScale*(n+=step);
|
|
directions[7] = normalize(vec3( 1.0, 1.0,-1.0))*fScale*(n+=step);
|
|
|
|
mediump vec3 randomSample = texture(shadowNoiseSampler, vec2(64.0, 64.0) * uv.xy / 4.0).xyz * 2.0 - 1.0;
|
|
|
|
|
|
|
|
float sum = 0.0;
|
|
|
|
// for( int i = 0; i < 4; i++ ) {
|
|
// vec3 sampler = reflect(directions[0], randomSample) * vSampleScale;
|
|
|
|
float pixelDepth = DecodeFloatRGBA( texture(shadowDepthSampler, projCoords.xy ) ) ; // + sampler.xy + sampler.z
|
|
|
|
if( pixelDepth + shadowBias > shadowDepth) {
|
|
sum += 1.0;
|
|
} else {
|
|
sum += 0.0;
|
|
}
|
|
// }
|
|
|
|
return sum;
|
|
}
|
|
|
|
|
|
float linestep(float min, float max, float value) {
|
|
return clamp((value - min) / (max - min), 0., 1.);
|
|
}
|
|
|
|
float reduceBleeding(float p_max, float amount) {
|
|
return linestep(amount, 1.0, p_max);
|
|
}
|
|
|
|
float ChebyshevUpperBound(vec2 moments, float distance) {
|
|
if (distance <= moments.x)
|
|
return 1.0;
|
|
|
|
float g_minVariance = .00007;
|
|
|
|
float variance = moments.y - (moments.x*moments.x);
|
|
variance = max(variance,g_minVariance);
|
|
|
|
float d = distance - moments.x;
|
|
float p_max = variance / (variance + d*d);
|
|
|
|
return reduceBleeding(p_max, .725);
|
|
}
|
|
|
|
float calculateShadowOcclusion( vec3 worldPosition, vec2 uv ) {
|
|
|
|
vec4 projCoords = lightViewProjection * vec4(worldPosition, 1.0) ;
|
|
|
|
float shadowDepth = length( lightPosition - worldPosition );
|
|
|
|
projCoords.xy /= projCoords.w;
|
|
projCoords = 0.49 * projCoords + 0.5;
|
|
|
|
vec4 moments = texture( shadowDepthSampler, projCoords.xy );
|
|
mediump vec2 randomSample = texture(shadowNoiseSampler, vec2(1024.) * uv / 64.0).xy * 2.0 - 1.0;
|
|
|
|
float outFrustum = 0.0;
|
|
|
|
if(projCoords.x < 0.0 || projCoords.x > 1.0) {
|
|
return 1.0;
|
|
}
|
|
|
|
if(projCoords.y < 0.0 || projCoords.y > 1.0) {
|
|
return 1.0;
|
|
}
|
|
|
|
if(projCoords.z < 1.0) {
|
|
return 1.0;
|
|
}
|
|
|
|
//return ChebyshevUpperBound(moments.xy, shadowDepth);
|
|
//if(uv.x < .5)
|
|
//return DecodeFloatRGBA( texture(shadowDepthSampler, projCoords.xy ) ) / 10.0;
|
|
//else
|
|
//return shadowDepth;
|
|
|
|
|
|
//return moments.x;
|
|
//return projCoords.x;
|
|
//return texture( shadowDepthSampler, uv ).x;//projCoords.xy
|
|
//return poissonPCFmultitap(projCoords, shadowDepth, uv);
|
|
//return PCF(sampler2D depthMap, vec4 p, vec2 randDirTC);
|
|
return PCF( shadowDepthSampler, projCoords, randomSample, shadowDepth );
|
|
//return 1.0 - ChebyshevUpperBound(moments.xy, shadowDepth);
|
|
// return smoothShadow(projCoords, shadowDepth,uv);
|
|
|
|
}
|
|
|
|
|
|
|
|
void main() {
|
|
vec2 textureCoordinate = v_textcoord;
|
|
vec3 normal;
|
|
|
|
#if NORMAL_MAP == 1
|
|
|
|
vec4 normalMap = texture(normalSampler, textureCoordinate * uvMultiplier) * 2.0 - 1.0;
|
|
normal = normalize((v_tangent.xyz * normalMap.x) + (v_binormal.xyz * normalMap.y) + (v_normal.xyz * normalMap.z));
|
|
|
|
mat3 tangentToWorld = transpose(mat3( v_tangent.xyz ,
|
|
v_binormal.xyz ,
|
|
v_normal.xyz));
|
|
|
|
|
|
normal = normalMap.xyz * tangentToWorld;
|
|
#else
|
|
|
|
normal = v_normal.xyz;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if PARALLAX == 1
|
|
|
|
const float max_samples = 30.0;
|
|
const float min_samples = 8.0;
|
|
|
|
vec3 view = normalize(v_view);
|
|
|
|
|
|
float num_steps = mix(max_samples, min_samples, dot(view, normal));
|
|
|
|
float current_height = 0.0;
|
|
float step_size = 1.0 / float(num_steps);
|
|
float prev_height = 1.0;
|
|
|
|
float step_index = 0.0;
|
|
|
|
|
|
vec2 tex_offset_per_step = step_size * v_offset;
|
|
vec2 tex_current_offset = v_textcoord;
|
|
float current_bound = 1.0;
|
|
float parallax_amount = 0.0;
|
|
|
|
vec2 pt1 = vec2(0.0);
|
|
vec2 pt2 = vec2(0.0);
|
|
|
|
vec2 tex_offset = vec2(0.0);
|
|
|
|
|
|
for(int x = 0; x < 30; x++) {
|
|
if(step_index < num_steps)
|
|
{
|
|
tex_current_offset -= tex_offset_per_step;
|
|
|
|
current_height = texture(heightSampler, tex_current_offset).r; //, dx, dy
|
|
|
|
current_bound -= step_size;
|
|
|
|
if(current_height > current_bound)
|
|
{
|
|
pt1 = vec2(current_bound, current_height);
|
|
pt2 = vec2(current_bound + step_size, prev_height);
|
|
|
|
tex_offset = tex_current_offset - tex_offset_per_step;
|
|
|
|
step_index = num_steps + 1.0;
|
|
}
|
|
else
|
|
{
|
|
step_index++;
|
|
prev_height = current_height;
|
|
}
|
|
}
|
|
}
|
|
|
|
float delta1 = pt1.x - pt1.y;
|
|
float delta2 = pt2.x - pt2.y;
|
|
float denominator = delta2 - delta1;
|
|
|
|
if(denominator == 0.0)
|
|
{
|
|
parallax_amount = 0.0;
|
|
}
|
|
else
|
|
{
|
|
parallax_amount = (pt1.x * delta2 - pt2.x * delta1) / denominator;
|
|
}
|
|
|
|
vec2 parallax_offset = v_offset * (1.0 - parallax_amount);
|
|
textureCoordinate.xy -= parallax_offset;
|
|
|
|
|
|
#endif
|
|
float gamma = 1.4;
|
|
|
|
vec3 baseColor;
|
|
vec4 diffuseMap;
|
|
|
|
#if TEXTURE == 1
|
|
|
|
diffuseMap = ( texture(diffuseSampler, textureCoordinate * uvMultiplier));//toLinear
|
|
baseColor = diffuseMap.rgb;
|
|
|
|
|
|
#else
|
|
|
|
baseColor = diffuseColor;
|
|
|
|
#endif
|
|
|
|
|
|
float f_roughness = roughness;
|
|
|
|
|
|
#if ROUGHNESS_MAP == 1
|
|
|
|
f_roughness = texture(roughnessSampler, textureCoordinate).x;
|
|
|
|
#endif
|
|
|
|
vec3 diffuse = baseColor ;
|
|
//
|
|
|
|
|
|
float opacity = 1.0;
|
|
float metallic = v_metallic / 2.0;
|
|
float reflectance = v_reflectance / 2.0;
|
|
|
|
|
|
vec3 viewDir = (cameraPosition - v_worldposition.xyz);
|
|
vec3 reflectionVector = reflect(-viewDir.xyz, normalize(normal.xyz));
|
|
vec3 reflectionSample = sampleReflection( reflectionVector );
|
|
|
|
if(render_type == 0.0) {
|
|
|
|
float shadow = calculateShadowOcclusion( v_worldposition.xyz, textureCoordinate );
|
|
|
|
|
|
vec4 pbr = surfaceShading(sRGBtoLinear(diffuse), normal, v_worldposition.xyz, metallic, f_roughness, reflectance, 1.0, v_tangent.xyz, shadow);
|
|
|
|
float exposure = 1.7;
|
|
|
|
|
|
pbr.rgb *= exposure;
|
|
|
|
|
|
deferred_diffuse_roughness = vec4(linearToSRGB(tonemap(pbr.rgb)), 1.0);
|
|
|
|
|
|
if(shadingModelID == 100.0) {
|
|
deferred_diffuse_roughness = vec4(reflectionSample, 1.0);
|
|
}
|
|
|
|
//if(textureCoordinate.x > .5)
|
|
//deferred_diffuse_roughness = vec4(vec3(shadow), 1.0);
|
|
|
|
} else {
|
|
deferred_diffuse_roughness = vec4( (diffuse), f_roughness); // //f_roughness kaj niet vergeten!!!
|
|
deferred_normal_depth = vec4(normalize(normal), v_depth);
|
|
deferred_position_material_ID = vec4(v_worldposition.xyz, float( shadingModelID ) );
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|