# Path Tracing Weights

This topic is 2242 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

Hi,

I'm trying to write the simplest possible (no importance sampling, etc.) path tracer from scratch. It will support only diffuse surfaces and area light sources.

A random path should be generated from the camera. Each ray is chosen uniformly from a hemisphere. The path is a maximum length (I realize this introduces bias, but it's a hard constraint. This maximum length can be very large, so the bias can be small).

How can I weight the each step of the path so that this works?

Thanks,
Ian

##### Share on other sites
I've made some progress. The following algorithm works:
-For each point:
....-Continue bouncing the ray with probability proportional to the diffuse color. The bounced ray is generated from a cosine-weighted distribution. You can either weight the ray based on the color's overall intensity, xor consider each channel separately).

This self-explanatory OpenCL code I wrote implements both algorithms. My question now is, given that the algorithm works, how can I change it to use weighting? Most simply, if I change the generate_path(...) function to generate unweighted rays over a hemisphere, how would I weight each ray?

Thanks,
Ian Edited by Geometrian

##### Share on other sites
I have made some more progress. Using unweighted paths, versus cosine weighted, one must correct by a factor of two. So, you sample rays from a random hemisphere. Weight each ray by 2.0*cos(theta) where theta is the angle of outgoing ray from the normal. One way I derived this by comparing the integrals of a standard hemisphere (integrate f(theta)=1 to get 2*pi, which is surface area) to that of a cosine weighted hemisphere (integrate f(theta)=cos(theta) to get pi). It took a while to prove this was the right answer, because a stupid bug prevented it from working.

Naturally, hemispherical sampling makes the convergence worse, because it no longer does importance sampling. However, I think this at least shows that my methodology is sound, and it's an important precursor to eventually making bidirectional path tracing. The below picture shows importance sampling on left versus hemispherical sampling with 2.0*cos(theta) weighting on right. The image was rendered with 2004 samples. The key thing to note is that the illumination is the same, even if the hemispherical sampling has higher variance.

Assuming that the ray scatters, it must go on the hemisphere. I speculate that, on average, the weight of a scatter in any direction on the hemisphere must be 1.0 (that is, the integral of the weights over the hemisphere must be 2*pi). For importance sampling, all the weights are one, but the probability of scattering away from the normal is lower. The integral is 2*pi. For cosine weighted, all the weights are cos(theta), but they need to be scaled by 2 to that the integral is 2*pi. This provides a nice way to make any BRDF--without importance sampling, simply weight each sample by the BRDF(theta), and then scale to ensure that the integral over the hemisphere is 2*pi.

Thanks,
Ian Edited by Geometrian

##### Share on other sites
. . . I guess this is turning into a how-to log for making a path tracer.

More progress: you can collapse all that Russian roulette into a simple weighting scheme. This means that, instead of simulating a bunch of rays conditionally stopping, or whatnot, you simulate a single ray, but weight contributions further along geometrically with reflectance. I feel like I tried this before, but for some reason it didn't work.

This self-explanatory OpenCL code works, though. Note that this uses an importance sampled path--one could generate the same result by sampling uniformly from a hemisphere, but weighting each sample by an extra 2.0*cos(theta), as I discovered in my last post.[source lang="c"]HitRecord hits_camera[N];
int max_depth = generate_path(ray,N, scene,rvec, hits_camera,NULL,true); //Generate importance sampled path
for (int i=0;i&lt;N;++i) {
const HitRecord* hit = hits_camera + i;
float3 f = hit->material->color_diffuse;
}[/source]On left, standard path tracing with Russian roulette ray termination. On right, weighting (the above code). Notice that the above code converges more quickly. Intuitively, this is because the weighting scheme needs only one ray to sample all path depths, whereas the Russian roulette needs at least as many rays as there are depths--and the variance for doing this is higher; for weighting, we use the expected value of the reflectance function.

Thanks,
Ian Edited by Geometrian

##### Share on other sites
Hmm but the point of RR is unbiased results... whereas your weighting scheme (btw that doesn't look like a weighting scheme... just a simplified normal lighting bounce calculation) stops at N bounces... what about N+1 bounces?

Russian roulette needs at least as many rays as there are depths[/quote]
This statement doesn't quite make sense. Edited by jameszhao00

##### Share on other sites
By weighting scheme, I mean I am weighting the ray so as to simulate a number of RR rays. The ray goes as far as possible (it can't go forever; I'm on the GPU), and then it's weighted. The result of shooting one ray, weighting each step is thus the same as shooting many RR rays and not weighting any (notice I get the same result either way, but shooting only one ray is faster, so it converges better).

##### Share on other sites
By rays, do you mean a path? So are you generating only 1 path per pixel? (aka 1 sample per pixel?)

Also, a key point of RR is
 float3 color = blah blah blah r = 0.3 (or some other ratio) if(rand() < r) color /= r <---- key else terminate next bounce... 

Unless I'm missing some context, your weighting scheme is what everyone does, as part of the standard lighting calculating. Edited by jameszhao00

1. 1
2. 2
3. 3
4. 4
Rutin
14
5. 5

• 12
• 12
• 9
• 14
• 10
• ### Forum Statistics

• Total Topics
632655
• Total Posts
3007670
• ### Who's Online (See full list)

There are no registered users currently online

×