diff options
author | Clément Foucault <foucault.clem@gmail.com> | 2017-04-18 13:50:09 +0300 |
---|---|---|
committer | Clément Foucault <foucault.clem@gmail.com> | 2017-04-18 14:10:17 +0300 |
commit | edcf128ce279e1fa721a1ba16fc3a3dfeac4833b (patch) | |
tree | 4317cd33b39f63f90a26c33faf5790b965ebc3cd /source/blender/draw/engines/eevee/shaders | |
parent | f1fb605ec9ffd69b82652f3702de8b7ada570fd8 (diff) |
Eevee: Introduction of world preconvolved envmap.
For now only compute GGX convolution. The GGX LUT used for the split sum approximation (UE4) is merged with the LTX mag LUT that uses the same parameters (theta and roughness)
Diffstat (limited to 'source/blender/draw/engines/eevee/shaders')
11 files changed, 282 insertions, 28 deletions
diff --git a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl index ef684e3b970..96402f5ada2 100644 --- a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl @@ -1,5 +1,6 @@ #define M_PI 3.14159265358979323846 /* pi */ +#define M_PI_2 1.57079632679489661923 /* pi/2 */ #define M_1_PI 0.318309886183790671538 /* 1/pi */ #define M_1_2PI 0.159154943091895335768 /* 1/(2*pi) */ #define M_1_PI2 0.101321183642337771443 /* 1/(pi^2) */ @@ -52,6 +53,10 @@ struct ShadowMapData { #define sh_map_far near_far_bias.y #define sh_map_bias near_far_bias.z +#ifndef MAX_CASCADE_NUM +#define MAX_CASCADE_NUM 1 +#endif + struct ShadowCascadeData { mat4 shadowmat[MAX_CASCADE_NUM]; vec4 bias_count; @@ -98,26 +103,6 @@ float hypot(float x, float y) { return sqrt(x*x + y*y); } float inverse_distance(vec3 V) { return max( 1 / length(V), 1e-8); } -float linear_depth(float z, float zf, float zn) -{ - if (gl_ProjectionMatrix[3][3] == 0.0) { - return (zn * zf) / (z * (zn - zf) + zf); - } - else { - return (z * 2.0 - 1.0) * zf; - } -} - -float buffer_depth(float z, float zf, float zn) -{ - if (gl_ProjectionMatrix[3][3] == 0.0) { - return (zf * (zn - z)) / (z * (zn - zf)); - } - else { - return (z / (zf * 2.0)) + 0.5; - } -} - float line_plane_intersect_dist(vec3 lineorigin, vec3 linedirection, vec3 planeorigin, vec3 planenormal) { return dot(planenormal, planeorigin - lineorigin) / dot(planenormal, linedirection); @@ -149,6 +134,45 @@ vec3 line_aligned_plane_intersect(vec3 lineorigin, vec3 linedirection, vec3 plan return lineorigin + linedirection * dist; } +/* -- Tangent Space conversion -- */ +vec3 tangent_to_world(vec3 vector, vec3 N, vec3 T, vec3 B) +{ + return T * vector.x + B * vector.y + N * vector.z; +} + +vec3 world_to_tangent(vec3 vector, vec3 N, vec3 T, vec3 B) +{ + return vec3( dot(T, vector), dot(B, vector), dot(N, vector)); +} + +void make_orthonormal_basis(vec3 N, out vec3 T, out vec3 B) +{ + vec3 UpVector = abs(N.z) < 0.99999 ? vec3(0.0,0.0,1.0) : vec3(1.0,0.0,0.0); + T = normalize( cross(UpVector, N) ); + B = cross(N, T); +} + +/* ---- Opengl Depth conversion ---- */ +float linear_depth(float z, float zf, float zn) +{ + if (gl_ProjectionMatrix[3][3] == 0.0) { + return (zn * zf) / (z * (zn - zf) + zf); + } + else { + return (z * 2.0 - 1.0) * zf; + } +} + +float buffer_depth(float z, float zf, float zn) +{ + if (gl_ProjectionMatrix[3][3] == 0.0) { + return (zf * (zn - z)) / (z * (zn - zf)); + } + else { + return (z / (zf * 2.0)) + 0.5; + } +} + float rectangle_solid_angle(AreaData ad) { vec3 n0 = normalize(cross(ad.corner[0], ad.corner[1])); @@ -166,7 +190,9 @@ float rectangle_solid_angle(AreaData ad) vec3 get_specular_dominant_dir(vec3 N, vec3 R, float roughness) { - return normalize(mix(N, R, 1.0 - roughness * roughness)); + float smoothness = 1.0 - roughness; + float fac = smoothness * (sqrt(smoothness) + roughness); + return normalize(mix(N, R, fac)); } /* From UE4 paper */ diff --git a/source/blender/draw/engines/eevee/shaders/bsdf_direct_lib.glsl b/source/blender/draw/engines/eevee/shaders/bsdf_direct_lib.glsl index afa87dfb2c8..105b637c371 100644 --- a/source/blender/draw/engines/eevee/shaders/bsdf_direct_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/bsdf_direct_lib.glsl @@ -129,7 +129,7 @@ float direct_ggx_sphere(LightData ld, ShadingData sd, float roughness) bsdf *= 1.25331413731; #endif - bsdf *= texture(ltcMag, uv).r; /* Bsdf intensity */ + bsdf *= texture(brdfLut, uv).b; /* Bsdf intensity */ bsdf *= M_1_2PI * M_1_PI; #else float energy_conservation; @@ -150,7 +150,7 @@ float direct_ggx_rectangle(LightData ld, ShadingData sd, float roughness) mat3 ltcmat = ltc_matrix(uv); float bsdf = ltc_evaluate(sd.N, sd.V, ltcmat, sd.area_data.corner); - bsdf *= texture(ltcMag, uv).r; /* Bsdf intensity */ + bsdf *= texture(brdfLut, uv).b; /* Bsdf intensity */ bsdf *= M_1_2PI; #else float energy_conservation; diff --git a/source/blender/draw/engines/eevee/shaders/bsdf_lut_frag.glsl b/source/blender/draw/engines/eevee/shaders/bsdf_lut_frag.glsl new file mode 100644 index 00000000000..b8fac61519e --- /dev/null +++ b/source/blender/draw/engines/eevee/shaders/bsdf_lut_frag.glsl @@ -0,0 +1,46 @@ + +out vec4 FragColor; + +void main() { + vec3 N, T, B, V; + + float NV = ( 1.0 - (clamp(gl_FragCoord.y / BRDF_LUT_SIZE, 1e-4, 0.9999))); + float sqrtRoughness = clamp(gl_FragCoord.x / BRDF_LUT_SIZE, 1e-4, 0.9999); + float a = sqrtRoughness * sqrtRoughness; + float a2 = a * a; + + N = vec3(0.0, 0.0, 1.0); + T = vec3(1.0, 0.0, 0.0); + B = vec3(0.0, 1.0, 0.0); + V = vec3(sqrt(1.0 - NV * NV), 0.0, NV); + + setup_noise(); + + /* Integrating BRDF */ + float brdf_accum = 0.0; + float fresnel_accum = 0.0; + for (float i = 0; i < sampleCount; i++) { + vec3 H = sample_ggx(i, a2, N, T, B); /* Microfacet normal */ + vec3 L = -reflect(V, H); + float NL = L.z; + + if (NL > 0.0) { + float NH = max(H.z, 0.0); + float VH = max(dot(V, H), 0.0); + + float G1_v = G1_Smith_GGX(NV, a2); + float G1_l = G1_Smith_GGX(NL, a2); + float G_smith = 4.0 * NV * NL / (G1_v * G1_l); /* See G1_Smith_GGX for explanations. */ + + float brdf = (G_smith * VH) / (NH * NV); + float Fc = pow(1.0 - VH, 5.0); + + brdf_accum += (1.0 - Fc) * brdf; + fresnel_accum += Fc * brdf; + } + } + brdf_accum /= sampleCount; + fresnel_accum /= sampleCount; + + FragColor = vec4(brdf_accum, fresnel_accum, 0.0, 1.0); +}
\ No newline at end of file diff --git a/source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl b/source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl new file mode 100644 index 00000000000..da14a2dfee4 --- /dev/null +++ b/source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl @@ -0,0 +1,54 @@ + +uniform sampler1D texHammersley; +uniform sampler2D texJitter; +uniform float sampleCount; +uniform float invSampleCount; + +vec2 jitternoise = vec2(0.0); + +void setup_noise(void) +{ + jitternoise = texture(texJitter, gl_FragCoord.xy / NOISE_SIZE, 0).rg; /* Global variable */ +} + +vec3 hammersley_3d(float i, float invsamplenbr) +{ + vec3 Xi; /* Theta, cos(Phi), sin(Phi) */ + + Xi.x = i * invsamplenbr; /* i/samples */ + Xi.x = fract(Xi.x + jitternoise.x); + + int u = int(mod(i + jitternoise.y * HAMMERSLEY_SIZE, HAMMERSLEY_SIZE)); + + Xi.yz = texelFetch(texHammersley, u, 0).rg; + + return Xi; +} + +vec3 hammersley_3d(float i) +{ + return hammersley_3d(i, invSampleCount); +} + +/* -------------- BSDFS -------------- */ + +float pdf_ggx_reflect(float NH, float a2) +{ + return NH * a2 / D_ggx_opti(NH, a2); +} + +vec3 sample_ggx(float nsample, float a2, vec3 N, vec3 T, vec3 B) +{ + vec3 Xi = hammersley_3d(nsample); + + /* Theta is the aperture angle of the cone */ + float z = sqrt( (1.0 - Xi.x) / ( 1.0 + a2 * Xi.x - Xi.x ) ); /* cos theta */ + float r = sqrt( 1.0 - z * z ); /* sin theta */ + float x = r * Xi.y; + float y = r * Xi.z; + + /* Microfacet Normal */ + vec3 Ht = vec3(x, y, z); + + return tangent_to_world(Ht, N, T, B); +} diff --git a/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl b/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl index 6c62e7c2e47..9bd8dba452d 100644 --- a/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl @@ -3,6 +3,13 @@ uniform int light_count; uniform vec3 cameraPos; uniform vec3 eye; uniform mat4 ProjectionMatrix; + +uniform samplerCube probeFiltered; +uniform float lodMax; + +#ifndef USE_LTC +uniform sampler2D brdfLut; +#endif uniform sampler2DArrayShadow shadowCubes; uniform sampler2DArrayShadow shadowMaps; // uniform sampler2DArrayShadow shadowCascades; @@ -190,13 +197,16 @@ void main() sd.R = reflect(-sd.V, sd.N); /* hardcoded test vars */ - vec3 albedo = vec3(0.8); - vec3 specular = mix(vec3(0.03), vec3(1.0), pow(max(0.0, 1.0 - dot(sd.N, sd.V)), 5.0)); - float roughness = 0.1; + vec3 albedo = vec3(0.0); + vec3 f0 = mix(vec3(0.83, 0.5, 0.1), vec3(0.03, 0.03, 0.03), saturate(worldPosition.y/2)); + vec3 specular = mix(f0, vec3(1.0), pow(max(0.0, 1.0 - dot(sd.N, sd.V)), 5.0)); + float roughness = saturate(worldPosition.x/lodMax); sd.spec_dominant_dir = get_specular_dominant_dir(sd.N, sd.R, roughness); vec3 radiance = vec3(0.0); + + /* Analitic Lights */ for (int i = 0; i < MAX_LIGHT && i < light_count; ++i) { LightData ld = lights_data[i]; @@ -212,5 +222,11 @@ void main() radiance += vis * (albedo * diff + specular * spec) * ld.l_color; } + /* Envmaps */ + vec2 uv = ltc_coords(dot(sd.N, sd.V), sqrt(roughness)); + vec2 brdf_lut = texture(brdfLut, uv).rg; + vec3 Li = textureLod(probeFiltered, sd.spec_dominant_dir, roughness * lodMax).rgb; + radiance += Li * brdf_lut.y + f0 * Li * brdf_lut.x; + fragColor = vec4(radiance, 1.0); }
\ No newline at end of file diff --git a/source/blender/draw/engines/eevee/shaders/ltc_lib.glsl b/source/blender/draw/engines/eevee/shaders/ltc_lib.glsl index 131b0c2de78..279b18313e7 100644 --- a/source/blender/draw/engines/eevee/shaders/ltc_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/ltc_lib.glsl @@ -4,7 +4,7 @@ #define LTC_LUT_SIZE 64 uniform sampler2D ltcMat; -uniform sampler2D ltcMag; +uniform sampler2D brdfLut; /* from Real-Time Area Lighting: a Journey from Research to Production * Stephen Hill and Eric Heitz */ diff --git a/source/blender/draw/engines/eevee/shaders/probe_filter_frag.glsl b/source/blender/draw/engines/eevee/shaders/probe_filter_frag.glsl new file mode 100644 index 00000000000..553b0a0f27b --- /dev/null +++ b/source/blender/draw/engines/eevee/shaders/probe_filter_frag.glsl @@ -0,0 +1,49 @@ + +uniform samplerCube probeHdr; +uniform float roughnessSquared; +uniform float lodFactor; +uniform float lodMax; + +in vec3 worldPosition; + +out vec4 FragColor; + +void main() { + vec3 N, T, B, V; + + vec3 R = normalize(worldPosition); + + /* Isotropic assumption */ + N = V = R; + + make_orthonormal_basis(N, T, B); /* Generate tangent space */ + + /* Noise to dither the samples */ + /* Note : ghosting is better looking than noise. */ + // setup_noise(); + + /* Integrating Envmap */ + float weight = 0.0; + vec3 out_radiance = vec3(0.0); + for (float i = 0; i < sampleCount; i++) { + vec3 H = sample_ggx(i, roughnessSquared, N, T, B); /* Microfacet normal */ + vec3 L = -reflect(V, H); + float NL = dot(N, L); + + if (NL > 0.0) { + float NH = max(1e-8, dot(N, H)); /* cosTheta */ + + /* Coarse Approximation of the mapping distortion + * Unit Sphere -> Cubemap Face */ + const float dist = 4.0 * M_PI / 6.0; + float pdf = pdf_ggx_reflect(NH, roughnessSquared); + /* http://http.developer.nvidia.com/GPUGems3/gpugems3_ch20.html : Equation 13 */ + float lod = clamp(lodFactor - 0.5 * log2(pdf * dist), 0.0, lodMax) ; + + out_radiance += textureCubeLod(probeHdr, L, lod).rgb * NL; + weight += NL; + } + } + + FragColor = vec4(out_radiance / weight, 1.0); +}
\ No newline at end of file diff --git a/source/blender/draw/engines/eevee/shaders/probe_frag.glsl b/source/blender/draw/engines/eevee/shaders/probe_frag.glsl new file mode 100644 index 00000000000..1a2d2f48989 --- /dev/null +++ b/source/blender/draw/engines/eevee/shaders/probe_frag.glsl @@ -0,0 +1,26 @@ + +in vec3 worldPosition; + +uniform sampler2D probeLatLong; + +out vec4 FragColor; + +float hypot(float x, float y) { return sqrt(x*x + y*y); } + +void node_tex_environment_equirectangular(vec3 co, sampler2D ima, out vec4 color) +{ + vec3 nco = normalize(co); + float u = -atan(nco.y, nco.x) / (2.0 * 3.1415) + 0.5; + float v = atan(nco.z, hypot(nco.x, nco.y)) / 3.1415 + 0.5; + + color = texture2D(ima, vec2(u, v)); +} + +void main() { + vec3 L = normalize(worldPosition); + vec2 uvs = gl_FragCoord.xy / 256.0; + float dist = dot(L, vec3(0.0,1.0,0.0)); + dist = (dist > 0.99) ? 1e1 : 0.0; + FragColor = vec4(dist,dist,dist, 1.0); + node_tex_environment_equirectangular(L, probeLatLong, FragColor); +}
\ No newline at end of file diff --git a/source/blender/draw/engines/eevee/shaders/probe_geom.glsl b/source/blender/draw/engines/eevee/shaders/probe_geom.glsl new file mode 100644 index 00000000000..ad112977e9f --- /dev/null +++ b/source/blender/draw/engines/eevee/shaders/probe_geom.glsl @@ -0,0 +1,28 @@ + +layout(triangles) in; +layout(triangle_strip, max_vertices=3) out; + +uniform int Layer; + +in vec4 vPos[]; +in int face[]; + +out vec3 worldPosition; +out vec3 worldNormal; + +const vec3 maj_axes[6] = vec3[6](vec3(1.0, 0.0, 0.0), vec3(-1.0, 0.0, 0.0), vec3(0.0, 1.0, 0.0), vec3(0.0, -1.0, 0.0), vec3( 0.0, 0.0, 1.0), vec3( 0.0, 0.0, -1.0)); +const vec3 x_axis[6] = vec3[6](vec3(0.0, 0.0, -1.0), vec3( 0.0, 0.0, 1.0), vec3(1.0, 0.0, 0.0), vec3(1.0, 0.0, 0.0), vec3( 1.0, 0.0, 0.0), vec3(-1.0, 0.0, 0.0)); +const vec3 y_axis[6] = vec3[6](vec3(0.0, -1.0, 0.0), vec3( 0.0, -1.0, 0.0), vec3(0.0, 0.0, 1.0), vec3(0.0, 0.0, -1.0), vec3( 0.0, -1.0, 0.0), vec3( 0.0, -1.0, 0.0)); + +void main() { + int f = face[0]; + gl_Layer = Layer + f; + + for (int v = 0; v < 3; ++v) { + gl_Position = vPos[v]; + worldPosition = x_axis[f] * vPos[v].x + y_axis[f] * vPos[v].y + maj_axes[f]; + EmitVertex(); + } + + EndPrimitive(); +}
\ No newline at end of file diff --git a/source/blender/draw/engines/eevee/shaders/probe_vert.glsl b/source/blender/draw/engines/eevee/shaders/probe_vert.glsl new file mode 100644 index 00000000000..16b66a584a3 --- /dev/null +++ b/source/blender/draw/engines/eevee/shaders/probe_vert.glsl @@ -0,0 +1,10 @@ + +in vec3 pos; + +out vec4 vPos; +out int face; + +void main() { + vPos = vec4(pos, 1.0); + face = gl_InstanceID; +}
\ No newline at end of file diff --git a/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl b/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl index 1adf2ccfab9..c7f4d4ba777 100644 --- a/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl +++ b/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl @@ -1,5 +1,4 @@ -uniform mat4 ShadowMatrix; uniform mat4 ModelMatrix; in vec3 pos; |