Adaptive sampling improvements

Discussion related to the LuxCore functionality, implementations and API.
User avatar
alpistinho
Developer
Developer
Posts: 198
Joined: Thu Jul 05, 2018 11:38 pm
Location: Rio de Janeiro

Re: Adaptive sampling improvements

Post by alpistinho »

It has to do with the scrambling pass.

When I hardcode these values, the distribution returns to look like Sobol.

Code: Select all

sobolSequence.rng0 = 0.2;//rngGenerator.
sobolSequence.rng1 = 0.7;//rngGenerator.floatValue();
sobolSequence.rngPass = 0.55;//rngGenerator.uintValue();
Using the same seed for every pixel, even though each one is in a different pass may not be the right thing to do
Support LuxCoreRender project with salts and bounties
User avatar
alpistinho
Developer
Developer
Posts: 198
Joined: Thu Jul 05, 2018 11:38 pm
Location: Rio de Janeiro

Re: Adaptive sampling improvements

Post by alpistinho »

I have absolutely no idea how mathematically sound this is but using the pixelIndex as the seed for the RNG seems to work...

Code: Select all

		// Initialize rng0, rng1 and rngPass
		rngGenerator.init(pixelIndex % (0xFFFFFFFFu - 1u) + 1u);
		sobolSequence.rng0 = rngGenerator.floatValue();
		sobolSequence.rng1 = rngGenerator.floatValue();
		sobolSequence.rngPass = rngGenerator.uintValue();
Uniform Sobol (25 Spp)
RGB_IMAGEPIPELINE_uniform_sobol.png
Adaptive Sobol (25 Spp avg.)
RGB_IMAGEPIPELINE_adaptive_sobol_using_pixelPass_as_seed.png
Samplecount
Screenshot from 2019-04-16 22-27-08.png
Support LuxCoreRender project with salts and bounties
User avatar
Dade
Developer
Developer
Posts: 5672
Joined: Mon Dec 04, 2017 8:36 pm
Location: Italy

Re: Adaptive sampling improvements

Post by Dade »

Your code will produce duplicate samples on multiple GPUs and when using CPU+GPU (so there is a lot of wasted work). You need to use "seedBase + pixelIndex".

You can't also call rngGenerator.init() for every samples, the overhead is too high (check the code), your slowing the rendering too much.

Fixing the above two problems leads back to the original code :?:
Support LuxCoreRender project with salts and bounties
User avatar
alpistinho
Developer
Developer
Posts: 198
Joined: Thu Jul 05, 2018 11:38 pm
Location: Rio de Janeiro

Re: Adaptive sampling improvements

Post by alpistinho »

Sure, I was not proposing leaving the code like that. I am still investigating the cause and hope to find a better solution.

I am not 100% sure about what is causing the issue, but as you can see on the samples distributions I've posted, the current solution is making Sobol more like Random.
Support LuxCoreRender project with salts and bounties
User avatar
Dade
Developer
Developer
Posts: 5672
Joined: Mon Dec 04, 2017 8:36 pm
Location: Italy

Re: Adaptive sampling improvements

Post by Dade »

alpistinho wrote: Wed Apr 17, 2019 9:41 am I am not 100% sure about what is causing the issue, but as you can see on the samples distributions I've posted, the current solution is making Sobol more like Random.
In theory, a sequence of (pseudo)random numbers is the same of a sequence of random numbers but I would be very suprised if the problem is really in the correlation of the sequence (pseudo)random.

The other option is that there is something going wrong with the value "seedBase", have you tried to use this code ?

Code: Select all

		// Initialize rng0, rng1 and rngPass
		rngGenerator.init(seedBase + pixelIndex % (0xFFFFFFFFu - 1u) + 1u);
		sobolSequence.rng0 = rngGenerator.floatValue();
		sobolSequence.rng1 = rngGenerator.floatValue();
		sobolSequence.rngPass = rngGenerator.uintValue();
The only difference with your code is the "seedBase +".
Support LuxCoreRender project with salts and bounties
User avatar
alpistinho
Developer
Developer
Posts: 198
Joined: Thu Jul 05, 2018 11:38 pm
Location: Rio de Janeiro

Re: Adaptive sampling improvements

Post by alpistinho »

Dade wrote: Wed Apr 17, 2019 10:39 am The other option is that there is something going wrong with the value "seedBase", have you tried to use this code ?

Code: Select all

		// Initialize rng0, rng1 and rngPass
		rngGenerator.init(seedBase + pixelIndex % (0xFFFFFFFFu - 1u) + 1u);
		sobolSequence.rng0 = rngGenerator.floatValue();
		sobolSequence.rng1 = rngGenerator.floatValue();
		sobolSequence.rngPass = rngGenerator.uintValue();
