예제 #1
0
bool MultiQuadLight::sampleDirect(uint32 threadIndex, const Vec3f &p, PathSampleGenerator &pathSampler, LightSample &sample) const
{
    float xi = pathSampler.next1D(EmitterSample);

    ThreadlocalSampleInfo &sampler = *_samplers[threadIndex];

    std::pair<int, float> result = _sampleBvh->sampleLight(p, &sampler.sampleWeights[0],
            &sampler.insideIds[0], xi, [&](uint32 id) {
        return approximateQuadContribution(p, id);
    });
    if (result.first == -1)
        return false;

    int idx = pathSampler.next1D(EmitterSample) < 0.5f ? result.first*2 : result.first*2 + 1;

    const QuadGeometry::TriangleInfo &t = _geometry.triangle(idx);

    Vec3f q = SampleWarp::uniformTriangle(pathSampler.next2D(EmitterSample), t.p0, t.p1, t.p2);
    Vec3f L = q - p;

    float rSq = L.lengthSq();
    sample.dist = std::sqrt(rSq);
    sample.d = L/sample.dist;
    float cosTheta = -(t.Ng.dot(sample.d));
    if (cosTheta <= 0.0f)
        return false;
    sample.pdf = result.second*0.5f*rSq/(cosTheta*_triangleAreas[idx]);

    return true;
}
예제 #2
0
bool Cube::samplePosition(PathSampleGenerator &sampler, PositionSample &sample) const
{
    float u = sampler.next1D();
    int dim = sampleFace(u);
    float s = (dim + 1) % 3;
    float t = (dim + 2) % 3;

    Vec2f xi = sampler.next2D();

    Vec3f n(0.0f);
    n[dim] = u < 0.5f ? -1.0f : 1.0f;

    Vec3f p(0.0f);
    p[dim] = n[dim]*_scale[dim];
    p[s] = (xi.x()*2.0f - 1.0f)*_scale[s];
    p[t] = (xi.y()*2.0f - 1.0f)*_scale[t];

    sample.p = _rot*p + _pos;
    sample.pdf = _invArea;
    sample.uv = xi;
    sample.weight = PI*_area*(*_emission)[sample.uv];
    sample.Ng = _rot*n;

    return true;
}
예제 #3
0
float ErlangTransmittance::sampleSurface(PathSampleGenerator &sampler) const
{
    float xi = sampler.next1D();
    float x = 0.5f;
    for (int i = 0; i < 10; ++i) {
        x += (xi - (1.0f - surfaceSurface(Vec3f(x))[0]))/surfaceMedium(Vec3f(x))[0];
        x = max(x, 0.0f);
    }
    return x;
}
예제 #4
0
bool ExponentialMedium::sampleDistance(PathSampleGenerator &sampler, const Ray &ray,
        MediumState &state, MediumSample &sample) const
{
    if (state.bounce > _maxBounce)
        return false;

    float  x = _falloffScale*(ray.pos() - _unitPoint).dot(_unitFalloffDirection);
    float dx = _falloffScale*ray.dir().dot(_unitFalloffDirection);

    float maxT = ray.farT();
    if (_absorptionOnly) {
        if (maxT == Ray::infinity() && dx <= 0.0f)
            return false;
        sample.t = maxT;
        sample.weight = std::exp(-_sigmaT*densityIntegral(x, dx, ray.farT()));
        sample.pdf = 1.0f;
        sample.exited = true;
    } else {
        int component = sampler.nextDiscrete(3);
        float sigmaTc = _sigmaT[component];
        float xi = 1.0f - sampler.next1D();
        float logXi = std::log(xi);

        float t = inverseOpticalDepth(x, dx, sigmaTc, logXi);
        sample.t = min(t, maxT);
        sample.weight = std::exp(-_sigmaT*densityIntegral(x, dx, sample.t));
        sample.exited = (t >= maxT);
        if (sample.exited) {
            sample.pdf = sample.weight.avg();
        } else {
            float rho = density(x, dx, sample.t);
            sample.pdf = (rho*_sigmaT*sample.weight).avg();
            sample.weight *= rho*_sigmaS;
        }
        sample.weight /= sample.pdf;

        state.advance();
    }
    sample.p = ray.pos() + sample.t*ray.dir();
    sample.phase = _phaseFunction.get();

    return true;
}
예제 #5
0
bool AtmosphericMedium::sampleDistance(PathSampleGenerator &sampler, const Ray &ray,
        MediumState &state, MediumSample &sample) const
{
    if (state.bounce > _maxBounce)
        return false;

    Vec3f p = (ray.pos() - _center);
    float t0 = p.dot(ray.dir());
    float  h = (p - t0*ray.dir()).length();

    float maxT = ray.farT() + t0;
    if (_absorptionOnly) {
        sample.t = ray.farT();
        sample.weight = std::exp(-_sigmaT*densityIntegral(h, t0, maxT));
        sample.pdf = 1.0f;
        sample.exited = true;
    } else {
        int component = sampler.nextDiscrete(3);
        float sigmaTc = _sigmaT[component];
        float xi = 1.0f - sampler.next1D();

        float t = inverseOpticalDepth(h, t0, sigmaTc, xi);
        sample.t = min(t, maxT);
        sample.weight = std::exp(-_sigmaT*densityIntegral(h, t0, sample.t));
        sample.exited = (t >= maxT);
        if (sample.exited) {
            sample.pdf = sample.weight.avg();
        } else {
            float rho = density(h, sample.t);
            sample.pdf = (rho*_sigmaT*sample.weight).avg();
            sample.weight *= rho*_sigmaS;
        }
        sample.weight /= sample.pdf;
        sample.t -= t0;

        state.advance();
    }
    sample.p = ray.pos() + sample.t*ray.dir();
    sample.phase = _phaseFunction.get();

    return true;
}
예제 #6
0
bool HomogeneousMedium::sampleDistance(PathSampleGenerator &sampler, const Ray &ray,
        MediumState &state, MediumSample &sample) const
{
    if (state.bounce > _maxBounce)
        return false;

    float maxT = ray.farT();
    if (_absorptionOnly) {
        if (maxT == Ray::infinity())
            return false;
        sample.t = maxT;
        sample.weight = std::exp(-_sigmaT*maxT);
        sample.pdf = 1.0f;
        sample.exited = true;
    } else {
        int component = sampler.nextDiscrete(3);
        float sigmaTc = _sigmaT[component];

        float t = -std::log(1.0f - sampler.next1D())/sigmaTc;
        sample.t = min(t, maxT);
        sample.weight = std::exp(-sample.t*_sigmaT);
        sample.exited = (t >= maxT);
        if (sample.exited) {
            sample.pdf = sample.weight.avg();
        } else {
            sample.pdf = (_sigmaT*sample.weight).avg();
            sample.weight *= _sigmaS;
        }
        sample.weight /= sample.pdf;

        state.advance();
    }
    sample.p = ray.pos() + sample.t*ray.dir();
    sample.phase = _phaseFunction.get();

    return true;
}
예제 #7
0
Vec2f VdbGrid::inverseOpticalDepth(PathSampleGenerator &sampler, Vec3f p, Vec3f w, float t0, float t1,
        float sigmaT, float xi) const
{
    auto accessor = _grid->getConstAccessor();

    if (_sampleMethod == SampleMethod::ExactNearest) {
        VdbRaymarcher<openvdb::FloatGrid::TreeType, 3> dda;

        float integral = 0.0f;
        Vec2f result(t1, 0.0f);
        bool exited = !dda.march(DdaRay(p + 0.5f, w), t0, t1, accessor, [&](openvdb::Coord voxel, float ta, float tb) {
            float v = accessor.getValue(voxel);
            float delta = v*sigmaT*(tb - ta);
            if (integral + delta >= xi) {
                result = Vec2f(ta + (tb - ta)*(xi - integral)/delta, v);
                return true;
            }
            integral += delta;
            return false;
        });
        return exited ? Vec2f(t1, integral) : result;
    } else if (_sampleMethod == SampleMethod::ExactLinear) {
        VdbRaymarcher<openvdb::FloatGrid::TreeType, 3> dda;

        float integral = 0.0f;
        float fa = gridAt(accessor, p + w*t0);
        Vec2f result(t1, 0.0f);
        bool exited = !dda.march(DdaRay(p + 0.5f, w), t0, t1, accessor, [&](openvdb::Coord /*voxel*/, float ta, float tb) {
            float fb = gridAt(accessor, p + tb*w);
            float delta = (fb + fa)*0.5f*sigmaT*(tb - ta);
            if (integral + delta >= xi) {
                float a = (fb - fa)*sigmaT;
                float b = fa*sigmaT;
                float c = (integral - xi)/(tb - ta);
                float mantissa = max(b*b - 2.0f*a*c, 0.0f);
                float x1 = (-b + std::sqrt(mantissa))/a;
                result = Vec2f(ta + (tb - ta)*x1, fa + (fb - fa)*x1);
                return true;
            }
            integral += delta;
            fa = fb;
            return false;
        });
        return exited ? Vec2f(t1, integral) : result;
    } else {
        float ta = t0;
        float fa = gridAt(accessor, p + w*t0);
        float integral = 0.0f;
        float dT = sampler.next1D()*_stepSize;
        do {
            float tb = min(ta + dT, t1);
            float fb = gridAt(accessor, p + w*tb);
            float delta = (fa + fb)*sigmaT*0.5f*(tb - ta);
            if (integral + delta >= xi) {
                float a = (fb - fa)*sigmaT;
                float b = fa*sigmaT;
                float c = (integral - xi)/(tb - ta);
                float mantissa = max(b*b - 2.0f*a*c, 0.0f);
                float x1 = (-b + std::sqrt(mantissa))/a;
                return Vec2f(ta + (tb - ta)*x1, fa + (fb - fa)*x1);
            }
            integral += delta;
            ta = tb;
            fa = fb;
            dT = _stepSize;
        } while (ta < t1);
        return Vec2f(t1, integral);
    }
}
예제 #8
0
Vec3f VdbGrid::transmittance(PathSampleGenerator &sampler, Vec3f p, Vec3f w, float t0, float t1, Vec3f sigmaT) const
{
    auto accessor = _grid->getConstAccessor();

    if (_integrationMethod == IntegrationMethod::ExactNearest) {
        VdbRaymarcher<openvdb::FloatGrid::TreeType, 3> dda;

        float integral = 0.0f;
        dda.march(DdaRay(p + 0.5f, w), t0, t1, accessor, [&](openvdb::Coord voxel, float ta, float tb) {
            integral += accessor.getValue(voxel)*(tb - ta);
            return false;
        });
        return std::exp(-integral*sigmaT);
    } else if (_integrationMethod == IntegrationMethod::ExactLinear) {
        VdbRaymarcher<openvdb::FloatGrid::TreeType, 3> dda;

        float integral = 0.0f;
        float fa = gridAt(accessor, p + w*t0);
        dda.march(DdaRay(p, w), t0, t1, accessor, [&](openvdb::Coord /*voxel*/, float ta, float tb) {
            float fb = gridAt(accessor, p + w*tb);
            integral += (fa + fb)*0.5f*(tb - ta);
            fa = fb;
            return false;
        });
        return std::exp(-integral*sigmaT);
    } else if (_integrationMethod == IntegrationMethod::ResidualRatio) {
        VdbRaymarcher<Vec2fGrid::TreeType, 3> dda;

        float scale = _supergridSubsample;
        float invScale = 1.0f/scale;
        sigmaT *= scale;

        float sigmaTc = sigmaT.max();

        auto superAccessor =  _superGrid->getConstAccessor();

        UniformSampler &generator = sampler.uniformGenerator();

        float controlIntegral = 0.0f;
        Vec3f Tr(1.0f);
        dda.march(DdaRay(p*invScale + 0.5f, w), t0*invScale, t1*invScale, superAccessor, [&](openvdb::Coord voxel, float ta, float tb) {
            openvdb::Vec2s v = superAccessor.getValue(voxel);
            float muC = v.x();
            float muR = v.y();
            muR *= sigmaTc;

            controlIntegral += muC*(tb - ta);

            while (true) {
                ta -= BitManip::normalizedLog(generator.nextI())/muR;
                if (ta >= tb)
                    break;
                Tr *= 1.0f - sigmaT*((gridAt(accessor, p + w*ta*scale) - muC)/muR);
            }

            return false;
        });
        return std::exp(-controlIntegral*sigmaT)*Tr;
    } else {
        float ta = t0;
        float fa = gridAt(accessor, p + w*t0);
        float integral = 0.0f;
        float dT = sampler.next1D()*_stepSize;
        do {
            float tb = min(ta + dT, t1);
            float fb = gridAt(accessor, p + w*tb);
            integral += (fa + fb)*0.5f*(tb - ta);
            ta = tb;
            fa = fb;
            dT = _stepSize;
        } while (ta < t1);
        return std::exp(-integral*sigmaT);
    }
}
예제 #9
0
float ErlangTransmittance::sampleMedium(PathSampleGenerator &sampler) const
{
    return -1.0f/_lambda*std::log(sampler.next1D()*sampler.next1D());
}