armory/raw/deferred_light/deferred_light.frag.glsl

259 lines
8.3 KiB
Plaintext
Raw Normal View History

2016-01-28 00:58:00 +01:00
#version 450
2016-01-03 19:41:00 +01:00
#ifdef GL_ES
precision mediump float;
#endif
2016-03-20 18:44:11 +01:00
#define PI 3.1415926535
#define TwoPI (2.0 * PI)
uniform sampler2D gbuffer0;
uniform sampler2D gbuffer1;
uniform sampler2D gbuffer2;
2016-01-03 19:41:00 +01:00
2016-03-22 12:04:08 +01:00
uniform sampler2D ssaotex;
2016-03-19 21:25:53 +01:00
uniform sampler2D shadowMap;
uniform sampler2D senvmapRadiance;
uniform sampler2D senvmapIrradiance;
uniform sampler2D senvmapBrdf;
// uniform mat4 invVP;
2016-03-22 23:35:54 +01:00
uniform mat4 LMVP;
2016-03-20 18:44:11 +01:00
uniform vec3 light;
uniform vec3 eye;
uniform vec3 eyeLook;
2016-03-20 18:44:11 +01:00
2016-01-28 00:58:00 +01:00
in vec2 texCoord;
in vec3 viewRay;
2016-01-03 19:41:00 +01:00
2016-05-01 00:56:40 +02:00
// Separable SSS Transmittance Function, ref to sss_pass
vec3 SSSSTransmittance(float translucency, float sssWidth, vec3 worldPosition, vec3 worldNormal, vec3 lightDir) {
float scale = 8.25 * (1.0 - translucency) / sssWidth;
vec4 shrinkedPos = vec4(worldPosition - 0.005 * worldNormal, 1.0);
vec4 shadowPosition = LMVP * shrinkedPos;
float d1 = texture(shadowMap, shadowPosition.xy / shadowPosition.w).r; // 'd1' has a range of 0..1
float d2 = shadowPosition.z; // 'd2' has a range of 0..'lightFarPlane'
const float lightFarPlane = 120 / 3.5;
d1 *= lightFarPlane; // So we scale 'd1' accordingly:
float d = scale * abs(d1 - d2);
float dd = -d * d;
vec3 profile = vec3(0.233, 0.455, 0.649) * exp(dd / 0.0064) +
vec3(0.1, 0.336, 0.344) * exp(dd / 0.0484) +
vec3(0.118, 0.198, 0.0) * exp(dd / 0.187) +
vec3(0.113, 0.007, 0.007) * exp(dd / 0.567) +
vec3(0.358, 0.004, 0.0) * exp(dd / 1.99) +
vec3(0.078, 0.0, 0.0) * exp(dd / 7.41);
return profile * clamp(0.3 + dot(lightDir, -worldNormal), 0.0, 1.0);
}
2016-03-20 18:44:11 +01:00
vec2 envMapEquirect(vec3 normal) {
float phi = acos(normal.z);
float theta = atan(-normal.y, normal.x) + PI;
return vec2(theta / TwoPI, phi / PI);
}
float getMipLevelFromRoughness(float roughness) {
// First mipmap level = roughness 0, last = roughness = 1
// 6 mipmaps + baseColor
// TODO: set number of mipmaps
2016-03-20 18:44:11 +01:00
return roughness * 7.0;
}
vec3 surfaceAlbedo(vec3 baseColor, float metalness) {
return mix(baseColor, vec3(0.0), metalness);
}
vec3 surfaceF0(vec3 baseColor, float metalness) {
return mix(vec3(0.04), baseColor, metalness);
}
vec3 f_schlick(vec3 f0, float vh) {
return f0 + (1.0-f0)*exp2((-5.55473 * vh - 6.98316)*vh);
}
float v_smithschlick(float nl, float nv, float a) {
return 1.0 / ( (nl*(1.0-a)+a) * (nv*(1.0-a)+a) );
}
float d_ggx(float nh, float a) {
float a2 = a*a;
float denom = pow(nh*nh * (a2-1.0) + 1.0, 2.0);
return a2 * (1.0 / 3.1415926535) / denom;
}
vec3 specularBRDF(vec3 f0, float roughness, float nl, float nh, float nv, float vh, float lh) {
float a = roughness * roughness;
return d_ggx(nh, a) * clamp(v_smithschlick(nl, nv, a), 0.0, 1.0) * f_schlick(f0, vh) / 4.0;
//return vec3(LightingFuncGGX_OPT3(nl, lh, nh, roughness, f0[0]));
}
vec3 lambert(vec3 albedo, float nl) {
return albedo * max(0.0, nl);
}
vec3 diffuseBRDF(vec3 albedo, float roughness, float nv, float nl, float vh, float lv) {
return lambert(albedo, nl);
}
2016-03-22 23:35:54 +01:00
float texture2DCompare(vec2 uv, float compare){
float depth = texture(shadowMap, uv).r * 2.0 - 1.0;
return step(compare, depth);
}
float texture2DShadowLerp(vec2 size, vec2 uv, float compare){
vec2 texelSize = vec2(1.0) / size;
vec2 f = fract(uv * size + 0.5);
vec2 centroidUV = floor(uv * size + 0.5) / size;
float lb = texture2DCompare(centroidUV + texelSize * vec2(0.0, 0.0), compare);
float lt = texture2DCompare(centroidUV + texelSize * vec2(0.0, 1.0), compare);
float rb = texture2DCompare(centroidUV + texelSize * vec2(1.0, 0.0), compare);
float rt = texture2DCompare(centroidUV + texelSize * vec2(1.0, 1.0), compare);
float a = mix(lb, lt, f.y);
float b = mix(rb, rt, f.y);
float c = mix(a, b, f.x);
return c;
}
2016-04-08 16:17:57 +02:00
float PCF(vec2 size, vec2 uv, float compare) {
2016-03-22 23:35:54 +01:00
float result = 0.0;
// for (int x = -1; x <= 1; x++){
// for(int y = -1; y <= 1; y++){
// vec2 off = vec2(x, y) / size;
// result += texture2DShadowLerp(size, uv + off, compare);
vec2 off = vec2(-1, -1) / size;
result += texture2DShadowLerp(size, uv + off, compare);
off = vec2(-1, 0) / size;
result += texture2DShadowLerp(size, uv + off, compare);
off = vec2(-1, 1) / size;
result += texture2DShadowLerp(size, uv + off, compare);
off = vec2(0, -1) / size;
result += texture2DShadowLerp(size, uv + off, compare);
off = vec2(0, 0) / size;
result += texture2DShadowLerp(size, uv + off, compare);
off = vec2(0, 1) / size;
result += texture2DShadowLerp(size, uv + off, compare);
off = vec2(1, -1) / size;
result += texture2DShadowLerp(size, uv + off, compare);
off = vec2(1, 0) / size;
result += texture2DShadowLerp(size, uv + off, compare);
off = vec2(1, 1) / size;
result += texture2DShadowLerp(size, uv + off, compare);
// }
// }
return result / 9.0;
}
float shadowTest(vec4 lPos) {
vec4 lPosH = lPos / lPos.w;
lPosH.x = (lPosH.x + 1.0) / 2.0;
lPosH.y = 1.0 - ((-lPosH.y + 1.0) / (2.0));
return PCF(vec2(2048, 2048), lPosH.st, lPosH.z - 0.005);
}
2016-04-16 13:19:03 +02:00
vec2 octahedronWrap(vec2 v) {
return (1.0 - abs(v.yx)) * (vec2(v.x >= 0.0 ? 1.0 : -1.0, v.y >= 0.0 ? 1.0 : -1.0));
}
vec3 getPos(float depth) {
// vec4 pos = vec4(coord * 2.0 - 1.0, depth * 2.0 - 1.0, 1.0);
// vec4 pos = vec4(coord * 2.0 - 1.0, depth, 1.0);
// pos = invVP * pos;
// pos.xyz /= pos.w;
// return pos.xyz;
2016-04-17 16:07:54 +02:00
vec3 vray = normalize(viewRay);
const float znear = 0.1;
const float zfar = 1000.0;
const float projectionA = zfar / (zfar - znear);
const float projectionB = (-zfar * znear) / (zfar - znear);
// float linearDepth = projectionB / (depth - projectionA);
float linearDepth = projectionB / (depth * 0.5 + 0.5 - projectionA);
float viewZDist = dot(eyeLook, vray);
vec3 wposition = eye + vray * (linearDepth / viewZDist);
return wposition;
}
vec2 unpackFloat(float f) {
float index = floor(f) / 1000.0;
float alpha = fract(f);
return vec2(index, alpha);
2016-04-17 16:07:54 +02:00
}
2016-01-24 22:32:51 +01:00
void main() {
2016-03-22 12:04:08 +01:00
vec4 g0 = texture(gbuffer0, texCoord); // Normals, depth
float depth = 1.0 - g0.a;
if (depth == 0.0) discard;
2016-03-20 18:44:11 +01:00
vec4 g1 = texture(gbuffer1, texCoord); // Base color, roughness
vec4 g2 = texture(gbuffer2, texCoord); // 0,0,0, metalness
2016-04-12 14:44:21 +02:00
float ao = texture(ssaotex, texCoord).r;
2016-03-20 18:44:11 +01:00
2016-04-16 18:57:32 +02:00
vec2 enc = g0.rg;
vec3 n;
n.z = 1.0 - abs(enc.x) - abs(enc.y);
n.xy = n.z >= 0.0 ? enc.xy : octahedronWrap(enc.xy);
n = normalize(n);
2016-04-16 13:19:03 +02:00
vec3 p = getPos(depth);
vec3 baseColor = g1.rgb;
vec2 roughmet = unpackFloat(g1.a);
float roughness = roughmet.x;
float metalness = roughmet.y;
2016-03-20 18:44:11 +01:00
// float occlusion = g2.a;
vec3 lightDir = light - p.xyz;
vec3 eyeDir = eye - p.xyz;
vec3 l = normalize(lightDir);
vec3 v = normalize(eyeDir);
vec3 h = normalize(v + l);
float dotNL = max(dot(n, l), 0.0);
float dotNV = max(dot(n, v), 0.0);
float dotNH = max(dot(n, h), 0.0);
float dotVH = max(dot(v, h), 0.0);
float dotLV = max(dot(l, v), 0.0);
float dotLH = max(dot(l, h), 0.0);
vec3 albedo = surfaceAlbedo(baseColor, metalness);
vec3 f0 = surfaceF0(baseColor, metalness);
2016-03-22 23:35:54 +01:00
vec4 lPos = LMVP * vec4(vec3(p), 1.0);
2016-03-20 18:44:11 +01:00
float visibility = 1.0;
2016-03-22 23:35:54 +01:00
if (lPos.w > 0.0) {
visibility = shadowTest(lPos);
// visibility = 1.0;
}
2016-03-20 18:44:11 +01:00
// Direct
vec3 direct = diffuseBRDF(albedo, roughness, dotNV, dotNL, dotVH, dotLV) + specularBRDF(f0, roughness, dotNL, dotNH, dotNV, dotVH, dotLH);
2016-05-01 00:56:40 +02:00
// SSS only masked objects
if (texture(gbuffer0, texCoord).b == 2.0) {
direct.rgb = direct.rgb * SSSSTransmittance(1.0, 0.005, p, n, lightDir);
}
2016-03-20 18:44:11 +01:00
// Indirect
vec3 indirectDiffuse = texture(senvmapIrradiance, envMapEquirect(n)).rgb;
indirectDiffuse = pow(indirectDiffuse, vec3(2.2)) * albedo;
vec3 reflectionWorld = reflect(-v, n);
float lod = getMipLevelFromRoughness(roughness);// + 1.0;
vec3 prefilteredColor = textureLod(senvmapRadiance, envMapEquirect(reflectionWorld), lod).rgb;
prefilteredColor = pow(prefilteredColor, vec3(2.2));
vec2 envBRDF = texture(senvmapBrdf, vec2(roughness, 1.0 - dotNV)).xy;
vec3 indirectSpecular = prefilteredColor * (f0 * envBRDF.x + envBRDF.y);
vec3 indirect = indirectDiffuse + indirectSpecular;
2016-01-03 19:41:00 +01:00
2016-03-26 12:53:25 +01:00
vec4 outColor = vec4(vec3(direct * visibility + indirect * ao), 1.0);
2016-03-20 18:44:11 +01:00
// outColor.rgb *= occlusion;
2016-04-22 16:52:38 +02:00
// outColor = vec4(pow(outColor.rgb, vec3(1.0 / 2.2)), outColor.a);
2016-04-08 21:55:07 +02:00
gl_FragColor = vec4(outColor.rgb, outColor.a);
2016-01-03 19:41:00 +01:00
}