public static Vector Cross(Normal v1, Vector v2) { if (v1.HasNaNs() || v2.HasNaNs()) throw new InvalidOperationException(); double v1x = v1.x, v1y = v1.y, v1z = v1.z; double v2x = v2.x, v2y = v2.y, v2z = v2.z; return new Vector((v1y * v2z) - (v1z * v2y), (v1z * v2x) - (v1x * v2z), (v1x * v2y) - (v1y * v2x)); }
public DifferentialGeometry(Point P, Vector DPDU, Vector DPDV, Normal DNDU, Normal DNDV, double uu, double vv, Shape sh) { p = P; dpdu = DPDU; dpdv = DPDV; dndu = DNDU; dndv = DNDV; // Initialize _DifferentialGeometry_ from parameters nn = new Normal(Geometry.Normalize(Geometry.Cross(dpdu, dpdv))); u = uu; v = vv; shape = sh; dudx = dvdx = dudy = dvdy = 0.0d; // Adjust normal based on orientation and handedness if (shape != null && (shape.ReverseOrientation ^ shape.TransformSwapsHandedness)) nn *= -1.0d; }
public override bool Intersect(Ray r, out double tHit, out double rayEpsilon, out DifferentialGeometry dg) { tHit = Double.NaN; rayEpsilon = Double.NaN; dg = null; // Transform _Ray_ to object space Ray ray = WorldToObject.Apply(r); // Compute plane intersection for disk if (Math.Abs(ray.d.z) < 1e-7) return false; double thit = (height - ray.o.z) / ray.d.z; if (thit < ray.mint || thit > ray.maxt) return false; // See if hit point is inside disk radii and $\phimax$ Point phit = ray.GetPointAt(thit); double dist2 = phit.x * phit.x + phit.y * phit.y; if (dist2 > radius * radius || dist2 < innerRadius * innerRadius) return false; // Test disk $\phi$ value against $\phimax$ double phi = Math.Atan2(phit.y, phit.x); if (phi < 0) phi += 2.0d * Math.PI; if (phi > phiMax) return false; // Find parametric representation of disk hit double u = phi / phiMax; double oneMinusV = ((Math.Sqrt(dist2) - innerRadius) / (radius - innerRadius)); double invOneMinusV = (oneMinusV > 0.0d) ? (1.0d / oneMinusV) : 0.0d; double v = 1.0d - oneMinusV; Vector dpdu = new Vector(-phiMax * phit.y, phiMax * phit.x, 0.0d); Vector dpdv = new Vector(-phit.x * invOneMinusV, -phit.y * invOneMinusV, 0.0d); dpdu *= phiMax * Constants.INV_TWOPI; dpdv *= (radius - innerRadius) / radius; Normal dndu = new Normal(0, 0, 0); Normal dndv = new Normal(0, 0, 0); // Initialize _DifferentialGeometry_ from parametric information Transform o2w = ObjectToWorld; dg = new DifferentialGeometry(o2w.Apply(phit), o2w.Apply(dpdu), o2w.Apply(dpdv), o2w.Apply(dndu), o2w.Apply(dndv), u, v, this); // Update _tHit_ for quadric intersection tHit = thit; // Compute _rayEpsilon_ for quadric intersection rayEpsilon = 5e-4d * tHit; return true; }
public TriangleMesh(Transform o2w, Transform w2o, bool ro, int nt, int nv, int[] vi, Point[] P, Normal[] N, Vector[] S, double[] uv, Texture<double> atex) : base(o2w, w2o, ro) { alphaTexture = atex; ntris = nt; nverts = nv; vertexIndex = new int[ntris * 3]; Array.Copy(vi, 0, vertexIndex, 0, ntris * 3); // Copy _uv_, _N_, and _S_ vertex data, if present if (uv != null) { uvs = new double[2 * nverts]; Array.Copy(uv, 0, uvs, 0, 2 * nverts); } else { uvs = null; } p = new Point[nverts]; if (N != null) { n = new Normal[nverts]; Array.Copy(N, 0, n, 0, nverts); } else { n = null; } if (S != null) { s = new Vector[nverts]; Array.Copy(S, 0, s, 0, nverts); } else { s = null; } // Transform mesh vertices to world space for (int i = 0; i < nverts; ++i) { p[i] = ObjectToWorld.Apply(P[i]); } }
public Normal Apply(Normal n) { double x = n.x, y = n.y, z = n.z; return new Normal(mInv.m[0, 0] * x + mInv.m[1, 0] * y + mInv.m[2, 0] * z, mInv.m[0, 1] * x + mInv.m[1, 1] * y + mInv.m[2, 1] * z, mInv.m[0, 2] * x + mInv.m[1, 2] * y + mInv.m[2, 2] * z); }
public virtual Point Sample(Point p, double u1, double u2, ref Normal ns) { return Sample(u1, u2, ref ns); }
public virtual Point Sample(double u1, double u2, ref Normal ns) { throw new NotImplementedException(); }
public override bool Intersect(Ray r, out double tHit, out double rayEpsilon, out DifferentialGeometry dg) { double phi; Point phit; tHit = Double.NaN; rayEpsilon = Double.NaN; dg = null; // Transform _Ray_ to object space Ray ray = WorldToObject.Apply(r); // Compute quadratic sphere coefficients double A = ray.d.x * ray.d.x + ray.d.y * ray.d.y + ray.d.z * ray.d.z; double B = 2 * (ray.d.x * ray.o.x + ray.d.y * ray.o.y + ray.d.z * ray.o.z); double C = ray.o.x * ray.o.x + ray.o.y * ray.o.y + ray.o.z * ray.o.z - radius * radius; // Solve quadratic equation for _t_ values double t0, t1; if (!Utility.Quadratic(A, B, C, out t0, out t1)) return false; // Compute intersection distance along ray if (t0 > ray.maxt || t1 < ray.mint) return false; double thit = t0; if (t0 < ray.mint) { thit = t1; if (thit > ray.maxt) return false; } // Compute sphere hit position and $\phi$ phit = ray.GetPointAt(thit); if (phit.x == 0.0d && phit.y == 0.0d) phit.x = 1e-5d * radius; phi = Math.Atan2(phit.y, phit.x); if (phi < 0.0d) phi += 2.0d * Math.PI; // Test sphere intersection against clipping parameters if ((zmin > -radius && phit.z < zmin) || (zmax < radius && phit.z > zmax) || phi > phiMax) { if (thit == t1) return false; if (t1 > ray.maxt) return false; thit = t1; // Compute sphere hit position and $\phi$ phit = ray.GetPointAt(thit); if (phit.x == 0.0d && phit.y == 0.0d) phit.x = 1e-5d * radius; phi = Math.Atan2(phit.y, phit.x); if (phi < 0.0d) phi += 2.0d * Math.PI; if ((zmin > -radius && phit.z < zmin) || (zmax < radius && phit.z > zmax) || phi > phiMax) return false; } // Find parametric representation of sphere hit double u = phi / phiMax; double theta = Math.Acos(Utility.Clamp(phit.z / radius, -1.0d, 1.0d)); double v = (theta - thetaMin) / (thetaMax - thetaMin); // Compute sphere $\dpdu$ and $\dpdv$ double zradius = Math.Sqrt(phit.x * phit.x + phit.y * phit.y); double invzradius = 1.0d / zradius; double cosphi = phit.x * invzradius; double sinphi = phit.y * invzradius; Vector dpdu = new Vector(-phiMax * phit.y, phiMax * phit.x, 0); Vector dpdv = (thetaMax - thetaMin) * new Vector(phit.z * cosphi, phit.z * sinphi, -radius * Math.Sin(theta)); // Compute sphere $\dndu$ and $\dndv$ Vector d2Pduu = -phiMax * phiMax * new Vector(phit.x, phit.y, 0); Vector d2Pduv = (thetaMax - thetaMin) * phit.z * phiMax * new Vector(-sinphi, cosphi, 0.0d); Vector d2Pdvv = -(thetaMax - thetaMin) * (thetaMax - thetaMin) * new Vector(phit.x, phit.y, phit.z); // Compute coefficients for fundamental forms double E = Geometry.Dot(dpdu, dpdu); double F = Geometry.Dot(dpdu, dpdv); double G = Geometry.Dot(dpdv, dpdv); Vector N = Geometry.Normalize(Geometry.Cross(dpdu, dpdv)); double e = Geometry.Dot(N, d2Pduu); double f = Geometry.Dot(N, d2Pduv); double g = Geometry.Dot(N, d2Pdvv); // Compute $\dndu$ and $\dndv$ from fundamental form coefficients double invEGF2 = 1.0d / (E * G - F * F); Normal dndu = new Normal((f * F - e * G) * invEGF2 * dpdu + (e * F - f * E) * invEGF2 * dpdv); Normal dndv = new Normal((g * F - f * G) * invEGF2 * dpdu + (f * F - g * E) * invEGF2 * dpdv); // Initialize _DifferentialGeometry_ from parametric information Transform o2w = ObjectToWorld; dg = new DifferentialGeometry(o2w.Apply(phit), o2w.Apply(dpdu), o2w.Apply(dpdv), o2w.Apply(dndu), o2w.Apply(dndv), u, v, this); // Update _tHit_ for quadric intersection tHit = thit; // Compute _rayEpsilon_ for quadric intersection rayEpsilon = 5e-4d * tHit; return true; }
public static Normal Faceforward(Normal n1, Normal n2) { return (Dot(n1, n2) < 0.0d) ? -n1 : n1; }
public override Point Sample(double u1, double u2, ref Normal ns) { double z = Utility.Lerp(u1, zmin, zmax); double t = u2 * phiMax; Point p = new Point(radius * Math.Cos(t), radius * Math.Sin(t), z); ns = Geometry.Normalize(ObjectToWorld.Apply(new Normal(p.x, p.y, 0.0d))); if (ReverseOrientation) ns *= -1.0d; return ObjectToWorld.Apply(p); }
public static double AbsDot(Normal n1, Normal n2) { if (n1.HasNaNs() || n2.HasNaNs()) throw new InvalidOperationException(); return Math.Abs(n1.x * n2.x + n1.y * n2.y + n1.z * n2.z); }
public override Point Sample(double u1, double u2, ref Normal ns) { Point p = new Point(); MonteCarlo.ConcentricSampleDisk(u1, u2, ref p.x, ref p.y); p.x *= radius; p.y *= radius; p.z = height; ns = Geometry.Normalize(ObjectToWorld.Apply(new Normal(0, 0, 1))); if (ReverseOrientation) ns *= -1.0d; return ObjectToWorld.Apply(p); }
public Spectrum L(Point point, Normal normal, Vector w) { throw new NotImplementedException(); }
public static double Dot(Vector v, Normal n) { if (v.HasNaNs() || n.HasNaNs()) throw new InvalidOperationException(); return v.x * n.x + v.y * n.y + v.z * n.z; }
public static double Dot(Normal n, Vector v) { if (n.HasNaNs() || v.HasNaNs()) throw new InvalidOperationException(); return n.x * v.x + n.y * v.y + n.z * v.z; }
public static Vector Faceforward(Vector v, Normal n) { return (Dot(v, n) < 0.0d) ? -v : v; }
public void Apply(Normal n, ref Normal nt) { double x = n.x, y = n.y, z = n.z; nt.x = mInv.m[0, 0] * x + mInv.m[1, 0] * y + mInv.m[2, 0] * z; nt.y = mInv.m[0, 1] * x + mInv.m[1, 1] * y + mInv.m[2, 1] * z; nt.z = mInv.m[0, 2] * x + mInv.m[1, 2] * y + mInv.m[2, 2] * z; }
public override Point Sample(double u1, double u2, ref Normal ns) { double b1, b2; MonteCarlo.UniformSampleTriangle(u1, u2, out b1, out b2); // Get triangle vertices in _p1_, _p2_, and _p3_ Point p1 = mesh.p[v[0]]; Point p2 = mesh.p[v[1]]; Point p3 = mesh.p[v[2]]; Point p = b1 * p1 + b2 * p2 + (1.0d - b1 - b2) * p3; Normal n = new Normal(Geometry.Cross(p2 - p1, p3 - p1)); ns = Geometry.Normalize(n); if (ReverseOrientation) ns *= -1.0d; return p; }
public Vector(Normal v) { this.x = v.x; this.y = v.y; this.z = v.z; }
public static Normal Normalize(Normal n) { return n / n.Length(); }
public override bool Intersect(Ray r, out double tHit, out double rayEpsilon, out DifferentialGeometry dg) { double phi, v; Point phit; tHit = Double.NaN; rayEpsilon = Double.NaN; dg = null; // Transform _Ray_ to object space Ray ray = WorldToObject.Apply(r); // Compute quadratic hyperboloid coefficients double A = a * ray.d.x * ray.d.x + a * ray.d.y * ray.d.y - c * ray.d.z * ray.d.z; double B = 2.0d * (a * ray.d.x * ray.o.x + a * ray.d.y * ray.o.y - c * ray.d.z * ray.o.z); double C = a * ray.o.x * ray.o.x + a * ray.o.y * ray.o.y - c * ray.o.z * ray.o.z - 1; // Solve quadratic equation for _t_ values double t0, t1; if (!Utility.Quadratic(A, B, C, out t0, out t1)) return false; // Compute intersection distance along ray if (t0 > ray.maxt || t1 < ray.mint) return false; double thit = t0; if (t0 < ray.mint) { thit = t1; if (thit > ray.maxt) return false; } // Compute hyperboloid inverse mapping phit = ray.GetPointAt(thit); v = (phit.z - p1.z) / (p2.z - p1.z); Point pr = (1.0d - v) * p1 + v * p2; phi = Math.Atan2(pr.x * phit.y - phit.x * pr.y, phit.x * pr.x + phit.y * pr.y); if (phi < 0) phi += 2 * Math.PI; // Test hyperboloid intersection against clipping parameters if (phit.z < zmin || phit.z > zmax || phi > phiMax) { if (thit == t1) return false; thit = t1; if (t1 > ray.maxt) return false; // Compute hyperboloid inverse mapping phit = ray.GetPointAt(thit); v = (phit.z - p1.z) / (p2.z - p1.z); pr = (1.0d - v) * p1 + v * p2; phi = Math.Atan2(pr.x * phit.y - phit.x * pr.y, phit.x * pr.x + phit.y * pr.y); if (phi < 0) phi += 2 * Math.PI; if (phit.z < zmin || phit.z > zmax || phi > phiMax) return false; } // Compute parametric representation of hyperboloid hit double u = phi / phiMax; // Compute hyperboloid $\dpdu$ and $\dpdv$ double cosphi = Math.Cos(phi), sinphi = Math.Sin(phi); Vector dpdu = new Vector(-phiMax * phit.y, phiMax * phit.x, 0.0d); Vector dpdv = new Vector((p2.x - p1.x) * cosphi - (p2.y - p1.y) * sinphi, (p2.x - p1.x) * sinphi + (p2.y - p1.y) * cosphi, p2.z - p1.z); // Compute hyperboloid $\dndu$ and $\dndv$ Vector d2Pduu = -phiMax * phiMax * new Vector(phit.x, phit.y, 0); Vector d2Pduv = phiMax * new Vector(-dpdv.y, dpdv.x, 0.0d); Vector d2Pdvv = new Vector(0, 0, 0); // Compute coefficients for fundamental forms double E = Geometry.Dot(dpdu, dpdu); double F = Geometry.Dot(dpdu, dpdv); double G = Geometry.Dot(dpdv, dpdv); Vector N = Geometry.Normalize(Geometry.Cross(dpdu, dpdv)); double e = Geometry.Dot(N, d2Pduu); double f = Geometry.Dot(N, d2Pduv); double g = Geometry.Dot(N, d2Pdvv); // Compute $\dndu$ and $\dndv$ from fundamental form coefficients double invEGF2 = 1.0d / (E * G - F * F); Normal dndu = new Normal((f * F - e * G) * invEGF2 * dpdu + (e * F - f * E) * invEGF2 * dpdv); Normal dndv = new Normal((g * F - f * G) * invEGF2 * dpdu + (f * F - g * E) * invEGF2 * dpdv); // Initialize _DifferentialGeometry_ from parametric information Transform o2w = ObjectToWorld; dg = new DifferentialGeometry(o2w.Apply(phit), o2w.Apply(dpdu), o2w.Apply(dpdv), o2w.Apply(dndu), o2w.Apply(dndv), u, v, this); // Update _tHit_ for quadric intersection tHit = thit; // Compute _rayEpsilon_ for quadric intersection rayEpsilon = 5e-4d * tHit; return true; }
public override Point Sample(double u1, double u2, ref Normal ns) { Point p = new Point(0, 0, 0) + radius * MonteCarlo.UniformSampleSphere(u1, u2); ns = Geometry.Normalize(ObjectToWorld.Apply(new Normal(p.x, p.y, p.z))); if (ReverseOrientation) ns *= -1.0d; return ObjectToWorld.Apply(p); }
public override void GetShadingGeometry(Transform obj2world, DifferentialGeometry dg, out DifferentialGeometry dgShading) { if (mesh.n == null && mesh.s == null) { dgShading = dg; return; } // Initialize _Triangle_ shading geometry with _n_ and _s_ // Compute barycentric coordinates for point double[] b = new double[3]; // Initialize _A_ and _C_ matrices for barycentrics double[,] uv = new double[3, 2]; GetUVs(uv); double[,] A = { { uv[1,0] - uv[0,0], uv[2,0] - uv[0,0] }, { uv[1,1] - uv[0,1], uv[2,1] - uv[0,1] } }; double[] C = { dg.u - uv[0, 0], dg.v - uv[0, 1] }; if (!Utility.SolveLinearSystem2x2(A, C, out b[1], out b[2])) { // Handle degenerate parametric mapping b[0] = b[1] = b[2] = 1.0f / 3.0f; } else b[0] = 1.0d - b[1] - b[2]; // Use _n_ and _s_ to compute shading tangents for triangle, _ss_ and _ts_ Normal ns; Vector ss, ts; if (mesh.n != null) ns = Geometry.Normalize(obj2world.Apply(b[0] * mesh.n[v[0]] + b[1] * mesh.n[v[1]] + b[2] * mesh.n[v[2]])); else ns = dg.nn; if (mesh.s != null) ss = Geometry.Normalize(obj2world.Apply(b[0] * mesh.s[v[0]] + b[1] * mesh.s[v[1]] + b[2] * mesh.s[v[2]])); else ss = Geometry.Normalize(dg.dpdu); ts = Geometry.Cross(ss, ns); if (ts.LengthSquared() > 0.0d) { ts = Geometry.Normalize(ts); ss = Geometry.Cross(ts, ns); } else Geometry.CoordinateSystem(new Vector(ns), out ss, out ts); Normal dndu, dndv; // Compute $\dndu$ and $\dndv$ for triangle shading geometry if (mesh.n != null) { double[,] uvs = new double[3, 2]; GetUVs(uvs); // Compute deltas for triangle partial derivatives of normal double du1 = uvs[0, 0] - uvs[2, 0]; double du2 = uvs[1, 0] - uvs[2, 0]; double dv1 = uvs[0, 1] - uvs[2, 1]; double dv2 = uvs[1, 1] - uvs[2, 1]; Normal dn1 = mesh.n[v[0]] - mesh.n[v[2]]; Normal dn2 = mesh.n[v[1]] - mesh.n[v[2]]; double determinant = du1 * dv2 - dv1 * du2; if (determinant == 0.0d) dndu = dndv = new Normal(0, 0, 0); else { double invdet = 1.0d / determinant; dndu = (dv2 * dn1 - dv1 * dn2) * invdet; dndv = (-du2 * dn1 + du1 * dn2) * invdet; } } else dndu = dndv = new Normal(0, 0, 0); dgShading = new DifferentialGeometry(dg.p, ss, ts, ObjectToWorld.Apply(dndu), ObjectToWorld.Apply(dndv), dg.u, dg.v, dg.shape); dgShading.dudx = dg.dudx; dgShading.dvdx = dg.dvdx; dgShading.dudy = dg.dudy; dgShading.dvdy = dg.dvdy; dgShading.dpdx = dg.dpdx; dgShading.dpdy = dg.dpdy; }
public override Point Sample(Point p, double u1, double u2, ref Normal ns) { // Compute coordinate system for sphere sampling Point Pcenter = ObjectToWorld.Apply(new Point(0, 0, 0)); Vector wc = Geometry.Normalize(Pcenter - p); Vector wcX, wcY; Geometry.CoordinateSystem(wc, out wcX, out wcY); // Sample uniformly on sphere if $\pt{}$ is inside it if (Geometry.DistanceSquared(p, Pcenter) - radius * radius < 1e-4f) return Sample(u1, u2, ref ns); // Sample sphere uniformly inside subtended cone double sinThetaMax2 = radius * radius / Geometry.DistanceSquared(p, Pcenter); double cosThetaMax = Math.Sqrt(Math.Max(0.0d, 1.0d - sinThetaMax2)); DifferentialGeometry dgSphere; double thit, rayEpsilon; Point ps; Ray r = new Ray(p, MonteCarlo.UniformSampleCone(u1, u2, cosThetaMax, wcX, wcY, wc), 1e-3d); if (!Intersect(r, out thit, out rayEpsilon, out dgSphere)) thit = Geometry.Dot(Pcenter - p, Geometry.Normalize(r.d)); ps = r.GetPointAt(thit); ns = new Normal(Geometry.Normalize(ps - Pcenter)); if (ReverseOrientation) ns *= -1.0d; return ps; }
public override bool Intersect(Ray r, out double tHit, out double rayEpsilon, out DifferentialGeometry dg) { double phi; Point phit; tHit = Double.NaN; rayEpsilon = Double.NaN; dg = null; // Transform _Ray_ to object space Ray ray = WorldToObject.Apply(r); // Compute quadratic paraboloid coefficients double k = zmax / (radius * radius); double A = k * (ray.d.x * ray.d.x + ray.d.y * ray.d.y); double B = 2 * k * (ray.d.x * ray.o.x + ray.d.y * ray.o.y) - ray.d.z; double C = k * (ray.o.x * ray.o.x + ray.o.y * ray.o.y) - ray.o.z; // Solve quadratic equation for _t_ values double t0, t1; if (!Utility.Quadratic(A, B, C, out t0, out t1)) return false; // Compute intersection distance along ray if (t0 > ray.maxt || t1 < ray.mint) return false; double thit = t0; if (t0 < ray.mint) { thit = t1; if (thit > ray.maxt) return false; } // Compute paraboloid inverse mapping phit = ray.GetPointAt(thit); phi = Math.Atan2(phit.y, phit.x); if (phi < 0.0d) phi += 2.0d * Math.PI; // Test paraboloid intersection against clipping parameters if (phit.z < zmin || phit.z > zmax || phi > phiMax) { if (thit == t1) return false; thit = t1; if (t1 > ray.maxt) return false; // Compute paraboloid inverse mapping phit = ray.GetPointAt(thit); phi = Math.Atan2(phit.y, phit.x); if (phi < 0.0d) phi += 2.0d * Math.PI; if (phit.z < zmin || phit.z > zmax || phi > phiMax) return false; } // Find parametric representation of paraboloid hit double u = phi / phiMax; double v = (phit.z - zmin) / (zmax - zmin); // Compute parabaloid $\dpdu$ and $\dpdv$ Vector dpdu = new Vector(-phiMax * phit.y, phiMax * phit.x, 0.0d); Vector dpdv = (zmax - zmin) * new Vector(phit.x / (2.0d * phit.z), phit.y / (2.0d * phit.z), 1.0d); // Compute parabaloid $\dndu$ and $\dndv$ Vector d2Pduu = -phiMax * phiMax * new Vector(phit.x, phit.y, 0); Vector d2Pduv = (zmax - zmin) * phiMax * new Vector(-phit.y / (2.0d * phit.z), phit.x / (2.0d * phit.z), 0); Vector d2Pdvv = -(zmax - zmin) * (zmax - zmin) * new Vector(phit.x / (4.0d * phit.z * phit.z), phit.y / (4.0d * phit.z * phit.z), 0.0d); // Compute coefficients for fundamental forms double E = Geometry.Dot(dpdu, dpdu); double F = Geometry.Dot(dpdu, dpdv); double G = Geometry.Dot(dpdv, dpdv); Vector N = Geometry.Normalize(Geometry.Cross(dpdu, dpdv)); double e = Geometry.Dot(N, d2Pduu); double f = Geometry.Dot(N, d2Pduv); double g = Geometry.Dot(N, d2Pdvv); // Compute $\dndu$ and $\dndv$ from fundamental form coefficients double invEGF2 = 1.0d / (E * G - F * F); Normal dndu = new Normal((f * F - e * G) * invEGF2 * dpdu + (e * F - f * E) * invEGF2 * dpdv); Normal dndv = new Normal((g * F - f * G) * invEGF2 * dpdu + (f * F - g * E) * invEGF2 * dpdv); // Initialize _DifferentialGeometry_ from parametric information Transform o2w = ObjectToWorld; dg = new DifferentialGeometry(o2w.Apply(phit), o2w.Apply(dpdu), o2w.Apply(dpdv), o2w.Apply(dndu), o2w.Apply(dndv), u, v, this); // Update _tHit_ for quadric intersection tHit = thit; // Compute _rayEpsilon_ for quadric intersection rayEpsilon = 5e-4d * tHit; return true; }
public static Normal Faceforward(Normal n, Vector v) { return (Dot(n, v) < 0.0d) ? -n : n; }