1
2#pragma BLENDER_REQUIRE(workbench_data_lib.glsl)
3
4/* [Drobot2014a] Low Level Optimizations for GCN */
5vec4 fast_rcp(vec4 v)
6{
7  return intBitsToFloat(0x7eef370b - floatBitsToInt(v));
8}
9
10vec3 brdf_approx(vec3 spec_color, float roughness, float NV)
11{
12  /* Very rough own approx. We don't need it to be correct, just fast.
13   * Just simulate fresnel effect with roughness attenuation. */
14  float fresnel = exp2(-8.35 * NV) * (1.0 - roughness);
15  return mix(spec_color, vec3(1.0), fresnel);
16}
17
18void prep_specular(
19    vec3 L, vec3 I, vec3 N, vec3 R, out float NL, out float wrapped_NL, out float spec_angle)
20{
21  wrapped_NL = dot(L, R);
22  vec3 half_dir = normalize(L + I);
23  spec_angle = clamp(dot(half_dir, N), 0.0, 1.0);
24  NL = clamp(dot(L, N), 0.0, 1.0);
25}
26
27/* Normalized Blinn shading */
28vec4 blinn_specular(vec4 shininess, vec4 spec_angle, vec4 NL)
29{
30  /* Pi is already divided in the light power.
31   * normalization_factor = (shininess + 8.0) / (8.0 * M_PI) */
32  vec4 normalization_factor = shininess * 0.125 + 1.0;
33  vec4 spec_light = pow(spec_angle, shininess) * NL * normalization_factor;
34
35  return spec_light;
36}
37
38/* NL need to be unclamped. w in [0..1] range. */
39vec4 wrapped_lighting(vec4 NL, vec4 w)
40{
41  vec4 w_1 = w + 1.0;
42  vec4 denom = fast_rcp(w_1 * w_1);
43  return clamp((NL + w) * denom, 0.0, 1.0);
44}
45
46vec3 get_world_lighting(vec3 base_color, float roughness, float metallic, vec3 N, vec3 I)
47{
48  vec3 specular_color, diffuse_color;
49
50  if (world_data.use_specular) {
51    diffuse_color = mix(base_color, vec3(0.0), metallic);
52    specular_color = mix(vec3(0.05), base_color, metallic);
53  }
54  else {
55    diffuse_color = base_color;
56    specular_color = vec3(0.0);
57  }
58
59  vec3 specular_light = world_data.ambient_color.rgb;
60  vec3 diffuse_light = world_data.ambient_color.rgb;
61  vec4 wrap = vec4(world_data.lights[0].diffuse_color_wrap.a,
62                   world_data.lights[1].diffuse_color_wrap.a,
63                   world_data.lights[2].diffuse_color_wrap.a,
64                   world_data.lights[3].diffuse_color_wrap.a);
65
66  if (world_data.use_specular) {
67    /* Prepare Specular computation. Eval 4 lights at once. */
68    vec3 R = -reflect(I, N);
69    vec4 spec_angle, spec_NL, wrap_NL;
70    prep_specular(world_data.lights[0].direction.xyz, I, N, R, spec_NL.x, wrap_NL.x, spec_angle.x);
71    prep_specular(world_data.lights[1].direction.xyz, I, N, R, spec_NL.y, wrap_NL.y, spec_angle.y);
72    prep_specular(world_data.lights[2].direction.xyz, I, N, R, spec_NL.z, wrap_NL.z, spec_angle.z);
73    prep_specular(world_data.lights[3].direction.xyz, I, N, R, spec_NL.w, wrap_NL.w, spec_angle.w);
74
75    vec4 gloss = vec4(1.0 - roughness);
76    /* Reduce gloss for smooth light. (simulate bigger light) */
77    gloss *= 1.0 - wrap;
78    vec4 shininess = exp2(10.0 * gloss + 1.0);
79
80    vec4 spec_light = blinn_specular(shininess, spec_angle, spec_NL);
81
82    /* Simulate Env. light. */
83    vec4 w = mix(wrap, vec4(1.0), roughness);
84    vec4 spec_env = wrapped_lighting(wrap_NL, w);
85
86    spec_light = mix(spec_light, spec_env, wrap * wrap);
87
88    /* Multiply result by lights specular colors. */
89    specular_light += spec_light.x * world_data.lights[0].specular_color.rgb;
90    specular_light += spec_light.y * world_data.lights[1].specular_color.rgb;
91    specular_light += spec_light.z * world_data.lights[2].specular_color.rgb;
92    specular_light += spec_light.w * world_data.lights[3].specular_color.rgb;
93
94    float NV = clamp(dot(N, I), 0.0, 1.0);
95    specular_color = brdf_approx(specular_color, roughness, NV);
96  }
97  specular_light *= specular_color;
98
99  /* Prepare diffuse computation. Eval 4 lights at once. */
100  vec4 diff_NL;
101  diff_NL.x = dot(world_data.lights[0].direction.xyz, N);
102  diff_NL.y = dot(world_data.lights[1].direction.xyz, N);
103  diff_NL.z = dot(world_data.lights[2].direction.xyz, N);
104  diff_NL.w = dot(world_data.lights[3].direction.xyz, N);
105
106  vec4 diff_light = wrapped_lighting(diff_NL, wrap);
107
108  /* Multiply result by lights diffuse colors. */
109  diffuse_light += diff_light.x * world_data.lights[0].diffuse_color_wrap.rgb;
110  diffuse_light += diff_light.y * world_data.lights[1].diffuse_color_wrap.rgb;
111  diffuse_light += diff_light.z * world_data.lights[2].diffuse_color_wrap.rgb;
112  diffuse_light += diff_light.w * world_data.lights[3].diffuse_color_wrap.rgb;
113
114  /* Energy conservation with colored specular look strange.
115   * Limit this strangeness by using mono-chromatic specular intensity. */
116  float spec_energy = dot(specular_color, vec3(0.33333));
117
118  diffuse_light *= diffuse_color * (1.0 - spec_energy);
119
120  return diffuse_light + specular_light;
121}
122
123uniform bool forceShadowing = false;
124
125float get_shadow(vec3 N)
126{
127  float light_factor = -dot(N, world_data.shadow_direction_vs.xyz);
128  float shadow_mix = smoothstep(world_data.shadow_shift, world_data.shadow_focus, light_factor);
129  shadow_mix *= forceShadowing ? 0.0 : world_data.shadow_mul;
130  return shadow_mix + world_data.shadow_add;
131}
132