コード例 #1
0
	void test02_shSampler() {
		/* Draw 100 samples from a SH expansion of a clamped cosine-shaped
		   distribution and verify the returned probabilities */
		int bands = 13, numSamples = 100, depth = 12;

		Vector v = normalize(Vector(1, 2, 3));
		ref<Random> random = new Random();
		SHVector clampedCos = SHVector(bands);
		clampedCos.project(ClampedCos(v), numSamples);
		//Float clampedCosError = clampedCos.l2Error(ClampedCos(v), numSamples);
		clampedCos.normalize();

		//cout << "Projection error = " << clampedCosError << endl;
		//cout << "Precomputing mip-maps" << endl;
		ref<SHSampler> sampler = new SHSampler(bands, depth);
		//cout << "Done: "<< sampler->toString() << endl;
		Float accum = 0;
		int nsamples = 100, nInAvg = 0;
		for (int i=0; i<=nsamples; ++i) {
			Point2 sample(random->nextFloat(), random->nextFloat());
			Float pdf1 = sampler->warp(clampedCos, sample);
			Float pdf2 = dot(v, sphericalDirection(sample.x, sample.y))/M_PI;
			Float relerr = std::abs(pdf1-pdf2)/pdf2;
			if (pdf2 > 0.01) {
				accum += relerr; ++nInAvg;
				assertTrue(relerr < 0.08);
			}
		}
		assertTrue(accum / nInAvg < 0.01);
	}
コード例 #2
0
ファイル: kkay.cpp プロジェクト: tomka/mitsuba-renderer
    /// For testing purposes
    Float integrateOverOutgoing(const Vector &wi) {
        MediumSamplingRecord mRec;
        mRec.orientation = Vector(0,0,1);
        int res = 100;
        /* Nested composite Simpson's rule */
        Float hExt = M_PI / res,
              hInt = (2*M_PI)/(res*2);

        Float result = 0;

        for (int i=0; i<=res; ++i) {
            Float theta = hExt*i;
            Float weightExt = (i & 1) ? 4.0f : 2.0f;
            if (i == 0 || i == res)
                weightExt = 1;

            for (int j=0; j<=res*2; ++j) {
                Float phi = hInt*j;
                Float weightInt = (j & 1) ? 4.0f : 2.0f;
                if (j == 0 || j == 2*res)
                    weightInt = 1;

                Float value = f(mRec, wi, sphericalDirection(theta, phi))[0]*std::sin(theta)
                              * weightExt*weightInt;

                result += value;
            }
        }

        return hExt*hInt/9;
    }
