Subsurface Scattering - Transmittance

Started by
7 comments, last by fire67 8 years, 3 months ago

This is my first post on the gamedev.net forums. So, Hi everyone ! smile.png

I have a question related to SSS and especially transmittance. I've looked at several papers about that topic, most of them from Jorge Jimenez, which are very interesting and, I admit, a bit hard for me.

Here is one of the papers : http://www.iryoku.com/translucency/

I have some difficulties to understand the way it works and the way it calculates the distance the light traveled through the object. I think that I understand the very big lines but I am also a bit confused as I am trying to integrate this into the Unity engine and I have some difficulties to match Unity engine available values such as the shadows maps, the shadows coords, etc... to make them fit the way they are used in the paper.

So here it is, I am a bit lost in the "in-between" and I hope that somebody might be able to help me.

Thanks a lot.

Advertisement

Hi and welcome,

It's been a while since I implemented this effect, so I may be a bit hazy on some details. Basically what's happening is this.

  1. You have a world space position (PWS). Nothing too special here, just a plain world space position.
  2. You transform position PWS by the light's view-projection matrix (PLVP). This is similar to what you do for shadow mapping, but in this case instead of transforming a vertex, you're transforming the exact pixel's world space value.
  3. You then need to transform PLVP into texture space. You can do this manually, or just add the texture space transform to the light's view-projection matrix, because the only component of PLVP that we need is the z-component (depth).
  4. Divide PLVP.xy by PLVP.w and use that as the texture coordinate to sample your shadow map (D1).
  5. Extract the z-component from PLVP (D2).
  6. In the implementation I followed (and the one you cited) they store their shadow maps linearly. I don't do this, so I reconstruct their linear depth. D1 and D2 both need to have linear depth. If your shadow map is stored linearly, you can just multiply each by the far plane used in the light's projection matrix, otherwise you can use projection values to reconstruct them. See MJP's post if you're unclear on what values to use: https://mynameismjp.wordpress.com/2010/09/05/position-from-depth-3/
  7. Now that you have both values linearized, you can take the absolute value of their difference to find the distance between the depths DIST = abs(D1 - D2).

The rest of the effect is based on the scale, weights, and variances values that are generally defined per-kernel. They will vary from material to material, but the code provided should give you all you need for using them properly.

The links below are a little more recent than the one you posted and include the transmittance function as part of the larger solution.

https://cg.tuwien.ac.at/~zsolnai/gfx/separable-subsurface-scattering-with-activision-blizzard/

http://www.iryoku.com/stare-into-the-future

Thank you for your precisions @WFP !

Unfortunately, the directional lights are calculated in screen space in Unity so that might break a bit the calculation of the transmittance, right ?

Do you know if there's a workaround ?

I haven't worked with Unity so I'm not sure on some of its details, but from your description it sounds like you're using a deferred shading pipeline. You should still have all you need to get the transmittance effect working.

From my description above, PWS comes from reconstructing the world space position from the depth buffer at a given pixel, or sampling it directly from a buffer that stores position - whichever Unity uses. If you have access to that and the light's view-projection matrix, which should be included somewhere in a constant buffer as long as the shadow map is being applied to the light, you should have everything you need. You shouldn't need any off-screen information for this effect.

Thank you again for your precisions, this gives me a good path to follow.

Unfortunately, I am in forward rendering mode but as long as I have access to the depth buffer there should not be any problem right ? And deferred is also a path I want to handle.

Just a little addition to my first post fell free to take a look at my question on the Unity forum, it might be a bit focused on some Unity tech but it might also helps understanding my misunderstanding : http://forum.unity3d.com/threads/unity-5-lighting-shadows-coordinates-and-stuff-shader-pro-needed.376875/

From what I understand, I need the depth based on light view and I had some issues about retrieving it for the directional lights.

There shouldn't be any issue using the technique in a forward shading path. You just apply it at the same time you draw and light your geometry. If it's not already, add the world position as an output from the vertex shader / input to the pixel shader. This way you don't even need to reconstruct it, you can use the interpolated value that gets generated from the rasterizer as the same value you'd be getting from reconstruction in a deferred setup. You'll still need to access to your light's view-projection matrix and shadow map for sampling. The steps are the same as above, minus position reconstruction, once you get to the pixel shader.

I'm not sure I'm interpreting Aras's comment correctly from the link you posted, but if he's saying that the shadow map isn't accessible, there might not be a good way to do this as it's a key part of the technique. I'd be surprised if there wasn't some way to customize the pipeline though to provide the shadow map. This is where my limited knowledge of Unity isn't helping.

As Unity provides pixel world position, there should not be any problem about this.

The main bad thing concerns the directional light and I think that I need to hack a bit the pipeline to retrieve the shadow map...

On the other hand there are some other algorithm that handle transmittance such as Dice's one which use a Translucency texture or the one that consists of rendering front and back faces. Do you know any other one ?

Unfortunately I haven't used either of the other approaches, so I won't be able to be too much help there. If you render the front and back faces, you should be able to calculate the thickness of the geometry and use that as a replacement for the thickness value you'd get from the shadow map. The difference, though, is that using that value won't account for other occluders in the scene that would otherwise obstruct the light and diminish or cancel the transmittance effect.

Thanks for your help WFP, this is a lot clearer now but the hard thing is now to access all those values which is not really easy...

This topic is closed to new replies.

Advertisement