Beispiel #1
0
// wo.z >= 0 is guaranteed
// Note the sampled wi ~ D(wh)*cos(thetah)/(4*dot(wo,wh))
// and pdf = 0 when dot(wo, wh) < 0 (make sure Pdf() does the same thing)
void
GGXForHeitz::Sample_f(const Vector &wo, Vector *wi, float u1, float u2,
                     float *pdf) const
{
    // We allow cos(theta_o) == 0 because it doesn't break our computation
    Assert(CosTheta(wo) >= 0.f);

    // From [Walter et al., 2007]
    float thetah = atanf(mAlpha * sqrt(u1) / sqrt(1.f-u1)),
          costhetah = cosf(thetah), 
          sinthetah = sinf(thetah),
          phih = u2 * 2.f * M_PI;
    Vector wh = SphericalDirection(sinthetah, costhetah, phih);

    // Compute incident direction by reflecting about $\wh$
    float dotHO = Dot(wo, wh);

    if (dotHO < sSmallValue) {
        *pdf = 0.f;

    } else {
        *wi = -wo + 2.f * dotHO * wh;
        // TODO: test
        //if (wi->z < 0) {
        //    fprintf(stderr, "wi.z == %f\n", wi->z);
        //}
        // TODO: can be optimized
        *pdf = D(wh) * costhetah / (4.f * dotHO);
    }
}
Beispiel #2
0
Vector3f TrowbridgeReitzDistribution::Sample_wh(const Vector3f &wo,
                                                const Point2f &u) const {
    Vector3f wh;
    if (!sampleVisibleArea) {
        Float cosTheta = 0, phi = (2 * Pi) * u[1];
        if (alphax == alphay) {
            Float tanTheta2 = alphax * alphax * u[0] / (1.0f - u[0]);
            cosTheta = 1 / std::sqrt(1 + tanTheta2);
        } else {
            phi =
                std::atan(alphay / alphax * std::tan(2 * Pi * u[1] + .5f * Pi));
            if (u[1] > .5f) phi += Pi;
            Float sinPhi = std::sin(phi), cosPhi = std::cos(phi);
            const Float alphax2 = alphax * alphax, alphay2 = alphay * alphay;
            const Float alpha2 =
                1 / (cosPhi * cosPhi / alphax2 + sinPhi * sinPhi / alphay2);
            Float tanTheta2 = alpha2 * u[0] / (1 - u[0]);
            cosTheta = 1 / std::sqrt(1 + tanTheta2);
        }
        Float sinTheta =
            std::sqrt(std::max((Float)0., (Float)1. - cosTheta * cosTheta));
        wh = SphericalDirection(sinTheta, cosTheta, phi);
        if (!SameHemisphere(wo, wh)) wh = -wh;
    } else {
        bool flip = wo.z < 0;
        wh = TrowbridgeReitzSample(flip ? -wo : wo, alphax, alphay, u[0], u[1]);
        if (flip) wh = -wh;
    }
    return wh;
}
// commented, dpl 10 august 2005
Spectrum Lafortune::Sample_f(const Vector &wo, Vector *wi,
		float u1, float u2, float *pdf) const {
	u_int comp = RandomUInt() % (nLobes+1);
	if (comp == nLobes) {
		// Cosine-sample the hemisphere, flipping the direction if necessary
		*wi = CosineSampleHemisphere(u1, u2);
		if (wo.z < 0.) wi->z *= -1.f;
	}
	else {
		// Sample lobe _comp_ for Lafortune BRDF
		float xlum = x[comp].y();
		float ylum = y[comp].y();
		float zlum = z[comp].y();
		float costheta = powf(u1, 1.f / (.8f * exponent[comp].y() + 1));
		float sintheta = sqrtf(max(0.f, 1.f - costheta*costheta));
		float phi = u2 * 2.f * M_PI;
		Vector lobeCenter = Normalize(Vector(xlum * wo.x, ylum * wo.y, zlum * wo.z));
		Vector lobeX, lobeY;
		CoordinateSystem(lobeCenter, &lobeX, &lobeY);
		*wi = SphericalDirection(sintheta, costheta, phi, lobeX, lobeY,
			lobeCenter);
	}
	if (!SameHemisphere(wo, *wi)) return Spectrum(0.f);
	*pdf = Pdf(wo, *wi);
	return f(wo, *wi);
}
// commented, dpl 10 august 2005
void Anisotropic::Sample_f(const Vector &wo, Vector *wi,
		float u1, float u2, float *pdf) const {
	// Sample from first quadrant and remap to hemisphere to sample \wh
	float phi, costheta;
	if (u1 < .25f) {
		sampleFirstQuadrant(4.f * u1, u2, &phi, &costheta);
	} else if (u1 < .5f) {
		u1 = 4.f * (.5f - u1);
		sampleFirstQuadrant(u1, u2, &phi, &costheta);
		phi = M_PI - phi;
	} else if (u1 < .75f) {
		u1 = 4.f * (u1 - .5f);
		sampleFirstQuadrant(u1, u2, &phi, &costheta);
		phi += M_PI;
	} else {
		u1 = 4.f * (1.f - u1);
		sampleFirstQuadrant(u1, u2, &phi, &costheta);
		phi = 2.f * M_PI - phi;
	}
	float sintheta = sqrtf(max(0.f, 1.f - costheta*costheta));
	Vector H = SphericalDirection(sintheta, costheta, phi);
	if (Dot(wo, H) < 0.f) H = -H;
	// Compute incident direction by reflecting about $\wh$
	*wi = -wo + 2.f * Dot(wo, H) * H;
	// Compute PDF for \wi from Anisotropic distribution
	float anisotropic_pdf = D(H) / (4.f * Dot(wo, H));
	*pdf = anisotropic_pdf;
}
Beispiel #5
0
Vector SampleHG(const Vector &w, float g, float u1, float u2) {
    float costheta;
    if (fabsf(g) < 1e-3)
        costheta = 1.f - 2.f * u1;
    else {
        float sqrTerm = (1.f - g * g) /
                        (1.f - g + 2.f * g * u1);
        costheta = (1.f + g * g - sqrTerm * sqrTerm) / (2.f * g);
    }
    float sintheta = sqrtf(max(0.f, 1.f-costheta*costheta));
    float phi = 2.f * M_PI * u2;
    Vector v1, v2;
    CoordinateSystem(w, &v1, &v2);
    return SphericalDirection(sintheta, costheta, phi, v1, v2, w);
}
Beispiel #6
0
Vector SampleHG(const Vector &w, float g, const float u1, const float u2) {
	float costheta;
	if (fabsf(g) < 1e-3f)
		costheta = 1.f - 2.f * u1;
	else {
		// NOTE - lordcrc - Bugfix, pbrt tracker id 0000082: bug in SampleHG
		const float sqrTerm = (1.f - g * g) / (1.f - g + 2.f * g * u1);
		costheta = (1.f + g * g - sqrTerm * sqrTerm) / (2.f * g);
	}
	const float sintheta = sqrtf(Max(0.f, 1.f - costheta * costheta));
	const float phi = 2.f * M_PI * u2;
	Vector v1, v2;
	CoordinateSystem(w, &v1, &v2);
	return SphericalDirection(sintheta, costheta, phi, v1, v2, w);
}
void Blinn::Sample_f(const Vector &wo, Vector *wi,
		float u1, float u2, float *pdf) const {
	// Compute sampled half-angle vector $\wh$ for Blinn distribution
	float costheta = powf(u1, 1.f / (exponent+1));
	float sintheta = sqrtf(max(0.f, 1.f - costheta*costheta));
	float phi = u2 * 2.f * M_PI;
	Vector H = SphericalDirection(sintheta, costheta, phi);
	if (Dot(wo, H) < 0.f) H = -H;
	// Compute incident direction by reflecting about $\wh$
	*wi = -wo + 2.f * Dot(wo, H) * H;
	// Compute PDF for \wi from Blinn distribution
	float blinn_pdf = ((exponent + 2.f) *
	                   powf(costheta, exponent)) /
		(2.f * M_PI * 4.f * Dot(wo, H));
	*pdf = blinn_pdf;
}
Beispiel #8
0
Interaction Sphere::Sample(const Interaction &ref, const Point2f &u) const {
    // Compute coordinate system for sphere sampling
    Point3f pCenter = (*ObjectToWorld)(Point3f(0, 0, 0));
    Vector3f wc = Normalize(pCenter - ref.p);
    Vector3f wcX, wcY;
    CoordinateSystem(wc, &wcX, &wcY);

    // Sample uniformly on sphere if $\pt{}$ is inside it
    Point3f pOrigin =
        OffsetRayOrigin(ref.p, ref.pError, ref.n, pCenter - ref.p);
    if (DistanceSquared(pOrigin, pCenter) <= radius * radius) return Sample(u);

    // Sample sphere uniformly inside subtended cone

    // Compute $\theta$ and $\phi$ values for sample in cone
    Float sinThetaMax2 = radius * radius / DistanceSquared(ref.p, pCenter);
    Float cosThetaMax = std::sqrt(std::max((Float)0, 1 - sinThetaMax2));
    Float cosTheta = (1 - u[0]) + u[0] * cosThetaMax;
    Float sinTheta = std::sqrt(1 - cosTheta * cosTheta);
    Float phi = u[1] * 2 * Pi;

    // Compute angle $\alpha$ from center of sphere to sampled point on surface
    Float dc = Distance(ref.p, pCenter);
    Float ds = dc * cosTheta -
               std::sqrt(std::max(
                   (Float)0, radius * radius - dc * dc * sinTheta * sinTheta));
    Float cosAlpha = (dc * dc + radius * radius - ds * ds) / (2 * dc * radius);
    Float sinAlpha = std::sqrt(std::max((Float)0, 1 - cosAlpha * cosAlpha));

    // Compute surface normal and sampled point on sphere
    Vector3f nObj =
        SphericalDirection(sinAlpha, cosAlpha, phi, -wcX, -wcY, -wc);
    Point3f pObj = radius * Point3f(nObj.x, nObj.y, nObj.z);

    // Return _Interaction_ for sampled point on sphere
    Interaction it;

    // Reproject _pObj_ to sphere surface and compute _pObjError_
    pObj *= radius / Distance(pObj, Point3f(0, 0, 0));
    Vector3f pObjError = gamma(5) * Abs((Vector3f)pObj);
    it.p = (*ObjectToWorld)(pObj, pObjError, &it.pError);
    it.n = (*ObjectToWorld)(Normal3f(nObj));
    if (reverseOrientation) it.n *= -1.f;
    return it;
}
Beispiel #9
0
void SampleBlinn(const Vector &wo, Vector *wi, float u1, float u2, float *pdf,
        float exponent) {
    // Compute sampled half-angle vector $\wh$ for Blinn distribution
    float costheta = powf(u1, 1.f / (exponent+1));
    float sintheta = sqrtf(max(0.f, 1.f - costheta*costheta));
    float phi = u2 * 2.f * M_PI;
    Vector wh = SphericalDirection(sintheta, costheta, phi);
    if (!SameHemisphere(wo, wh)) wh = -wh;

    // Compute incident direction by reflecting about $\wh$
    *wi = -wo + 2.f * Dot(wo, wh) * wh;

    // Compute PDF for $\wi$ from Blinn distribution
    float blinn_pdf = ((exponent + 1.f) * powf(costheta, exponent)) /
                      (2.f * M_PI * 4.f * Dot(wo, wh));
    if (Dot(wo, wh) < 0.f) blinn_pdf = 0.f;
    *pdf = blinn_pdf;
}
Beispiel #10
0
// HenyeyGreenstein Method Definitions
Float HenyeyGreenstein::Sample_p(const Vector3f &wo, Vector3f *wi,
                                 const Point2f &u) const {
    // Compute $\cos \theta$ for Henyey--Greenstein sample
    Float cosTheta;
    if (std::abs(g) < 1e-3)
        cosTheta = 1 - 2 * u[0];
    else {
        Float sqrTerm = (1 - g * g) / (1 - g + 2 * g * u[0]);
        cosTheta = (1 + g * g - sqrTerm * sqrTerm) / (2 * g);
    }

    // Compute direction _wi_ for Henyey--Greenstein sample
    Float sinTheta = std::sqrt(std::max((Float)0, 1 - cosTheta * cosTheta));
    Float phi = 2 * Pi * u[1];
    Vector3f v1, v2;
    CoordinateSystem(wo, &v1, &v2);
    *wi = SphericalDirection(sinTheta, cosTheta, phi, v1, v2, -wo);
    return PhaseHG(-cosTheta, g);
}
Beispiel #11
0
Vector3f BeckmannDistribution::Sample_wh(const Vector3f &wo,
                                         const Point2f &u) const {
    if (!sampleVisibleArea) {
        // Sample full distribution of normals for Beckmann distribution

        // 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;
    } else {
        // Sample visible area of normals with Beckmann distribution
        Vector3f wh;
        bool flip = wo.z < 0;
        wh = BeckmannSample(flip ? -wo : wo, alphax, alphay, u[0], u[1]);
        if (flip) wh = -wh;
        return wh;
    }
}
Beispiel #12
0
//复制自PBRT
void Anisotropic::Sample_f(const Vector3f &wo, Vector3f *wi, Float u1, Float u2,
		Float *pdf) const {
	Float phi, costheta;
	if (u1 < .25f) {
		sampleFirstQuadrant(4.f * u1, u2, &phi, &costheta);
	} else if (u1 < .5f) {
		u1 = 4.f * (.5f - u1);
		sampleFirstQuadrant(u1, u2, &phi, &costheta);
		phi = Pi - phi;
	} else if (u1 < .75f) {
		u1 = 4.f * (u1 - .5f);
		sampleFirstQuadrant(u1, u2, &phi, &costheta);
		phi += Pi;
	} else {
		u1 = 4.f * (1.f - u1);
		sampleFirstQuadrant(u1, u2, &phi, &costheta);
		phi = 2.f * Pi - phi;
	}
	Float sintheta = sqrtf(std::max(0.f, 1.f - costheta * costheta));
	Vector3f wh = SphericalDirection(sintheta, costheta, phi);
	if (!SameHemisphere(wo, wh))
		wh = -wh;

	// Compute incident direction by reflecting about $\wh$
	*wi = -wo + 2.f * Dot(wo, wh) * wh;

	// Compute PDF for $\wi$ from anisotropic distribution
	Float costhetah = AbsCosTheta(wh);
	Float ds = 1.f - costhetah * costhetah;
	Float anisotropic_pdf = 0.f;
	if (ds > 0.f && Dot(wo, wh) > 0.f) {
		Float e = (ex * wh.x * wh.x + ey * wh.y * wh.y) / ds;
		Float d = sqrtf((ex + 1.f) * (ey + 1.f)) * InvTwoPi
				* powf(costhetah, e);
		anisotropic_pdf = d / (4.f * Dot(wo, wh));
	}
	*pdf = anisotropic_pdf;
}
Beispiel #13
0
MeasuredMaterial::MeasuredMaterial(string matName, const string &filename,
      Reference<Texture<float> > bump): Material(matName) {

   
    bumpMap = bump;
    const char *suffix = strrchr(filename.c_str(), '.');
    regularHalfangleData = NULL;
    thetaPhiData = NULL;
    if (!suffix)
        Error("No suffix in measured BRDF filename \"%s\".  "
              "Can't determine file type (.brdf / .merl)", filename.c_str());
    else if (!strcmp(suffix, ".brdf") || !strcmp(suffix, ".BRDF")) {
        // Load $(\theta, \phi)$ measured BRDF data
        if (loadedThetaPhi.find(filename) != loadedThetaPhi.end()) {
            thetaPhiData = loadedThetaPhi[filename];
            return;
        }
        
        vector<float> values;
        if (!ReadFloatFile(filename.c_str(), &values)) {
            Error("Unable to read BRDF data from file \"%s\"", filename.c_str());
            return;
        }
        
        uint32_t pos = 0;
        int numWls = int(values[pos++]);
        if ((values.size() - 1 - numWls) % (4 + numWls) != 0) {
            Error("Excess or insufficient data in theta, phi BRDF file \"%s\"",
                  filename.c_str());
            return;
        }

        vector<float> wls;
        for (int i = 0; i < numWls; ++i)
            wls.push_back(values[pos++]);
        
        BBox bbox;
        vector<IrregIsotropicBRDFSample> samples;
        while (pos < values.size()) {
            float thetai = values[pos++];
            float phii = values[pos++];
            float thetao = values[pos++];
            float phio = values[pos++];
            Vector wo = SphericalDirection(sinf(thetao), cosf(thetao), phio);
            Vector wi = SphericalDirection(sinf(thetai), cosf(thetai), phii);
            Spectrum s = Spectrum::FromSampled(&wls[0], &values[pos], numWls);
            pos += numWls;
            pbrt::Point p = BRDFRemap(wo, wi);
            samples.push_back(IrregIsotropicBRDFSample(p, s));
            bbox = Union(bbox, p);
        }
        loadedThetaPhi[filename] = thetaPhiData = new KdTree<IrregIsotropicBRDFSample>(samples);
    }
    else {
        // Load RegularHalfangle BRDF Data
        nThetaH = 90;
        nThetaD = 90;
        nPhiD = 180;
        
        if (loadedRegularHalfangle.find(filename) != loadedRegularHalfangle.end()) {
            regularHalfangleData = loadedRegularHalfangle[filename];
            return;
        }
        
        FILE *f = fopen(filename.c_str(), "rb");
        if (!f) {
            Error("Unable to open BRDF data file \"%s\"", filename.c_str());
            return;
        }
        int dims[3];
        if (fread(dims, sizeof(int), 3, f) != 3) {
            Error("Premature end-of-file in measured BRDF data file \"%s\"",
                  filename.c_str());
            fclose(f);
            return;
        }
        uint32_t n = dims[0] * dims[1] * dims[2];
        if (n != nThetaH * nThetaD * nPhiD)  {
            Error("Dimensions don't match\n");
            fclose(f);
            return;
        }
        
        regularHalfangleData = new float[3*n];
        const uint32_t chunkSize = 2*nPhiD;
        double *tmp = ALLOCA(double, chunkSize);
        uint32_t nChunks = n / chunkSize;
        Assert((n % chunkSize) == 0);
        float scales[3] = { 1.f/1500.f, 1.15f/1500.f, 1.66f/1500.f };
        for (int c = 0; c < 3; ++c) {
            int offset = 0;
            for (uint32_t i = 0; i < nChunks; ++i) {
                if (fread(tmp, sizeof(double), chunkSize, f) != chunkSize) {
                    Error("Premature end-of-file in measured BRDF data file \"%s\"",
                          filename.c_str());
                    delete[] regularHalfangleData;
                    regularHalfangleData = NULL;
                    fclose(f);
                    return;
                }
                for (uint32_t j = 0; j < chunkSize; ++j)
                    regularHalfangleData[3 * offset++ + c] = max(0., tmp[j] * scales[c]);
            }
        }
        
        loadedRegularHalfangle[filename] = regularHalfangleData;
        fclose(f);
    }
}