POV-Ray : Newsgroups : povray.off-topic : Random vector through a hemisphere? Server Time
11 Oct 2024 01:22:05 EDT (-0400)
  Random vector through a hemisphere? (Message 6 to 15 of 15)  
<<< Previous 5 Messages Goto Initial 10 Messages
From: scott
Subject: Re: Random vector through a hemisphere?
Date: 18 Feb 2008 03:57:27
Message: <47b94877$1@news.povray.org>
> I use this:
>
> y = sqrt(rand(0..1))
> theta = acos(y)
> phi = 2*PI*rand(0..1)
>
> x = sin(theta)*cos(phi)
> z = sin(theta)*sin(phi)
>
> What I don't get is the sqrt(rand()). Why sqrt? Why not just rnd()? Does
> the sqrt give us the cosine distribution and should remove the need to
> later scale by taking cosine of the angle between normal and the light 
> ray?

No, you are simply choosing a fixed Y position, which then defines a ring 
around the sphere of possible points.  Then phi is used to choose a point at 
random on this ring which gives you the final point.

The reason for using sqrt for y is because you want points equally 
distributed over the surface of the sphere, not between y=0 to 1.  You can 
visualise this by drawing a straight line alongside a circle.  If you 
distribute points evenly on the line, then trace them across to the circle, 
they won't be distributed evenly on the circle.  The sqrt fixes that.


Post a reply to this message

From: Severi Salminen
Subject: Re: Random vector through a hemisphere?
Date: 18 Feb 2008 05:12:33
Message: <47b95a11@news.povray.org>
>> y = sqrt(rand(0..1))
>> theta = acos(y)
>> phi = 2*PI*rand(0..1)
>>
>> x = sin(theta)*cos(phi)
>> z = sin(theta)*sin(phi)

> The reason for using sqrt for y is because you want points equally
> distributed over the surface of the sphere, not between y=0 to 1.

Hmm. Ok. I think I got it. So without sqrt() we get too few rays going
through the top part? A few more questions.

1. Is this equally good as the above - at least it looks to be. And a
bit faster.

    double y = sqrt((double) rand()/RAND_MAX);
    double phi = 2*M_PI* (double)rand()/RAND_MAX;
    double x = sqrt(1-y*y)*cos(phi);
    double z = sqrt(1-y*y)*sin(phi);


What is the proper way to actually test the uniformity?

2. I read about "cosine weighted distribution" which should remove the
need to scale with cosine term. This sounds ideal solution. But
according tho this:

http://www.cs.kuleuven.be/~phil/GI/TotalCompendium.pdf

"Generating points uniformly on the disk (see 19), and then projecting
them on the hemisphere, also gives a cosine-weighted distribution of
points on the hemisphere."

I also tried that:


    do{
        x = (double) 2.0*rand()/RAND_MAX -1.0;
        z = (double) 2.0*rand()/RAND_MAX-1.0;
    }
    while(x*x+z*z > 1.0);

    y = sqrt(1.0-(x*x+z*z));

And the results are very close to the 2 other methods.

This is what I read from comp.graphics.algorithms:

"One other way to reduce variance in this situation is to shoot rays
with a cosine-weighted distribution. Generate points distributed
uniformly on the unit disk, then project up to the unit
hemisphere. Each point will define a ray drawn from the proper
distribution. Then, at least for the indirect lighting, you don't need
to include the cosine explicitly at all. But that's not the real win:
the win is that each sample actually contains more information about
the mean value, so variance will be less with the same number of rays."

So what is the truth here? Do I need to account the angle of the ray or
not?


Post a reply to this message

From: Severi Salminen
Subject: Re: Random vector through a hemisphere?
Date: 18 Feb 2008 05:15:35
Message: <47b95ac7$1@news.povray.org>
Severi Salminen wrote:

> I also tried that:
> 
> 
>     do{
>         x = (double) 2.0*rand()/RAND_MAX -1.0;
>         z = (double) 2.0*rand()/RAND_MAX-1.0;
>     }
>     while(x*x+z*z > 1.0);
> 
>     y = sqrt(1.0-(x*x+z*z));
> 
> And the results are very close to the 2 other methods.