The only difference with your code is the "seedBase +".
It makes the rendering noisier again and the distribution for an arbitrary pixel I chose looks random and not Sobol.
I've had little time today and will not have much until Friday to dedicate to this issue
Support LuxCoreRender project with salts and bounties
User avatar
alpistinho
Developer
Developer
Posts: 198
Joined: Thu Jul 05, 2018 11:38 pm
Location: Rio de Janeiro

Re: Adaptive sampling improvements

Post by alpistinho »

Dade wrote: Wed Apr 17, 2019 10:39 am In theory, a sequence of (pseudo)random numbers is the same of a sequence of random numbers but I would be very suprised if the problem is really in the correlation of the sequence (pseudo)random.
I am not saying it is this necessarily, but somehow initializing rngGenerator using different values causes the distribution to degrade into a simple Random sampling.

Am I correct to assume that this seed is used to drive the RNG that draws the values used in the Cranley-Patterson rotation and the offset put into the SobolDimension function under SobolSequence::GetSample?

If I am correct, I understand why using the pixelIndex as seed will really cause the sample repetition between multiple devices, since there would be nothing to differentiate them as the pass and rngPass would be the same.

I could create a vector to hold an TauswortheRandomGenerator for each pixel, but I guess that would create an overhead of height * width * 12 bytes. That would be 96 MB for a 4K image, which is guess it's a bit too much when summed to the height * width * 4 bytes from the passPerPixel variable
Support LuxCoreRender project with salts and bounties
User avatar
Dade
Developer
Developer
Posts: 5672
Joined: Mon Dec 04, 2017 8:36 pm
Location: Italy

Re: Adaptive sampling improvements

Post by Dade »

alpistinho wrote: Thu Apr 18, 2019 1:42 am It makes the rendering noisier again and the distribution for an arbitrary pixel I chose looks random and not Sobol.
But this is very strange is like saying that the this sequence of a0-aN:

Code: Select all

rngGenerator.init(1);
a0 = rngGenerator.floatValue();
a1 = rngGenerator.floatValue();
a2 = rngGenerator.floatValue();
a3 = rngGenerator.floatValue();
...
have different randomness than this sequence of a0-aN:

Code: Select all

rngGenerator.init(1);
a0 = rngGenerator.floatValue();
rngGenerator.init(2);
a1 = rngGenerator.floatValue();
rngGenerator.init(3);
a2 = rngGenerator.floatValue();
rngGenerator.init(4);
a3 = rngGenerator.floatValue();
...
Support LuxCoreRender project with salts and bounties
User avatar
FarbigeWelt
Donor
Donor
Posts: 1046
Joined: Sun Jul 01, 2018 12:07 pm
Location: Switzerland
Contact:

Re: Adaptive sampling improvements

Post by FarbigeWelt »

But this is very strange is like saying that the this sequence of a0-aN:

have different randomness than this sequence of a0-aN:

[/quote]

Actually these are two different series of random numbers. Each init leads to slightly different randomness, if statistically evaluated. If the random generator was perfect then the randomness would be equal in both cases if evaluated over a very large number of values. Generators are biased, some more some less, enough unbiased though for a lot of applications. Very random number can be generated if init(clock) whereas clock is at least in milliseconds and two following clocks are never the same number or at least for millions of inits..
Light and Word designing Creator - www.farbigewelt.ch - aka quantenkristall || #luxcorerender
MacBook Air with M1
User avatar
alpistinho
Developer
Developer
Posts: 198
Joined: Thu Jul 05, 2018 11:38 pm
Location: Rio de Janeiro

Re: Adaptive sampling improvements

Post by alpistinho »

Hello,

I think I've found the issue.

Currently, the seed for the RNG is based on the seedBase, that is a fixed value, and on the pixelIndex inside SobolSharedSampler. The pixelIndex is incremented by SOBOL_THREAD_WORK_SIZE every time the GetNewPixelIndex is called.

This means that several seeds are used per pass, but they are always the same across passes. When uniform sampling is used, the pixels are sampled sequentially, so a given pixel always uses the same sobolSequence.rng0, sobolSequence.rng1 and sobolSequence.rngPass values across different passes.
I don't know if this is by design or not.

The adaptive sampling is used, the stochastic nature breaks this and the values uses vary across passes and somehow this leads to a worse sampling distribution.
alpistinho wrote: Wed Apr 17, 2019 1:28 am I have absolutely no idea how mathematically sound this is but using the pixelIndex as the seed for the RNG seems to work...

Code: Select all

		// Initialize rng0, rng1 and rngPass
		rngGenerator.init(pixelIndex % (0xFFFFFFFFu - 1u) + 1u);
		sobolSequence.rng0 = rngGenerator.floatValue();
		sobolSequence.rng1 = rngGenerator.floatValue();
		sobolSequence.rngPass = rngGenerator.uintValue();
When I used the code above, the distribution started being fixed per pixel again, restoring the original behavior.

I have to see now how to implement this without resorting to initializing the RNG all the time
Support LuxCoreRender project with salts and bounties
Post Reply