Ejemplo n.º 1
0
Float PerspectiveCamera::GenerateRayDifferential(const CameraSample &sample,
                                                 RayDifferential *ray) const {
    ProfilePhase prof(Prof::GenerateCameraRay);
    // Compute raster and camera sample positions
    Point3f pFilm = Point3f(sample.pFilm.x, sample.pFilm.y, 0);
    Point3f pCamera = RasterToCamera(pFilm);
    Vector3f dir = Normalize(Vector3f(pCamera.x, pCamera.y, pCamera.z));
    *ray = RayDifferential(Point3f(0, 0, 0), dir);
    // Modify ray for depth of field
    if (lensRadius > 0) {
        // Sample point on lens
        Point2f pLens = lensRadius * ConcentricSampleDisk(sample.pLens);

        // Compute point on plane of focus
        Float ft = focalDistance / ray->d.z;
        Point3f pFocus = (*ray)(ft);

        // Update ray for effect of lens
        ray->o = Point3f(pLens.x, pLens.y, 0);
        ray->d = Normalize(pFocus - ray->o);
    }

    // Compute offset rays for _PerspectiveCamera_ ray differentials
    if (lensRadius > 0) {
        // Compute _PerspectiveCamera_ ray differentials accounting for lens

        // Sample point on lens
        Point2f pLens = lensRadius * ConcentricSampleDisk(sample.pLens);
        Vector3f dx = Normalize(Vector3f(pCamera + dxCamera));
        Float ft = focalDistance / dx.z;
        Point3f pFocus = Point3f(0, 0, 0) + (ft * dx);
        ray->rxOrigin = Point3f(pLens.x, pLens.y, 0);
        ray->rxDirection = Normalize(pFocus - ray->rxOrigin);

        Vector3f dy = Normalize(Vector3f(pCamera + dyCamera));
        ft = focalDistance / dy.z;
        pFocus = Point3f(0, 0, 0) + (ft * dy);
        ray->ryOrigin = Point3f(pLens.x, pLens.y, 0);
        ray->ryDirection = Normalize(pFocus - ray->ryOrigin);
    } else {
        ray->rxOrigin = ray->ryOrigin = ray->o;
        ray->rxDirection = Normalize(Vector3f(pCamera) + dxCamera);
        ray->ryDirection = Normalize(Vector3f(pCamera) + dyCamera);
    }
    ray->time = Lerp(sample.time, shutterOpen, shutterClose);
    ray->medium = medium;
    *ray = CameraToWorld(*ray);
    ray->hasDifferentials = true;
    return 1;
}
Ejemplo n.º 2
0
Float OrthographicCamera::GenerateRayDifferential(const CameraSample &sample,
                                                  RayDifferential *ray) const {
    ProfilePhase prof(Prof::GenerateCameraRay);
    // Compute main orthographic viewing ray

    // Compute raster and camera sample positions
    Point3f pFilm = Point3f(sample.pFilm.x, sample.pFilm.y, 0);
    Point3f pCamera = RasterToCamera(pFilm);
    *ray = RayDifferential(pCamera, Vector3f(0, 0, 1));

    // Modify ray for depth of field
    if (lensRadius > 0) {
        // Sample point on lens
        Point2f pLens = lensRadius * ConcentricSampleDisk(sample.pLens);

        // Compute point on plane of focus
        Float ft = focalDistance / ray->d.z;
        Point3f pFocus = (*ray)(ft);

        // Update ray for effect of lens
        ray->o = Point3f(pLens.x, pLens.y, 0);
        ray->d = Normalize(pFocus - ray->o);
    }

    // Compute ray differentials for _OrthographicCamera_
    if (lensRadius > 0) {
        // Compute _OrthographicCamera_ ray differentials accounting for lens

        // Sample point on lens
        Point2f pLens = lensRadius * ConcentricSampleDisk(sample.pLens);
        Float ft = focalDistance / ray->d.z;

        Point3f pFocus = pCamera + dxCamera + (ft * Vector3f(0, 0, 1));
        ray->rxOrigin = Point3f(pLens.x, pLens.y, 0);
        ray->rxDirection = Normalize(pFocus - ray->rxOrigin);

        pFocus = pCamera + dyCamera + (ft * Vector3f(0, 0, 1));
        ray->ryOrigin = Point3f(pLens.x, pLens.y, 0);
        ray->ryDirection = Normalize(pFocus - ray->ryOrigin);
    } else {
        ray->rxOrigin = ray->o + dxCamera;
        ray->ryOrigin = ray->o + dyCamera;
        ray->rxDirection = ray->ryDirection = ray->d;
    }
    ray->time = Lerp(sample.time, shutterOpen, shutterClose);
    ray->hasDifferentials = true;
    ray->medium = medium;
    *ray = CameraToWorld(*ray);
    return 1;
}
Ejemplo n.º 3
0
float OrthoCamera::GenerateRayDifferential(const CameraSample &sample,
        RayDifferential *ray) const {
    // Compute main orthographic viewing ray

    // Generate raster and camera samples
    PbrtPoint Pras(sample.imageX, sample.imageY, 0);
    PbrtPoint Pcamera;
    RasterToCamera(Pras, &Pcamera);
    *ray = RayDifferential(Pcamera, Vector(0,0,1), 0., INFINITY);

    // Modify ray for depth of field
    if (lensRadius > 0.) {
        // Sample point on lens
        float lensU, lensV;
        ConcentricSampleDisk(sample.lensU, sample.lensV, &lensU, &lensV);
        lensU *= lensRadius;
        lensV *= lensRadius;

        // Compute point on plane of focus
        float ft = focalDistance / ray->d.z;
        PbrtPoint Pfocus = (*ray)(ft);

        // Update ray for effect of lens
        ray->o = PbrtPoint(lensU, lensV, 0.f);
        ray->d = Normalize(Pfocus - ray->o);
    }
    ray->time = Lerp(sample.time, shutterOpen, shutterClose);
    ray->rxOrigin = ray->o + dxCamera;
    ray->ryOrigin = ray->o + dyCamera;
    ray->rxDirection = ray->ryDirection = ray->d;
    ray->hasDifferentials = true;
    CameraToWorld(*ray, ray);
    return 1.f;
}
Ejemplo n.º 4
0
float OrthoCamera::GenerateRay(const Sample &sample,
                               Ray *ray) const {
	// Generate raster and camera samples
	Point Pras(sample.imageX, sample.imageY, 0);
	Point Pcamera;
	RasterToCamera(Pras, &Pcamera);
	ray->o = Pcamera;
	ray->d = Vector(0,0,1);
	// Set ray time value
	ray->time = Lerp(sample.time, ShutterOpen, ShutterClose);
	// Modify ray for depth of field
	if (LensRadius > 0.) {
		// Sample point on lens
		float lensU, lensV;
		ConcentricSampleDisk(sample.lensU, sample.lensV,
		                     &lensU, &lensV);
		lensU *= LensRadius;
		lensV *= LensRadius;
		// Compute point on plane of focus
		float ft = (FocalDistance - ClipHither) / ray->d.z;
		Point Pfocus = (*ray)(ft);
		// Update ray for effect of lens
		ray->o.x += lensU * (FocalDistance - ClipHither) / FocalDistance;
		ray->o.y += lensV * (FocalDistance - ClipHither) / FocalDistance;
		ray->d = Pfocus - ray->o;
	}
	ray->mint = 0.;
	ray->maxt = ClipYon - ClipHither;
	ray->d = Normalize(ray->d);
	CameraToWorld(*ray, ray);
	return 1.f;
}
Ejemplo n.º 5
0
// OrthographicCamera Definitions
Float OrthographicCamera::GenerateRay(const CameraSample &sample,
                                      Ray *ray) const {
    ProfilePhase prof(Prof::GenerateCameraRay);
    // Compute raster and camera sample positions
    Point3f pFilm = Point3f(sample.pFilm.x, sample.pFilm.y, 0);
    Point3f pCamera = RasterToCamera(pFilm);
    *ray = Ray(pCamera, Vector3f(0, 0, 1));
    // Modify ray for depth of field
    if (lensRadius > 0) {
        // Sample point on lens
        Point2f pLens = lensRadius * ConcentricSampleDisk(sample.pLens);

        // Compute point on plane of focus
        Float ft = focalDistance / ray->d.z;
        Point3f pFocus = (*ray)(ft);

        // Update ray for effect of lens
        ray->o = Point3f(pLens.x, pLens.y, 0);
        ray->d = Normalize(pFocus - ray->o);
    }
    ray->time = Lerp(sample.time, shutterOpen, shutterClose);
    ray->medium = medium;
    *ray = CameraToWorld(*ray);
    return 1;
}
Ejemplo n.º 6
0
float PerspectiveCamera::GenerateRayDifferential(const CameraSample &sample,
                                                 RayDifferential *ray) const {
    // Generate raster and camera samples
    Point Pras(sample.imageX, sample.imageY, 0);
    Point Pcamera;
    RasterToCamera(Pras, &Pcamera);
    Vector dir = Normalize(Vector(Pcamera.x, Pcamera.y, Pcamera.z));
    *ray = RayDifferential(Point(0,0,0), dir, 0.f, INFINITY);
    // Modify ray for depth of field
    if (lensRadius > 0.) {
        // Sample point on lens
        float lensU, lensV;
        ConcentricSampleDisk(sample.lensU, sample.lensV, &lensU, &lensV);
        lensU *= lensRadius;
        lensV *= lensRadius;

        // Compute point on plane of focus
        float ft = focalDistance / ray->d.z;
        Point Pfocus = (*ray)(ft);

        // Update ray for effect of lens
        ray->o = Point(lensU, lensV, 0.f);
        ray->d = Normalize(Pfocus - ray->o);
    }

    // Compute offset rays for _PerspectiveCamera_ ray differentials
    ray->rxOrigin = ray->ryOrigin = ray->o;
    ray->rxDirection = Normalize(Vector(Pcamera) + dxCamera);
    ray->ryDirection = Normalize(Vector(Pcamera) + dyCamera);
    ray->time = Lerp(sample.time, shutterOpen, shutterClose);
    CameraToWorld(*ray, ray);
    ray->hasDifferentials = true;
    return 1.f;
}
Ejemplo n.º 7
0
float PerspectiveCamera::GenerateRay(const CameraSample &sample,
                                     Ray *ray) const {
    // Generate raster and camera samples
    Point Pras(sample.imageX, sample.imageY, 0);
    Point Pcamera;
    RasterToCamera(Pras, &Pcamera);
    *ray = Ray(Point(0,0,0), Normalize(Vector(Pcamera)), 0.f, INFINITY);
    // Modify ray for depth of field
    if (lensRadius > 0.) {
        // Sample point on lens
        float lensU, lensV;
        ConcentricSampleDisk(sample.lensU, sample.lensV, &lensU, &lensV);
        lensU *= lensRadius;
        lensV *= lensRadius;

        // Compute point on plane of focus
        float ft = focalDistance / ray->d.z;
        Point Pfocus = (*ray)(ft);

        // Update ray for effect of lens
        ray->o = Point(lensU, lensV, 0.f);
        ray->d = Normalize(Pfocus - ray->o);
    }
    ray->time = Lerp(sample.time, shutterOpen, shutterClose);
    CameraToWorld(*ray, ray);
    return 1.f;
}
Ejemplo n.º 8
0
Spectrum InfiniteAreaLight::Sample_L(const Point2f &u1, const Point2f &u2,
                                     Float time, Ray *ray, Normal3f *nLight,
                                     Float *pdfPos, Float *pdfDir) const {
    // Compute direction for infinite light sample ray
    Point2f lightSample = u1;

    // Find $(u,v)$ sample coordinates in infinite light texture
    Float mapPdf;
    Point2f uv = distribution->SampleContinuous(lightSample, &mapPdf);
    if (mapPdf == 0.f) return Spectrum(0.f);
    Float theta = uv[1] * Pi, phi = uv[0] * 2.f * Pi;
    Float cosTheta = std::cos(theta), sinTheta = std::sin(theta);
    Float sinPhi = std::sin(phi), cosPhi = std::cos(phi);
    Vector3f d =
        -LightToWorld(Vector3f(sinTheta * cosPhi, sinTheta * sinPhi, cosTheta));
    *nLight = (Normal3f)d;

    // Compute origin for infinite light sample ray
    Vector3f v1, v2;
    CoordinateSystem(-d, &v1, &v2);
    Point2f cd = ConcentricSampleDisk(u2);
    Point3f Pdisk = worldCenter + worldRadius * (cd.x * v1 + cd.y * v2);
    *ray = Ray(Pdisk + worldRadius * -d, d, Infinity, time);

    // Compute _InfiniteAreaLight_ ray PDF
    *pdfDir = mapPdf / (2 * Pi * Pi * sinTheta);
    *pdfPos = 1 / (Pi * worldRadius * worldRadius);
    if (sinTheta == 0) *pdfDir = 0;
    return Spectrum(Lmap->Lookup(uv), SpectrumType::Illuminant);
}
Ejemplo n.º 9
0
Vector3D ParticleGenerator::sampleDir(int index)
{
    index %= 256;
    double u = static_cast<double>(index % sample_div) / sample_div;
    double v = static_cast<double>(index / sample_div) / sample_div;
    double dx, dy;
    ConcentricSampleDisk(u, v, dx, dy);
    return nz + (dx * nx + dy * ny) * distri_r;
}
Ejemplo n.º 10
0
bool Disk::Sample(const Point2f &sample, Interaction *it) const {
    Point2f pd = ConcentricSampleDisk(sample);
    Point3f pObj(pd.x * radius, pd.y * radius, height);
    it->n = Normalize((*ObjectToWorld)(Normal3f(0, 0, 1)));
    if (ReverseOrientation) it->n *= -1.f;
    Vector3f pObjError(0.f, 0.f, MachineEpsilon * height);
    it->p = (*ObjectToWorld)(pObj, pObjError, &it->pError);
    return true;
}
Ejemplo n.º 11
0
Point Disk::Sample(float u1, float u2, Normal *Ns) const {
    Point p;
    ConcentricSampleDisk(u1, u2, &p.x, &p.y);
    p.x *= radius;
    p.y *= radius;
    p.z = height;
    *Ns = Normalize((*ObjectToWorld)(Normal(0,0,1)));
    if (ReverseOrientation) *Ns *= -1.f;
    return (*ObjectToWorld)(p);
}
Ejemplo n.º 12
0
Spectrum DistantLight::Sample_L(const Point2f &sample1, const Point2f &sample2,
                                Float time, Ray *ray, Normal3f *Ns,
                                Float *pdfPos, Float *pdfDir) const {
    // Choose point on disk oriented toward infinite light direction
    Vector3f v1, v2;
    CoordinateSystem(wLight, &v1, &v2);
    Point2f cd = ConcentricSampleDisk(sample1);
    Point3f Pdisk = worldCenter + worldRadius * (cd.x * v1 + cd.y * v2);

    // Set ray origin and direction for infinite light ray
    *ray = Ray(Pdisk + worldRadius * wLight, -wLight, Infinity, time);
    *Ns = (Normal3f)ray->d;
    *pdfPos = 1.f / (Pi * worldRadius * worldRadius);
    *pdfDir = 1.f;
    return L;
}
Ejemplo n.º 13
0
void RealisticCamera::TestExitPupilBounds() const {
    Float filmDiagonal = film->diagonal;

    static RNG rng;

    Float u = rng.UniformFloat();
    Point3f pFilm(u * filmDiagonal / 2, 0, 0);

    Float r = pFilm.x / (filmDiagonal / 2);
    int pupilIndex =
        std::min((int)exitPupilBounds.size() - 1,
                 (int)std::floor(r * (exitPupilBounds.size() - 1)));
    Bounds2f pupilBounds = exitPupilBounds[pupilIndex];
    if (pupilIndex + 1 < (int)exitPupilBounds.size())
        pupilBounds = Union(pupilBounds, exitPupilBounds[pupilIndex + 1]);

    // Now, randomly pick points on the aperture and see if any are outside
    // of pupil bounds...
    for (int i = 0; i < 1000; ++i) {
        Point2f pd = ConcentricSampleDisk(
                         Point2f(rng.UniformFloat(), rng.UniformFloat()));
        pd *= RearElementRadius();

        Ray testRay(pFilm, Point3f(pd.x, pd.y, 0.f) - pFilm);
        Ray testOut;
        if (!TraceLensesFromFilm(testRay, &testOut)) continue;

        if (!Inside(pd, pupilBounds)) {
            fprintf(stderr,
                    "Aha! (%f,%f) went through, but outside bounds (%f,%f) - "
                    "(%f,%f)\n",
                    pd.x, pd.y, pupilBounds.pMin[0], pupilBounds.pMin[1],
                    pupilBounds.pMax[0], pupilBounds.pMax[1]);
            RenderExitPupil(
                (Float)pupilIndex / exitPupilBounds.size() * filmDiagonal / 2.f,
                0.f, "low.exr");
            RenderExitPupil((Float)(pupilIndex + 1) / exitPupilBounds.size() *
                            filmDiagonal / 2.f,
                            0.f, "high.exr");
            RenderExitPupil(pFilm.x, 0.f, "mid.exr");
            exit(0);
        }
    }
    fprintf(stderr, ".");
}
Ejemplo n.º 14
0
Spectrum DistantLight::Sample_L(const Scene *scene, const LightSample &ls,
        float u1, float u2, float time, Ray *ray, Normal *Ns,
        float *pdf) const {
    // Choose point on disk oriented toward infinite light direction
    Point worldCenter;
    float worldRadius;
    scene->WorldBound().BoundingSphere(&worldCenter, &worldRadius);
    Vector v1, v2;
    CoordinateSystem(lightDir, &v1, &v2);
    float d1, d2;
    ConcentricSampleDisk(ls.uPos[0], ls.uPos[1], &d1, &d2);
    Point Pdisk = worldCenter + worldRadius * (d1 * v1 + d2 * v2);

    // Set ray origin and direction for infinite light ray
    *ray = Ray(Pdisk + worldRadius * lightDir, -lightDir, 0.f, INFINITY, time);
    *pdf = 1.f / (M_PI * worldRadius * worldRadius);
    return L;
}
Ejemplo n.º 15
0
Spectrum DistantLight::Sample_L(const Scene *scene,
		float u1, float u2, float u3, float u4,
		Ray *ray, float *pdf) const {
	// Choose point on disk oriented toward infinite light direction
	Point worldCenter;
	float worldRadius;
	scene->WorldBound().BoundingSphere(&worldCenter,
	                                   &worldRadius);
	Vector v1, v2;
	CoordinateSystem(lightDir, &v1, &v2);
	float d1, d2;
	ConcentricSampleDisk(u1, u2, &d1, &d2);
	Point Pdisk =
		worldCenter + worldRadius * (d1 * v1 + d2 * v2);
	// Set ray origin and direction for infinite light ray
	ray->o = Pdisk + worldRadius * lightDir;
	ray->d = -lightDir;
	*pdf = 1.f / (M_PI * worldRadius * worldRadius);
	return L;
}
Ejemplo n.º 16
0
Vec3 PointLight::sampleDir() {
    //Amostrar ponto no globo
    Vec3 tempDir = UniformSampleHemisphere(drand48(), drand48()); 
    float px, py;
    ConcentricSampleDisk(drand48(), drand48(), &px, &py);
    
    float prob = drand48();
    Vec3 nn;
    if(prob < 0.5f)
        nn = Vec3(0.0, 1.0, 0.0);
    else
        nn = Vec3(0.0, -1.0, 0.0);

    Vec3 dpdu(-py, px, 0.f);
    Vec3 sn = normalize(dpdu);
    Vec3 tn = cross(nn, sn);

    //Local to world
    return Vec3(sn.x*tempDir.x + tn.x*tempDir.y + nn.x*tempDir.z,
            sn.y*tempDir.x + tn.y*tempDir.y + nn.y*tempDir.z,
            sn.z*tempDir.x + tn.z*tempDir.y + nn.z*tempDir.z);

}
Ejemplo n.º 17
0
Spectrum PerspectiveCamera::Sample_Wi(const Interaction &ref, const Point2f &u,
                                      Vector3f *wi, Float *pdf,
                                      Point2f *pRaster,
                                      VisibilityTester *vis) const {
    // Uniformly sample a lens interaction _lensIntr_
    Point2f pLens = lensRadius * ConcentricSampleDisk(u);
    Point3f pLensWorld = CameraToWorld(ref.time, Point3f(pLens.x, pLens.y, 0));
    Interaction lensIntr(pLensWorld, ref.time, medium);
    lensIntr.n = Normal3f(CameraToWorld(ref.time, Vector3f(0, 0, 1)));

    // Populate arguments and compute the importance value
    *vis = VisibilityTester(ref, lensIntr);
    *wi = lensIntr.p - ref.p;
    Float dist = wi->Length();
    *wi /= dist;

    // Compute PDF for importance arriving at _ref_

    // Compute lens area of perspective camera
    Float lensArea = lensRadius != 0 ? (Pi * lensRadius * lensRadius) : 1;
    *pdf = (dist * dist) / (AbsDot(lensIntr.n, *wi) * lensArea);
    return We(lensIntr, -*wi, pRaster);
}
Ejemplo n.º 18
0
float RealisticCamera::GenerateRay(const CameraSample &sample, Ray *ray) const {
	// Generate raster and back lens samples
	Point Praster(sample.imageX, sample.imageY, 0.f);
	Point Pcamera;
	RasterToCamera(Praster, &Pcamera);

	const Lens &backLens = lensgroup.back();
	float lensU, lensV, lensZ;

	// Get Sample Pback (lensU, lensV, -distToBack)

	// Method 1: pbrt-v2 provide
	ConcentricSampleDisk(sample.lensU, sample.lensV, &lensU, &lensV);
	lensU *= backLensAperture;
	lensV *= backLensAperture;
	lensZ = -distToBack;

	// Method 2: textbook, r = \sqrt{lensU}, theta = 2 \pi lensV
	//float r = sqrtf(sample.lensU), theta = 2 * M_PI * sample.lensV;
	//lensU = backLens.aperture * r * cosf(theta);
	//lensV = backLens.aperture * r * sinf(theta);
	//lensZ = -distToBack;

	// Method 3: textbook refer common error sampling, r = lensU, theta = 2 \pi lensV
	//float r = sample.lensU, theta = 2 * M_PI * sample.lensV;
	//lensU = backLens.aperture * r * cosf(theta);
	//lensV = backLens.aperture * r * sinf(theta);
	//lensZ = -distToBack;

	// camera -> inner lens -> outer lens

	// hit point on the surface of the inner lens
	ray->o = Pcamera;
	ray->d = Normalize(Point(lensU, lensV, lensZ) - Pcamera);
	ray->time = Lerp(sample.time, shutterOpen, shutterClose);
	ray->mint = 0.f;
		
	// iterator over the lens components from inner to outer
	for (int i = lensgroup.size() - 1; i >= 0; i--) {
		if (lensgroup[i].end) {
			// ray run pass aperture (not lens)
			float deltaZ = lensgroup[i].z - ray->o.z;
			ray->o = ray->o + (deltaZ / ray->d.z) * ray->d;
			if (lensgroup[i].outOfRange(ray->o.x, ray->o.y))
				return 0.f;
			
		} else {
			float n = (i == 0) ? 1.f : lensgroup[i-1].n;
			if (!lensgroup[i].Refraction(ray, n))
				return 0.f;
		}
	}	
	
	// set exposure weight
	float cosTheta = Dot(Normalize(ray->o - Pcamera), Vector(0, 0, 1));
	float Z = filmdistance;
	float weight = (backLens.aperture * backLens.aperture * M_PI) / ( Z * Z);
	weight = weight * cosTheta * cosTheta * cosTheta * cosTheta;

	ray->maxt = (yon - hither) / ray->d.z;
	CameraToWorld(*ray, ray);
	ray->d = Normalize(ray->d);
	return weight;
}
Ejemplo n.º 19
0
float RealisticCamera::GenerateRay(const CameraSample &sample, Ray *ray) const {

	// STEP 1 - generate first ray

	// use sample->imageX and sample->imageY to get raster-space coordinates of the sample point on the film.
	Point Pras(sample.imageX, sample.imageY, 0);
	Point Pcamera;
	RasterToCamera(Pras, &Pcamera);

	// use sample->lensU and sample->lensV to get a sample position on the lens
	float lensU, lensV;
	ConcentricSampleDisk(sample.lensU, sample.lensV, &lensU, &lensV);
	lensU *= lens[lensnum - 1].apradius;
	lensV *= lens[lensnum - 1].apradius;

	float pfz = lens[lensnum - 1].centerz + sqrtf(lens[lensnum - 1].radiusSquard - lensU * lensU - lensV * lensV);
	Point Pfocus = Point(lensU, lensV, pfz);
	Vector Rdir = Normalize(Pfocus - Pcamera);
	ray->o = Pcamera;
	ray->d = Rdir;
	ray->time = Lerp(sample.time, shutteropen, shutterclose);

	// STEP 2 - ray through the lens
	Point Plens;
	for (int i = 0; i < lensnum; i++) {

		lensData ls = lens[i];

		if ( ls.plane ){
			float t = (ls.centerz - ray->o.z) / ray->d.z;
			float x = ray->o.x + t * ray->d.x;
			float y = ray->o.y + t * ray->d.y;

			if (x * x + y * y > ls.apradiusSquared) 
				return 0.f;
		}
		else
		{
			// Find the intersection point
			Vector oc = ray->o - Point(0.f, 0.f, ls.centerz);
			float l1 = oc.LengthSquared();
			float rz = Dot(oc, ray->d);
			float l2 = rz *rz - l1 + ls.radiusSquard;
			if (l2 < 0.f)
				return 0.f;
			float t = (ls.radius > 0.f) ? (-rz + sqrtf(l2)) : (-rz - sqrtf(l2));
			
			Plens = ray->o + t * ray->d;
			if (Plens.x*Plens.x + Plens.y*Plens.y > ls.apradiusSquared) 
				return 0.f;

			// calculate the refraction 
			Vector N = (ls.radius > 0.f) ? Normalize(Point(0.f, 0.f, ls.centerz) - Plens)
				: Normalize(Plens - Point(0.f, 0.f, ls.centerz));
			Vector I = ray->d;
			float c1, c2;
			c1 = -Dot(I, N);
			c2 = ls.nratioSquared - 1.f + c1 * c1;
			if (c2 < 0.f) 	
				return 0.f;
			c2 = c1 - sqrtf(c2);
			Vector T = (I + c2 * N) / ls.nratio;

			ray->o = Plens;
			ray->d = Normalize(T);
		}
	}

	ray->mint = cliphiter;
	ray->maxt = (clipyon - cliphiter) / ray->d.z;

	// STEP 3 - output the ray and weight
	CameraToWorld(*ray, ray);
	
	float weight = Dot(Normalize(Plens - Pcamera), Vector(0, 0, 1));
	weight *= weight / totallength;
	weight *= weight * (lens[lensnum - 1].apradiusSquared * M_PI);
	return weight;

}