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