Subsurface scattering in Vulkan path tracing

Started by
68 comments, last by taby 1 month, 2 weeks ago

taby said:
What benefits would there be if I did use ray marching?

Blurry rabbits, of coarse. And the fog / haze stuff i have mentioned before.
We could argue that DOF is enough to get blurry stuff, but no. People don't like DOF, because it's blurry. And because they can't control their focus to decide themselves what's sharp and what not. Thus DOF is useful only for cutscenes.

But people do like atmospheric haze stuff. It would be very nice if we could improve over the cheap volumetric lighting approximations we have now, which lack the blur.

It also would be nice to have walls made of ice, and you can see what's behind but it's diffuse and blurry, e.g. a big area light, turning the ice wall into something beautiful.

Things like that. The closest attempt i remember is this: http://www.zyanidelab.com/lighting-participating-media-with-thousands-of-lights/


However, doing this with RT requires to trace primary visibility, ditching efficient rasterization completely.
Almost nobody is doing this right now, for good reasons.
So i would work on this only for fun and learning purposes.

taby said:
Believe me, I tried other methods… 5 in total, over the past month. I'm just glad to have finally found a solution.

Sounds you mostly reinvent wheels on your own?
That's not necessarily bad, but the movie guys have figured out all the stuff already. How's it with the PBRT book, which is free and online?
Personally i can't read it's equations. I also tried to read Veachs thesis, which is even worse. But i just lack the background. PBRT has code as well, however.

And how serious are you about a path traced game?

Advertisement

taby said:
What benefits would there be if I did use ray marching?

I didn't investigate your code thoroughly - but in general when scattering (like in the following image) you want to achieve some kind of effect like this:

Of course, this is from participating media - not subsurface scattering (still subsurface should be able to achieve similar effect to volumetrics - like shadow caster in/through milk, or in your case (I assume) scattering of small bunny-shaped light through leaf → should still keep the bunny shape at the end of day).

I'm not sure whether non-marching approach can achieve those.

My current blog on programming, linux and stuff - http://gameprogrammerdiary.blogspot.com

Vilem Otte said:
you want to achieve some kind of effect like this:

Yes, but… can you make the sphere blurry, or is it already to some subtle amount i can't see?

I guess it's very uncommon to implement this, but i want to see it so badly… :D

Vilem Otte said:
I'm not sure whether non-marching approach can achieve those.

Probably we can, by jittering the ray on the surface of something like rough glass.

But for fog, no way around marching. Crazy expensive ofc.

Edit:

In software we could do it efficiently, since marching could preserve the traversal stack on substeps, so we don't have to restart from the root.

Here is a small code to do marching. I tried it before, and it works pretty good. It's a start anyway:

void get_fog2(
	const vec3 start_location,
	const vec3 end_location,
	const vec3 direction,
	inout float dist_color, 
	inout float dist_opacity,
	const float hue,
	const float eta,
	const vec3 colour)
{
	dist_color = 0;
	dist_opacity = 0;

	const vec3 mask = hsv2rgb(vec3(hue, 1.0, 1.0));

	vec3 start = start_location;
	vec3 end = end_location;

	const float target_step_length = 0.01;

	const int num_steps = int(floor((distance(start, end) / target_step_length)));

	if(num_steps >= 2)
	{
		const vec3 step = (end - start) / (num_steps - 1);

		vec3 curr_step = start;

		for(int j = 0; j < num_steps; j++, curr_step += step)
		{
			float colour = get_omni_radiance_backward(10, 5, curr_step, hue, eta);

			const float trans = 1.0 - clamp(dist_opacity, 0.0, 1.0);
			dist_color += colour*trans;
			dist_opacity += 0.1*trans;
		}
	}

	dist_color *= (colour.r*mask.r + colour.g*mask.g + colour.b*mask.b);

	//dist_color = 1 - dist_color;
}

P.S. You guys rock. Thanks for the input!

Well, I get a regular bunny. I don't know what I'm doing, yet. :)

Edit: There are two spots in the ray generation shader that do the magic. First is the light transport section, which generates caustics and subsurface scattering. Second is the ray splitting/transmitting code.

When the primary ray hits the sphere, you would need to jitter the refraction ray going inwards, similar to the reflection ray going outwards (based on surface roughness). This would make the bunny blurry.

To get scattering inside the medium, you would need to jitter the ray at each marching step, so generating a new ray each time.
Your example code only segments the straight ray. This way you can integrate volume lighting, but the ray itself does not scatter and thus causes no blur.

For efficiency reasons a middle ground should work. E.g. jitter the ray only one times at one random marching step, but still subdivide to integrate volumetrics.

I've tried these things. I tried 5 different methods of attacking the problem, 3 of them with regard to the ray generation section, 2 of them with regard to the light transport section. Perhaps I was missing something trivial. :(

Thanks again so much for your guidance!

This topic is closed to new replies.

Advertisement