void test02_roughTransmittance() {
		RoughTransmittance rtr(MicrofacetDistribution::EBeckmann);
		ref<Random> random = new Random();

		for (int i=0; i<50; ++i) {
			Float alpha = std::pow(random->nextFloat(), (Float) 4.0f)*4;
			Float eta = 1 + std::pow(random->nextFloat(), (Float) 4.0f)*3;
			if (alpha < 1e-5)
				alpha = 1e-5f;
			if (eta < 1+1e-5)
				eta = 1+1e-5f;
			//eta = 1/eta;

			Float refD = computeDiffuseTransmittance("beckmann", eta, alpha);
			Float datD = rtr.evalDiffuse(alpha, eta);

			cout << "Testing " << i << "/50" << endl;
			if (std::abs(refD-datD) > 1e-3f) {
				cout << endl;
				cout << "eta = " << eta << endl;
				cout << "alpha = " << alpha << endl;
				cout << "diff=" << datD-refD << " (datD=" << datD << ", ref=" << refD << ")" << endl;
			}
		}

		Float avgErr = 0.0f;
		for (int i=0; i<1000; ++i) {
			Float cosTheta = random->nextFloat();
			Float alpha = std::pow(random->nextFloat(), (Float) 4.0f)*4;
			Float eta = 1 + std::pow(random->nextFloat(), (Float) 4.0f)*3;
			if (cosTheta < 1e-5)
				cosTheta = 1e-5f;
			if (alpha < 1e-5)
				alpha = 1e-5f;
			if (eta < 1+1e-5)
				eta = 1+1e-5f;
			//eta = 1/eta;

			Float ref = computeTransmittance("beckmann", eta, alpha, cosTheta);
			Float dat = rtr.eval(cosTheta, alpha, eta);

			if (i % 20 == 0)
				cout << "Testing " << i << "/1000" << endl;
			if (std::abs(ref-dat) > 1e-3f) {
				cout << endl;
				cout << "eta = " << eta << endl;
				cout << "alpha = " << alpha << endl;
				cout << "cosTheta = " << cosTheta << endl;
				cout << "diff=" << dat-ref << " (dat=" << dat << ", ref=" << ref << ")" << endl;
			}

			avgErr += ref-dat;
		}
		avgErr /= 1000;
		cout << "Avg error = " << avgErr << endl;
	}
	void test04_roughTransmittanceFixedEtaFixedAlpha() {
		ref<Timer> timer = new Timer();
		RoughTransmittance rtr(MicrofacetDistribution::EBeckmann);
		Float eta = 1.5f;
		Float alpha = 0.2f;
		rtr.setEta(eta);
		rtr.setAlpha(alpha);
		cout << "Loading and projecting took " << timer->getMilliseconds() << " ms" << endl;

		ref<Random> random = new Random();

		Float refD = computeDiffuseTransmittance("beckmann", eta, alpha);
		Float datD = rtr.evalDiffuse(alpha, eta);

		if (std::abs(refD-datD) > 1e-3f) {
			cout << endl;
			cout << "alpha = " << alpha << endl;
			cout << "diff=" << datD-refD << " (datD=" << datD << ", ref=" << refD << ")" << endl;
		}

		Float avgErr = 0.0f;
		for (int i=0; i<1000; ++i) {
			Float cosTheta = random->nextFloat();
			if (cosTheta < 1e-5)
				cosTheta = 1e-5f;

			Float ref = computeTransmittance("beckmann", eta, alpha, cosTheta);
			Float dat = rtr.eval(cosTheta, alpha, eta);

			if (i % 20 == 0)
				cout << "Testing " << i << "/1000" << endl;
			if (std::abs(ref-dat) > 1e-3f) {
				cout << endl;
				cout << "eta = " << eta << endl;
				cout << "alpha = " << alpha << endl;
				cout << "cosTheta = " << cosTheta << endl;
				cout << "diff=" << dat-ref << " (dat=" << dat << ", ref=" << ref << ")" << endl;
			}

			avgErr += ref-dat;
		}
		avgErr /= 1000;
		cout << "Avg error = " << avgErr << endl;
	}
	void fit(const char *name, int inverted) {
		size_t resolutionIOR = RESOLUTION_IOR,
			   resolutionAlpha = RESOLUTION_ROUGHNESS,
			   resolutionTheta = RESOLUTION_THETA;

		Float alphaStart = ROUGHNESS_START,
			  alphaEnd   = ROUGHNESS_END,
			  iorStart   = IOR_START,
			  iorEnd     = IOR_END;

		std::ofstream os(formatString("%s%i.m", name, inverted).c_str());
		os << std::fixed << std::setprecision(8);

		os << "alphaStart=" << alphaStart << ";" << endl;
		os << "alphaEnd=" << alphaEnd << ";" << endl;
		os << "iorStart=" << iorStart << ";" << endl;
		os << "iorEnd=" << iorEnd << ";" << endl;
		os << "alphaSteps=" << resolutionAlpha << ";" << endl;
		os << "thetaSteps=" << resolutionTheta << ";" << endl;
		os << "iorSteps=" << resolutionIOR << ";" << endl;

		os << "transmittance={" << endl;
		ref<FileStream> fstream = new FileStream(formatString("data/microfacet/%s.dat", name).c_str(),
				inverted ? FileStream::EAppendReadWrite : FileStream::ETruncReadWrite);

		fstream->setByteOrder(Stream::ELittleEndian);

		if (!inverted) {
			fstream->write("MTS_TRANSMITTANCE", 17);
			fstream->writeSize(resolutionIOR);
			fstream->writeSize(resolutionAlpha);
			fstream->writeSize(resolutionTheta);
			fstream->writeSingle(iorStart);
			fstream->writeSingle(iorEnd);
			fstream->writeSingle(alphaStart);
			fstream->writeSingle(alphaEnd);
		}

		Float iorStepSize   = 1.0f / (resolutionIOR-1),
			  alphaStepSize = 1.0f / (resolutionAlpha-1);

		for (size_t i=0; i<resolutionIOR; ++i) {
			Float t = i * iorStepSize;
			Float ior = iorStart + (iorEnd-iorStart) * std::pow(t, (Float) 4.0f);
			cout << "ior = " << ior << endl;
			os << "\t{" << endl;
			for (size_t j=0; j<resolutionAlpha; ++j) {
				Float t = j * alphaStepSize;
				Float alpha = alphaStart + (alphaEnd-alphaStart) * std::pow(t, (Float) 4.0f);
				cout << "alpha = " << alpha << endl;
				Float diffTrans;
				Float *transmittance = computeTransmittance(name,
						ior, alpha, resolutionTheta, diffTrans, inverted);
				os << "\t\t{";
				for (size_t k=0; k<resolutionTheta; ++k) {
					fstream->writeSingle((float) transmittance[k]);
					os << transmittance[k];
					if (k+1 < resolutionTheta)
						os << ", ";
				}
				os << "}";
				if (j + 1 < resolutionAlpha)
					os << ",";
				os << endl;
				delete[] transmittance;
				fstream->writeSingle((float) diffTrans);
			}
			os << "\t}";
			if (i + 1 < resolutionIOR)
				os << ",";
			os << endl;
			cout << endl;
		}
		os << "};" << endl;
		os.close();
		fstream->close();
	}