And this is also the fastest algorithm of the tree.


Post a reply to this message

From: scott
Subject: Re: Random vector through a hemisphere?
Date: 18 Feb 2008 05:34:11
Message: <47b95f23$1@news.povray.org>
> 1. Is this equally good as the above - at least it looks to be. And a
> bit faster.
>
>    double y = sqrt((double) rand()/RAND_MAX);
>    double phi = 2*M_PI* (double)rand()/RAND_MAX;
>    double x = sqrt(1-y*y)*cos(phi);
>    double z = sqrt(1-y*y)*sin(phi);

Looks ok to me.

> What is the proper way to actually test the uniformity?

Either mathematically proving it, or write a test program that measures the 
density of points over the surface.

> I also tried that:
>
>
>    do{
>        x = (double) 2.0*rand()/RAND_MAX -1.0;
>        z = (double) 2.0*rand()/RAND_MAX-1.0;
>    }
>    while(x*x+z*z > 1.0);
>
>    y = sqrt(1.0-(x*x+z*z));
>
> And the results are very close to the 2 other methods.

This result is different to the above and not spread uniformly over the 
surface of the sphere (it is uniform only in the xz plane).


Post a reply to this message

From: Severi Salminen
Subject: Re: Random vector through a hemisphere?
Date: 18 Feb 2008 05:49:58
Message: <47b962d6$1@news.povray.org>
>>    double y = sqrt((double) rand()/RAND_MAX);
>>    double phi = 2*M_PI* (double)rand()/RAND_MAX;
>>    double x = sqrt(1-y*y)*cos(phi);
>>    double z = sqrt(1-y*y)*sin(phi);
> 
> Or:
>
>>    do{
>>        x = (double) 2.0*rand()/RAND_MAX -1.0;
>>        z = (double) 2.0*rand()/RAND_MAX-1.0;
>>    }
>>    while(x*x+z*z > 1.0);
>>
>>    y = sqrt(1.0-(x*x+z*z));
>>
> This result is different to the above and not spread uniformly over the
> surface of the sphere (it is uniform only in the xz plane).

Ok, that makes me wonder, because:

1. The 2 methods above produce 100% identical images. It was a scene of
one light emitting sphere, ground and 3 diffusing spheres of different
colors. (I did use the cosine ratio relative to the angle of light
falling on surface.) I can post the images if needed. The only
difference is that the second method is faster - with a great margin.

2. If the distribution is not identical by the 2 methods, why are the
images still 100% identical?


Post a reply to this message

From: scott
Subject: Re: Random vector through a hemisphere?
Date: 18 Feb 2008 07:15:42
Message: <47b976ee$1@news.povray.org>
> Ok, that makes me wonder, because:
>
> 1. The 2 methods above produce 100% identical images. It was a scene of
> one light emitting sphere, ground and 3 diffusing spheres of different
> colors. (I did use the cosine ratio relative to the angle of light
> falling on surface.) I can post the images if needed. The only
> difference is that the second method is faster - with a great margin.
>
> 2. If the distribution is not identical by the 2 methods, why are the
> images still 100% identical?

Actually yes, they are both the same, and wrong ;-)  I hadn't checked your 
y=sqrt(rand()) method, just assumed it was correct.

A correct way is:

y = rand(0...1);
phi = rand(0...2pi)
x = sqrt(1-y*y) * cos(phi)
z = sqrt(1-y*y) * sin(phi)

This will give a more even distribution, if you visualise the results you'll 
see that your earlier attempts don't give many points around the equator.


Post a reply to this message

From: Severi Salminen
Subject: Re: Random vector through a hemisphere?
Date: 18 Feb 2008 08:23:19
Message: <47b986c7$1@news.povray.org>
> Actually yes, they are both the same, and wrong ;-)  I hadn't checked
> your y=sqrt(rand()) method, just assumed it was correct.
> 
> A correct way is:
> 
> y = rand(0...1);
> phi = rand(0...2pi)
> x = sqrt(1-y*y) * cos(phi)
> z = sqrt(1-y*y) * sin(phi)
> 
> This will give a more even distribution, if you visualise the results
> you'll see that your earlier attempts don't give many points around the
> equator.

