Merge branch 'master' into blender2.8
authorBrecht Van Lommel <brechtvanlommel@gmail.com>
Wed, 13 Jun 2018 17:24:17 +0000 (19:24 +0200)
committerBrecht Van Lommel <brechtvanlommel@gmail.com>
Wed, 13 Jun 2018 17:26:52 +0000 (19:26 +0200)
This includes making Eevee match Cycles behavior of inserting an emission
node when linking colors to closures.

1  2 
source/blender/blenkernel/intern/undo_system.c
source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl
source/blender/editors/animation/anim_ops.c
source/blender/editors/screen/screen_ops.c
source/blender/editors/undo/ed_undo.c
source/blender/gpu/intern/gpu_codegen.c
source/blender/gpu/shaders/gpu_shader_material.glsl

index a189043,0000000..8b232bf
mode 100644,000000..100644
--- /dev/null
@@@ -1,841 -1,0 +1,855 @@@
 +
 +#define M_PI        3.14159265358979323846  /* pi */
 +#define M_2PI       6.28318530717958647692  /* 2*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) */
 +
 +#define LUT_SIZE 64
 +
 +/* Buffers */
 +uniform sampler2D colorBuffer;
 +uniform sampler2D depthBuffer;
 +uniform sampler2D maxzBuffer;
 +uniform sampler2D minzBuffer;
 +uniform sampler2DArray planarDepth;
 +
 +#define cameraForward   normalize(ViewMatrixInverse[2].xyz)
 +#define cameraPos       ViewMatrixInverse[3].xyz
 +#define cameraVec      ((ProjectionMatrix[3][3] == 0.0) ? normalize(cameraPos - worldPosition) : cameraForward)
 +#define viewCameraVec  ((ProjectionMatrix[3][3] == 0.0) ? normalize(-viewPosition) : vec3(0.0, 0.0, 1.0))
 +
 +/* ------- Structures -------- */
 +
 +/* ------ Lights ----- */
 +struct LightData {
 +      vec4 position_influence;      /* w : InfluenceRadius */
 +      vec4 color_spec;              /* w : Spec Intensity */
 +      vec4 spotdata_radius_shadow;  /* x : spot size, y : spot blend, z : radius, w: shadow id */
 +      vec4 rightvec_sizex;          /* xyz: Normalized up vector, w: area size X or spot scale X */
 +      vec4 upvec_sizey;             /* xyz: Normalized right vector, w: area size Y or spot scale Y */
 +      vec4 forwardvec_type;         /* xyz: Normalized forward vector, w: Lamp Type */
 +};
 +
 +/* convenience aliases */
 +#define l_color        color_spec.rgb
 +#define l_spec         color_spec.a
 +#define l_position     position_influence.xyz
 +#define l_influence    position_influence.w
 +#define l_sizex        rightvec_sizex.w
 +#define l_sizey        upvec_sizey.w
 +#define l_right        rightvec_sizex.xyz
 +#define l_up           upvec_sizey.xyz
 +#define l_forward      forwardvec_type.xyz
 +#define l_type         forwardvec_type.w
 +#define l_spot_size    spotdata_radius_shadow.x
 +#define l_spot_blend   spotdata_radius_shadow.y
 +#define l_radius       spotdata_radius_shadow.z
 +#define l_shadowid     spotdata_radius_shadow.w
 +
 +/* ------ Shadows ----- */
 +#ifndef MAX_CASCADE_NUM
 +#define MAX_CASCADE_NUM 4
 +#endif
 +
 +struct ShadowData {
 +      vec4 near_far_bias_exp;
 +      vec4 shadow_data_start_end;
 +      vec4 contact_shadow_data;
 +};
 +
 +struct ShadowCubeData {
 +      vec4 position;
 +};
 +
 +struct ShadowCascadeData {
 +      mat4 shadowmat[MAX_CASCADE_NUM];
 +      vec4 split_start_distances;
 +      vec4 split_end_distances;
 +};
 +
 +/* convenience aliases */
 +#define sh_near   near_far_bias_exp.x
 +#define sh_far    near_far_bias_exp.y
 +#define sh_bias   near_far_bias_exp.z
 +#define sh_exp    near_far_bias_exp.w
 +#define sh_bleed  near_far_bias_exp.w
 +#define sh_tex_start    shadow_data_start_end.x
 +#define sh_data_start   shadow_data_start_end.y
 +#define sh_multi_nbr    shadow_data_start_end.z
 +#define sh_blur         shadow_data_start_end.w
 +#define sh_contact_dist            contact_shadow_data.x
 +#define sh_contact_offset          contact_shadow_data.y
 +#define sh_contact_spread          contact_shadow_data.z
 +#define sh_contact_thickness       contact_shadow_data.w
 +
 +/* ------- Convenience functions --------- */
 +
 +vec3 mul(mat3 m, vec3 v) { return m * v; }
 +mat3 mul(mat3 m1, mat3 m2) { return m1 * m2; }
 +vec3 transform_direction(mat4 m, vec3 v) { return mat3(m) * v; }
 +vec3 transform_point(mat4 m, vec3 v) { return (m * vec4(v, 1.0)).xyz; }
 +vec3 project_point(mat4 m, vec3 v) {
 +      vec4 tmp = m * vec4(v, 1.0);
 +      return tmp.xyz / tmp.w;
 +}
 +
 +#define min3(a, b, c)                   min(a, min(b, c))
 +#define min4(a, b, c, d)                min(a, min3(b, c, d))
 +#define min5(a, b, c, d, e)             min(a, min4(b, c, d, e))
 +#define min6(a, b, c, d, e, f)          min(a, min5(b, c, d, e, f))
 +#define min7(a, b, c, d, e, f, g)       min(a, min6(b, c, d, e, f, g))
 +#define min8(a, b, c, d, e, f, g, h)    min(a, min7(b, c, d, e, f, g, h))
 +#define min9(a, b, c, d, e, f, g, h, i) min(a, min8(b, c, d, e, f, g, h, i))
 +
 +#define max3(a, b, c)                   max(a, max(b, c))
 +#define max4(a, b, c, d)                max(a, max3(b, c, d))
 +#define max5(a, b, c, d, e)             max(a, max4(b, c, d, e))
 +#define max6(a, b, c, d, e, f)          max(a, max5(b, c, d, e, f))
 +#define max7(a, b, c, d, e, f, g)       max(a, max6(b, c, d, e, f, g))
 +#define max8(a, b, c, d, e, f, g, h)    max(a, max7(b, c, d, e, f, g, h))
 +#define max9(a, b, c, d, e, f, g, h, i) max(a, max8(b, c, d, e, f, g, h, i))
 +
 +#define avg3(a, b, c)                   (a + b + c) * (1.0 / 3.0)
 +#define avg4(a, b, c, d)                (a + b + c + d) * (1.0 / 4.0)
 +#define avg5(a, b, c, d, e)             (a + b + c + d + e) * (1.0 / 5.0)
 +#define avg6(a, b, c, d, e, f)          (a + b + c + d + e + f) * (1.0 / 6.0)
 +#define avg7(a, b, c, d, e, f, g)       (a + b + c + d + e + f + g) * (1.0 / 7.0)
 +#define avg8(a, b, c, d, e, f, g, h)    (a + b + c + d + e + f + g + h) * (1.0 / 8.0)
 +#define avg9(a, b, c, d, e, f, g, h, i) (a + b + c + d + e + f + g + h + i) * (1.0 / 9.0)
 +
 +float min_v2(vec2 v) { return min(v.x, v.y); }
 +float min_v3(vec3 v) { return min(v.x, min(v.y, v.z)); }
 +float max_v2(vec2 v) { return max(v.x, v.y); }
 +float max_v3(vec3 v) { return max(v.x, max(v.y, v.z)); }
 +
 +float sum(vec2 v) { return dot(vec2(1.0), v); }
 +float sum(vec3 v) { return dot(vec3(1.0), v); }
 +float sum(vec4 v) { return dot(vec4(1.0), v); }
 +
 +float saturate(float a) { return clamp(a, 0.0, 1.0); }
 +vec2 saturate(vec2 a) { return clamp(a, 0.0, 1.0); }
 +vec3 saturate(vec3 a) { return clamp(a, 0.0, 1.0); }
 +vec4 saturate(vec4 a) { return clamp(a, 0.0, 1.0); }
 +
 +float distance_squared(vec2 a, vec2 b) { a -= b; return dot(a, a); }
 +float distance_squared(vec3 a, vec3 b) { a -= b; return dot(a, a); }
 +float len_squared(vec3 a) { return dot(a, a); }
 +
 +float inverse_distance(vec3 V) { return max( 1 / length(V), 1e-8); }
 +
 +vec2 mip_ratio_interp(float mip) {
 +      float low_mip = floor(mip);
 +      return mix(mipRatio[int(low_mip)], mipRatio[int(low_mip + 1.0)], mip - low_mip);
 +}
 +
 +/* ------- RNG ------- */
 +
 +float wang_hash_noise(uint s)
 +{
 +      s = (s ^ 61u) ^ (s >> 16u);
 +      s *= 9u;
 +      s = s ^ (s >> 4u);
 +      s *= 0x27d4eb2du;
 +      s = s ^ (s >> 15u);
 +
 +      return fract(float(s) / 4294967296.0);
 +}
 +
 +/* ------- Fast Math ------- */
 +
 +/* [Drobot2014a] Low Level Optimizations for GCN */
 +float fast_sqrt(float v)
 +{
 +      return intBitsToFloat(0x1fbd1df5 + (floatBitsToInt(v) >> 1));
 +}
 +
 +vec2 fast_sqrt(vec2 v)
 +{
 +      return intBitsToFloat(0x1fbd1df5 + (floatBitsToInt(v) >> 1));
 +}
 +
 +/* [Eberly2014] GPGPU Programming for Games and Science */
 +float fast_acos(float v)
 +{
 +      float res = -0.156583 * abs(v) + M_PI_2;
 +      res *= fast_sqrt(1.0 - abs(v));
 +      return (v >= 0) ? res : M_PI - res;
 +}
 +
 +vec2 fast_acos(vec2 v)
 +{
 +      vec2 res = -0.156583 * abs(v) + M_PI_2;
 +      res *= fast_sqrt(1.0 - abs(v));
 +      v.x = (v.x >= 0) ? res.x : M_PI - res.x;
 +      v.y = (v.y >= 0) ? res.y : M_PI - res.y;
 +      return v;
 +}
 +
 +float point_plane_projection_dist(vec3 lineorigin, vec3 planeorigin, vec3 planenormal)
 +{
 +      return dot(planenormal, planeorigin - lineorigin);
 +}
 +
 +float line_plane_intersect_dist(vec3 lineorigin, vec3 linedirection, vec3 planeorigin, vec3 planenormal)
 +{
 +      return dot(planenormal, planeorigin - lineorigin) / dot(planenormal, linedirection);
 +}
 +
 +float line_plane_intersect_dist(vec3 lineorigin, vec3 linedirection, vec4 plane)
 +{
 +      vec3 plane_co = plane.xyz * (-plane.w / len_squared(plane.xyz));
 +      vec3 h = lineorigin - plane_co;
 +      return -dot(plane.xyz, h) / dot(plane.xyz, linedirection);
 +}
 +
 +vec3 line_plane_intersect(vec3 lineorigin, vec3 linedirection, vec3 planeorigin, vec3 planenormal)
 +{
 +      float dist = line_plane_intersect_dist(lineorigin, linedirection, planeorigin, planenormal);
 +      return lineorigin + linedirection * dist;
 +}
 +
 +vec3 line_plane_intersect(vec3 lineorigin, vec3 linedirection, vec4 plane)
 +{
 +      float dist = line_plane_intersect_dist(lineorigin, linedirection, plane);
 +      return lineorigin + linedirection * dist;
 +}
 +
 +float line_aligned_plane_intersect_dist(vec3 lineorigin, vec3 linedirection, vec3 planeorigin)
 +{
 +      /* aligned plane normal */
 +      vec3 L = planeorigin - lineorigin;
 +      float diskdist = length(L);
 +      vec3 planenormal = -normalize(L);
 +      return -diskdist / dot(planenormal, linedirection);
 +}
 +
 +vec3 line_aligned_plane_intersect(vec3 lineorigin, vec3 linedirection, vec3 planeorigin)
 +{
 +      float dist = line_aligned_plane_intersect_dist(lineorigin, linedirection, planeorigin);
 +      if (dist < 0) {
 +              /* if intersection is behind we fake the intersection to be
 +               * really far and (hopefully) not inside the radius of interest */
 +              dist = 1e16;
 +      }
 +      return lineorigin + linedirection * dist;
 +}
 +
 +float line_unit_sphere_intersect_dist(vec3 lineorigin, vec3 linedirection)
 +{
 +      float a = dot(linedirection, linedirection);
 +      float b = dot(linedirection, lineorigin);
 +      float c = dot(lineorigin, lineorigin) - 1;
 +
 +      float dist = 1e15;
 +      float determinant = b * b - a * c;
 +      if (determinant >= 0)
 +              dist = (sqrt(determinant) - b) / a;
 +
 +      return dist;
 +}
 +
 +float line_unit_box_intersect_dist(vec3 lineorigin, vec3 linedirection)
 +{
 +      /* https://seblagarde.wordpress.com/2012/09/29/image-based-lighting-approaches-and-parallax-corrected-cubemap/ */
 +      vec3 firstplane  = (vec3( 1.0) - lineorigin) / linedirection;
 +      vec3 secondplane = (vec3(-1.0) - lineorigin) / linedirection;
 +      vec3 furthestplane = max(firstplane, secondplane);
 +
 +      return min_v3(furthestplane);
 +}
 +
 +
 +/* Return texture coordinates to sample Surface LUT */
 +vec2 lut_coords(float cosTheta, float roughness)
 +{
 +      float theta = acos(cosTheta);
 +      vec2 coords = vec2(roughness, theta / M_PI_2);
 +
 +      /* scale and bias coordinates, for correct filtered lookup */
 +      return coords * (LUT_SIZE - 1.0) / LUT_SIZE + 0.5 / LUT_SIZE;
 +}
 +
 +/* -- 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(bool is_persp, float z, float zf, float zn)
 +{
 +      if (is_persp) {
 +              return (zn  * zf) / (z * (zn - zf) + zf);
 +      }
 +      else {
 +              return (z * 2.0 - 1.0) * zf;
 +      }
 +}
 +
 +float buffer_depth(bool is_persp, float z, float zf, float zn)
 +{
 +      if (is_persp) {
 +              return (zf * (zn - z)) / (z * (zn - zf));
 +      }
 +      else {
 +              return (z / (zf * 2.0)) + 0.5;
 +      }
 +}
 +
 +float get_view_z_from_depth(float depth)
 +{
 +      if (ProjectionMatrix[3][3] == 0.0) {
 +              float d = 2.0 * depth - 1.0;
 +              return -ProjectionMatrix[3][2] / (d + ProjectionMatrix[2][2]);
 +      }
 +      else {
 +              return viewVecs[0].z + depth * viewVecs[1].z;
 +      }
 +}
 +
 +float get_depth_from_view_z(float z)
 +{
 +      if (ProjectionMatrix[3][3] == 0.0) {
 +              float d = (-ProjectionMatrix[3][2] / z) - ProjectionMatrix[2][2];
 +              return d * 0.5 + 0.5;
 +      }
 +      else {
 +              return (z - viewVecs[0].z) / viewVecs[1].z;
 +      }
 +}
 +
 +vec2 get_uvs_from_view(vec3 view)
 +{
 +      vec3 ndc = project_point(ProjectionMatrix, view);
 +      return ndc.xy * 0.5 + 0.5;
 +}
 +
 +vec3 get_view_space_from_depth(vec2 uvcoords, float depth)
 +{
 +      if (ProjectionMatrix[3][3] == 0.0) {
 +              return vec3(viewVecs[0].xy + uvcoords * viewVecs[1].xy, 1.0) * get_view_z_from_depth(depth);
 +      }
 +      else {
 +              return viewVecs[0].xyz + vec3(uvcoords, depth) * viewVecs[1].xyz;
 +      }
 +}
 +
 +vec3 get_world_space_from_depth(vec2 uvcoords, float depth)
 +{
 +      return (ViewMatrixInverse * vec4(get_view_space_from_depth(uvcoords, depth), 1.0)).xyz;
 +}
 +
 +vec3 get_specular_reflection_dominant_dir(vec3 N, vec3 V, float roughness)
 +{
 +      vec3 R = -reflect(V, N);
 +      float smoothness = 1.0 - roughness;
 +      float fac = smoothness * (sqrt(smoothness) + roughness);
 +      return normalize(mix(N, R, fac));
 +}
 +
 +float specular_occlusion(float NV, float AO, float roughness)
 +{
 +      return saturate(pow(NV + AO, roughness) - 1.0 + AO);
 +}
 +
 +/* --- Refraction utils --- */
 +
 +float ior_from_f0(float f0)
 +{
 +      float f = sqrt(f0);
 +      return (-f - 1.0) / (f - 1.0);
 +}
 +
 +float f0_from_ior(float eta)
 +{
 +      float A = (eta - 1.0) / (eta + 1.0);
 +      return A * A;
 +}
 +
 +vec3 get_specular_refraction_dominant_dir(vec3 N, vec3 V, float roughness, float ior)
 +{
 +      /* TODO: This a bad approximation. Better approximation should fit
 +       * the refracted vector and roughness into the best prefiltered reflection
 +       * lobe. */
 +      /* Correct the IOR for ior < 1.0 to not see the abrupt delimitation or the TIR */
 +      ior = (ior < 1.0) ? mix(ior, 1.0, roughness) : ior;
 +      float eta = 1.0 / ior;
 +
 +      float NV = dot(N, -V);
 +
 +      /* Custom Refraction. */
 +      float k = 1.0 - eta * eta * (1.0 - NV * NV);
 +      k = max(0.0, k); /* Only this changes. */
 +      vec3 R = eta * -V - (eta * NV + sqrt(k)) * N;
 +
 +      return R;
 +}
 +
 +float get_btdf_lut(sampler2DArray btdf_lut_tex, float NV, float roughness, float ior)
 +{
 +      const vec3 lut_scale_bias_texel_size = vec3((LUT_SIZE - 1.0), 0.5, 1.5) / LUT_SIZE;
 +
 +      vec3 coords;
 +      /* Try to compensate for the low resolution and interpolation error. */
 +      coords.x = (ior > 1.0)
 +                 ? (0.9 + lut_scale_bias_texel_size.z) + (0.1 - lut_scale_bias_texel_size.z) * f0_from_ior(ior)
 +                 : (0.9 + lut_scale_bias_texel_size.z) * ior * ior;
 +      coords.y = 1.0 - saturate(NV);
 +      coords.xy *= lut_scale_bias_texel_size.x;
 +      coords.xy += lut_scale_bias_texel_size.y;
 +
 +      const float lut_lvl_ofs = 4.0; /* First texture lvl of roughness. */
 +      const float lut_lvl_scale = 16.0; /* How many lvl of roughness in the lut. */
 +
 +      float mip = roughness * lut_lvl_scale;
 +      float mip_floor = floor(mip);
 +
 +      coords.z = lut_lvl_ofs + mip_floor + 1.0;
 +      float btdf_high = textureLod(btdf_lut_tex, coords, 0.0).r;
 +
 +      coords.z -= 1.0;
 +      float btdf_low = textureLod(btdf_lut_tex, coords, 0.0).r;
 +
 +      float btdf = (ior == 1.0) ? 1.0 : mix(btdf_low, btdf_high, mip - coords.z);
 +
 +      return btdf;
 +}
 +
 +/* ---- Encode / Decode Normal buffer data ---- */
 +/* From http://aras-p.info/texts/CompactNormalStorage.html
 + * Using Method #4: Spheremap Transform */
 +vec2 normal_encode(vec3 n, vec3 view)
 +{
 +      float p = sqrt(n.z * 8.0 + 8.0);
 +      return n.xy / p + 0.5;
 +}
 +
 +vec3 normal_decode(vec2 enc, vec3 view)
 +{
 +      vec2 fenc = enc * 4.0 - 2.0;
 +      float f = dot(fenc, fenc);
 +      float g = sqrt(1.0 - f / 4.0);
 +      vec3 n;
 +      n.xy = fenc*g;
 +      n.z = 1 - f / 2;
 +      return n;
 +}
 +
 +/* ---- RGBM (shared multiplier) encoding ---- */
 +/* From http://iwasbeingirony.blogspot.fr/2010/06/difference-between-rgbm-and-rgbd.html */
 +
 +/* Higher RGBM_MAX_RANGE gives imprecision issues in low intensity. */
 +#define RGBM_MAX_RANGE 512.0
 +
 +vec4 rgbm_encode(vec3 rgb)
 +{
 +      float maxRGB = max_v3(rgb);
 +      float M = maxRGB / RGBM_MAX_RANGE;
 +      M = ceil(M * 255.0) / 255.0;
 +      return vec4(rgb / (M * RGBM_MAX_RANGE), M);
 +}
 +
 +vec3 rgbm_decode(vec4 data)
 +{
 +      return data.rgb * (data.a * RGBM_MAX_RANGE);
 +}
 +
 +/* ---- RGBE (shared exponent) encoding ---- */
 +vec4 rgbe_encode(vec3 rgb)
 +{
 +      float maxRGB = max_v3(rgb);
 +      float fexp = ceil(log2(maxRGB));
 +      return vec4(rgb / exp2(fexp), (fexp + 128.0) / 255.0);
 +}
 +
 +vec3 rgbe_decode(vec4 data)
 +{
 +      float fexp = data.a * 255.0 - 128.0;
 +      return data.rgb * exp2(fexp);
 +}
 +
 +#if 1
 +#define irradiance_encode rgbe_encode
 +#define irradiance_decode rgbe_decode
 +#else /* No ecoding (when using floating point format) */
 +#define irradiance_encode(X) (X).rgbb
 +#define irradiance_decode(X) (X).rgb
 +#endif
 +
 +/* Irradiance Visibility Encoding */
 +#if 1
 +vec4 visibility_encode(vec2 accum, float range)
 +{
 +      accum /= range;
 +
 +      vec4 data;
 +      data.x = fract(accum.x);
 +      data.y = floor(accum.x) / 255.0;
 +      data.z = fract(accum.y);
 +      data.w = floor(accum.y) / 255.0;
 +
 +      return data;
 +}
 +
 +vec2 visibility_decode(vec4 data, float range)
 +{
 +      return (data.xz + data.yw * 255.0) * range;
 +}
 +#else /* No ecoding (when using floating point format) */
 +vec4 visibility_encode(vec2 accum, float range)
 +{
 +      return accum.xyxy;
 +}
 +
 +vec2 visibility_decode(vec4 data, float range)
 +{
 +      return data.xy;
 +}
 +#endif
 +
 +/* Fresnel monochromatic, perfect mirror */
 +float F_eta(float eta, float cos_theta)
 +{
 +      /* compute fresnel reflectance without explicitly computing
 +       * the refracted direction */
 +      float c = abs(cos_theta);
 +      float g = eta * eta - 1.0 + c * c;
 +      float result;
 +
 +      if (g > 0.0) {
 +              g = sqrt(g);
 +              vec2 g_c = vec2(g) + vec2(c, -c);
 +              float A = g_c.y / g_c.x;
 +              A *= A;
 +              g_c *= c;
 +              float B = (g_c.y - 1.0) / (g_c.x + 1.0);
 +              B *= B;
 +              result = 0.5 * A * (1.0 + B);
 +      }
 +      else {
 +              result = 1.0;  /* TIR (no refracted component) */
 +      }
 +
 +      return result;
 +}
 +
 +/* Fresnel */
 +vec3 F_schlick(vec3 f0, float cos_theta)
 +{
 +      float fac = 1.0 - cos_theta;
 +      float fac2 = fac * fac;
 +      fac = fac2 * fac2 * fac;
 +
 +      /* Unreal specular matching : if specular color is below 2% intensity,
 +       * (using green channel for intensity) treat as shadowning */
 +      return saturate(50.0 * dot(f0, vec3(0.3, 0.6, 0.1))) * fac + (1.0 - fac) * f0;
 +}
 +
 +/* Fresnel approximation for LTC area lights (not MRP) */
 +vec3 F_area(vec3 f0, vec2 lut)
 +{
 +      vec2 fac = normalize(lut.xy); /* XXX FIXME this does not work!!! */
 +
 +      /* Unreal specular matching : if specular color is below 2% intensity,
 +       * treat as shadowning */
 +      return saturate(50.0 * dot(f0, vec3(0.3, 0.6, 0.1))) * fac.y + fac.x * f0;
 +}
 +
 +/* Fresnel approximation for IBL */
 +vec3 F_ibl(vec3 f0, vec2 lut)
 +{
 +      /* Unreal specular matching : if specular color is below 2% intensity,
 +       * treat as shadowning */
 +      return saturate(50.0 * dot(f0, vec3(0.3, 0.6, 0.1))) * lut.y + lut.x * f0;
 +}
 +
 +/* GGX */
 +float D_ggx_opti(float NH, float a2)
 +{
 +      float tmp = (NH * a2 - NH) * NH + 1.0;
 +      return M_PI * tmp*tmp; /* Doing RCP and mul a2 at the end */
 +}
 +
 +float G1_Smith_GGX(float NX, float a2)
 +{
 +      /* Using Brian Karis approach and refactoring by NX/NX
 +       * this way the (2*NL)*(2*NV) in G = G1(V) * G1(L) gets canceled by the brdf denominator 4*NL*NV
 +       * Rcp is done on the whole G later
 +       * Note that this is not convenient for the transmition formula */
 +      return NX + sqrt(NX * (NX - NX * a2) + a2);
 +      /* return 2 / (1 + sqrt(1 + a2 * (1 - NX*NX) / (NX*NX) ) ); /* Reference function */
 +}
 +
 +float bsdf_ggx(vec3 N, vec3 L, vec3 V, float roughness)
 +{
 +      float a = roughness;
 +      float a2 = a * a;
 +
 +      vec3 H = normalize(L + V);
 +      float NH = max(dot(N, H), 1e-8);
 +      float NL = max(dot(N, L), 1e-8);
 +      float NV = max(dot(N, V), 1e-8);
 +
 +      float G = G1_Smith_GGX(NV, a2) * G1_Smith_GGX(NL, a2); /* Doing RCP at the end */
 +      float D = D_ggx_opti(NH, a2);
 +
 +      /* Denominator is canceled by G1_Smith */
 +      /* bsdf = D * G / (4.0 * NL * NV); /* Reference function */
 +      return NL * a2 / (D * G); /* NL to Fit cycles Equation : line. 345 in bsdf_microfacet.h */
 +}
 +
 +void accumulate_light(vec3 light, float fac, inout vec4 accum)
 +{
 +      accum += vec4(light, 1.0) * min(fac, (1.0 - accum.a));
 +}
 +
 +/* ----------- Cone Apperture Approximation --------- */
 +
 +/* Return a fitted cone angle given the input roughness */
 +float cone_cosine(float r)
 +{
 +      /* Using phong gloss
 +       * roughness = sqrt(2/(gloss+2)) */
 +      float gloss = -2 + 2 / (r * r);
 +      /* Drobot 2014 in GPUPro5 */
 +      // return cos(2.0 * sqrt(2.0 / (gloss + 2)));
 +      /* Uludag 2014 in GPUPro5 */
 +      // return pow(0.244, 1 / (gloss + 1));
 +      /* Jimenez 2016 in Practical Realtime Strategies for Accurate Indirect Occlusion*/
 +      return exp2(-3.32193 * r * r);
 +}
 +
 +/* --------- Closure ---------- */
 +#ifdef VOLUMETRICS
 +
 +struct Closure {
 +      vec3 absorption;
 +      vec3 scatter;
 +      vec3 emission;
 +      float anisotropy;
 +};
 +
 +#define CLOSURE_DEFAULT Closure(vec3(0.0), vec3(0.0), vec3(0.0), 0.0)
 +
 +Closure closure_mix(Closure cl1, Closure cl2, float fac)
 +{
 +      Closure cl;
 +      cl.absorption = mix(cl1.absorption, cl2.absorption, fac);
 +      cl.scatter = mix(cl1.scatter, cl2.scatter, fac);
 +      cl.emission = mix(cl1.emission, cl2.emission, fac);
 +      cl.anisotropy = mix(cl1.anisotropy, cl2.anisotropy, fac);
 +      return cl;
 +}
 +
 +Closure closure_add(Closure cl1, Closure cl2)
 +{
 +      Closure cl;
 +      cl.absorption = cl1.absorption + cl2.absorption;
 +      cl.scatter = cl1.scatter + cl2.scatter;
 +      cl.emission = cl1.emission + cl2.emission;
 +      cl.anisotropy = (cl1.anisotropy + cl2.anisotropy) / 2.0; /* Average phase (no multi lobe) */
 +      return cl;
 +}
 +
