public virtual float GenerateRayDifferential(CameraSample sample, out RayDifferential rd) { Ray ray; float wt = GenerateRay(sample, out ray); rd = RayDifferential.FromRay(ray); // Find ray after shifting one pixel in the $x$ direction CameraSample sshift = sample; ++(sshift.ImageX); Ray rx; float wtx = GenerateRay(sshift, out rx); rd.RxOrigin = rx.Origin; rd.RxDirection = rx.Direction; // Find ray after shifting one pixel in the $y$ direction --(sshift.ImageX); ++(sshift.ImageY); Ray ry; float wty = GenerateRay(sshift, out ry); rd.RyOrigin = ry.Origin; rd.RyDirection = ry.Direction; if (wtx == 0.0f || wty == 0.0f) return 0.0f; rd.HasDifferentials = true; return wt; }
public override float GenerateRayDifferential(CameraSample sample, out RayDifferential ray) { // Generate raster and camera samples Point Pras = new Point(sample.ImageX, sample.ImageY, 0); Point Pcamera = RasterToCamera.TransformPoint(ref Pras); ray = new RayDifferential(new Point(0, 0, 0), Vector.Normalize((Vector) Pcamera), 0.0f); // Modify ray for depth of field if (LensRadius > 0.0f) { // Sample point on lens float lensU, lensV; MonteCarloUtilities.ConcentricSampleDisk(sample.LensU, sample.LensV, out lensU, out lensV); lensU *= LensRadius; lensV *= LensRadius; // Compute point on plane of focus float ft = FocalDistance / ray.Direction.Z; Point Pfocus = ray.Evaluate(ft); // Update ray for effect of lens ray.Origin = new Point(lensU, lensV, 0.0f); ray.Direction = Vector.Normalize(Pfocus - ray.Origin); } // Compute offset rays for _PerspectiveCamera_ ray differentials ray.RxOrigin = ray.RyOrigin = ray.Origin; ray.RxDirection = Vector.Normalize((Vector) Pcamera + _dxCamera); ray.RyDirection = Vector.Normalize((Vector) Pcamera + _dyCamera); ray.Time = sample.Time; ray = CameraToWorld.TransformRayDifferential(ray); return 1.0f; }
public override void AddSample(CameraSample sample, Spectrum l) { // Compute sample's raster extent float dimageX = sample.ImageX - 0.5f; float dimageY = sample.ImageY - 0.5f; int x0 = MathUtility.Ceiling(dimageX - _filter.XWidth); int x1 = MathUtility.Floor(dimageX + _filter.XWidth); int y0 = MathUtility.Ceiling(dimageY - _filter.YWidth); int y1 = MathUtility.Floor(dimageY + _filter.YWidth); x0 = Math.Max(x0, _xPixelStart); x1 = Math.Min(x1, _xPixelStart + _xPixelCount - 1); y0 = Math.Max(y0, _yPixelStart); y1 = Math.Min(y1, _yPixelStart + _yPixelCount - 1); if ((x1 - x0) < 0 || (y1 - y0) < 0) return; // Loop over filter support and add sample to pixel arrays var xyz = l.ToXyz(); // Precompute $x$ and $y$ filter table offsets var ifx = new int[x1 - x0 + 1]; for (int x = x0; x <= x1; ++x) { float fx = Math.Abs((x - dimageX) * _filter.InverseXWidth * FilterTableSize); ifx[x - x0] = Math.Min(MathUtility.Floor(fx), FilterTableSize - 1); } var ify = new int[y1 - y0 + 1]; for (int y = y0; y <= y1; ++y) { float fy = Math.Abs((y - dimageY) * _filter.InverseYWidth * FilterTableSize); ify[y - y0] = Math.Min(MathUtility.Floor(fy), FilterTableSize - 1); } bool syncNeeded = (_filter.XWidth > 0.5f || _filter.YWidth > 0.5f); for (int y = y0; y <= y1; ++y) { for (int x = x0; x <= x1; ++x) { // Evaluate filter value at $(x,y)$ pixel int offset = ify[y - y0] * FilterTableSize + ifx[x - x0]; float filterWt = _filterTable[offset]; // Update pixel values with filtered sample contribution var pixel = _pixels[x - _xPixelStart, y - _yPixelStart]; if (!syncNeeded) { pixel.Lxyz[0] += filterWt * xyz[0]; pixel.Lxyz[1] += filterWt * xyz[1]; pixel.Lxyz[2] += filterWt * xyz[2]; pixel.WeightSum += filterWt; } else { // Safely update _Lxyz_ and _weightSum_ even with concurrency AtomicAdd(ref pixel.Lxyz[0], filterWt * xyz[0]); AtomicAdd(ref pixel.Lxyz[1], filterWt * xyz[1]); AtomicAdd(ref pixel.Lxyz[2], filterWt * xyz[2]); AtomicAdd(ref pixel.WeightSum, filterWt); } } } }
public override void Splat(CameraSample sample, Spectrum l) { var xyz = l.ToXyz(); int x = MathUtility.Floor(sample.ImageX), y = MathUtility.Floor(sample.ImageY); if (x < _xPixelStart || x - _xPixelStart >= _xPixelCount || y < _yPixelStart || y - _yPixelStart >= _yPixelCount) return; var pixel = _pixels[x - _xPixelStart, y - _yPixelStart]; AtomicAdd(ref pixel.SplatXyz[0], xyz[0]); AtomicAdd(ref pixel.SplatXyz[1], xyz[1]); AtomicAdd(ref pixel.SplatXyz[2], xyz[2]); }
public abstract float GenerateRay(CameraSample sample, out Ray ray);
/// Updates the stored image. Splatted values are summed, rather than /// a weighted average as is the case with AddSample. public abstract void Splat(CameraSample sample, Spectrum l);
/// Updates the stored image with a given sample and corresponding radiance. /// The selected reconstruction filter will be applied. public abstract void AddSample(CameraSample sample, Spectrum l);