Merge branch 'master' into blender2.8
[blender.git] / source / blender / gpu / shaders / gpu_shader_material.glsl
index 1f5ffbdcc7e25df60f0e3147bd85b02876dc04c5..7acd9aa1fd579c5a98521a243b6700bbc572f377 100644 (file)
@@ -1,11 +1,57 @@
+
+uniform mat4 ModelViewMatrix;
+#ifndef EEVEE_ENGINE
+uniform mat4 ProjectionMatrix;
+uniform mat4 ViewMatrixInverse;
+uniform mat4 ViewMatrix;
+#endif
+uniform mat4 ModelMatrix;
+uniform mat4 ModelMatrixInverse;
+uniform mat4 ModelViewMatrixInverse;
+uniform mat4 ProjectionMatrixInverse;
+uniform mat3 NormalMatrix;
+uniform vec4 CameraTexCoFactors;
+
+/* Old glsl mode compat. */
+
+#ifndef CLOSURE_DEFAULT
+
+struct Closure {
+       vec3 radiance;
+       float opacity;
+};
+
+#define CLOSURE_DEFAULT Closure(vec3(0.0), 1.0)
+
+Closure closure_mix(Closure cl1, Closure cl2, float fac)
+{
+       Closure cl;
+       cl.radiance = mix(cl1.radiance, cl2.radiance, fac);
+       cl.opacity = mix(cl1.opacity, cl2.opacity, fac);
+       return cl;
+}
+
+Closure closure_add(Closure cl1, Closure cl2)
+{
+       Closure cl;
+       cl.radiance = cl1.radiance + cl2.radiance;
+       cl.opacity = cl1.opacity + cl2.opacity;
+       return cl;
+}
+
+Closure nodetree_exec(void); /* Prototype */
+
+#endif /* CLOSURE_DEFAULT */
+
+
 /* Converters */
 
 float convert_rgba_to_float(vec4 color)
 {
 #ifdef USE_NEW_SHADING
-       return color.r * 0.2126 + color.g * 0.7152 + color.b * 0.0722;
+       return dot(color.rgb, vec3(0.2126, 0.7152, 0.0722));
 #else
-       return (color.r + color.g + color.b) / 3.0;
+       return (color.r + color.g + color.b) * 0.333333;
 #endif
 }
 
@@ -53,7 +99,7 @@ void rgb_to_hsv(vec4 rgb, out vec4 outcol)
                h = 0.0;
        }
        else {
-               c = (vec3(cmax, cmax, cmax) - rgb.xyz) / cdelta;
+               c = (vec3(cmax) - rgb.xyz) / cdelta;
 
                if (rgb.x == cmax) h = c[2] - c[1];
                else if (rgb.y == cmax) h = 2.0 + c[0] -  c[2];
@@ -155,15 +201,18 @@ void color_to_blender_normal_new_shading(vec3 color, out vec3 normal)
        normal.y = -2.0 * ((color.g) - 0.5);
        normal.z = -2.0 * ((color.b) - 0.5);
 }
-
+#ifndef M_PI
 #define M_PI 3.14159265358979323846
-#define M_1_PI 0.31830988618379069
+#endif
+#ifndef M_1_PI
+#define M_1_PI 0.318309886183790671538
+#endif
 
 /*********** SHADER NODES ***************/
 
 void vcol_attribute(vec4 attvcol, out vec4 vcol)
 {
-       vcol = vec4(attvcol.x, attvcol.y, attvcol.z, 1.0);
+       vcol = vec4(attvcol.xyz, 1.0);
 }
 
 void uv_attribute(vec2 attuv, out vec3 uv)