コード例 #3
0
ファイル: microfacet.cpp プロジェクト: entropian/CRaytracer
void MicrofacetDistribution_sample_wh(vec3 wh, const vec3 wo, const vec2 sample,
                                      const MicrofacetDistribution* distrib)
{
    /*
        // Compute $\tan^2 \theta$ and $\phi$ for Beckmann distribution sample
        Float tan2Theta, phi;
        if (alphax == alphay) {
            Float logSample = std::log(u[0]);
            if (std::isinf(logSample)) logSample = 0;
            tan2Theta = -alphax * alphax * logSample;
            phi = u[1] * 2 * Pi;
        } else {
            // Compute _tan2Theta_ and _phi_ for anisotropic Beckmann
            // distribution
            Float logSample = std::log(u[0]);
            if (std::isinf(logSample)) logSample = 0;
            phi = std::atan(alphay / alphax *
                            std::tan(2 * Pi * u[1] + 0.5f * Pi));
            if (u[1] > 0.5f) phi += Pi;
            Float sinPhi = std::sin(phi), cosPhi = std::cos(phi);
            Float alphax2 = alphax * alphax, alphay2 = alphay * alphay;
            tan2Theta = -logSample /
                        (cosPhi * cosPhi / alphax2 + sinPhi * sinPhi / alphay2);
        }
        // Map sampled Beckmann angles to normal direction _wh_
        Float cosTheta = 1 / std::sqrt(1 + tan2Theta);
        Float sinTheta = std::sqrt(std::max((Float)0, 1 - cosTheta * cosTheta));
        Vector3f wh = SphericalDirection(sinTheta, cosTheta, phi);
        if (!SameHemisphere(wo, wh)) wh = -wh;
        return wh;
     */
    float tan_2_theta, phi;
    if(distrib->alphax == distrib->alphay)
    {
        float log_sample = logf(sample[0]);
        if(isinf(log_sample))
            log_sample = 0.0f;
        tan_2_theta = -distrib->alphax * distrib->alphax * log_sample;
        phi = sample[1] * 2.0f * PI;
    }else
    {
        float log_sample = logf(sample[0]);
        if(isinf(log_sample))
            log_sample = 0.0f;
        phi = atanf(distrib->alphay / distrib->alphax *
                    tanf(2.0f * PI * sample[1] + 0.5f * PI));
        if(sample[1] > 0.5f) phi += PI;
        float sin_phi = sinf(phi), cos_phi = cosf(phi);
        float alphax2 = distrib->alphax * distrib->alphax;
        float alphay2 = distrib->alphay * distrib->alphay;
        tan_2_theta = -log_sample /
            (cos_phi * cos_phi / alphax2 + sin_phi * sin_phi / alphay2);
    }
    float cos_theta = 1.0f / sqrtf(1.0f + tan_2_theta);
    float sin_theta = sqrtf(max(0.0f, 1.0f - cos_theta * cos_theta));
    sphericalDirection(wh, sin_theta, cos_theta, phi);
    if(!sameHemisphere(wo, wh))
        vec3_negate(wh, wh);
}
コード例 #4
0
ファイル: mut_caustic.cpp プロジェクト: akaterin/ray-tracer
bool CausticPerturbation::sampleMutation(
		Path &source, Path &proposal, MutationRecord &muRec) {
	int k = source.length(), m = k - 1, l = m - 1;

	if (k < 4 || !source.vertex(l)->isConnectable())
		return false;
	--l;

	while (l >= 0 && !source.vertex(l)->isConnectable())
		--l;

	if (l < 1)
		return false;

	muRec = MutationRecord(ECausticPerturbation, l, m, m-l,
		source.getPrefixSuffixWeight(l, m));
	statsAccepted.incrementBase();
	statsGenerated.incrementBase();

	/* Heuristic perturbation size computation (Veach, p.354) */
	Float lengthE = source.edge(m-1)->length;
	Float lengthL = 0;
	for (int i=l; i<m-1; ++i)
		lengthL += source.edge(i)->length;
	Float factor = lengthE/lengthL,
		theta1 = m_theta1 * factor,
		theta2 = m_theta2 * factor;

	Vector woSource = normalize(source.vertex(l+1)->getPosition()
			- source.vertex(l)->getPosition());
	Float phi = m_sampler->next1D() * 2 * M_PI;
	Float theta = theta2 * math::fastexp(m_logRatio * m_sampler->next1D());
	Vector wo = Frame(woSource).toWorld(sphericalDirection(theta, phi));

	/* Allocate memory for the proposed path */
	proposal.clear();
	proposal.append(source, 0, l+1);
	proposal.append(m_pool.allocEdge());
	for (int i=l+1; i<m; ++i) {
		proposal.append(m_pool.allocVertex());
		proposal.append(m_pool.allocEdge());
	}
	proposal.append(source, m, k+1);
	proposal.vertex(l) = proposal.vertex(l)->clone(m_pool);
	proposal.vertex(m) = proposal.vertex(m)->clone(m_pool);
	BDAssert(proposal.vertexCount() == source.vertexCount());
	BDAssert(proposal.edgeCount() == source.edgeCount());

	Float dist = source.edge(l)->length +
		perturbMediumDistance(m_sampler, source.vertex(l+1));

	/* Sample a perturbation and propagate it through specular interactions */
	if (!proposal.vertex(l)->perturbDirection(m_scene,
			proposal.vertex(l-1), proposal.edge(l-1),
			proposal.edge(l), proposal.vertex(l+1), wo, dist,
			source.vertex(l+1)->getType(), EImportance)) {
		proposal.release(l, m+1, m_pool);
		return false;
	}

	Vector woProposal = normalize(proposal.vertex(l+1)->getPosition()
			- source.vertex(l)->getPosition());
	theta = unitAngle(woSource, woProposal);
	if (theta >= theta2 || theta <= theta1) {
		proposal.release(l, m+1, m_pool);
		return false;
	}

	/* If necessary, propagate the perturbation through a sequence of
	   ideally specular interactions */
	for (int i=l+1; i<m-1; ++i) {
		Float dist = source.edge(i)->length +
			perturbMediumDistance(m_sampler, source.vertex(i+1));

		if (!proposal.vertex(i)->propagatePerturbation(m_scene,
				proposal.vertex(i-1), proposal.edge(i-1),
				proposal.edge(i), proposal.vertex(i+1),
				source.vertex(i)->getComponentType(), dist,
				source.vertex(i+1)->getType(), EImportance)) {
			proposal.release(l, m+1, m_pool);
			return false;
		}
	}

	if (!PathVertex::connect(m_scene,
			proposal.vertex(m-2),
			proposal.edge(m-2),
			proposal.vertex(m-1),
			proposal.edge(m-1),
			proposal.vertex(m),
			proposal.edge(m),
			proposal.vertex(m+1))) {
		proposal.release(l, m+1, m_pool);
		return false;
	}

	proposal.vertex(k-1)->updateSamplePosition(
		proposal.vertex(k-2));

	++statsGenerated;
	return true;
}
コード例 #5
0
ファイル: ward.cpp プロジェクト: blckshrk/IFT6042
	inline Spectrum sample(BSDFSamplingRecord &bRec, Float &_pdf, const Point2 &_sample) const {
		Point2 sample(_sample);

		bool hasSpecular = (bRec.typeMask & EGlossyReflection)
				&& (bRec.component == -1 || bRec.component == 0);
		bool hasDiffuse  = (bRec.typeMask & EDiffuseReflection)
				&& (bRec.component == -1 || bRec.component == 1);

		if (!hasSpecular && !hasDiffuse)
			return Spectrum(0.0f);

		bool choseSpecular = hasSpecular;

		if (hasDiffuse && hasSpecular) {
			if (sample.x <= m_specularSamplingWeight) {
				sample.x /= m_specularSamplingWeight;
			} else {
				sample.x = (sample.x - m_specularSamplingWeight)
					/ (1-m_specularSamplingWeight);
				choseSpecular = false;
			}
		}

		if (choseSpecular) {
			Float alphaU = m_alphaU->eval(bRec.its).average();
			Float alphaV = m_alphaV->eval(bRec.its).average();

			Float phiH = std::atan(alphaV/alphaU
				* std::tan(2.0f * M_PI * sample.y));
			if (sample.y > 0.5f)
				phiH += M_PI;
			Float cosPhiH = std::cos(phiH);
			Float sinPhiH = math::safe_sqrt(1.0f-cosPhiH*cosPhiH);

			Float thetaH = std::atan(math::safe_sqrt(
				-math::fastlog(sample.x) / (
					(cosPhiH*cosPhiH) / (alphaU*alphaU) +
					(sinPhiH*sinPhiH) / (alphaV*alphaV)
			)));
			Vector H = sphericalDirection(thetaH, phiH);
			bRec.wo = H * (2.0f * dot(bRec.wi, H)) - bRec.wi;

			bRec.sampledComponent = 1;
			bRec.sampledType = EGlossyReflection;

			if (Frame::cosTheta(bRec.wo) <= 0.0f)
				return Spectrum(0.0f);
		} else {
			bRec.wo = Warp::squareToCosineHemisphere(sample);
			bRec.sampledComponent = 0;
			bRec.sampledType = EDiffuseReflection;
		}
		bRec.eta = 1.0f;

		_pdf = pdf(bRec, ESolidAngle);

		if (_pdf == 0)
			return Spectrum(0.0f);
		else
			return eval(bRec, ESolidAngle) / _pdf;
	}