++Closure closure_emission(vec3 rgb)
++{
++      Closure cl = CLOSURE_DEFAULT;
++      cl.emission = rgb;
++      return cl;
++}
++
 +#else /* VOLUMETRICS */
 +
 +struct Closure {
 +      vec3 radiance;
 +      float opacity;
 +#  ifdef USE_SSS
 +      vec4 sss_data;
 +#    ifdef USE_SSS_ALBEDO
 +      vec3 sss_albedo;
 +#    endif
 +#  endif
 +      vec4 ssr_data;
 +      vec2 ssr_normal;
 +      int ssr_id;
 +};
 +
 +/* This is hacking ssr_id to tag transparent bsdf */
 +#define TRANSPARENT_CLOSURE_FLAG -2
 +#define REFRACT_CLOSURE_FLAG -3
 +#define NO_SSR -999
 +
 +#  ifdef USE_SSS
 +#    ifdef USE_SSS_ALBEDO
 +#define CLOSURE_DEFAULT Closure(vec3(0.0), 1.0, vec4(0.0), vec3(0.0), vec4(0.0), vec2(0.0), -1)
 +#    else
 +#define CLOSURE_DEFAULT Closure(vec3(0.0), 1.0, vec4(0.0), vec4(0.0), vec2(0.0), -1)
 +#    endif
 +#  else
 +#define CLOSURE_DEFAULT Closure(vec3(0.0), 1.0, vec4(0.0), vec2(0.0), -1)
 +#  endif
 +
 +uniform int outputSsrId;
 +
 +Closure closure_mix(Closure cl1, Closure cl2, float fac)
 +{
 +      Closure cl;
 +
 +      if (cl1.ssr_id == TRANSPARENT_CLOSURE_FLAG) {
 +              cl1.radiance = cl2.radiance;
 +              cl1.ssr_normal = cl2.ssr_normal;
 +              cl1.ssr_data = cl2.ssr_data;
 +              cl1.ssr_id = cl2.ssr_id;
 +#  ifdef USE_SSS
 +              cl1.sss_data = cl2.sss_data;
 +#    ifdef USE_SSS_ALBEDO
 +              cl1.sss_albedo = cl2.sss_albedo;
 +#    endif
 +#  endif
 +      }
 +      if (cl2.ssr_id == TRANSPARENT_CLOSURE_FLAG) {
 +              cl2.radiance = cl1.radiance;
 +              cl2.ssr_normal = cl1.ssr_normal;
 +              cl2.ssr_data = cl1.ssr_data;
 +              cl2.ssr_id = cl1.ssr_id;
 +#  ifdef USE_SSS
 +              cl2.sss_data = cl1.sss_data;
 +#    ifdef USE_SSS_ALBEDO
 +              cl2.sss_albedo = cl1.sss_albedo;
 +#    endif
 +#  endif
 +      }
 +      if (cl1.ssr_id == outputSsrId) {
 +              cl.ssr_data = mix(cl1.ssr_data.xyzw, vec4(vec3(0.0), cl1.ssr_data.w), fac); /* do not blend roughness */
 +              cl.ssr_normal = cl1.ssr_normal;
 +              cl.ssr_id = cl1.ssr_id;
 +      }
 +      else {
 +              cl.ssr_data = mix(vec4(vec3(0.0), cl2.ssr_data.w), cl2.ssr_data.xyzw, fac); /* do not blend roughness */
 +              cl.ssr_normal = cl2.ssr_normal;
 +              cl.ssr_id = cl2.ssr_id;
 +      }
 +      cl.radiance = mix(cl1.radiance, cl2.radiance, fac);
 +      cl.opacity = mix(cl1.opacity, cl2.opacity, fac);
 +
 +#  ifdef USE_SSS
 +      cl.sss_data.rgb = mix(cl1.sss_data.rgb, cl2.sss_data.rgb, fac);
 +      cl.sss_data.a = (cl1.sss_data.a > 0.0) ? cl1.sss_data.a : cl2.sss_data.a;
 +#    ifdef USE_SSS_ALBEDO
 +      /* TODO Find a solution to this. Dither? */
 +      cl.sss_albedo = (cl1.sss_data.a > 0.0) ? cl1.sss_albedo : cl2.sss_albedo;
 +#    endif
 +#  endif
 +
 +      return cl;
 +}
 +
 +Closure closure_add(Closure cl1, Closure cl2)
 +{
 +      Closure cl = (cl1.ssr_id == outputSsrId) ? cl1 : cl2;
 +#  ifdef USE_SSS
 +      cl.sss_data = (cl1.sss_data.a > 0.0) ? cl1.sss_data : cl2.sss_data;
 +#    ifdef USE_SSS_ALBEDO
 +      /* TODO Find a solution to this. Dither? */
 +      cl.sss_albedo = (cl1.sss_data.a > 0.0) ? cl1.sss_albedo : cl2.sss_albedo;
 +#    endif
 +#  endif
 +      cl.radiance = cl1.radiance + cl2.radiance;
 +      cl.opacity = saturate(cl1.opacity + cl2.opacity);
 +      return cl;
 +}
 +
++Closure closure_emission(vec3 rgb)
++{
++      Closure cl = CLOSURE_DEFAULT;
++      cl.radiance = rgb;
++      return cl;
++}
++
 +#  if defined(MESH_SHADER) && !defined(USE_ALPHA_HASH) && !defined(USE_ALPHA_CLIP) && !defined(SHADOW_SHADER) && !defined(USE_MULTIPLY)
 +layout(location = 0) out vec4 fragColor;
 +layout(location = 1) out vec4 ssrNormals;
 +layout(location = 2) out vec4 ssrData;
 +#    ifdef USE_SSS
 +layout(location = 3) out vec4 sssData;
 +#      ifdef USE_SSS_ALBEDO
 +layout(location = 4) out vec4 sssAlbedo;
 +#      endif /* USE_SSS_ALBEDO */
 +#    endif /* USE_SSS */
 +
 +Closure nodetree_exec(void); /* Prototype */
 +
 +#    if defined(USE_ALPHA_BLEND_VOLUMETRICS)
 +/* Prototype because this file is included before volumetric_lib.glsl */
 +vec4 volumetric_resolve(vec4 scene_color, vec2 frag_uvs, float frag_depth);
 +#    endif
 +
 +#define NODETREE_EXEC
 +void main()
 +{
 +      Closure cl = nodetree_exec();
 +#    ifndef USE_ALPHA_BLEND
 +      /* Prevent alpha hash material writing into alpha channel. */
 +      cl.opacity = 1.0;
 +#    endif
 +
 +#    if defined(USE_ALPHA_BLEND_VOLUMETRICS)
 +      /* XXX fragile, better use real viewport resolution */
 +      vec2 uvs = gl_FragCoord.xy / vec2(2 * textureSize(maxzBuffer, 0).xy);
 +      fragColor = volumetric_resolve(vec4(cl.radiance, cl.opacity), uvs, gl_FragCoord.z);
 +#    else
 +      fragColor = vec4(cl.radiance, cl.opacity);
 +#    endif
 +
 +      ssrNormals = cl.ssr_normal.xyyy;
 +      ssrData = cl.ssr_data;
 +#    ifdef USE_SSS
 +      sssData = cl.sss_data;
 +#      ifdef USE_SSS_ALBEDO
 +      sssAlbedo = cl.sss_albedo.rgbb;
 +#      endif
 +#    endif
 +
 +      /* For Probe capture */
 +#    ifdef USE_SSS
 +#      ifdef USE_SSS_ALBEDO
 +      fragColor.rgb += cl.sss_data.rgb * cl.sss_albedo.rgb * float(!sssToggle);
 +#      else
 +      fragColor.rgb += cl.sss_data.rgb * float(!sssToggle);
 +#      endif
 +#    endif
 +}
 +
 +#  endif /* MESH_SHADER && !SHADOW_SHADER */
 +
 +#endif /* VOLUMETRICS */
 +
 +Closure nodetree_exec(void); /* Prototype */
 +
 +/* TODO find a better place */
 +#ifdef USE_MULTIPLY
 +
 +out vec4 fragColor;
 +
 +#define NODETREE_EXEC
 +void main()
 +{
 +      Closure cl = nodetree_exec();
 +      fragColor = vec4(mix(vec3(1.0), cl.radiance, cl.opacity), 1.0);
 +}
 +#endif
Simple merge
@@@ -416,16 -343,14 +416,27 @@@ static void codegen_convert_datatype(Dy
                else if (from == GPU_FLOAT)
                        BLI_dynstr_appendf(ds, "vec3(%s, %s, %s)", name, name, name);
        }
--      else {
++      else if (to == GPU_VEC4) {
                if (from == GPU_VEC3)
                        BLI_dynstr_appendf(ds, "vec4(%s, 1.0)", name);
                else if (from == GPU_VEC2)
                        BLI_dynstr_appendf(ds, "vec4(%s.r, %s.r, %s.r, %s.g)", name, name, name, name);
                else if (from == GPU_FLOAT)
                        BLI_dynstr_appendf(ds, "vec4(%s, %s, %s, 1.0)", name, name, name);
-               else /* can happen with closure */
-                       BLI_dynstr_append(ds, name);
+       }
++      else if (to == GPU_CLOSURE) {
++              if (from == GPU_VEC4)
++                      BLI_dynstr_appendf(ds, "closure_emission(%s.rgb)", name);
++              else if (from == GPU_VEC3)
++                      BLI_dynstr_appendf(ds, "closure_emission(%s.rgb)", name);
++              else if (from == GPU_VEC2)
++                      BLI_dynstr_appendf(ds, "closure_emission(%s.rrr)", name);
++              else if (from == GPU_FLOAT)
++                      BLI_dynstr_appendf(ds, "closure_emission(vec3(%s, %s, %s))", name, name, name);
++      }
++      else {
++              BLI_dynstr_append(ds, name);
 +      }
  }
  
  static void codegen_print_datatype(DynStr *ds, const GPUType type, float *data)
@@@ -1,45 -1,3 +1,13 @@@
- /* 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 */
 +
 +uniform mat4 ModelMatrix;
 +uniform mat4 ModelViewMatrix;
 +uniform mat4 ModelViewMatrixInverse;
 +uniform mat3 NormalMatrix;
 +
 +#ifndef ATTRIB
 +uniform mat4 ModelMatrixInverse;
 +#endif
 +
  /* Converters */
  
  float convert_rgba_to_float(vec4 color)