1
2#pragma BLENDER_REQUIRE(common_view_lib.glsl)
3#pragma BLENDER_REQUIRE(common_math_geom_lib.glsl)
4#pragma BLENDER_REQUIRE(common_utiltex_lib.glsl)
5#pragma BLENDER_REQUIRE(lights_lib.glsl)
6
7in vec4 uvcoordsvar;
8
9out vec4 FragColor;
10
11uniform sampler2D depthBuffer;
12uniform sampler1D sssTexProfile;
13uniform sampler2D sssRadius;
14uniform sampler2DArray sssShadowCubes;
15uniform sampler2DArray sssShadowCascades;
16
17#define MAX_SSS_SAMPLES 65
18#define SSS_LUT_SIZE 64.0
19#define SSS_LUT_SCALE ((SSS_LUT_SIZE - 1.0) / float(SSS_LUT_SIZE))
20#define SSS_LUT_BIAS (0.5 / float(SSS_LUT_SIZE))
21
22layout(std140) uniform sssProfile
23{
24  vec4 kernel[MAX_SSS_SAMPLES];
25  vec4 radii_max_radius;
26  int sss_samples;
27};
28
29vec3 sss_profile(float s)
30{
31  s /= radii_max_radius.w;
32  return texture(sssTexProfile, saturate(s) * SSS_LUT_SCALE + SSS_LUT_BIAS).rgb;
33}
34
35float light_translucent_power_with_falloff(LightData ld, vec3 N, vec4 l_vector)
36{
37  float power, falloff;
38  /* XXX : Removing Area Power. */
39  /* TODO : put this out of the shader. */
40  if (ld.l_type >= AREA_RECT) {
41    power = (ld.l_sizex * ld.l_sizey * 4.0 * M_PI) * (1.0 / 80.0);
42    if (ld.l_type == AREA_ELLIPSE) {
43      power *= M_PI * 0.25;
44    }
45    power *= 0.3 * 20.0 *
46             max(0.0, dot(-ld.l_forward, l_vector.xyz / l_vector.w)); /* XXX ad hoc, empirical */
47    power /= (l_vector.w * l_vector.w);
48    falloff = dot(N, l_vector.xyz / l_vector.w);
49  }
50  else if (ld.l_type == SUN) {
51    power = 1.0 / (1.0 + (ld.l_radius * ld.l_radius * 0.5));
52    power *= ld.l_radius * ld.l_radius * M_PI; /* Removing area light power*/
53    power *= M_2PI * 0.78;                     /* Matching cycles with point light. */
54    power *= 0.082;                            /* XXX ad hoc, empirical */
55    falloff = dot(N, -ld.l_forward);
56  }
57  else {
58    power = (4.0 * ld.l_radius * ld.l_radius) * (1.0 / 10.0);
59    power *= 1.5; /* XXX ad hoc, empirical */
60    power /= (l_vector.w * l_vector.w);
61    falloff = dot(N, l_vector.xyz / l_vector.w);
62  }
63  /* No transmittance at grazing angle (hide artifacts) */
64  return power * saturate(falloff * 2.0);
65}
66
67/* Some driver poorly optimize this code. Use direct reference to matrices. */
68#define sd(x) shadows_data[x]
69#define scube(x) shadows_cube_data[x]
70#define scascade(x) shadows_cascade_data[x]
71
72float shadow_cube_radial_depth(vec3 cubevec, float tex_id, int shadow_id)
73{
74  float depth = sample_cube(sssShadowCubes, cubevec, tex_id).r;
75  /* To reverting the constant bias from shadow rendering. (Tweaked for 16bit shadowmaps) */
76  const float depth_bias = 3.1e-5;
77  depth = saturate(depth - depth_bias);
78
79  depth = linear_depth(true, depth, sd(shadow_id).sh_far, sd(shadow_id).sh_near);
80  depth *= length(cubevec / max_v3(abs(cubevec)));
81  return depth;
82}
83
84vec3 light_translucent(LightData ld, vec3 W, vec3 N, vec4 l_vector, vec2 rand, float sss_scale)
85{
86  int shadow_id = int(ld.l_shadowid);
87
88  vec4 L = (ld.l_type != SUN) ? l_vector : vec4(-ld.l_forward, 1.0);
89
90  /* We use the full l_vector.xyz so that the spread is minimize
91   * if the shading point is further away from the light source */
92  /* TODO(fclem): do something better than this. */
93  vec3 T, B;
94  make_orthonormal_basis(L.xyz / L.w, T, B);
95
96  vec3 n;
97  vec4 depths;
98  float d, dist;
99  int data_id = int(sd(shadow_id).sh_data_index);
100  if (ld.l_type == SUN) {
101    vec4 view_z = vec4(dot(W - cameraPos, cameraForward));
102
103    vec4 weights = step(scascade(data_id).split_end_distances, view_z);
104    float id = abs(4.0 - dot(weights, weights));
105    if (id > 3.0) {
106      return vec3(0.0);
107    }
108
109    /* Same factor as in get_cascade_world_distance(). */
110    float range = abs(sd(shadow_id).sh_far - sd(shadow_id).sh_near);
111
112    vec4 shpos = scascade(data_id).shadowmat[int(id)] * vec4(W, 1.0);
113    dist = shpos.z * range;
114
115    if (shpos.z > 1.0 || shpos.z < 0.0) {
116      return vec3(0.0);
117    }
118
119    float tex_id = scascade(data_id).sh_tex_index + id;
120
121    /* Assume cascades have same height and width. */
122    vec2 ofs = vec2(1.0, 0.0) / float(textureSize(sssShadowCascades, 0).x);
123    d = sample_cascade(sssShadowCascades, shpos.xy, tex_id).r;
124    depths.x = sample_cascade(sssShadowCascades, shpos.xy + ofs.xy, tex_id).r;
125    depths.y = sample_cascade(sssShadowCascades, shpos.xy + ofs.yx, tex_id).r;
126    depths.z = sample_cascade(sssShadowCascades, shpos.xy - ofs.xy, tex_id).r;
127    depths.w = sample_cascade(sssShadowCascades, shpos.xy - ofs.yx, tex_id).r;
128
129    /* To reverting the constant bias from shadow rendering. (Tweaked for 16bit shadowmaps) */
130    float depth_bias = 3.1e-5;
131    depths = saturate(depths - depth_bias);
132    d = saturate(d - depth_bias);
133
134    /* Size of a texel in world space.
135     * FIXME This is only correct if l_right is the same right vector used for shadowmap creation.
136     * This won't work if the shadow matrix is rotated (soft shadows).
137     * TODO precompute */
138    float unit_world_in_uv_space = length(mat3(scascade(data_id).shadowmat[int(id)]) * ld.l_right);
139    float dx_scale = 2.0 * ofs.x / unit_world_in_uv_space;
140
141    d *= range;
142    depths *= range;
143
144    /* This is the normal of the occluder in world space. */
145    // vec3 T = ld.l_forward * dx + ld.l_right * dx_scale;
146    // vec3 B = ld.l_forward * dy + ld.l_up * dx_scale;
147    // n = normalize(cross(T, B));
148  }
149  else {
150    float ofs = 1.0 / float(textureSize(sssShadowCubes, 0).x);
151
152    vec3 cubevec = transform_point(scube(data_id).shadowmat, W);
153    dist = length(cubevec);
154    cubevec /= dist;
155    /* tex_id == data_id for cube shadowmap */
156    float tex_id = float(data_id);
157    d = shadow_cube_radial_depth(cubevec, tex_id, shadow_id);
158    /* NOTE: The offset is irregular in respect to cubeface uvs. But it has
159     * a much more uniform behavior than biasing based on face derivatives. */
160    depths.x = shadow_cube_radial_depth(cubevec + T * ofs, tex_id, shadow_id);
161    depths.y = shadow_cube_radial_depth(cubevec + B * ofs, tex_id, shadow_id);
162    depths.z = shadow_cube_radial_depth(cubevec - T * ofs, tex_id, shadow_id);
163    depths.w = shadow_cube_radial_depth(cubevec - B * ofs, tex_id, shadow_id);
164  }
165
166  float dx = depths.x - depths.z;
167  float dy = depths.y - depths.w;
168
169  float s = min(d, min_v4(depths));
170
171  /* To avoid light leak from depth discontinuity and shadowmap aliasing. */
172  float slope_bias = (abs(dx) + abs(dy)) * 0.5;
173  s -= slope_bias;
174
175  float delta = dist - s;
176
177  float power = light_translucent_power_with_falloff(ld, N, l_vector);
178
179  return power * sss_profile(abs(delta) / sss_scale);
180}
181
182#undef sd
183#undef scube
184#undef scsmd
185
186void main(void)
187{
188  vec2 uvs = uvcoordsvar.xy;
189  float sss_scale = texture(sssRadius, uvs).r;
190  vec3 W = get_world_space_from_depth(uvs, texture(depthBuffer, uvs).r);
191  vec3 N = normalize(cross(dFdx(W), dFdy(W)));
192
193  vec3 rand = texelfetch_noise_tex(gl_FragCoord.xy).zwy;
194  rand.xy *= fast_sqrt(rand.z);
195
196  vec3 accum = vec3(0.0);
197  for (int i = 0; i < MAX_LIGHT && i < laNumLight; i++) {
198    LightData ld = lights_data[i];
199
200    /* Only shadowed light can produce translucency */
201    if (ld.l_shadowid < 0.0) {
202      continue;
203    }
204
205    vec4 l_vector; /* Non-Normalized Light Vector with length in last component. */
206    l_vector.xyz = ld.l_position - W;
207    l_vector.w = length(l_vector.xyz);
208
209    float att = light_attenuation(ld, l_vector);
210    if (att < 1e-8) {
211      continue;
212    }
213
214    accum += att * ld.l_color * light_translucent(ld, W, -N, l_vector, rand.xy, sss_scale);
215  }
216
217  FragColor = vec4(accum, 1.0);
218}
219