コード例 #6
0
ファイル: ttest.cpp プロジェクト: Vertexwahn/nori
    /// Invoke a series of t-tests on the provided input
    void activate() {
        int total = 0, passed = 0;
        pcg32 random;

        if (!m_bsdfs.empty()) {
            if (m_references.size() * m_bsdfs.size() != m_angles.size())
                throw NoriException("Specified a different number of angles and reference values!");
            if (!m_scenes.empty())
                throw NoriException("Cannot test BSDFs and scenes at the same time!");

            /* Test each registered BSDF */
            int ctr = 0;
            for (auto bsdf : m_bsdfs) {
                for (size_t i=0; i<m_references.size(); ++i) {
                    float angle = m_angles[i], reference = m_references[ctr++];

                    cout << "------------------------------------------------------" << endl;
                    cout << "Testing (angle=" << angle << "): " << bsdf->toString() << endl;
                    ++total;

                    BSDFQueryRecord bRec(sphericalDirection(degToRad(angle), 0));

                    cout << "Drawing " << m_sampleCount << " samples .. " << endl;
                    double mean=0, variance = 0;
                    for (int k=0; k<m_sampleCount; ++k) {
                        Point2f sample(random.nextFloat(), random.nextFloat());
                        double result = (double) bsdf->sample(bRec, sample).getLuminance();

                        /* Numerically robust online variance estimation using an
                           algorithm proposed by Donald Knuth (TAOCP vol.2, 3rd ed., p.232) */
                        double delta = result - mean;
                        mean += delta / (double) (k+1);
                        variance += delta * (result - mean);
                    }
                    variance /= m_sampleCount - 1;
                    std::pair<bool, std::string>
                        result = hypothesis::students_t_test(mean, variance, reference,
                            m_sampleCount, m_significanceLevel, (int) m_references.size());

                    if (result.first)
                        ++passed;
                    cout << result.second << endl;
                }
            }
        } else {
            if (m_references.size() != m_scenes.size())
                throw NoriException("Specified a different number of scenes and reference values!");

            Sampler *sampler = static_cast<Sampler *>(
                NoriObjectFactory::createInstance("independent", PropertyList()));

            int ctr = 0;
            for (auto scene : m_scenes) {
                const Integrator *integrator = scene->getIntegrator();
                const Camera *camera = scene->getCamera();
                float reference = m_references[ctr++];

                cout << "------------------------------------------------------" << endl;
                cout << "Testing scene: " << scene->toString() << endl;
                ++total;

                cout << "Generating " << m_sampleCount << " paths.. " << endl;

                double mean = 0, variance = 0;
                for (int k=0; k<m_sampleCount; ++k) {
                    /* Sample a ray from the camera */
                    Ray3f ray;
                    Point2f pixelSample = (sampler->next2D().array()
                        * camera->getOutputSize().cast<float>().array()).matrix();
                    Color3f value = camera->sampleRay(ray, pixelSample, sampler->next2D());

                    /* Compute the incident radiance */
                    value *= integrator->Li(scene, sampler, ray);

                    /* Numerically robust online variance estimation using an
                       algorithm proposed by Donald Knuth (TAOCP vol.2, 3rd ed., p.232) */
                    double result = (double) value.getLuminance();
                    double delta = result - mean;
                    mean += delta / (double) (k+1);
                    variance += delta * (result - mean);
                }
                variance /= m_sampleCount - 1;

                std::pair<bool, std::string>
                    result = hypothesis::students_t_test(mean, variance, reference,
                        m_sampleCount, m_significanceLevel, (int) m_references.size());

                if (result.first)
                    ++passed;
                cout << result.second << endl;
            }
        }
        cout << "Passed " << passed << "/" << total << " tests." << endl;
    }