The last time we discussed about the approximations needed to compute translucency in real time using TSM. We also created a translucent shadow map and now we are going to use it…
4 – Light diffuses through the material
The light entering the material diffuses in it according to the Rd equation
(take a look at the figure on the right).
Thanks to the TSM computed in the last article, we only need two more informations: Xin and Xout. Xin represents the fragment coordinate (in light space) were light enters the material, while Xout is the point from which the light leaves the object.
In practice, Xout is the fragment coordinate as seen by the camera moving around the object PROJECTED in light space. Once you get the fragment coordinate from the vertex shade, you have it automatically projected in camera (or view) space: since we need to compare this with the data stored in the TSM, we must have them both in the same space (light space). The projection in light space is done by multiplying the view-space-projected coordinate by the camera’s model-view-projection matrix inverse: by doing so we get the object space coordinates, ready to be multiplied by the light’s model-view-projection matrix.
OCS = Object Coordinate System
WCS = World Coordinate System
VCS = View Coordinate System
NDSC = Normalized Device Coordinate System
DCS = Device Coordinate System
Once we have projected Xout in light space, calculating Xin is just a matter of shifting Xout’s (x, y) coordinates by a delta (usually the size of a pixel – 1.0/resX and 1.0/res if you want resolution/ratio independency). In this way we can compute translucency simply by filtering the TSM previously calculated. An elegant an also pretty fast solution, if you ask! Of course, this method have some drawbacks: it assumes the object being completely convex so some errors might occur, even though them not being visually important in the majority of cases…
Rd function in GLSL:
vec4 multipleScattering (vec4 Xin, vec4 Xout, float lvl)
{
vec4 finalColor = vec4(0.0,0.0,0.0,1.0);
float e = 2.718281828459;
/***************************/
//irradiance, depth and normals must account for coordinate shifting!
vec4 irradIN = texture2D(Irradiance, Xin.xy,lvl);
vec4 depthIN = texture2D(DepthBuff, Xin.xy,lvl);
vec4 sNormIN = texture2D(SNormals, Xin.xy,lvl);
//
vec4 sigma_a = lightFreqAbsorbed * tsm_freqAbsorption;
vec4 sigma_s = lightFreqAbsorbed * (1.5-tsm_freqAbsorption);
//
vec4 extinction_coeff = (sigma_a + sigma_s);
vec4 reduced_albedo = sigma_s / extinction_coeff;
vec4 effective_extinction_coeff = sqrt(3.0 * sigma_a * extinction_coeff);
vec4 D = 1.0/(3.0*extinction_coeff);
//
float fresnel_diff = -(1.440/(refr_index*refr_index))+(0.710/refr_index)+0.668+(0.0636*refr_index);
float A = (1.0+fresnel_diff)/(1.0-fresnel_diff);
//
vec4 zr = 1.0/extinction_coeff;
vec4 zv = zr + 4.0*A*D;
//
vec4 xr = Xin – zr * sNormIN;
vec4 xv = Xin + zv * sNormIN;
//
float dr = length(xr – Xout);
float dv = length(xv – Xout);
//
vec4 f1 = reduced_albedo/(4.0*3.1415296);
vec4 f2 = zr * (effective_extinction_coeff * dr + 1.0);
vec4 f3 = pow(vec4(e) , -effective_extinction_coeff * dr) / (extinction_coeff * pow(dr,3.0));
vec4 f4 = zv * (effective_extinction_coeff * dv + 1.0);
vec4 f5 = pow(vec4(e), -effective_extinction_coeff * dv) / (extinction_coeff * pow(dv,3.0));
//
finalColor = f1 * ( f2 * f3 + f4 * f5);
//
return irradIN*finalColor;
}