@@ -177,7 +226,7 @@ void geom(
         out vec3 normal, out vec4 vcol, out float vcol_alpha, out float frontback)
 {
        local = co;
-       view = (gl_ProjectionMatrix[3][3] == 0.0) ? normalize(local) : vec3(0.0, 0.0, -1.0);
+       view = (ProjectionMatrix[3][3] == 0.0) ? normalize(local) : vec3(0.0, 0.0, -1.0);
        global = (viewinvmat * vec4(local, 1.0)).xyz;
        orco = attorco;
        uv_attribute(attuv, uv);
@@ -421,13 +470,13 @@ void squeeze(float val, float width, float center, out float outval)
 void vec_math_add(vec3 v1, vec3 v2, out vec3 outvec, out float outval)
 {
        outvec = v1 + v2;
-       outval = (abs(outvec[0]) + abs(outvec[1]) + abs(outvec[2])) / 3.0;
+       outval = (abs(outvec[0]) + abs(outvec[1]) + abs(outvec[2])) * 0.333333;
 }
 
 void vec_math_sub(vec3 v1, vec3 v2, out vec3 outvec, out float outval)
 {
        outvec = v1 - v2;
-       outval = (abs(outvec[0]) + abs(outvec[1]) + abs(outvec[2])) / 3.0;
+       outval = (abs(outvec[0]) + abs(outvec[1]) + abs(outvec[2])) * 0.333333;
 }
 
 void vec_math_average(vec3 v1, vec3 v2, out vec3 outvec, out float outval)
@@ -443,7 +492,7 @@ void vec_math_mix(float strength, vec3 v1, vec3 v2, out vec3 outvec)
 
 void vec_math_dot(vec3 v1, vec3 v2, out vec3 outvec, out float outval)
 {
-       outvec = vec3(0, 0, 0);
+       outvec = vec3(0);
        outval = dot(v1, v2);
 }
 
@@ -485,9 +534,9 @@ void normal_new_shading(vec3 dir, vec3 nor, out vec3 outnor, out float outdot)
 
 void curves_vec(float fac, vec3 vec, sampler2D curvemap, out vec3 outvec)
 {
-       outvec.x = texture2D(curvemap, vec2((vec.x + 1.0) * 0.5, 0.0)).x;
-       outvec.y = texture2D(curvemap, vec2((vec.y + 1.0) * 0.5, 0.0)).y;
-       outvec.z = texture2D(curvemap, vec2((vec.z + 1.0) * 0.5, 0.0)).z;
+       outvec.x = texture(curvemap, vec2((vec.x + 1.0) * 0.5, 0.0)).x;
+       outvec.y = texture(curvemap, vec2((vec.y + 1.0) * 0.5, 0.0)).y;
+       outvec.z = texture(curvemap, vec2((vec.z + 1.0) * 0.5, 0.0)).z;
 
        if (fac != 1.0)
                outvec = (outvec * fac) + (vec * (1.0 - fac));
@@ -496,9 +545,9 @@ void curves_vec(float fac, vec3 vec, sampler2D curvemap, out vec3 outvec)
 
 void curves_rgb(float fac, vec4 col, sampler2D curvemap, out vec4 outcol)
 {
-       outcol.r = texture2D(curvemap, vec2(texture2D(curvemap, vec2(col.r, 0.0)).a, 0.0)).r;
-       outcol.g = texture2D(curvemap, vec2(texture2D(curvemap, vec2(col.g, 0.0)).a, 0.0)).g;
-       outcol.b = texture2D(curvemap, vec2(texture2D(curvemap, vec2(col.b, 0.0)).a, 0.0)).b;
+       outcol.r = texture(curvemap, vec2(texture(curvemap, vec2(col.r, 0.0)).a, 0.0)).r;
+       outcol.g = texture(curvemap, vec2(texture(curvemap, vec2(col.g, 0.0)).a, 0.0)).g;
+       outcol.b = texture(curvemap, vec2(texture(curvemap, vec2(col.b, 0.0)).a, 0.0)).b;
 
        if (fac != 1.0)
                outcol = (outcol * fac) + (col * (1.0 - fac));
@@ -818,22 +867,23 @@ void mix_linear(float fac, vec4 col1, vec4 col2, out vec4 outcol)
 
 void valtorgb(float fac, sampler2D colormap, out vec4 outcol, out float outalpha)
 {
-       outcol = texture2D(colormap, vec2(fac, 0.0));
+       outcol = texture(colormap, vec2(fac, 0.0));
        outalpha = outcol.a;
 }
 
 void rgbtobw(vec4 color, out float outval)
 {
 #ifdef USE_NEW_SHADING
-       outval = color.r * 0.2126 + color.g * 0.7152 + color.b * 0.0722;
+       vec3 factors = vec3(0.2126, 0.7152, 0.0722);
 #else
-       outval = color.r * 0.35 + color.g * 0.45 + color.b * 0.2; /* keep these factors in sync with texture.h:RGBTOBW */
+       vec3 factors = vec3(0.35, 0.45, 0.2); /* keep these factors in sync with texture.h:RGBTOBW */
 #endif
+       outval = dot(color.rgb, factors);
 }
 
 void invert(float fac, vec4 col, out vec4 outcol)
 {
-       outcol.xyz = mix(col.xyz, vec3(1.0, 1.0, 1.0) - col.xyz, fac);
+       outcol.xyz = mix(col.xyz, vec3(1.0) - col.xyz, fac);
        outcol.w = col.w;
 }
 
@@ -918,12 +968,12 @@ void texture_flip_blend(vec3 vec, out vec3 outvec)
 
 void texture_blend_lin(vec3 vec, out float outval)
 {
-       outval = (1.0 + vec.x) / 2.0;
+       outval = (1.0 + vec.x) * 0.5;
 }
 
 void texture_blend_quad(vec3 vec, out float outval)
 {
-       outval = max((1.0 + vec.x) / 2.0, 0.0);
+       outval = max((1.0 + vec.x) * 0.5, 0.0);
        outval *= outval;
 }
 
@@ -934,12 +984,12 @@ void texture_wood_sin(vec3 vec, out float value, out vec4 color, out vec3 normal
 
        value = wi;
        color = vec4(wi, wi, wi, 1.0);
-       normal = vec3(0.0, 0.0, 0.0);
+       normal = vec3(0.0);
 }
 
 void texture_image(vec3 vec, sampler2D ima, out float value, out vec4 color, out vec3 normal)
 {
-       color = texture2D(ima, (vec.xy + vec2(1.0, 1.0)) * 0.5);
+       color = texture(ima, (vec.xy + vec2(1.0)) * 0.5);
        value = color.a;
 
        normal.x = 2.0 * (color.r - 0.5);
@@ -1279,11 +1329,7 @@ void mtex_har_divide(float har, out float outhar)
 
 void mtex_har_multiply_clamp(float har, out float outhar)
 {
-       har *= 128.0;
-
-       if (har < 1.0) outhar = 1.0;
-       else if (har > 511.0) outhar = 511.0;
-       else outhar = har;
+       outhar = clamp(har * 128.0, 1.0, 511.0);
 }
 
 void mtex_alpha_from_col(vec4 col, out float alpha)
@@ -1352,14 +1398,14 @@ vec3 mtex_2d_mapping(vec3 vec)
 
 void mtex_cube_map(vec3 co, samplerCube ima, out float value, out vec4 color)
 {
-       color = textureCube(ima, co);
+       color = texture(ima, co);
        value = 1.0;
 }
 
 void mtex_cube_map_refl_from_refldir(
         samplerCube ima, vec3 reflecteddirection, out float value, out vec4 color)
 {
-        color = textureCube(ima, reflecteddirection);
+        color = texture(ima, reflecteddirection);
         value = color.a;
 }
 
@@ -1370,13 +1416,13 @@ void mtex_cube_map_refl(
        vec3 viewdirection = vec3(viewmatrixinverse * vec4(vp, 0.0));
        vec3 normaldirection = normalize(vec3(vec4(vn, 0.0) * viewmatrix));
        vec3 reflecteddirection = reflect(viewdirection, normaldirection);
-       color = textureCube(ima, reflecteddirection);
+       color = texture(ima, reflecteddirection);
        value = 1.0;
 }
 
 void mtex_image(vec3 texco, sampler2D ima, out float value, out vec4 color)
 {
-       color = texture2D(ima, texco.xy);
+       color = texture(ima, texco.xy);
        value = 1.0;
 }
 
@@ -1387,7 +1433,7 @@ void mtex_normal(vec3 texco, sampler2D ima, out vec3 normal)
        // It needs to be done because in Blender
        // the normal used points inward.
        // Should this ever change this negate must be removed.
-       vec4 color = texture2D(ima, texco.xy);
+       vec4 color = texture(ima, texco.xy);
        normal = 2.0 * (vec3(-color.r, color.g, color.b) - vec3(-0.5, 0.5, 0.5));
 }
 
@@ -1415,8 +1461,8 @@ void mtex_bump_init_objspace(
         out float fPrevMagnitude_out, out vec3 vNacc_out,
         out vec3 vR1, out vec3 vR2, out float fDet)
 {
-       mat3 obj2view = to_mat3(gl_ModelViewMatrix);
-       mat3 view2obj = to_mat3(gl_ModelViewMatrixInverse);
+       mat3 obj2view = to_mat3(ModelViewMatrix);
+       mat3 view2obj = to_mat3(ModelViewMatrixInverse);
 
        vec3 vSigmaS = view2obj * dFdx(surf_pos);
        vec3 vSigmaT = view2obj * dFdy(surf_pos);
@@ -1483,9 +1529,9 @@ void mtex_bump_tap3(
        vec2 STul = texco.xy + dFdy(texco.xy);
 
        float Hll, Hlr, Hul;
-       rgbtobw(texture2D(ima, STll), Hll);
-       rgbtobw(texture2D(ima, STlr), Hlr);
-       rgbtobw(texture2D(ima, STul), Hul);
+       rgbtobw(texture(ima, STll), Hll);
+       rgbtobw(texture(ima, STlr), Hlr);
+       rgbtobw(texture(ima, STul), Hul);
 
        dBs = hScale * (Hlr - Hll);
        dBt = hScale * (Hul - Hll);
@@ -1510,10 +1556,10 @@ void mtex_bump_bicubic(
        vec2 STd = texco.xy - 0.5 * TexDy;
        vec2 STu = texco.xy + 0.5 * TexDy;
 
-       rgbtobw(texture2D(ima, STl), Hl);
-       rgbtobw(texture2D(ima, STr), Hr);
-       rgbtobw(texture2D(ima, STd), Hd);
-       rgbtobw(texture2D(ima, STu), Hu);
+       rgbtobw(texture(ima, STl), Hl);
+       rgbtobw(texture(ima, STr), Hr);
+       rgbtobw(texture(ima, STd), Hd);
+       rgbtobw(texture(ima, STu), Hu);
 
        vec2 dHdxy = vec2(Hr - Hl, Hu - Hd);
        float fBlend = clamp(1.0 - textureQueryLOD(ima, texco.xy).x, 0.0, 1.0);
@@ -1599,11 +1645,11 @@ void mtex_bump_tap5(
        vec2 STu = texco.xy + 0.5 * TexDy;
 
        float Hc, Hl, Hr, Hd, Hu;
-       rgbtobw(texture2D(ima, STc), Hc);
-       rgbtobw(texture2D(ima, STl), Hl);
-       rgbtobw(texture2D(ima, STr), Hr);
-       rgbtobw(texture2D(ima, STd), Hd);
-       rgbtobw(texture2D(ima, STu), Hu);
+       rgbtobw(texture(ima, STc), Hc);
+       rgbtobw(texture(ima, STl), Hl);
+       rgbtobw(texture(ima, STr), Hr);
+       rgbtobw(texture(ima, STd), Hd);
+       rgbtobw(texture(ima, STu), Hu);
 
        dBs = hScale * (Hr - Hl);
        dBt = hScale * (Hu - Hd);
@@ -1620,7 +1666,7 @@ void mtex_bump_deriv(
        // this variant using a derivative map is described here
        // http://mmikkelsen3d.blogspot.com/2011/07/derivative-maps.html
        vec2 dim = vec2(ima_x, ima_y);
-       vec2 dBduv = hScale * dim * (2.0 * texture2D(ima, texco.xy).xy - 1.0);
+       vec2 dBduv = hScale * dim * (2.0 * texture(ima, texco.xy).xy - 1.0);
 
        dBs = dBduv.x * TexDx.x + s * dBduv.y * TexDx.y;
        dBt = dBduv.x * TexDy.x + s * dBduv.y * TexDy.y;
@@ -1672,7 +1718,7 @@ void mtex_nspace_world(mat4 viewmat, vec3 texnormal, out vec3 outnormal)
 
 void mtex_nspace_object(vec3 texnormal, out vec3 outnormal)
 {
-       outnormal = normalize(gl_NormalMatrix * texnormal);
+       outnormal = normalize(NormalMatrix * texnormal);
 }
 
 void mtex_blend_normal(float norfac, vec3 normal, vec3 newnormal, out vec3 outnormal)
@@ -1729,7 +1775,7 @@ void lamp_falloff_invcoefficients(float coeff_const, float coeff_lin, float coef
 
 void lamp_falloff_curve(float lampdist, sampler2D curvemap, float dist, out float visifac)
 {
-       visifac = texture2D(curvemap, vec2(dist / lampdist, 0.0)).x;
+       visifac = texture(curvemap, vec2(dist / lampdist, 0.0)).x;
 }
 
 void lamp_visibility_sphere(float lampdist, float dist, float visifac, out float outvisifac)
@@ -1796,7 +1842,7 @@ void lamp_visibility_clamp(float visifac, out float outvisifac)
 void world_paper_view(vec3 vec, out vec3 outvec)
 {
        vec3 nvec = normalize(vec);
-       outvec = (gl_ProjectionMatrix[3][3] == 0.0) ? vec3(nvec.x, 0.0, nvec.y) : vec3(0.0, 0.0, -1.0);
+       outvec = (ProjectionMatrix[3][3] == 0.0) ? vec3(nvec.x, 0.0, nvec.y) : vec3(0.0, 0.0, -1.0);
 }
 
 void world_zen_mapping(vec3 view, float zenup, float zendown, out float zenfac)
@@ -1830,7 +1876,7 @@ void world_blend(vec3 vec, out float blend)
 void shade_view(vec3 co, out vec3 view)
 {
        /* handle perspective/orthographic */
-       view = (gl_ProjectionMatrix[3][3] == 0.0) ? normalize(co) : vec3(0.0, 0.0, -1.0);
+       view = (ProjectionMatrix[3][3] == 0.0) ? normalize(co) : vec3(0.0, 0.0, -1.0);
 }
 
 void shade_tangent_v(vec3 lv, vec3 tang, out vec3 vn)
@@ -2022,7 +2068,7 @@ void shade_add_to_diffuse(float i, vec3 lampcol, vec3 col, out vec3 outcol)
        if (i > 0.0)
                outcol = i * lampcol * col;
        else
-               outcol = vec3(0.0, 0.0, 0.0);
+               outcol = vec3(0.0);
 }
 
 void shade_hemi_spec(vec3 vn, vec3 lv, vec3 view, float spec, float hard, float visifac, out float t)
@@ -2179,12 +2225,12 @@ void shade_madd(vec4 col, vec4 col1, vec4 col2, out vec4 outcol)
 
 void shade_add_clamped(vec4 col1, vec4 col2, out vec4 outcol)
 {
-       outcol = col1 + max(col2, vec4(0.0, 0.0, 0.0, 0.0));
+       outcol = col1 + max(col2, vec4(0.0));
 }
 
 void shade_madd_clamped(vec4 col, vec4 col1, vec4 col2, out vec4 outcol)
 {
-       outcol = col + max(col1 * col2, vec4(0.0, 0.0, 0.0, 0.0));
+       outcol = col + max(col1 * col2, vec4(0.0));
 }
 
 void env_apply(vec4 col, vec3 hor, vec3 zen, vec4 f, mat4 vm, vec3 vn, out vec4 outcol)
@@ -2221,7 +2267,7 @@ void shade_obcolor(vec4 col, vec4 obcol, out vec4 outcol)
 
 void ramp_rgbtobw(vec3 color, out float outval)
 {
-       outval = color.r * 0.3 + color.g * 0.58 + color.b * 0.12;
+       outval = dot(color, vec3(0.3, 0.58, 0.12));
 }
 
 void shade_only_shadow(float i, float shadfac, float energy, vec3 shadcol, out vec3 outshadrgb)
@@ -2257,10 +2303,12 @@ void test_shadowbuf(
                //float bias = (1.5 - inp*inp)*shadowbias;
                co.z -= shadowbias * co.w;
 
-               if (co.w > 0.0 && co.x > 0.0 && co.x / co.w < 1.0 && co.y > 0.0 && co.y / co.w < 1.0)
-                       result = shadow2DProj(shadowmap, co).x;
-               else
+               if (co.w > 0.0 && co.x > 0.0 && co.x / co.w < 1.0 && co.y > 0.0 && co.y / co.w < 1.0) {
+                       result = textureProj(shadowmap, co);
+               }
+               else {
                        result = 1.0;
+               }
        }
 }
 
@@ -2274,7 +2322,7 @@ void test_shadowbuf_vsm(
        else {
                vec4 co = shadowpersmat * vec4(rco, 1.0);
                if (co.w > 0.0 && co.x > 0.0 && co.x / co.w < 1.0 && co.y > 0.0 && co.y / co.w < 1.0) {
-                       vec2 moments = texture2DProj(shadowmap, co).rg;
+                       vec2 moments = textureProj(shadowmap, co).rg;
                        float dist = co.z / co.w;
                        float p = 0.0;
 
@@ -2333,7 +2381,7 @@ void shade_light_texture(vec3 rco, sampler2D cookie, mat4 shadowpersmat, out vec
 
        vec4 co = shadowpersmat * vec4(rco, 1.0);
 
-       result = texture2DProj(cookie, co);
+       result = textureProj(cookie, co);
 }
 
 void shade_exposure_correct(vec3 col, float linfac, float logfac, out vec3 outcol)
@@ -2348,7 +2396,7 @@ void shade_mist_factor(
        if (enable == 1.0) {
                float fac, zcor;
 
-               zcor = (gl_ProjectionMatrix[3][3] == 0.0) ? length(co) : -co[2];
+               zcor = (ProjectionMatrix[3][3] == 0.0) ? length(co) : -co[2];
 
                fac = clamp((zcor - miststa) / mistdist, 0.0, 1.0);
                if (misttype == 0.0) fac *= fac;
@@ -2423,7 +2471,15 @@ float hypot(float x, float y)
 
 void generated_from_orco(vec3 orco, out vec3 generated)
 {
-       generated = orco * 0.5 + vec3(0.5);
+#ifdef VOLUMETRICS
+#ifdef MESH_SHADER
+       generated = volumeObjectLocalCoord;
+#else
+       generated = worldPosition;
+#endif
+#else
+       generated = orco;
+#endif
 }
 
 int floor_to_int(float x)
@@ -2436,7 +2492,6 @@ int quick_floor(float x)
        return int(x) - ((x < 0) ? 1 : 0);
 }
 
-#ifdef BIT_OPERATIONS
 float integer_noise(int n)
 {
        int nn;
@@ -2500,7 +2555,6 @@ vec3 cellnoise_color(vec3 p)
 
        return vec3(r, g, b);
 }
-#endif  // BIT_OPERATIONS
 
 float floorfrac(float x, out int i)
 {
@@ -2562,41 +2616,107 @@ vec3 rotate_vector(vec3 p, vec3 n, float theta) {
               );
 }
 
+void prepare_tangent(
+        float anisotropic, float anisotropic_rotation, float roughness, vec3 N, vec3 T,
+        out vec3 X, out vec3 Y, out float ax, out float ay)
+{
+       /* rotate tangent */
+       if (anisotropic_rotation != 0.0) {
+               T = rotate_vector(T, N, anisotropic_rotation * 2.0 * M_PI);
+       }
+
+       Y = normalize(cross(T, N));
+
+       float aspect = sqrt(1.0 - anisotropic * 0.9);
+       float a = sqr(roughness);
+       ax = max(0.001, a / aspect);
+       ay = max(0.001, a * aspect);
+}
+
+void convert_metallic_to_specular(vec3 basecol, float metallic, float specular_fac, out vec3 diffuse, out vec3 f0)
+{
+       vec3 dielectric = vec3(0.034) * specular_fac * 2.0;
+       diffuse = mix(basecol, vec3(0.0), metallic);
+       f0 = mix(dielectric, basecol, metallic);
+}
+
+void convert_metallic_to_specular_tinted(
+        vec3 basecol, float metallic, float specular_fac, float specular_tint,
+        out vec3 diffuse, out vec3 f0)
+{
+       vec3 dielectric = vec3(0.034) * specular_fac * 2.0;
+       float lum = dot(basecol, vec3(0.3, 0.6, 0.1)); /* luminance approx. */
+       vec3 tint = lum > 0 ? basecol / lum : vec3(1.0); /* normalize lum. to isolate hue+sat */
+       f0 = mix(dielectric * mix(vec3(1.0), tint, specular_tint), basecol, metallic);
+       diffuse = mix(basecol, vec3(0.0), metallic);
+}
 
 /*********** NEW SHADER NODES ***************/
 
 #define NUM_LIGHTS 3
 
-/* bsdfs */
+struct glLight {
+       vec4 position;
+       vec4 diffuse;
+       vec4 specular;
+       vec4 halfVector;
+};
 
-void node_bsdf_diffuse(vec4 color, float roughness, vec3 N, out vec4 result)
-{
+layout(std140) uniform lightSource {
+       glLight glLightSource[NUM_LIGHTS];
+};
+
+#ifndef VOLUMETRICS
+/* bsdfs */
+void node_bsdf_diffuse(vec4 color, float roughness, vec3 N, out Closure result)
+{
+#ifdef EEVEE_ENGINE
+       vec3 vN = normalize(mat3(ViewMatrix) * N);
+       result = CLOSURE_DEFAULT;
+       result.ssr_normal = normal_encode(vN, viewCameraVec);
+       eevee_closure_diffuse(N, color.rgb, 1.0, result.radiance);
+       result.radiance *= color.rgb;
+#else
        /* ambient light */
        vec3 L = vec3(0.2);
 
        /* directional lights */
        for (int i = 0; i < NUM_LIGHTS; i++) {
-               vec3 light_position = gl_LightSource[i].position.xyz;
-               vec3 light_diffuse = gl_LightSource[i].diffuse.rgb;
+               vec3 light_position = glLightSource[i].position.xyz;
+               vec3 light_diffuse = glLightSource[i].diffuse.rgb;
 
                float bsdf = max(dot(N, light_position), 0.0);
                L += light_diffuse * bsdf;
        }
 
-       result = vec4(L * color.rgb, 1.0);
+       result = Closure(L * color.rgb, 1.0);
+#endif
 }
 
-void node_bsdf_glossy(vec4 color, float roughness, vec3 N, out vec4 result)
+void node_bsdf_glossy(vec4 color, float roughness, vec3 N, float ssr_id, out Closure result)
 {
+#ifdef EEVEE_ENGINE
+       vec3 out_spec, ssr_spec;
+       roughness = sqrt(roughness);
+       eevee_closure_glossy(N, vec3(1.0), int(ssr_id), roughness, 1.0, out_spec, ssr_spec);
+       vec3 vN = normalize(mat3(ViewMatrix) * N);
+       result = CLOSURE_DEFAULT;
+       result.radiance = out_spec * color.rgb;
+       result.ssr_data = vec4(ssr_spec * color.rgb, roughness);
+       result.ssr_normal = normal_encode(vN, viewCameraVec);
+       result.ssr_id = int(ssr_id);
+#else
        /* ambient light */
        vec3 L = vec3(0.2);
 
+       direction_transform_m4v3(N, ViewMatrix, N);
+
        /* directional lights */
        for (int i = 0; i < NUM_LIGHTS; i++) {
-               vec3 light_position = gl_LightSource[i].position.xyz;
-               vec3 H = gl_LightSource[i].halfVector.xyz;
-               vec3 light_diffuse = gl_LightSource[i].diffuse.rgb;
-               vec3 light_specular = gl_LightSource[i].specular.rgb;
+               vec3 light_position = glLightSource[i].position.xyz;
+               vec3 H = glLightSource[i].halfVector.xyz;
+               vec3 light_diffuse = glLightSource[i].diffuse.rgb;
+               vec3 light_specular = glLightSource[i].specular.rgb;
 
                /* we mix in some diffuse so low roughness still shows up */
                float bsdf = 0.5 * pow(max(dot(N, H), 0.0), 1.0 / roughness);
@@ -2604,30 +2724,52 @@ void node_bsdf_glossy(vec4 color, float roughness, vec3 N, out vec4 result)
                L += light_specular * bsdf;
        }
 
-       result = vec4(L * color.rgb, 1.0);
+       result = Closure(L * color.rgb, 1.0);
+#endif
 }
 
 void node_bsdf_anisotropic(
         vec4 color, float roughness, float anisotropy, float rotation, vec3 N, vec3 T,
-        out vec4 result)
+        out Closure result)
 {
        node_bsdf_diffuse(color, 0.0, N, result);
 }
 
-void node_bsdf_glass(vec4 color, float roughness, float ior, vec3 N, out vec4 result)
-{
+void node_bsdf_glass(vec4 color, float roughness, float ior, vec3 N, float ssr_id, out Closure result)
+{
+#ifdef EEVEE_ENGINE
+       vec3 out_spec, out_refr, ssr_spec;
+       roughness = sqrt(roughness);
+       vec3 refr_color = (refractionDepth > 0.0) ? color.rgb * color.rgb : color.rgb; /* Simulate 2 transmission event */
+       eevee_closure_glass(N, vec3(1.0), int(ssr_id), roughness, 1.0, ior, out_spec, out_refr, ssr_spec);
+       out_refr *= refr_color;
+       out_spec *= color.rgb;
+       float fresnel = F_eta(ior, dot(N, cameraVec));
+       vec3 vN = normalize(mat3(ViewMatrix) * N);
+       result = CLOSURE_DEFAULT;
+       result.radiance = mix(out_refr, out_spec, fresnel);
+       result.ssr_data = vec4(ssr_spec * color.rgb * fresnel, roughness);
+       result.ssr_normal = normal_encode(vN, viewCameraVec);
+       result.ssr_id = int(ssr_id);
+#else
        node_bsdf_diffuse(color, 0.0, N, result);
+#endif
 }
 
-void node_bsdf_toon(vec4 color, float size, float tsmooth, vec3 N, out vec4 result)
+void node_bsdf_toon(vec4 color, float size, float tsmooth, vec3 N, out Closure result)
 {
        node_bsdf_diffuse(color, 0.0, N, result);
 }
 
+#ifndef EEVEE_ENGINE
 void node_bsdf_principled(vec4 base_color, float subsurface, vec3 subsurface_radius, vec4 subsurface_color, float metallic, float specular,
        float specular_tint, float roughness, float anisotropic, float anisotropic_rotation, float sheen, float sheen_tint, float clearcoat,
-       float clearcoat_roughness, float ior, float transmission, float transmission_roughness, vec3 N, vec3 CN, vec3 T, vec3 I, out vec4 result)
+       float clearcoat_roughness, float ior, float transmission, float transmission_roughness, vec3 N, vec3 CN, vec3 T, vec3 I, out Closure result)
 {
+       vec3 X, Y;
+       float ax, ay;
+       prepare_tangent(anisotropic, anisotropic_rotation, roughness, N, T, X, Y, ax, ay);
+
        /* ambient light */
        // TODO: set ambient light to an appropriate value
        vec3 L = mix(0.1, 0.03, metallic) * mix(base_color.rgb, subsurface_color.rgb, subsurface * (1.0 - metallic));
@@ -2635,28 +2777,7 @@ void node_bsdf_principled(vec4 base_color, float subsurface, vec3 subsurface_rad
        float eta = (2.0 / (1.0 - sqrt(0.08 * specular))) - 1.0;
 
        /* set the viewing vector */
-       vec3 V = (gl_ProjectionMatrix[3][3] == 0.0) ? -normalize(I) : vec3(0.0, 0.0, 1.0);
-
-       /* get the tangent */
-       vec3 Tangent = T;
-       if (T == vec3(0.0)) {
-               // if no tangent is set, use a default tangent
-               if(N.x != N.y || N.x != N.z) {
-                       Tangent = vec3(N.z-N.y, N.x-N.z, N.y-N.x);  // (1,1,1) x N
-               }
-               else {
-                       Tangent = vec3(N.z-N.y, N.x+N.z, -N.y-N.x);  // (-1,1,1) x N
-               }
-       }
-
-       /* rotate tangent */
-       if (anisotropic_rotation != 0.0) {
-               Tangent = rotate_vector(Tangent, N, anisotropic_rotation * 2.0 * M_PI);
-       }
-
-       /* calculate the tangent and bitangent */
-       vec3 Y = normalize(cross(N, Tangent));
-       vec3 X = cross(Y, N);
+       vec3 V = (ProjectionMatrix[3][3] == 0.0) ? -normalize(I) : vec3(0.0, 0.0, 1.0);
 
        /* fresnel normalization parameters */
        float F0 = fresnel_dielectric_0(eta);
@@ -2664,13 +2785,13 @@ void node_bsdf_principled(vec4 base_color, float subsurface, vec3 subsurface_rad
 
        /* directional lights */
        for (int i = 0; i < NUM_LIGHTS; i++) {
-               vec3 light_position_world = gl_LightSource[i].position.xyz;
+               vec3 light_position_world = glLightSource[i].position.xyz;
                vec3 light_position = normalize(light_position_world);
 
                vec3 H = normalize(light_position + V);
 
-               vec3 light_diffuse = gl_LightSource[i].diffuse.rgb;
-               vec3 light_specular = gl_LightSource[i].specular.rgb;
+               vec3 light_diffuse = glLightSource[i].diffuse.rgb;
+               vec3 light_specular = glLightSource[i].specular.rgb;
 
                float NdotL = dot(N, light_position);
                float NdotV = dot(N, V);
@@ -2680,7 +2801,7 @@ void node_bsdf_principled(vec4 base_color, float subsurface, vec3 subsurface_rad
                if (NdotL >= 0.0 && NdotV >= 0.0) {
                        float NdotH = dot(N, H);
 
-                       float Cdlum = 0.3 * base_color.r + 0.6 * base_color.g + 0.1 * base_color.b; // luminance approx.
+                       float Cdlum = dot(base_color.rgb, vec3(0.3, 0.6, 0.1)); // luminance approx.
 
                        vec3 Ctint = Cdlum > 0 ? base_color.rgb / Cdlum : vec3(1.0); // normalize lum. to isolate hue+sat
                        vec3 Cspec0 = mix(specular * 0.08 * mix(vec3(1.0), Ctint, specular_tint), base_color.rgb, metallic);
@@ -2701,10 +2822,6 @@ void node_bsdf_principled(vec4 base_color, float subsurface, vec3 subsurface_rad
                        float ss = 1.25 * (Fss * (1.0 / (NdotL + NdotV) - 0.5) + 0.5);
 
                        // specular
-                       float aspect = sqrt(1.0 - anisotropic * 0.9);
-                       float a = sqr(roughness);
-                       float ax = max(0.001, a / aspect);
-                       float ay = max(0.001, a * aspect);
                        float Ds = GTR2_aniso(NdotH, dot(H, X), dot(H, Y), ax, ay); //GTR2(NdotH, a);
                        float FH = (fresnel_dielectric_cos(LdotH, eta) - F0) * F0_norm;
                        vec3 Fs = mix(Cspec0, vec3(1.0), FH);
@@ -2740,83 +2857,234 @@ void node_bsdf_principled(vec4 base_color, float subsurface, vec3 subsurface_rad
                L += diffuse_and_specular_bsdf + clearcoat_bsdf;
        }
 
-       result = vec4(L, 1.0);
+       result = Closure(L, 1.0);
 }
+#endif
 
-void node_bsdf_translucent(vec4 color, vec3 N, out vec4 result)
+void node_bsdf_principled_clearcoat(vec4 base_color, float subsurface, vec3 subsurface_radius, vec4 subsurface_color, float metallic, float specular,
+       float specular_tint, float roughness, float anisotropic, float anisotropic_rotation, float sheen, float sheen_tint, float clearcoat,
+       float clearcoat_roughness, float ior, float transmission, float transmission_roughness, vec3 N, vec3 CN, vec3 T, vec3 I, float ssr_id,
+       float sss_id, vec3 sss_scale, out Closure result)
 {
-       node_bsdf_diffuse(color, 0.0, N, result);
+#ifdef EEVEE_ENGINE
+       metallic = saturate(metallic);
+       transmission = saturate(transmission);
+
+       vec3 diffuse, f0, out_diff, out_spec, out_trans, out_refr, ssr_spec;
+       convert_metallic_to_specular_tinted(base_color.rgb, metallic, specular, specular_tint, diffuse, f0);
+
+       transmission *= 1.0 - metallic;
+       subsurface *= 1.0 - metallic;
+
+       clearcoat *= 0.25;
+       clearcoat *= 1.0 - transmission;
+
+#ifdef USE_SSS
+       diffuse = mix(diffuse, vec3(0.0), subsurface);
+#else
+       diffuse = mix(diffuse, subsurface_color.rgb, subsurface);
+#endif
+       f0 = mix(f0, vec3(1.0), transmission);
+
+       float sss_scalef = dot(sss_scale, vec3(1.0 / 3.0));
+       eevee_closure_principled(N, diffuse, f0, int(ssr_id), roughness,
+                                CN, clearcoat, clearcoat_roughness, 1.0, sss_scalef, ior,
+                                out_diff, out_trans, out_spec, out_refr, ssr_spec);
+
+       vec3 refr_color = base_color.rgb;
+       refr_color *= (refractionDepth > 0.0) ? refr_color : vec3(1.0); /* Simulate 2 transmission event */
+
+       float fresnel = F_eta(ior, dot(N, cameraVec));
+       vec3 refr_spec_color = base_color.rgb * fresnel;
+       /* This bit maybe innacurate. */
+       out_refr = out_refr * refr_color * (1.0 - fresnel) + out_spec * refr_spec_color;
+
+       ssr_spec = mix(ssr_spec, refr_spec_color, transmission);
+
+       vec3 vN = normalize(mat3(ViewMatrix) * N);
+       result = CLOSURE_DEFAULT;
+       result.radiance = out_spec + out_diff * diffuse;
+       result.radiance = mix(result.radiance, out_refr, transmission);
+       result.ssr_data = vec4(ssr_spec, roughness);
+       result.ssr_normal = normal_encode(vN, viewCameraVec);
+       result.ssr_id = int(ssr_id);
+#ifdef USE_SSS
+       result.sss_data.a = sss_scalef;
+       result.sss_data.rgb = out_diff + out_trans;
+#ifdef USE_SSS_ALBEDO
+       result.sss_albedo.rgb = mix(vec3(0.0), subsurface_color.rgb, subsurface);
+#else
+       result.sss_data.rgb *= mix(vec3(0.0), subsurface_color.rgb, subsurface);
+#endif
+       result.sss_data.rgb *= (1.0 - transmission);
+#endif
+
+#else
+       node_bsdf_principled(base_color, subsurface, subsurface_radius, subsurface_color, metallic, specular,
+               specular_tint, roughness, anisotropic, anisotropic_rotation, sheen, sheen_tint, clearcoat,
+               clearcoat_roughness, ior, transmission, transmission_roughness, N, CN, T, I, result);
+#endif
+}
+
+void node_bsdf_translucent(vec4 color, vec3 N, out Closure result)
+{
+       node_bsdf_diffuse(color, 0.0, -N, result);
 }
 
-void node_bsdf_transparent(vec4 color, out vec4 result)
+void node_bsdf_transparent(vec4 color, out Closure result)
 {
        /* this isn't right */
-       result.r = color.r;
-       result.g = color.g;
-       result.b = color.b;
-       result.a = 0.0;
+       result = CLOSURE_DEFAULT;
+       result.radiance = vec3(0.0);
+       result.opacity = 0.0;
+#ifdef EEVEE_ENGINE
+       result.ssr_id = TRANSPARENT_CLOSURE_FLAG;
+#endif
 }
 
-void node_bsdf_velvet(vec4 color, float sigma, vec3 N, out vec4 result)
+void node_bsdf_velvet(vec4 color, float sigma, vec3 N, out Closure result)
 {
        node_bsdf_diffuse(color, 0.0, N, result);
 }
 
 void node_subsurface_scattering(
-        vec4 color, float scale, vec3 radius, float sharpen, float texture_blur, vec3 N,
-        out vec4 result)
-{
+        vec4 color, float scale, vec3 radius, float sharpen, float texture_blur, vec3 N, float sss_id,
+        out Closure result)
+{
+#if defined(EEVEE_ENGINE) && defined(USE_SSS)
+       vec3 out_diff, out_trans;
+       vec3 vN = normalize(mat3(ViewMatrix) * N);
+       result = CLOSURE_DEFAULT;
+       result.ssr_data = vec4(0.0);
+       result.ssr_normal = normal_encode(vN, viewCameraVec);
+       result.ssr_id = -1;
+       result.sss_data.a = scale;
+       eevee_closure_subsurface(N, color.rgb, 1.0, scale, out_diff, out_trans);
+       result.sss_data.rgb = out_diff + out_trans;
+#ifdef USE_SSS_ALBEDO
+       /* Not perfect for texture_blur not exaclty equal to 0.0 or 1.0. */
+       result.sss_albedo.rgb = mix(color.rgb, vec3(1.0), texture_blur);
+       result.sss_data.rgb *= mix(vec3(1.0), color.rgb, texture_blur);
+#else
+       result.sss_data.rgb *= color.rgb;
+#endif
+#else
        node_bsdf_diffuse(color, 0.0, N, result);
+#endif
 }
 
-void node_bsdf_hair(vec4 color, float offset, float roughnessu, float roughnessv, vec3 tangent, out vec4 result)
+void node_bsdf_refraction(vec4 color, float roughness, float ior, vec3 N, out Closure result)
 {
-       result = color;
+#ifdef EEVEE_ENGINE
+       vec3 out_refr;
+       color.rgb *= (refractionDepth > 0.0) ? color.rgb : vec3(1.0); /* Simulate 2 absorption event. */
+       roughness = sqrt(roughness);
+       eevee_closure_refraction(N, roughness, ior, out_refr);
+       vec3 vN = normalize(mat3(ViewMatrix) * N);
+       result = CLOSURE_DEFAULT;
+       result.ssr_normal = normal_encode(vN, viewCameraVec);
+       result.radiance = out_refr * color.rgb;
+       result.ssr_id = REFRACT_CLOSURE_FLAG;
+#else
+       node_bsdf_diffuse(color, 0.0, N, result);
+#endif /* EEVEE_ENGINE */
 }
 
-void node_bsdf_refraction(vec4 color, float roughness, float ior, vec3 N, out vec4 result)
+/* Unsupported for now */
+#ifndef EEVEE_ENGINE
+void node_bsdf_hair(vec4 color, float offset, float roughnessu, float roughnessv, vec3 tangent, out Closure result)
 {
-       node_bsdf_diffuse(color, 0.0, N, result);
+       result = Closure(color.rgb, color.a);
 }
 
-void node_ambient_occlusion(vec4 color, out vec4 result)
+void node_ambient_occlusion(vec4 color, out Closure result)
 {
-       result = color;
+       result = Closure(color.rgb, color.a);
 }
+#endif /* EEVEE_ENGINE */
+
+#endif /* VOLUMETRICS */
 
 /* emission */
 
-void node_emission(vec4 color, float strength, vec3 N, out vec4 result)
+void node_emission(vec4 color, float strength, vec3 vN, out Closure result)
 {
-       result = color * strength;
+#ifndef VOLUMETRICS
+       color *= strength;
+#ifdef EEVEE_ENGINE
+       result = CLOSURE_DEFAULT;
+       result.radiance = color.rgb;
+       result.opacity = color.a;
+       result.ssr_normal = normal_encode(vN, viewCameraVec);
+#else
+       result = Closure(color.rgb, color.a);
+#endif
+#else
+       result = Closure(vec3(0.0), vec3(0.0), color.rgb * strength, 0.0);
+#endif
 }
 
 /* background */
 
 void background_transform_to_world(vec3 viewvec, out vec3 worldvec)
 {
-       vec4 v = (gl_ProjectionMatrix[3][3] == 0.0) ? vec4(viewvec, 1.0) : vec4(0.0, 0.0, 1.0, 1.0);
-       vec4 co_homogenous = (gl_ProjectionMatrixInverse * v);
+       vec4 v = (ProjectionMatrix[3][3] == 0.0) ? vec4(viewvec, 1.0) : vec4(0.0, 0.0, 1.0, 1.0);
+       vec4 co_homogenous = (ProjectionMatrixInverse * v);
 
        vec4 co = vec4(co_homogenous.xyz / co_homogenous.w, 0.0);
-       worldvec = (gl_ModelViewMatrixInverse * co).xyz;
+#if defined(WORLD_BACKGROUND) || defined(PROBE_CAPTURE)
+       worldvec = (ViewMatrixInverse * co).xyz;
+#else
+       worldvec = (ModelViewMatrixInverse * co).xyz;
+#endif
+}
+
+void node_background(vec4 color, float strength, out Closure result)
+{
+#ifndef VOLUMETRICS
+       color *= strength;
+#ifdef EEVEE_ENGINE
+       result = CLOSURE_DEFAULT;
+       result.radiance = color.rgb;
+       result.opacity = color.a;
+#else
+       result = Closure(color.rgb, color.a);
+#endif
+#else
+       result = CLOSURE_DEFAULT;
+#endif
+}
+
+/* volumes */
+
+void node_volume_scatter(vec4 color, float density, float anisotropy, out Closure result)
+{
+#ifdef VOLUMETRICS
+       result = Closure(vec3(0.0), color.rgb * density, vec3(0.0), anisotropy);
+#else
+       result = CLOSURE_DEFAULT;
+#endif
 }
 
-void node_background(vec4 color, float strength, vec3 N, out vec4 result)
+void node_volume_absorption(vec4 color, float density, out Closure result)
 {
-       result = color * strength;
+#ifdef VOLUMETRICS
+       result = Closure((1.0 - color.rgb) * density, vec3(0.0), vec3(0.0), 0.0);
+#else
+       result = CLOSURE_DEFAULT;
+#endif
 }
 
 /* closures */
 
-void node_mix_shader(float fac, vec4 shader1, vec4 shader2, out vec4 shader)
+void node_mix_shader(float fac, Closure shader1, Closure shader2, out Closure shader)
 {
-       shader = mix(shader1, shader2, fac);
+       shader = closure_mix(shader1, shader2, fac);
 }
 
-void node_add_shader(vec4 shader1, vec4 shader2, out vec4 shader)
+void node_add_shader(Closure shader1, Closure shader2, out Closure shader)
 {
-       shader = shader1 + shader2;
+       shader = closure_add(shader1, shader2);
 }
 
 /* fresnel */
@@ -2824,7 +3092,7 @@ void node_add_shader(vec4 shader1, vec4 shader2, out vec4 shader)
 void node_fresnel(float ior, vec3 N, vec3 I, out float result)
 {
        /* handle perspective/orthographic */
-       vec3 I_view = (gl_ProjectionMatrix[3][3] == 0.0) ? normalize(I) : vec3(0.0, 0.0, -1.0);
+       vec3 I_view = (ProjectionMatrix[3][3] == 0.0) ? normalize(I) : vec3(0.0, 0.0, -1.0);
 
        float eta = max(ior, 0.00001);
        result = fresnel_dielectric(I_view, N, (gl_FrontFacing) ? eta : 1.0 / eta);
@@ -2836,7 +3104,7 @@ void node_layer_weight(float blend, vec3 N, vec3 I, out float fresnel, out float
 {
        /* fresnel */
        float eta = max(1.0 - blend, 0.00001);
-       vec3 I_view = (gl_ProjectionMatrix[3][3] == 0.0) ? normalize(I) : vec3(0.0, 0.0, -1.0);
+       vec3 I_view = (ProjectionMatrix[3][3] == 0.0) ? normalize(I) : vec3(0.0, 0.0, -1.0);
 
        fresnel = fresnel_dielectric(I_view, N, (gl_FrontFacing) ? 1.0 / eta : eta);
 
@@ -2866,11 +3134,47 @@ void node_gamma(vec4 col, float gamma, out vec4 outcol)
 
 /* geometry */
 
+void node_attribute_volume_density(sampler3D tex, out vec4 outcol, out vec3 outvec, out float outf)
+{
+#if defined(EEVEE_ENGINE) && defined(MESH_SHADER) && defined(VOLUMETRICS)
+       vec3 cos = volumeObjectLocalCoord;
+#else
+       vec3 cos = vec3(0.0);
+#endif
+       outvec = texture(tex, cos).aaa;
+       outcol = vec4(outvec, 1.0);
+       outf = dot(vec3(1.0 / 3.0), outvec);
+}
+
+void node_attribute_volume_color(sampler3D tex, out vec4 outcol, out vec3 outvec, out float outf)
+{
+#if defined(EEVEE_ENGINE) && defined(MESH_SHADER) && defined(VOLUMETRICS)
+       vec3 cos = volumeObjectLocalCoord;
+#else
+       vec3 cos = vec3(0.0);
+#endif
+       outvec = texture(tex, cos).rgb;
+       outcol = vec4(outvec, 1.0);
+       outf = dot(vec3(1.0 / 3.0), outvec);
+}
+
+void node_attribute_volume_flame(sampler3D tex, out vec4 outcol, out vec3 outvec, out float outf)
+{
+#if defined(EEVEE_ENGINE) && defined(MESH_SHADER) && defined(VOLUMETRICS)
+       vec3 cos = volumeObjectLocalCoord;
+#else
+       vec3 cos = vec3(0.0);
+#endif
+       outvec = texture(tex, cos).rrr;
+       outcol = vec4(outvec, 1.0);
+       outf = dot(vec3(1.0 / 3.0), outvec);
+}
+
 void node_attribute(vec3 attr, out vec4 outcol, out vec3 outvec, out float outf)
 {
        outcol = vec4(attr, 1.0);
        outvec = attr;
-       outf = (attr.x + attr.y + attr.z) / 3.0;
+       outf =  dot(vec3(1.0 / 3.0), attr);
 }
 
 void node_uvmap(vec3 attr_uv, out vec3 outvec)
@@ -2878,19 +3182,51 @@ void node_uvmap(vec3 attr_uv, out vec3 outvec)
        outvec = attr_uv;
 }
 
+void tangent_orco_x(vec3 orco_in, out vec3 orco_out)
+{
+       orco_out = vec3(0.0, (orco_in.z - 0.5) * -0.5, (orco_in.y - 0.5) * 0.5);
+}
+
+void tangent_orco_y(vec3 orco_in, out vec3 orco_out)
+{
+       orco_out = vec3((orco_in.z - 0.5) * -0.5, 0.0, (orco_in.x - 0.5) * 0.5);
+}
+
+void tangent_orco_z(vec3 orco_in, out vec3 orco_out)
+{
+       orco_out = vec3((orco_in.y - 0.5) * -0.5, (orco_in.x - 0.5) * 0.5, 0.0);
+}
+
+void node_tangentmap(vec4 attr_tangent, mat4 toworld, out vec3 tangent)
+{
+       tangent = (toworld * vec4(attr_tangent.xyz, 0.0)).xyz;
+}
+
+void node_tangent(vec3 N, vec3 orco, mat4 objmat, mat4 toworld, out vec3 T)
+{
+       N = (toworld * vec4(N, 0.0)).xyz;
+       T = (objmat * vec4(orco, 0.0)).xyz;
+       T = cross(N, normalize(cross(T, N)));
+}
+
 void node_geometry(
-        vec3 I, vec3 N, mat4 toworld,
+        vec3 I, vec3 N, vec3 orco, mat4 objmat, mat4 toworld,
         out vec3 position, out vec3 normal, out vec3 tangent,
         out vec3 true_normal, out vec3 incoming, out vec3 parametric,
         out float backfacing, out float pointiness)
 {
+#ifdef EEVEE_ENGINE
+       position = worldPosition;
+#else
        position = (toworld * vec4(I, 1.0)).xyz;
+#endif
        normal = (toworld * vec4(N, 0.0)).xyz;
-       tangent = vec3(0.0);
+       tangent_orco_z(orco, orco);
+       node_tangent(N, orco, objmat, toworld, tangent);
        true_normal = normal;
 
        /* handle perspective/orthographic */
-       vec3 I_view = (gl_ProjectionMatrix[3][3] == 0.0) ? normalize(I) : vec3(0.0, 0.0, -1.0);
+       vec3 I_view = (ProjectionMatrix[3][3] == 0.0) ? normalize(I) : vec3(0.0, 0.0, -1.0);
        incoming = -(toworld * vec4(I_view, 0.0)).xyz;
 
        parametric = vec3(0.0);
@@ -2904,12 +3240,12 @@ void node_tex_coord(
         out vec3 generated, out vec3 normal, out vec3 uv, out vec3 object,
         out vec3 camera, out vec3 window, out vec3 reflection)
 {
-       generated = attr_orco * 0.5 + vec3(0.5);
+       generated = attr_orco;
        normal = normalize((obinvmat * (viewinvmat * vec4(N, 0.0))).xyz);
        uv = attr_uv;
        object = (obinvmat * (viewinvmat * vec4(I, 1.0))).xyz;
        camera = vec3(I.xy, -I.z);
-       vec4 projvec = gl_ProjectionMatrix * vec4(I, 1.0);
+       vec4 projvec = ProjectionMatrix * vec4(I, 1.0);
        window = vec3(mtex_2d_mapping(projvec.xyz / projvec.w).xy * camerafac.xy + camerafac.zw, 0.0);
 
        vec3 shade_I;
@@ -2924,13 +3260,18 @@ void node_tex_coord_background(
         out vec3 generated, out vec3 normal, out vec3 uv, out vec3 object,
         out vec3 camera, out vec3 window, out vec3 reflection)
 {
-       vec4 v = (gl_ProjectionMatrix[3][3] == 0.0) ? vec4(I, 1.0) : vec4(0.0, 0.0, 1.0, 1.0);
-       vec4 co_homogenous = (gl_ProjectionMatrixInverse * v);
+       vec4 v = (ProjectionMatrix[3][3] == 0.0) ? vec4(I, 1.0) : vec4(0.0, 0.0, 1.0, 1.0);
+       vec4 co_homogenous = (ProjectionMatrixInverse * v);
 
        vec4 co = vec4(co_homogenous.xyz / co_homogenous.w, 0.0);
 
        co = normalize(co);
-       vec3 coords = (gl_ModelViewMatrixInverse * co).xyz;
+
+#if defined(WORLD_BACKGROUND) || defined(PROBE_CAPTURE)
+       vec3 coords = (ViewMatrixInverse * co).xyz;
+#else
+       vec3 coords = (ModelViewMatrixInverse * co).xyz;
+#endif
 
        generated = coords;
        normal = -coords;
@@ -2938,13 +3279,17 @@ void node_tex_coord_background(
        object = coords;
 
        camera = vec3(co.xy, -co.z);
-       window = (gl_ProjectionMatrix[3][3] == 0.0) ?
+       window = (ProjectionMatrix[3][3] == 0.0) ?
                 vec3(mtex_2d_mapping(I).xy * camerafac.xy + camerafac.zw, 0.0) :
                 vec3(vec2(0.5) * camerafac.xy + camerafac.zw, 0.0);
 
        reflection = -coords;
 }
 
+#if defined(WORLD_BACKGROUND) || (defined(PROBE_CAPTURE) && !defined(MESH_SHADER))
+#define node_tex_coord node_tex_coord_background
+#endif
+
 /* textures */
 
 float calc_gradient(vec3 p, int gradient_type)
@@ -3014,7 +3359,6 @@ void node_tex_checker(vec3 co, vec4 color1, vec4 color2, float scale, out vec4 c
        fac = check ? 1.0 : 0.0;
 }
 
-#ifdef BIT_OPERATIONS
 vec2 calc_brick_texture(vec3 p, float mortar_size, float mortar_smooth, float bias,
                         float brick_width, float row_height,
                         float offset_amount, int offset_frequency,
@@ -3050,7 +3394,6 @@ vec2 calc_brick_texture(vec3 p, float mortar_size, float mortar_smooth, float bi
                return vec2(tint, smoothstep(0.0, mortar_smooth, min_dist));
        }
 }
-#endif
 
 void node_tex_brick(vec3 co,
                     vec4 color1, vec4 color2,
@@ -3061,7 +3404,6 @@ void node_tex_brick(vec3 co,
                     float squash_amount, float squash_frequency,
                     out vec4 color, out float fac)
 {
-#ifdef BIT_OPERATIONS
        vec2 f2 = calc_brick_texture(co * scale,
                                     mortar_size, mortar_smooth, bias,
                                     brick_width, row_height,
@@ -3075,10 +3417,6 @@ void node_tex_brick(vec3 co,
        }
        color = mix(color1, mortar, f);
        fac = f;
-#else
-       color = vec4(1.0);
-       fac = 1.0;
-#endif
 }
 
 void node_tex_clouds(vec3 co, float size, out vec4 color, out float fac)
@@ -3093,7 +3431,15 @@ void node_tex_environment_equirectangular(vec3 co, sampler2D ima, out vec4 color
        float u = -atan(nco.y, nco.x) / (2.0 * M_PI) + 0.5;
        float v = atan(nco.z, hypot(nco.x, nco.y)) / M_PI + 0.5;
 
-       color = texture2D(ima, vec2(u, v));
+       /* Fix pole bleeding */
+       float half_width = 0.5 / float(textureSize(ima, 0).x);
+       v = clamp(v, half_width, 1.0 - half_width);
+
+       /* Fix u = 0 seam */
+       /* This is caused by texture filtering, since uv don't have smooth derivatives
+        * at u = 0 or 2PI, hardware filtering is using the smallest mipmap for certain
+        * texels. So we force the highest mipmap and don't do anisotropic filtering. */
+       color = textureLod(ima, vec2(u, v), 0.0);
 }
 
 void node_tex_environment_mirror_ball(vec3 co, sampler2D ima, out vec4 color)
@@ -3109,7 +3455,7 @@ void node_tex_environment_mirror_ball(vec3 co, sampler2D ima, out vec4 color)
        float u = 0.5 * (nco.x + 1.0);
        float v = 0.5 * (nco.z + 1.0);
 
-       color = texture2D(ima, vec2(u, v));
+       color = texture(ima, vec2(u, v));
 }
 
 void node_tex_environment_empty(vec3 co, out vec4 color)
@@ -3119,7 +3465,7 @@ void node_tex_environment_empty(vec3 co, out vec4 color)
 
 void node_tex_image(vec3 co, sampler2D ima, out vec4 color, out float alpha)
 {
-       color = texture2D(ima, co.xy);
+       color = texture(ima, co.xy);
        alpha = color.a;
 }
 
@@ -3193,21 +3539,21 @@ void node_tex_image_box(vec3 texco,
                if(signed_N.x < 0.0) {
                        uv.x = 1.0 - uv.x;
                }
-               color += weight.x * texture2D(ima, uv);
+               color += weight.x * texture(ima, uv);
        }
        if (weight.y > 0.0) {
                vec2 uv = texco.xz;
                if(signed_N.y > 0.0) {
                        uv.x = 1.0 - uv.x;
                }
-               color += weight.y * texture2D(ima, uv);
+               color += weight.y * texture(ima, uv);
        }
        if (weight.z > 0.0) {
                vec2 uv = texco.yx;
                if(signed_N.z > 0.0) {
                        uv.x = 1.0 - uv.x;
                }
-               color += weight.z * texture2D(ima, uv);
+               color += weight.z * texture(ima, uv);
        }
 
        alpha = color.a;
@@ -3280,7 +3626,6 @@ void node_tex_magic(vec3 co, float scale, float distortion, float depth, out vec
        fac = (color.x + color.y + color.z) / 3.0;
 }
 
-#ifdef BIT_OPERATIONS
 float noise_fade(float t)
 {
        return t * t * t * (t * (t * 6.0 - 15.0) + 10.0);
@@ -3355,10 +3700,9 @@ float noise_turbulence(vec3 p, float octaves, int hard)
        float fscale = 1.0;
        float amp = 1.0;
        float sum = 0.0;
-       int i, n;
        octaves = clamp(octaves, 0.0, 16.0);
-       n = int(octaves);
-       for (i = 0; i <= n; i++) {
+       int n = int(octaves);
+       for (int i = 0; i <= n; i++) {
                float t = noise(fscale * p);
                if (hard != 0) {
                        t = abs(2.0 * t - 1.0);
@@ -3368,7 +3712,7 @@ float noise_turbulence(vec3 p, float octaves, int hard)
                fscale *= 2.0;
        }
        float rmd = octaves - floor(octaves);
-       if  (rmd != 0.0) {
+       if (rmd != 0.0) {
                float t = noise(fscale * p);
                if (hard != 0) {
                        t = abs(2.0 * t - 1.0);
@@ -3383,11 +3727,9 @@ float noise_turbulence(vec3 p, float octaves, int hard)
                return sum;
        }
 }
-#endif  // BIT_OPERATIONS
 
 void node_tex_noise(vec3 co, float scale, float detail, float distortion, out vec4 color, out float fac)
 {
-#ifdef BIT_OPERATIONS
        vec3 p = co * scale;
        int hard = 0;
        if (distortion != 0.0) {
@@ -3403,15 +3745,8 @@ void node_tex_noise(vec3 co, float scale, float detail, float distortion, out ve
                     noise_turbulence(vec3(p.y, p.x, p.z), detail, hard),
                     noise_turbulence(vec3(p.y, p.z, p.x), detail, hard),
                     1);
-#else  // BIT_OPERATIONS
-       color = vec4(1.0);
-       fac = 1.0;
-#endif  // BIT_OPERATIONS
 }
 
-
-#ifdef BIT_OPERATIONS
-
 /* Musgrave fBm
  *
  * H: fractal increment parameter
@@ -3427,9 +3762,8 @@ float noise_musgrave_fBm(vec3 p, float H, float lacunarity, float octaves)
        float value = 0.0;
        float pwr = 1.0;
        float pwHL = pow(lacunarity, -H);
-       int i;
 
-       for (i = 0; i < int(octaves); i++) {
+       for (int i = 0; i < int(octaves); i++) {
                value += snoise(p) * pwr;
                pwr *= pwHL;
                p *= lacunarity;
@@ -3455,9 +3789,8 @@ float noise_musgrave_multi_fractal(vec3 p, float H, float lacunarity, float octa
        float value = 1.0;
        float pwr = 1.0;
        float pwHL = pow(lacunarity, -H);
-       int i;
 
-       for (i = 0; i < int(octaves); i++) {
+       for (int i = 0; i < int(octaves); i++) {
                value *= (pwr * snoise(p) + 1.0);
                pwr *= pwHL;
                p *= lacunarity;
@@ -3483,13 +3816,12 @@ float noise_musgrave_hetero_terrain(vec3 p, float H, float lacunarity, float oct
        float value, increment, rmd;
        float pwHL = pow(lacunarity, -H);
        float pwr = pwHL;
-       int i;
 
        /* first unscaled octave of function; later octaves are scaled */
        value = offset + snoise(p);
        p *= lacunarity;
 
-       for (i = 1; i < int(octaves); i++) {
+       for (int i = 1; i < int(octaves); i++) {
                increment = (snoise(p) + offset) * pwr * value;
                value += increment;
                pwr *= pwHL;
@@ -3518,13 +3850,12 @@ float noise_musgrave_hybrid_multi_fractal(vec3 p, float H, float lacunarity, flo
        float result, signal, weight, rmd;
        float pwHL = pow(lacunarity, -H);
        float pwr = pwHL;
-       int i;
 
        result = snoise(p) + offset;
        weight = gain * result;
        p *= lacunarity;
 
-       for (i = 1; (weight > 0.001f) && (i < int(octaves)); i++) {
+       for (int i = 1; (weight > 0.001f) && (i < int(octaves)); i++) {
                if (weight > 1.0)
                        weight = 1.0;
 
@@ -3555,14 +3886,13 @@ float noise_musgrave_ridged_multi_fractal(vec3 p, float H, float lacunarity, flo
        float result, signal, weight;
        float pwHL = pow(lacunarity, -H);
        float pwr = pwHL;
-       int i;
 
        signal = offset - abs(snoise(p));
        signal *= signal;
        result = signal;
        weight = 1.0;
 
-       for (i = 1; i < int(octaves); i++) {
+       for (int i = 1; i < int(octaves); i++) {
                p *= lacunarity;
                weight = clamp(signal * gain, 0.0, 1.0);
                signal = offset - abs(snoise(p));
@@ -3584,19 +3914,18 @@ float svm_musgrave(int type,
                    float gain,
                    vec3 p)
 {
-       if (type == 0 /*NODE_MUSGRAVE_MULTIFRACTAL*/)
+       if (type == 0 /* NODE_MUSGRAVE_MULTIFRACTAL */)
                return intensity * noise_musgrave_multi_fractal(p, dimension, lacunarity, octaves);
-       else if (type == 1 /*NODE_MUSGRAVE_FBM*/)
+       else if (type == 1 /* NODE_MUSGRAVE_FBM */)
                return intensity * noise_musgrave_fBm(p, dimension, lacunarity, octaves);
-       else if (type == 2 /*NODE_MUSGRAVE_HYBRID_MULTIFRACTAL*/)
+       else if (type == 2 /* NODE_MUSGRAVE_HYBRID_MULTIFRACTAL */)
                return intensity * noise_musgrave_hybrid_multi_fractal(p, dimension, lacunarity, octaves, offset, gain);
-       else if (type == 3 /*NODE_MUSGRAVE_RIDGED_MULTIFRACTAL*/)
+       else if (type == 3 /* NODE_MUSGRAVE_RIDGED_MULTIFRACTAL */)
                return intensity * noise_musgrave_ridged_multi_fractal(p, dimension, lacunarity, octaves, offset, gain);
-       else if (type == 4 /*NODE_MUSGRAVE_HETERO_TERRAIN*/)
+       else if (type == 4 /* NODE_MUSGRAVE_HETERO_TERRAIN */)
                return intensity * noise_musgrave_hetero_terrain(p, dimension, lacunarity, octaves, offset);
        return 0.0;
 }
-#endif  // #ifdef BIT_OPERATIONS
 
 void node_tex_musgrave(vec3 co,
                        float scale,
@@ -3609,7 +3938,6 @@ void node_tex_musgrave(vec3 co,
                        out vec4 color,
                        out float fac)
 {
-#ifdef BIT_OPERATIONS
        fac = svm_musgrave(int(type),
                           dimension,
                           lacunarity,
@@ -3618,9 +3946,6 @@ void node_tex_musgrave(vec3 co,
                           1.0,
                           gain,
                           co * scale);
-#else
-       fac = 1.0;
-#endif
 
        color = vec4(fac, fac, fac, 1.0);
 }
@@ -3632,7 +3957,6 @@ void node_tex_sky(vec3 co, out vec4 color)
 
 void node_tex_voronoi(vec3 co, float scale, float coloring, out vec4 color, out float fac)
 {
-#ifdef BIT_OPERATIONS
        vec3 p = co * scale;
        int xx, yy, zz, xi, yi, zi;
        float da[4];
@@ -3697,13 +4021,8 @@ void node_tex_voronoi(vec3 co, float scale, float coloring, out vec4 color, out
                color = vec4(cellnoise_color(pa[0]), 1);
                fac = (color.x + color.y + color.z) * (1.0 / 3.0);
        }
-#else  // BIT_OPERATIONS
-       color = vec4(1.0);
-       fac = 1.0;
-#endif  // BIT_OPERATIONS
 }
 
-#ifdef BIT_OPERATIONS
 float calc_wave(vec3 p, float distortion, float detail, float detail_scale, int wave_type, int wave_profile)
 {
        float n;
@@ -3725,22 +4044,16 @@ float calc_wave(vec3 p, float distortion, float detail, float detail_scale, int
                return (n < 0.0) ? n + 1.0 : n;
        }
 }
-#endif  // BIT_OPERATIONS
 
 void node_tex_wave(
         vec3 co, float scale, float distortion, float detail, float detail_scale, float wave_type, float wave_profile,
         out vec4 color, out float fac)
 {
-#ifdef BIT_OPERATIONS
        float f;
        f = calc_wave(co * scale, distortion, detail, detail_scale, int(wave_type), int(wave_profile));
 
        color = vec4(f, f, f, 1.0);
        fac = f;
-#else  // BIT_OPERATIONS
-       color = vec4(1.0);
-       fac = 1;
-#endif  // BIT_OPERATIONS
 }
 
 /* light path */
@@ -3760,13 +4073,21 @@ void node_light_path(
        out float transparent_depth,
        out float transmission_depth)
 {
+#ifndef PROBE_CAPTURE
        is_camera_ray = 1.0;
-       is_shadow_ray = 0.0;
-       is_diffuse_ray = 0.0;
        is_glossy_ray = 0.0;
-       is_singular_ray = 0.0;
+       is_diffuse_ray = 0.0;
        is_reflection_ray = 0.0;
        is_transmission_ray = 0.0;
+#else
+       is_camera_ray = 0.0;
+       is_glossy_ray = 1.0;
+       is_diffuse_ray = 1.0;
+       is_reflection_ray = 1.0;
+       is_transmission_ray = 1.0;
+#endif
+       is_shadow_ray = 0.0;
+       is_singular_ray = 0.0;
        ray_length = 1.0;
        ray_depth = 1.0;
        diffuse_depth = 1.0;
@@ -3865,37 +4186,79 @@ void node_vector_displacement_world(vec4 vector, float midlevel, float scale, ou
 
 /* output */
 
-void node_output_material(vec4 surface, vec4 volume, vec3 displacement, out vec4 result)
+void node_output_material(Closure surface, Closure volume, vec3 displacement, out Closure result)
 {
+#ifdef VOLUMETRICS
+       result = volume;
+#else
        result = surface;
+#endif
 }
 
-void node_output_world(vec4 surface, vec4 volume, out vec4 result)
+uniform float backgroundAlpha;
+
+void node_output_world(Closure surface, Closure volume, out Closure result)
 {
-       result = surface;
+#ifndef VOLUMETRICS
+#ifdef EEVEE_ENGINE
+       result.radiance = surface.radiance;
+       result.opacity = backgroundAlpha;
+#else
+       result = Closure(surface.radiance, backgroundAlpha);
+#endif
+#else
+       result = volume;
+#endif /* VOLUMETRICS */
+}
+
+#ifndef VOLUMETRICS
+/* TODO : clean this ifdef mess */
+/* EEVEE output */
+#ifdef EEVEE_ENGINE
+void world_normals_get(out vec3 N)
+{
+       N = gl_FrontFacing ? worldNormal : -worldNormal;
+}
+
+void node_eevee_specular(
+        vec4 diffuse, vec4 specular, float roughness, vec4 emissive, float transp, vec3 normal,
+        float clearcoat, float clearcoat_roughness, vec3 clearcoat_normal,
+        float occlusion, float ssr_id, out Closure result)
+{
+       vec3 out_diff, out_spec, ssr_spec;
+       eevee_closure_default(normal, diffuse.rgb, specular.rgb, int(ssr_id), roughness, occlusion,
+                             out_diff, out_spec, ssr_spec);
+
+       vec3 vN = normalize(mat3(ViewMatrix) * normal);
+       result = CLOSURE_DEFAULT;
+       result.radiance = out_diff * diffuse.rgb + out_spec + emissive.rgb;
+       result.opacity = 1.0 - transp;
+       result.ssr_data = vec4(ssr_spec, roughness);
+       result.ssr_normal = normal_encode(vN, viewCameraVec);
+       result.ssr_id = int(ssr_id);
 }
 
+#endif /* EEVEE_ENGINE */
+#endif /* VOLUMETRICS */
+
 /* ********************** matcap style render ******************** */
 
 void material_preview_matcap(vec4 color, sampler2D ima, vec4 N, vec4 mask, out vec4 result)
 {
        vec3 normal;
-       vec2 tex;
        
 #ifndef USE_OPENSUBDIV
        /* remap to 0.0 - 1.0 range. This is done because OpenGL 2.0 clamps colors
         * between shader stages and we want the full range of the normal */
-       normal = vec3(2.0, 2.0, 2.0) * vec3(N.x, N.y, N.z) - vec3(1.0, 1.0, 1.0);
-       if (normal.z < 0.0) {
-               normal.z = 0.0;
-       }
+       normal = 2.0 * N.xyz - vec3(1.0);
+       normal.z = max(normal.z, 0.0);
        normal = normalize(normal);
 #else
        normal = inpt.v.normal;
-       mask = vec4(1.0, 1.0, 1.0, 1.0);
+       mask = vec4(1.0);
 #endif
 
-       tex.x = 0.5 + 0.49 * normal.x;
-       tex.y = 0.5 + 0.49 * normal.y;
-       result = texture2D(ima, tex) * mask;
+       vec2 tex = 0.49 * normal.xy + vec2(0.5);
+
+       result = texture(ima, tex) * mask;
 }