Welcome to mirror list, hosted at ThFree Co, Russian Federation.

workbench_world_light_lib.glsl « shaders « workbench « engines « draw « blender « source - git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 81f6e651be040e511a9ffe7d4d7b2795723f9729 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131

#pragma BLENDER_REQUIRE(workbench_data_lib.glsl)

/* [Drobot2014a] Low Level Optimizations for GCN */
vec4 fast_rcp(vec4 v)
{
  return intBitsToFloat(0x7eef370b - floatBitsToInt(v));
}

vec3 brdf_approx(vec3 spec_color, float roughness, float NV)
{
  /* Very rough own approx. We don't need it to be correct, just fast.
   * Just simulate fresnel effect with roughness attenuation. */
  float fresnel = exp2(-8.35 * NV) * (1.0 - roughness);
  return mix(spec_color, vec3(1.0), fresnel);
}

void prep_specular(
    vec3 L, vec3 I, vec3 N, vec3 R, out float NL, out float wrapped_NL, out float spec_angle)
{
  wrapped_NL = dot(L, R);
  vec3 half_dir = normalize(L + I);
  spec_angle = clamp(dot(half_dir, N), 0.0, 1.0);
  NL = clamp(dot(L, N), 0.0, 1.0);
}

/* Normalized Blinn shading */
vec4 blinn_specular(vec4 shininess, vec4 spec_angle, vec4 NL)
{
  /* Pi is already divided in the light power.
   * normalization_factor = (shininess + 8.0) / (8.0 * M_PI) */
  vec4 normalization_factor = shininess * 0.125 + 1.0;
  vec4 spec_light = pow(spec_angle, shininess) * NL * normalization_factor;

  return spec_light;
}

/* NL need to be unclamped. w in [0..1] range. */
vec4 wrapped_lighting(vec4 NL, vec4 w)
{
  vec4 w_1 = w + 1.0;
  vec4 denom = fast_rcp(w_1 * w_1);
  return clamp((NL + w) * denom, 0.0, 1.0);
}

vec3 get_world_lighting(vec3 base_color, float roughness, float metallic, vec3 N, vec3 I)
{
  vec3 specular_color, diffuse_color;

  if (world_data.use_specular) {
    diffuse_color = mix(base_color, vec3(0.0), metallic);
    specular_color = mix(vec3(0.05), base_color, metallic);
  }
  else {
    diffuse_color = base_color;
    specular_color = vec3(0.0);
  }

  vec3 specular_light = world_data.ambient_color.rgb;
  vec3 diffuse_light = world_data.ambient_color.rgb;
  vec4 wrap = vec4(world_data.lights[0].diffuse_color_wrap.a,
                   world_data.lights[1].diffuse_color_wrap.a,
                   world_data.lights[2].diffuse_color_wrap.a,
                   world_data.lights[3].diffuse_color_wrap.a);

  if (world_data.use_specular) {
    /* Prepare Specular computation. Eval 4 lights at once. */
    vec3 R = -reflect(I, N);
    vec4 spec_angle, spec_NL, wrap_NL;
    prep_specular(world_data.lights[0].direction.xyz, I, N, R, spec_NL.x, wrap_NL.x, spec_angle.x);
    prep_specular(world_data.lights[1].direction.xyz, I, N, R, spec_NL.y, wrap_NL.y, spec_angle.y);
    prep_specular(world_data.lights[2].direction.xyz, I, N, R, spec_NL.z, wrap_NL.z, spec_angle.z);
    prep_specular(world_data.lights[3].direction.xyz, I, N, R, spec_NL.w, wrap_NL.w, spec_angle.w);

    vec4 gloss = vec4(1.0 - roughness);
    /* Reduce gloss for smooth light. (simulate bigger light) */
    gloss *= 1.0 - wrap;
    vec4 shininess = exp2(10.0 * gloss + 1.0);

    vec4 spec_light = blinn_specular(shininess, spec_angle, spec_NL);

    /* Simulate Env. light. */
    vec4 w = mix(wrap, vec4(1.0), roughness);
    vec4 spec_env = wrapped_lighting(wrap_NL, w);

    spec_light = mix(spec_light, spec_env, wrap * wrap);

    /* Multiply result by lights specular colors. */
    specular_light += spec_light.x * world_data.lights[0].specular_color.rgb;
    specular_light += spec_light.y * world_data.lights[1].specular_color.rgb;
    specular_light += spec_light.z * world_data.lights[2].specular_color.rgb;
    specular_light += spec_light.w * world_data.lights[3].specular_color.rgb;

    float NV = clamp(dot(N, I), 0.0, 1.0);
    specular_color = brdf_approx(specular_color, roughness, NV);
  }
  specular_light *= specular_color;

  /* Prepare diffuse computation. Eval 4 lights at once. */
  vec4 diff_NL;
  diff_NL.x = dot(world_data.lights[0].direction.xyz, N);
  diff_NL.y = dot(world_data.lights[1].direction.xyz, N);
  diff_NL.z = dot(world_data.lights[2].direction.xyz, N);
  diff_NL.w = dot(world_data.lights[3].direction.xyz, N);

  vec4 diff_light = wrapped_lighting(diff_NL, wrap);

  /* Multiply result by lights diffuse colors. */
  diffuse_light += diff_light.x * world_data.lights[0].diffuse_color_wrap.rgb;
  diffuse_light += diff_light.y * world_data.lights[1].diffuse_color_wrap.rgb;
  diffuse_light += diff_light.z * world_data.lights[2].diffuse_color_wrap.rgb;
  diffuse_light += diff_light.w * world_data.lights[3].diffuse_color_wrap.rgb;

  /* Energy conservation with colored specular look strange.
   * Limit this strangeness by using mono-chromatic specular intensity. */
  float spec_energy = dot(specular_color, vec3(0.33333));

  diffuse_light *= diffuse_color * (1.0 - spec_energy);

  return diffuse_light + specular_light;
}

uniform bool forceShadowing = false;

float get_shadow(vec3 N)
{
  float light_factor = -dot(N, world_data.shadow_direction_vs.xyz);
  float shadow_mix = smoothstep(world_data.shadow_shift, world_data.shadow_focus, light_factor);
  shadow_mix *= forceShadowing ? 0.0 : world_data.shadow_mul;
  return shadow_mix + world_data.shadow_add;
}