I made finally a test program to see the distribution by looking down
the sphere. It seems that the above method and the first method in this
thread (x= sin(theta)*cos(phi)...) BOTH should NOT have sqrt to produce
even distribution on surface. It also seems that if the sqrt is
included, all 3 methods produce identical distribution which is weighted
to pole -> ie. less points on the equator. Or if you look along y axis,
they have uniform distribution projected on XZ plane.


Post a reply to this message

From: Nicolas Alvarez
Subject: Re: Random vector through a hemisphere?
Date: 18 Feb 2008 10:26:55
Message: <47b9a3bf$1@news.povray.org>

>> Another way is to generate a random vector:
>>
>> #local vResult=vrotate(x,<rand(Seed),rand(Seed),rand(Seed)>*360);
> 
> vResult is not uniformly distributed over the sphere with this approach 
> though...
> 

rand.inc has macros that return random vectors uniformly distributed 
over a sphere's volume or surface.


Post a reply to this message

From: John VanSickle
Subject: Re: Random vector through a hemisphere?
Date: 18 Feb 2008 17:36:46
Message: <47ba087e@news.povray.org>
Severi Salminen wrote:
> scott wrote:
>>> Another way is to generate a random vector:
>>>
>>> #local vResult=vrotate(x,<rand(Seed),rand(Seed),rand(Seed)>*360);
>> vResult is not uniformly distributed over the sphere with this approach
>> though...
> 
> I use this:
> 
> y = sqrt(rand(0..1))
> theta = acos(y)
> phi = 2*PI*rand(0..1)
> 
> x = sin(theta)*cos(phi)
> z = sin(theta)*sin(phi)
> 
> What I don't get is the sqrt(rand()). Why sqrt? Why not just rnd()? Does
> the sqrt give us the cosine distribution and should remove the need to
> later scale by taking cosine of the angle between normal and the light ray?

Actually, a plain rand() should work fine.  I did the calculus.

y = rand(0..1)
s = sqrt(1-y*y)
phi = 2*PI*rand(0..1)
x = s*cos(phi)
z = s*sin(phi)

Regards,
John


Post a reply to this message

From: Severi Salminen
Subject: Re: Random vector through a hemisphere?
Date: 19 Feb 2008 14:05:50
Message: <47bb288e$1@news.povray.org>
scott wrote:

>> What I don't get is the sqrt(rand()). Why sqrt? Why not just rnd()? Does
>> the sqrt give us the cosine distribution and should remove the need to
>> later scale by taking cosine of the angle between normal and the light
>> ray?
> 
> No, you are simply choosing a fixed Y position, which then defines a
> ring around the sphere of possible points.  Then phi is used to choose a
> point at random on this ring which gives you the final point.

I made a few more tests. And it really seems to be that if you use
cosine weighted distribution (with sqrt around y -> less rays at
equator, more at pole) you don't need to calculate cosine at all during
tracing! Benefits:

1. No need to do cosine calculation. This might be good/bad depending on
how you create the cosine weighted rays and how you would've calculated
the cosine. At least on my program it is faster to do one sqrt() than to
calculate the cosine of two vectors with dot product of the two.

A much bigger benefit:

2. It seems that you get less variance with this weighted method because
 rays coming near the normal give more information than rays coming from
equator. I guess this is called "importance sampling".

I'm testing this now and the new method gives identical results after
about 250 passes compared to about 360 passes of the old method. Judged
by my eye. And in addition each pass takes 10% less time than the old one!

So a BIG improvement!! That is if I'm not missing something important here.

I have to find a way to analyze the actual variance (noisiness) of the
image so that I don't have to trust my eyes. Any ideas?


Post a reply to this message

<<< Previous 5 Messages Goto Initial 10 Messages

Copyright 2003-2023 Persistence of Vision Raytracer Pty. Ltd.