WebGPU: Sobol random number generator#761
Conversation
…functions, inline lambertBsdf to use correct random.
|
@gkjohnson Let me know if you want this PR divided or just want to take a different direction for implementing different random number generators. |
| for ( var i = 0; i < INTEGRATION_SAMPLES; i++ ) { | ||
|
|
||
| let wh = ggxDirection( wo, vec2( alpha ), pcgRand2() ); | ||
| let wh = ${ ggxDirectionFunc }( wo, vec2( alpha ), ${ pcgFunctions.vec2f }() ); |
There was a problem hiding this comment.
It looks like this is always using "pcg" randomness. Is this intended?
There was a problem hiding this comment.
Yes, kind of. I think it does not really matter which random function we use here since there are many samples taken.
| enqueueRaysKernel.seed ++; | ||
| enqueueRaysKernel.seed = this.seed; |
There was a problem hiding this comment.
Can you explain the need for this change? We should still need to store a different seed per ray because they may each be at a different point in the path.
There was a problem hiding this comment.
You're right, if we're being proper, seed should be different for each ray. Fixed that.
| // Alpha test should be the last index as it is summed with triangle index | ||
| export const RNG_INDEX_RAY_JITTER = 0; | ||
| export const RNG_INDEX_ENVIRONMENT_SAMPLE = 1; | ||
| export const RNG_INDEX_SCATTER_TYPE = 2; | ||
| export const RNG_INDEX_SCATTER_DIRECTION = 3; | ||
| export const RNG_INDEX_ALPHA_TEST = 4; |
There was a problem hiding this comment.
I'm not fully understanding what this is for?
There was a problem hiding this comment.
Those are unique numbers for each sample of random numbers that are used for sobol number generation. They appear in webgl pathtracer as plain numbers:
state.isShadowRay = scatterRec.specularPdf < rand( 4 );
For better structure and to ensure there are no duplicates, I decided to define those constants here.
| rayQueue[ index ].pixel = indexUV; | ||
| rayQueue[ index ].throughputColor = vec3f( 1.0 ); | ||
| rayQueue[ index ].currentBounce = 0; | ||
| rayQueue[ index ].pcgStateS0 = ${ getPcgSeed }(); |
There was a problem hiding this comment.
Can you explain how this is working, now? Is this replaced by RNG_INDEX_RAY_JITTER?
There was a problem hiding this comment.
Not really, it just initializes each time without carrying it over. Will add a little fix to use current bounce in initialization. Although, if we are to keep only one random number generation algorithm, it should not matter as sobol numbers' state can be properly initialized on each stage properly.
Having thought through this a bit more - I'm thinking we don't really need a user-settable randomness function (at least for now). We can keep the PCG functions around but if we're seeing that Sobol is better than we should just export and use that everywhere. Then for dev we can change the randomness functions around in that source file if we have to. I don't think the toggle features is worth the implementation complexity atm. |
I understand not exposing the toggle to the users, but even implementing new random numbers and changing them in every place is tedious and make comparisons harder. I simplified the implementation a bit by extracting proxyFn nodes into a single object that is passed around. Let me know if complexity is still an issue. |


@gkjohnson
This PR makes a lot of changes in order to support selecting random number generator in API:
setRandomFunctionson PathtracerBackend unspecified, so derivations don't have to call super before doing their stuff. Not sure about this decision, but it felt easier to think about the system with material handled here. Let me know what you think.proxyFnnodes which feels a little messy. Perhaps there could be one place that creates proxy nodes and then distributes them? Not sure how this should be handledHere's some image comparisons between pcg and sobol random numbers. It looks like diffuse surfaces are not much by more uniform random numbers, unlike specular which has less noise (see clearcoat image).