RayTracing / raytracing.github.io

Main Web Site (Online Books)
https://raytracing.github.io/
Creative Commons Zero v1.0 Universal
8.71k stars 856 forks source link

`while(true)` in `random_in_unit_sphere` (section 9.1) #1577

Closed PoneyUHC closed 2 months ago

PoneyUHC commented 3 months ago

Hello,

I am having some issues understanding why we should adopt a rejection method here. Doesn't a normalized random vector3 give a vector on the unit sphere anyway ?

I can not figure out why any vector normalized and then inverted if needed would not be on the right atmosphere.

This is the code I use :

inline Vec3 RandomInSameHemisphere() const {
    Vec3 other = Vec3::Random(-1, 1);
    other = other.Normalized();
    return other.Dot(*this) > 0.0 ? other : -other;
}

With no rejection method, I can achieve to produce this image, which seems fine :

render

Also I don't get why it is needed to keep the vector coordinates in ]-1;1[, as any normalized vector gets mapped to the unit sphere. However, when I remove this condition I get a slightly different output, as if my probability distribution was shifted to the right (mapping floor rebound in the sphere's direction, creating shadow) :

render(1)

If you need more insights on the code, it is available here. The precise commit was af3348c7ccdb92b66c7a031d11d71ec78033bc69, in vec.hpp file

PoneyUHC commented 3 months ago

After some thoughts about it, I may have a piece of reason about the while loop. Without the while loop, we generate a vector in a 2-unit square. The distribution of generated coordinates in the square in uniform (random). However, the distribution of normalized vectors on the unit sphere is not uniform, having maximum likelywood when the vectors are aligned with the corners of the square, and minimum likelywood when they are oriented to the points of intersections between the square and the sphere.

Lun4m commented 2 months ago

Just stumbled upon this and was wondering the same. Yeah, the problem is that the sampling wouldn't be uniformly distributed. That while loop is so slow though, for me the cube root solution seems to be ~20% faster.

PoneyUHC commented 2 months ago

@Lun4m I randomly (let's admit the algorithm got me on this one) got that video ("The BEST Way to Find a Random Point in a Circle", by nubNotDev in case link breaks) in my youtube recommendations the other day. In fact, knowing that the statistical expectation of generating a point inside the sphere is about 1.2 iteration with the rejection method, it is not so much of a bad method, because you have no square root or sin/cos to compute ;)

Lun4m commented 2 months ago

1.2 seems really good, I thought it would be worse since the cube-to-sphere volume ratio is ~2, which gives 50% chance per try of generating a point inside the sphere. But I haven't done proper statistics in a while :) Anyway thanks for the link, I'll check it out!