public bool TryIntersect(Ray ray, double tmin, double tmax, ref ShadeRecord sr) { var t = (this.k - ray.Origin.Z) / ray.Direction.Z; if (t < tmin || t > tmax) { return(false); } var x = ray.Origin.X + t * ray.Direction.X; var y = ray.Origin.Y + t * ray.Direction.Y; if (x < x0 || x > x1 || y < y0 || y > y1) { return(false); } var u = (x - x0) / (x1 - x0); var v = (y - y0) / (y1 - y0); var n = new Normal3(0, 0, 1); sr = new ShadeRecord { U = u, V = v, T = t, Material = this.material, Point = ray.GetPosition(t), }; sr.SetFaceNormal(ray, n); return(true); }
public bool TryIntersect(Ray ray, double tmin, double tmax, ref ShadeRecord sr) { var t = (this.k - ray.Origin.X) / ray.Direction.X; if (t < tmin || t > tmax) { return(false); } var y = ray.Origin.Y + t * ray.Direction.Y; var z = ray.Origin.Z + t * ray.Direction.Z; if (y < y0 || y > y1 || z < z0 || z > z1) { return(false); } var u = (y - y0) / (y1 - y0); var v = (z - z0) / (z1 - z0); var n = new Normal3(1, 0, 0); sr = new ShadeRecord { U = u, V = v, T = t, Material = this.material, Point = ray.GetPosition(t), }; sr.SetFaceNormal(ray, n); return(true); }
public Normal3 Sample(Random random) { ISphere sphere = new UnitSphere(Position3.Origin); Normal3 direction = ((Direction3)sphere.SurfacePosition(random)).Normalized(); return(IDirection3.InSameClosedHemisphere(Orientation, direction) ? direction : -direction); }
public Interaction(Point3 <float> p, Normal3 <float> n, Vector3 <float> pError, Vector3 <float> wo, float time /*, MediumInterface medium*/) { P = p; N = n; PError = pError; Wo = wo; Time = time; }
public void TestCtor() { var n = new Normal3(1, 2, 3); Assert.Equal(1, n.X); Assert.Equal(2, n.Y); Assert.Equal(3, n.Z); }
public void TestExplicitVector4() { var n = new Normal3(1, 2, 3); Vector4 u = (Vector4)n; Assert.True(u.IsDirection); Assert.Equal(1, u.X); Assert.Equal(2, u.Y); Assert.Equal(3, u.Z); }
public BSDF(SurfaceInteraction inter, float eta = 1) { Eta = eta; ng = inter.N; ns = inter.Shading.N; ss = inter.Shading.DpDu.Normalized(); ts = Vector3 <float> .Cross(ns.ToVector3(), ss); }
/// <summary> Split this node </summary> /// <param name="split">The split to split this node with</param> protected virtual void Split(Split split) { Left = new BoundingVolumeHierarchy(split.Left); Right = new BoundingVolumeHierarchy(split.Right); SplitDirection = split.Direction; Items = new HashSet <ISceneObject>() { Left, Right }; }
public static Vector3 Refract( this Vector3 uv, Normal3 n, double etaiOverEtat) { var cosTheta = Math.Min(Vector3.Dot(-uv, n), 1); var rOutPerp = etaiOverEtat * (uv + cosTheta * n); var rOutParallel = -Math.Sqrt( Math.Abs(1.0 - Vector3.MagnitudeSquared(rOutPerp))) * n; return(rOutPerp + rOutParallel); }
public void SplitPlanes() { for (int i = 0; i < 100; i++) { Normal3 direction = Normal3.UnitX; float start = (float)Utils.ThreadRandom.NextDouble(); float end = (float)Utils.ThreadRandom.NextDouble(); SpatialBin bin = new(AxisAlignedPlane.X, start, end); Assert.AreEqual(direction * start, bin.SplitPlaneLeft.Position); Assert.AreEqual(direction, bin.SplitPlaneLeft.Normal); Assert.AreEqual(direction * end, bin.SplitPlaneRight.Position); Assert.AreEqual(-direction, bin.SplitPlaneRight.Normal); } }
public Normal3 Sample(Random random) { /// Compute Height double theta = Math.Pow((random.NextDouble() - 0.5d) * Math.PI, Exponent); double r = Math.Cos(theta); double w = Math.Sin(theta); /// Compute u and v double angle = random.NextDouble() * 2 * Math.PI; double u = r * Math.Cos(angle); double v = r * Math.Sin(angle); /// Transform to Orientation Normal3 uDirection = Normal3.AnyPerpendicular(Orientation); Normal3 vDirection = Normal3.Perpendicular(Orientation, uDirection); return(new Normal3(uDirection * (float)u + vDirection * (float)v + Orientation * (float)w)); }
public void Sample() { Normal3 orientation = Random.Shared.Normal3(); var distribution = new HemisphericalDiffuse(orientation); int samples = 10_000; int intervalCount = 10; int[] sampleCount = new int[intervalCount]; for (int i = 0; i < samples; i++) { Normal3 sample = distribution.Sample(Random.Shared); double dot = Normal3.Similarity(orientation, sample); int index = (int)(dot * intervalCount); sampleCount[index]++; } }
public Normal3 Sample(Random random) { /// Get Point uniformly on Disc double angle = random.NextDouble() * 2 * Math.PI; double r = random.NextDouble() + random.NextDouble(); r = r < 1 ? r : 2 - r; double u = r * Math.Cos(angle); double v = r * Math.Sin(angle); /// Raise Disc point to Hemisphere double w = Math.Sqrt(1 - u * u - v * v); Normal3 uDirection = Normal3.AnyPerpendicular(Orientation); Normal3 vDirection = Normal3.Perpendicular(Orientation, uDirection); return(new Normal3(uDirection * (float)u + vDirection * (float)v + Orientation * (float)w)); }
/// <summary> Get the best spatial binning split for a certain axis </summary> /// <param name="clipPlaneCreator">The direction the binning proces is going</param> /// <param name="axis">The axis selector</param> /// <returns>The best spatial binning split in the specified direction</returns> Split?BestSpatialBinSplit(Normal3 splitDirection, Func <bool, float, AxisAlignedPlane> clipPlaneCreator, Func <Vector3, float> axis) { float binStart = axis(Shape.BoundingBox.MinCorner.Vector); float binEnd = axis(Shape.BoundingBox.MaxCorner.Vector); float binSize = axis(Shape.BoundingBox.Size.Vector) / SpatialBinAmount; float k1 = SpatialBinAmount * BinningEpsilon / axis(Shape.BoundingBox.Size.Vector); float bestSplitCost = SurfaceAreaHeuristic(Items.Count, Shape.BoundingBox.SurfaceArea); Split?bestSplit = null; for (int i = 1; i < SpatialBinAmount; i++) { SpatialBin left = new(clipPlaneCreator, binStart, binSize *i); SpatialBin right = new(clipPlaneCreator, binSize *i, binEnd); // Populate Split foreach (ISceneObject primitive in Items) { int binID1 = (int)(k1 * (axis(primitive.Shape.BoundingBox.MinCorner.Vector) - axis(Shape.BoundingBox.MinCorner.Vector))); int binID2 = (int)(k1 * (axis(primitive.Shape.BoundingBox.MaxCorner.Vector) - axis(Shape.BoundingBox.MinCorner.Vector))); if (binID1 < i && binID2 < i) { left.Aggregate.Add(primitive); } else if (binID1 > i && binID2 > i) { right.Aggregate.Add(primitive); } else { left.ClipAndAdd(primitive); right.ClipAndAdd(primitive); } } // Evaluate Split Split split = new(splitDirection, left.Aggregate, right.Aggregate); float splitCost = split.SurfaceAreaHeuristic; if (splitCost < bestSplitCost) { bestSplitCost = splitCost; bestSplit = split; } } // TODO: Reference Unsplitting on best Split return(bestSplit); }
public SurfaceInteraction(Point3 <float> p, Vector3 <float> pError, Point2 <float> uv, Vector3 <float> wo, Vector3 <float> dpdu, Vector3 <float> dpdv, Normal3 <float> dndu, Normal3 <float> dndv, float time, Shape shape) : base(p, new Normal3 <float>(Vector3 <float> .Cross(dpdu, dpdv).Normalized()), pError, wo, time) { Uv = uv; DpDu = dpdu; DpDv = dpdv; DnDu = dndu; DnDv = dndv; Shape = shape; // Initialize the shading data from the true geometry Shading.N = N; Shading.DpDu = DpDu; Shading.DpDv = DpDv; Shading.DnDu = DnDu; Shading.DnDv = DnDv; }
Vector3 SampleVNDF(float r1, float r2) { // Rotate so UnitZ is up, and flip incoming to outgoing direction Normal3 up = Normal3.UnitZ; OpenTK.Mathematics.Quaternion rotation; if (Orientation == -up) { rotation = new OpenTK.Mathematics.Quaternion(Normal3.AnyPerpendicular(up).Vector, 0f); } else { rotation = new OpenTK.Mathematics.Quaternion(Vector3.Cross(Orientation.Vector, up.Vector), Vector3.Dot(Orientation.Vector, up.Vector) + 1f).Normalized(); } Vector3 Ve = rotation * -IncomingDirection.Vector; // Section 3.2: transforming the view direction to the hemisphere configuration Vector3 Vh = new Vector3(Roughness * Ve.X, Roughness * Ve.Y, Ve.Z).Normalized(); // Section 4.1: orthonormal basis (with special case if cross product is zero) float lensq = Vh.X * Vh.X + Vh.Y * Vh.Y; Vector3 T1 = lensq > 0 ? new Vector3(-Vh.Y, Vh.X, 0) / (float)Math.Sqrt(lensq) : new Vector3(1f, 0f, 0f); Vector3 T2 = Vector3.Cross(Vh, T1); // Section 4.2: parameterization of the projected area float r = (float)Math.Sqrt(r1); float phi = 2.0f * (float)Math.PI * r2; float t1 = r * (float)Math.Cos(phi); float t2 = r * (float)Math.Sin(phi); float s = 0.5f * (1f + Vh.Z); t2 = (1f - s) * (float)Math.Sqrt(1f - t1 * t1) + s * t2; // Section 4.3: reprojection onto hemisphere Vector3 Nh = t1 * T1 + t2 * T2 + (float)Math.Sqrt(Math.Max(0f, 1f - t1 * t1 - t2 * t2)) * Vh; // Section 3.4: transforming the normal back to the ellipsoid configuration Vector3 Ne = new(Roughness * Nh.X, Roughness *Nh.Y, (float)Math.Max(0.0, Nh.Z)); return(rotation.Inverted() * Ne); }
public bool TryIntersect( Ray ray, double tmin, double tmax, ref ShadeRecord sr) { var origin = new Point3( this.cosTheta * ray.Origin.X - this.sinTheta * ray.Origin.Z, ray.Origin.Y, this.sinTheta * ray.Origin.X + this.cosTheta * ray.Origin.Z); var direction = new Vector3( this.cosTheta * ray.Direction.X - this.sinTheta * ray.Direction.Z, ray.Direction.Y, this.sinTheta * ray.Direction.X + this.cosTheta * ray.Direction.Z); var rotatedRay = new Ray(origin, direction, ray.Time); if (!this.obj.TryIntersect(rotatedRay, tmin, tmax, ref sr)) { return(false); } var p = new Point3( this.cosTheta * sr.Point.X + this.sinTheta * sr.Point.Z, sr.Point.Y, -this.sinTheta * sr.Point.X + this.cosTheta * sr.Point.Z); var n = new Normal3( this.cosTheta * sr.Normal.X + this.sinTheta * sr.Normal.Z, sr.Normal.Y, -this.sinTheta * sr.Normal.X + this.cosTheta * sr.Normal.Z); sr.Point = p; sr.SetFaceNormal(rotatedRay, n); return(true); }
public bool Contains(Normal3 sample) => IDirection3.InSameClosedHemisphere(Orientation, sample);
public HemisphericalUniform(Normal3 orientation) { Orientation = orientation; }
public void SetShadingGeometry(Vector3 <float> dpdu, Vector3 <float> dpdv, Normal3 <float> dndu, Normal3 <float> dndv) { throw new NotImplementedException(); }
public ISpectrum GetEmittance(Position3 position, Normal3 orientation, Normal3 direction) { return(Spectrum); }
public IProbabilityDistribution <Normal3> GetDirections(Normal3 incomingDirection, Position3 position, Normal3 orientation, ISpectrum spectrum) { return(new SphericalUniform()); }
/// <summary> Create a new split with AABB's </summary> /// <param name="left">The left AABB</param> /// <param name="right">The right AABB</param> public Split(Normal3 direction, IAggregate left, IAggregate right) { Direction = direction; Left = left; Right = right; }
public IProbabilityDistribution <Normal3> GetDirections(Normal3 incomingDirection, Position3 position, Normal3 orientation, ISpectrum spectrum) { throw new NotImplementedException("Requires structure to remember indices of refraction"); }
/// <summary> Create a new split with primitives </summary> /// <param name="primitivesLeft">The primitives for the left AABB</param> /// <param name="primitivesRight">The primitives for the right AABB</param> public Split(Normal3 direction, IEnumerable <ISceneObject> primitivesLeft, IEnumerable <ISceneObject> primitivesRight) { Direction = direction; Left = new Aggregate(primitivesLeft); Right = new Aggregate(primitivesRight); }
public double ProbabilityDensity(Normal3 sample) => Contains(sample) ? 1 / DomainSize : 0;
public IRay GetRay(Position3 position, Normal3 orientation, Normal3 direction) { return(new Ray(position, direction)); }
public IProbabilityDistribution <Normal3> GetOrientations(Position3 position, Normal3 direction, IShape shape) { return(new UniformPMF <Normal3>(shape.OutwardsDirection(position))); }
public ISpectrum GetAlbedo(Position3 position, Normal3 orientation, Normal3 direction) { return(Albedo); }
public IProbabilityDistribution <Normal3> GetDirections(Normal3 incomingDirection, Position3 position, Normal3 orientation, ISpectrum spectrum) { return(new HemisphericalDiffuse(orientation)); }