Skip to content

DiskLight::sample() function injects too much energy when sampling a textured DiskLight #250

@jlanz

Description

@jlanz

There’s an ancient code relic in DiskLight::sample() for sampling a textured DiskLight which looks like this:

        const unsigned maxTries = 8;
        unsigned attempts = 0;
        while(attempts != maxTries) {
            mDistribution->sample(r1, r2, 0, &isect.uv, nullptr, mTextureFilter);
            float x = isect.uv.x * 2.0f - 1.0f;
            float y = isect.uv.y * 2.0f - 1.0f;
            if (x*x + y*y < 1.0f) {
                break;
            }
            // Generate new random numbers based on these ones.
            // TODO: this is hacky code, do a better job of generating
            //       further random numbers
            r1 = scene_rdl2::math::fmod(r1 + 0.789f, 1.0f);
            r2 = scene_rdl2::math::fmod(r2 + 0.331f, 1.0f);
            attempts++;
        }
        if (attempts == maxTries) {
            return false;
        }

This has a bug. In a small minority of cases, the initially generated sample point will fall outside the disk. The probability of this happening is kept fairly low by preconditioning the Distribution2D such that the sampling weights of texels outside the disk are zeroed out. However, some texels straddle the boundary, and it’s possible for the generated point to be inside one of these texels but still lie outside the disk. In such cases, the normal approach would be to reject the point (either by invalidating it or returning black), which is correct behaviour. In this code, though, it goes on to add energy by rehashing the random values and repeating the process for the resulting point.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions