/// <inheritdoc /> public override double GenerateRay(CameraSample sample, out Ray ray) { //ProfilePhase prof(Prof::GenerateCameraRay); // Compute raster and camera sample positions Point3D pFilm = new Point3D(sample.FilmPoint.X, sample.FilmPoint.Y, 0.0); Point3D pCamera = RasterToCamera.AtPoint(pFilm); ray = new Ray(new Point3D(0.0, 0.0, 0.0), pCamera.ToVector3D().Normalize()); // Modify ray for depth of field if (LensRadius > 0.0) { // Sample point on lens Point2D pLens = LensRadius * Sampling.ConcentricSampleDisk(sample.LensPoint); // Compute point on plane of focus double ft = FocalDistance / ray.Direction.Z; Point3D pFocus = ray.AtPoint(ft); // Update ray for effect of lens ray.Origin = new Point3D(pLens.X, pLens.Y, 0.0); ray.Direction = (pFocus - ray.Origin).ToVector3D().Normalize(); } ray.Time = PbrtMath.Lerp(sample.Time, ShutterOpen, ShutterClose); ray.Medium = Medium; ray = CameraToWorld.ExecuteTransform(ray); return(1.0); }
public Point3D ExecuteTransform(Point3D p, out Vector3D pError) { double x = p.X, y = p.Y, z = p.Z; // Compute transformed coordinates from point _pt_ double xp = M[0, 0] * x + M[0, 1] * y + M[0, 2] * z + M[0, 3]; double yp = M[1, 0] * x + M[1, 1] * y + M[1, 2] * z + M[1, 3]; double zp = M[2, 0] * x + M[2, 1] * y + M[2, 2] * z + M[2, 3]; double wp = M[3, 0] * x + M[3, 1] * y + M[3, 2] * z + M[3, 3]; // Compute absolute error for transformed point double xAbsSum = (Math.Abs(M[0, 0] * x) + Math.Abs(M[0, 1] * y) + Math.Abs(M[0, 2] * z) + Math.Abs(M[0, 3])); double yAbsSum = (Math.Abs(M[1, 0] * x) + Math.Abs(M[1, 1] * y) + Math.Abs(M[1, 2] * z) + Math.Abs(M[1, 3])); double zAbsSum = (Math.Abs(M[2, 0] * x) + Math.Abs(M[2, 1] * y) + Math.Abs(M[2, 2] * z) + Math.Abs(M[2, 3])); pError = PbrtMath.Gamma(3) * new Vector3D(xAbsSum, yAbsSum, zAbsSum); //CHECK_NE(wp, 0); if (wp == 1.0) { return(new Point3D(xp, yp, zp)); } else { return(new Point3D(xp, yp, zp) / wp); } }
public bool IntersectP(Ray ray, out double hitt0, out double hitt1) { double t0 = 0, t1 = ray.TMax; for (int i = 0; i < 3; ++i) { // Update interval for _i_th bounding box slab double invRayDir = 1 / ray.Direction[i]; double tNear = (MinPoint[i] - ray.Origin[i]) * invRayDir; double tFar = (MaxPoint[i] - ray.Origin[i]) * invRayDir; // Update parametric interval from slab intersection $t$ values if (tNear > tFar) { double temp = tNear; tNear = tFar; tFar = temp; } // Update _tFar_ to ensure robust ray--bounds intersection tFar *= 1 + 2 * PbrtMath.Gamma(3); t0 = tNear > t0 ? tNear : t0; t1 = tFar < t1 ? tFar : t1; if (t0 > t1) { hitt0 = 0.0; hitt1 = 0.0; return(false); } } hitt0 = t0; hitt1 = t1; return(true); }
public Point3D OffsetRayOrigin(Vector3D pError, Normal3D n, Vector3D w) { double d = n.Abs().Dot(pError); // We have tons of precision; for now bump up the offset a bunch just // to be extra sure that we start on the right side of the surface // (In case of any bugs in the epsilons code...) d *= 1024.0; Point3D offset = d * n.ToPoint3D(); if (w.Dot(n) < 0.0) { offset = -offset; } Point3D po = this + offset; // Round offset point _po_ away from _p_ for (int i = 0; i < 3; ++i) { if (offset[i] > 0.0) { po[i] = PbrtMath.NextFloatUp(po[i]); } else if (offset[i] < 0.0) { po[i] = PbrtMath.NextFloatDown(po[i]); } } return(po); }
/// <inheritdoc /> public override double GenerateRayDifferential(CameraSample sample, out RayDifferential ray) { //ProfilePhase prof(Prof::GenerateCameraRay); // Compute raster and camera sample positions Point3D pFilm = new Point3D(sample.FilmPoint.X, sample.FilmPoint.Y, 0.0); Point3D pCamera = RasterToCamera.ExecuteTransform(pFilm); Vector3D dir = new Vector3D(pCamera.X, pCamera.Y, pCamera.Z).Normalize(); ray = new RayDifferential(new Point3D(0.0, 0.0, 0.0), dir); // Modify ray for depth of field if (LensRadius > 0.0) { // Sample point on lens Point2D pLens = LensRadius * Sampling.ConcentricSampleDisk(sample.LensPoint); // Compute point on plane of focus double ft = FocalDistance / ray.Direction.Z; Point3D pFocus = ray.AtPoint(ft); // Update ray for effect of lens ray.Origin = new Point3D(pLens.X, pLens.Y, 0.0); ray.Direction = (pFocus - ray.Origin).ToVector3D().Normalize(); } // Compute offset rays for _PerspectiveCamera_ ray differentials if (LensRadius > 0.0) { // Compute _PerspectiveCamera_ ray differentials accounting for lens // Sample point on lens Point2D pLens = LensRadius * Sampling.ConcentricSampleDisk(sample.LensPoint); Vector3D dx = (pCamera.ToVector3D() + _dxCamera).Normalize(); double ft = FocalDistance / dx.Z; Point3D pFocus = new Point3D(0.0, 0.0, 0.0) + (ft * dx).ToPoint3D(); ray.RxOrigin = new Point3D(pLens.X, pLens.Y, 0.0); ray.RxDirection = (pFocus - ray.RxOrigin).ToVector3D().Normalize(); Vector3D dy = (pCamera.ToVector3D() + _dyCamera).Normalize(); ft = FocalDistance / dy.Z; pFocus = new Point3D(0.0, 0.0, 0.0) + (ft * dy).ToPoint3D(); ray.RyOrigin = new Point3D(pLens.X, pLens.Y, 0.0); ray.RyDirection = (pFocus - ray.RyOrigin).ToVector3D().Normalize(); } else { ray.RxOrigin = ray.RyOrigin = ray.Origin; ray.RxDirection = (pCamera.ToVector3D() + _dxCamera).Normalize(); ray.RyDirection = (pCamera.ToVector3D() + _dyCamera).Normalize(); } ray.Time = PbrtMath.Lerp(sample.Time, ShutterOpen, ShutterClose); ray.Medium = Medium; ray = new RayDifferential(CameraToWorld.ExecuteTransform(ray)) { HasDifferentials = true }; return(1.0); }
public static Transform Perspective(double fov, float n, double f) { // Perform projective divide for perspective projection Matrix4x4 persp = new Matrix4x4(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, f / (f - n), -f * n / (f - n), 0, 0, 1, 0); // Scale canonical perspective view to specified field of view double invTanAng = 1.0 / Math.Tan(PbrtMath.Radians(fov) / 2); return(Transform.Scale(invTanAng, invTanAng, 1.0) * new Transform(persp)); }
public static Camera Create(ParamSet paramSet, AnimatedTransform cam2World, Film film, Medium medium) { // Extract common camera parameters from _ParamSet_ double shutteropen = paramSet.FindOneFloat("shutteropen", 0.0); double shutterclose = paramSet.FindOneFloat("shutterclose", 1.0); if (shutterclose < shutteropen) { //Warning("Shutter close time [%f] < shutter open [%f]. Swapping them.", // shutterclose, shutteropen); PbrtMath.Swap(ref shutterclose, ref shutteropen); } double lensradius = paramSet.FindOneFloat("lensradius", 0.0); double focaldistance = paramSet.FindOneFloat("focaldistance", 1e6); double frame = paramSet.FindOneFloat( "frameaspectratio", Convert.ToDouble(film.FullResolution.X) / Convert.ToDouble(film.FullResolution.Y)); Bounds2D screen; if (frame > 1.0) { screen = new Bounds2D(new Point2D(-frame, -1.0), new Point2D(frame, 1.0)); } else { screen = new Bounds2D(new Point2D(-1.0, -1.0 / frame), new Point2D(1.0, 1.0 / frame)); } double[] sw = paramSet.FindFloat("screenwindow"); if (sw != null) { if (sw.Length == 4) { screen = new Bounds2D(new Point2D(sw[0], sw[2]), new Point2D(sw[1], sw[3])); } else { //Error("\"screenwindow\" should have four values"); } } double fov = paramSet.FindOneFloat("fov", 90.0); double halffov = paramSet.FindOneFloat("halffov", -1.0); if (halffov > 0.0) { // hack for structure synth, which exports half of the full fov fov = 2.0 * halffov; } return(new PerspectiveCamera(cam2World, screen, shutteropen, shutterclose, lensradius, focaldistance, fov, film, medium)); }
public bool IntersectP(Ray ray, Vector3D invDir, bool[] dirIsNeg) { // Check for ray intersection against $x$ and $y$ slabs double tMin = (this[dirIsNeg[0] ? 1 : 0].X - ray.Origin.X) * invDir.X; double tMax = (this[dirIsNeg[0] ? 0 : 1].X - ray.Origin.X) * invDir.X; double tyMin = (this[dirIsNeg[1] ? 1 : 0].Y - ray.Origin.Y) * invDir.Y; double tyMax = (this[dirIsNeg[1] ? 0 : 1].Y - ray.Origin.Y) * invDir.Y; // Update _tMax_ and _tyMax_ to ensure robust bounds intersection tMax *= 1.0 + 2.0 * PbrtMath.Gamma(3); tyMax *= 1.0 + 2.0 * PbrtMath.Gamma(3); if (tMin > tyMax || tyMin > tMax) { return(false); } if (tyMin > tMin) { tMin = tyMin; } if (tyMax < tMax) { tMax = tyMax; } // Check for ray intersection against $z$ slab double tzMin = (this[dirIsNeg[2] ? 1 : 0].Z - ray.Origin.Z) * invDir.Z; double tzMax = (this[dirIsNeg[2] ? 0 : 1].Z - ray.Origin.Z) * invDir.Z; // Update _tzMax_ to ensure robust bounds intersection tzMax *= 1.0 + 2.0 * PbrtMath.Gamma(3); if (tMin > tzMax || tzMin > tMax) { return(false); } if (tzMin > tMin) { tMin = tzMin; } if (tzMax < tMax) { tMax = tzMax; } return((tMin < ray.TMax) && (tMax > 0.0)); }
// Returns the solid angle subtended by the shape w.r.t. the reference // point p, given in world space. Some shapes compute this value in // closed-form, while the default implementation uses Monte Carlo // integration; the nSamples parameter determines how many samples are // used in this case. public virtual double SolidAngle(Point3D p, int nSamples = 512) { Interaction it = new Interaction(p, new Normal3D(), new Vector3D(), new Vector3D(0.0, 0.0, 1.0), 0.0, new MediumInterface()); double solidAngle = 0.0; for (int i = 0; i < nSamples; ++i) { Point2D u = new Point2D(PbrtMath.RadicalInverse(0, i), PbrtMath.RadicalInverse(1, i)); double pdf; Interaction pShape = Sample(it, u, out pdf); if (pdf > 0.0 && !IntersectP(new Ray(p, (pShape.P - p).ToVector3D(), 0.999))) { solidAngle += 1.0 / pdf; } } return(solidAngle / nSamples); }
public Point2I Lerp(Point2I t) { return(new Point2I(PbrtMath.Lerp(t.X, MinPoint.X, MaxPoint.X), PbrtMath.Lerp(t.Y, MinPoint.Y, MaxPoint.Y))); }
public Point3D Lerp(Point3D t) { return(new Point3D(PbrtMath.Lerp(t.X, MinPoint.X, MaxPoint.X), PbrtMath.Lerp(t.Y, MinPoint.Y, MaxPoint.Y), PbrtMath.Lerp(t.Z, MinPoint.Z, MaxPoint.Z))); }
public void ComputeDifferentials(RayDifferential ray) { if (ray.HasDifferentials) { try { // Estimate screen space change in $\pt{}$ and $(u,v)$ // Compute auxiliary intersection points with plane double d = N.Dot(P.ToVector3D()); double tx = -(N.Dot(ray.RxOrigin.ToVector3D()) - d) / N.Dot(ray.RxDirection); if (double.IsInfinity(tx) || double.IsNaN(tx)) { throw new InvalidOperationException(); } Point3D px = (ray.RxOrigin.ToVector3D() + tx * ray.RxDirection).ToPoint3D(); double ty = -(N.Dot(ray.RyOrigin.ToVector3D()) - d) / N.Dot(ray.RyDirection); if (double.IsInfinity(ty) || double.IsNaN(ty)) { throw new InvalidOperationException(); } Point3D py = (ray.RyOrigin.ToVector3D() + ty * ray.RyDirection).ToPoint3D(); Dpdx = (px - P).ToVector3D(); Dpdy = (py - P).ToVector3D(); // Compute $(u,v)$ offsets at auxiliary points // Choose two dimensions to use for ray offset computation int[] dim = new int[2]; if (Math.Abs(N.X) > Math.Abs(N.Y) && Math.Abs(N.X) > Math.Abs(N.Z)) { dim[0] = 1; dim[1] = 2; } else if (Math.Abs(N.Y) > Math.Abs(N.Z)) { dim[0] = 0; dim[1] = 2; } else { dim[0] = 0; dim[1] = 1; } // Initialize _A_, _Bx_, and _By_ matrices for offset computation double[,] a = new double[2, 2]; a[0, 0] = Dpdu[dim[0]]; a[0, 1] = Dpdv[dim[0]]; a[1, 0] = Dpdu[dim[1]]; a[1, 1] = Dpdv[dim[1]]; //Float A[2][2] = {{dpdu[dim[0]], dpdv[dim[0]] // }, // {dpdu[dim[1]], dpdv[dim[1]] // }}; double[] bx = new double[2]; bx[0] = px[dim[0]] - P[dim[0]]; bx[1] = px[dim[1]] - P[dim[1]]; double[] by = new double[2]; by[0] = py[dim[0]] - P[dim[0]]; by[1] = py[dim[1]] - P[dim[1]]; if (PbrtMath.SolveLinearSystem2x2(a, bx, out double du1, out double dv1)) { Dudx = du1; Dvdx = dv1; } else { Dudx = 0.0; Dvdx = 0.0; } if (PbrtMath.SolveLinearSystem2x2(a, by, out double du2, out double dv2)) { Dudx = du2; Dvdx = dv2; }
public static Film Create(PbrtOptions options, ParamSet paramSet, Filter filter) { string filename; if (options.ImageFile != "") { filename = options.ImageFile; string paramsFilename = paramSet.FindOneString("filename", ""); if (paramsFilename != "") { //Warning( // "Output filename supplied on command line, \"%s\" is overriding filename provided in scene description file, \"%s\".", //PbrtOptions.imageFile.c_str(), paramsFilename.c_str()); } } else { filename = paramSet.FindOneString("filename", "pbrt.exr"); } int xres = paramSet.FindOneInt("xresolution", 1280); int yres = paramSet.FindOneInt("yresolution", 720); if (options.QuickRender) { xres = Math.Max(1, xres / 4); } if (options.QuickRender) { yres = Math.Max(1, yres / 4); } Bounds2D crop; int cwi; double[] cr = paramSet.FindFloat("cropwindow"); if (cr != null && cr.Length == 4) { double minx = PbrtMath.Clamp(Math.Min(cr[0], cr[1]), 0.0, 1.0); double maxx = PbrtMath.Clamp(Math.Max(cr[0], cr[1]), 0.0, 1.0); double miny = PbrtMath.Clamp(Math.Min(cr[2], cr[3]), 0.0, 1.0); double maxy = PbrtMath.Clamp(Math.Max(cr[2], cr[3]), 0.0, 1.0); crop = new Bounds2D(new Point2D(minx, miny), new Point2D(maxx, maxy)); } else if (cr != null) { throw new InvalidOperationException(); //Error("%d values supplied for \"cropwindow\". Expected 4.", cwi); } else { crop = new Bounds2D(new Point2D(PbrtMath.Clamp(options.CropWindow[0, 0], 0.0, 1.0), PbrtMath.Clamp(options.CropWindow[1, 0], 0.0, 1.0)), new Point2D(PbrtMath.Clamp(options.CropWindow[0, 1], 0.0, 1.0), PbrtMath.Clamp(options.CropWindow[1, 1], 0.0, 1.0))); } double scale = paramSet.FindOneFloat("scale", 1.0); double diagonal = paramSet.FindOneFloat("diagonal", 35.0); double maxSampleLuminance = paramSet.FindOneFloat("maxsampleluminance", double.PositiveInfinity); return(new Film(new Point2I(xres, yres), crop, filter, diagonal, filename, scale, maxSampleLuminance)); }
public Matrix4x4 Inverse() { int[] indxc = new int[4]; int[] indxr = new int[4]; int[] ipiv = { 0, 0, 0, 0 }; double[,] minv = new double[4, 4]; Array.Copy(_m, minv, 4 * 4); for (int i = 0; i < 4; i++) { int irow = 0; int icol = 0; double big = 0.0; // Choose pivot for (int j = 0; j < 4; j++) { if (ipiv[j] != 1) { for (int k = 0; k < 4; k++) { if (ipiv[k] == 0) { if (Math.Abs(minv[j, k]) >= big) { big = Math.Abs(minv[j, k]); irow = j; icol = k; } } else if (ipiv[k] > 1.0) { throw new InvalidOperationException("Singular matrix in MatrixInvert"); } } } } ++ipiv[icol]; // Swap rows _irow_ and _icol_ for pivot if (irow != icol) { for (int k = 0; k < 4; ++k) { PbrtMath.Swap(ref minv[irow, k], ref minv[icol, k]); } } indxr[i] = irow; indxc[i] = icol; if (minv[icol, icol] == 0.0) { throw new InvalidOperationException("Singular matrix in MatrixInvert"); } // Set $m[icol,icol]$ to one by scaling row _icol_ appropriately double pivinv = 1.0 / minv[icol, icol]; minv[icol, icol] = 1.0; for (int j = 0; j < 4; j++) { minv[icol, j] *= pivinv; } // Subtract this row from others to zero out their columns for (int j = 0; j < 4; j++) { if (j != icol) { double save = minv[j, icol]; minv[j, icol] = 0; for (int k = 0; k < 4; k++) { minv[j, k] -= minv[icol, k] * save; } } } } // Swap columns to reflect permutation for (int j = 3; j >= 0; j--) { if (indxr[j] != indxc[j]) { for (int k = 0; k < 4; k++) { PbrtMath.Swap(ref minv[k, indxr[j]], ref minv[k, indxc[j]]); } } } return(new Matrix4x4(minv)); }