public Sphere() { fromOrigin = true; Center = new Tuple4(0.0, 0.0, 0.0, TupleFlavour.Point); Radius = 1.0; radius2 = 1.0; }
private double[] GetIntersectionsFromBook(Tuple4 origin, Tuple4 dir) { if (!Constants.EpsilonCompare(1.0, dir.Length())) { throw new ArgumentException("Direction should be normalized", nameof(dir)); } var sphereToRay = Tuple4.Subtract(origin, Tuple4.ZeroPoint); var a = Tuple4.DotProduct(dir, dir); var b = 2 * Tuple4.DotProduct(dir, sphereToRay); var c = Tuple4.DotProduct(sphereToRay, sphereToRay) - 1.0; var discriminant = b * b - 4 * a * c; if (discriminant < 0.0) { return(null); } var discriminantSqrt = Math.Sqrt(discriminant); var t0 = (-b - discriminantSqrt) / (2 * a); var t1 = (-b + discriminantSqrt) / (2 * a); // Ray originates inside sphere // When t > 0 that is intersection in the direction of the ray // other intersection is in the opposite direction return(new double[] { t0, t1 }); }
// https://en.wikipedia.org/wiki/Euler_angles // The basic theory of this camera model is that we want to build a camera matrix that first rotates pitch angle about the X axis, // then rotates yaw angle about the Y axis, then translates to some position in the world. // Since we want the view matrix, we need to compute the inverse of the resulting matrix. // V=(T(RyRx))^-1 public static IMatrix EulerAnglesTransform(Tuple4 from, double pitch, double yaw) { var orientation = MatrixOperations.Geometry3D.RotateZXY(pitch, yaw, 0); var translation = Translation(from.X, from.Y, from.Z); return(Invert(Multiply(translation, orientation))); }
public Sphere(Tuple4 center, double radius) { fromOrigin = false; Center = center; Radius = radius; radius2 = radius * radius; }
protected internal virtual double DistanceFrom(Tuple4 point) { if (point.IsVector()) { throw new ArgumentException("Argument is not a point"); } throw new NotImplementedException(); }
public static IMatrix FromTuple(Tuple4 tuple) { return(new Matrix(new double[, ] { { tuple.X }, { tuple.Y }, { tuple.Z }, { tuple.W } }, false)); }
public virtual Tuple4 GetNormal(Tuple4 objectPoint) { var estimateNormal = new Tuple4( DistanceFrom(new Tuple4(objectPoint.X + epsilon, objectPoint.Y, objectPoint.Z, TupleFlavour.Point)) - DistanceFrom(new Tuple4(objectPoint.X - epsilon, objectPoint.Y, objectPoint.Z, TupleFlavour.Point)), DistanceFrom(new Tuple4(objectPoint.X, objectPoint.Y + epsilon, objectPoint.Z, TupleFlavour.Point)) - DistanceFrom(new Tuple4(objectPoint.X, objectPoint.Y - epsilon, objectPoint.Z, TupleFlavour.Point)), DistanceFrom(new Tuple4(objectPoint.X, objectPoint.Y, objectPoint.Z + epsilon, TupleFlavour.Point)) - DistanceFrom(new Tuple4(objectPoint.X, objectPoint.Y, objectPoint.Z - epsilon, TupleFlavour.Point)), TupleFlavour.Vector ); return(estimateNormal); }
public static Tuple4 MovePoint(Tuple4 origin, Tuple4 dir, double t) { if (!dir.IsVector()) { throw new ArgumentException("Not a vector"); } return(new Tuple4( origin.X + t * dir.X, origin.Y + t * dir.Y, origin.Z + t * dir.Z, TupleFlavour.Point )); }
public Ray(Tuple4 origin, Tuple4 dir) { if (!origin.IsPoint()) { throw new ArgumentException("Not a point", nameof(origin)); } if (!dir.IsVector()) { throw new ArgumentException("Not a vector", nameof(dir)); } this.origin = origin; this.dir = dir; }
public static Tuple4 Transform(IMatrix matrix, Tuple4 tuple) { if (Object.ReferenceEquals(Matrix4x4.Identity, matrix)) { return(tuple); } return(new Tuple4( matrix[0, 0] * tuple.X + matrix[0, 1] * tuple.Y + matrix[0, 2] * tuple.Z + matrix[0, 3] * tuple.W, matrix[1, 0] * tuple.X + matrix[1, 1] * tuple.Y + matrix[1, 2] * tuple.Z + matrix[1, 3] * tuple.W, matrix[2, 0] * tuple.X + matrix[2, 1] * tuple.Y + matrix[2, 2] * tuple.Z + matrix[2, 3] * tuple.W, matrix[3, 0] * tuple.X + matrix[3, 1] * tuple.Y + matrix[3, 2] * tuple.Z + matrix[3, 3] * tuple.W )); }
public static IMatrix LookAtTransform(Tuple4 from, Tuple4 to, Tuple4 up) { var forward = Tuple4.Normalize(Tuple4.Subtract(to, from)); var upNormalized = Tuple4.Normalize(up); var left = Tuple4.CrossProduct(forward, upNormalized); var trueUp = Tuple4.CrossProduct(left, forward); var viewMatrix = new Matrix(new double[, ] { { left.X, left.Y, left.Z, -Tuple4.DotProduct(left, from) }, { trueUp.X, trueUp.Y, trueUp.Z, -Tuple4.DotProduct(trueUp, from) }, { -forward.X, -forward.Y, -forward.Z, Tuple4.DotProduct(forward, from) }, { 0.0, 0.0, 0.0, 1.0 } }); return(viewMatrix); /* * // Create a 4x4 orientation matrix from the left, up, and forward vectors * // This is transposed which is equivalent to performing an inverse * // if the matrix is orthonormalized (in this case, it is). * var orientation = new Matrix(new double[,] * { * { left.X, left.Y, left.Z, 0.0 }, * { trueUp.X, trueUp.Y, trueUp.Z, 0.0 }, * { -forward.X, -forward.Y, -forward.Z, 0.0 }, * { 0.0, 0.0, 0.0, 1.0 } * }, false); * * // Create a 4x4 translation matrix. * // The eye position is negated which is equivalent * // to the inverse of the translation matrix. * var translation = Translation(-from.X, -from.Y, -from.Z); * * // Combine the orientation and translation to compute * // the final view matrix. Note that the order of * // multiplication is reversed because the matrices * // are already inverted. * return Multiply(orientation, translation); */ }
public static IMatrix EulerAnglesTransformDirectConstruction(Tuple4 from, double pitch, double yaw) { double cosPitch = Math.Cos(pitch); double sinPitch = Math.Sin(pitch); double cosYaw = Math.Cos(yaw); double sinYaw = Math.Sin(yaw); Tuple4 xaxis = new Tuple4(cosYaw, 0, -sinYaw, TupleFlavour.Vector); Tuple4 yaxis = new Tuple4(sinYaw * sinPitch, cosPitch, cosYaw * sinPitch, TupleFlavour.Vector); Tuple4 zaxis = new Tuple4(sinYaw * cosPitch, -sinPitch, cosPitch * cosYaw, TupleFlavour.Vector); var viewMatrix = new Matrix(new double[, ] { { xaxis.X, xaxis.Y, xaxis.Z, -Tuple4.DotProduct(xaxis, from) }, { yaxis.X, yaxis.Y, yaxis.Z, -Tuple4.DotProduct(yaxis, from) }, { zaxis.X, zaxis.Y, zaxis.Z, -Tuple4.DotProduct(zaxis, from) }, { 0, 0, 0, 1 } }); return(viewMatrix); }
private double[] GetIntersections(Tuple4 origin, Tuple4 dir) { if (!Constants.EpsilonCompare(1.0, dir.Length())) { throw new ArgumentException("Direction should be normalized", nameof(dir)); } var t = 0.0; while (t < maxDistance) { var p = Tuple4.Geometry3D.MovePoint(origin, dir, t); var d = DistanceFrom(p); if (Math.Abs(d) < epsilon) { return(new double[] { t }); } t += d; } return(null); }
private double[] GetIntersections(Tuple4 origin, Tuple4 dir) { if (!Constants.EpsilonCompare(1.0, dir.Length())) { throw new ArgumentException("Direction should be normalized", nameof(dir)); } var l = Tuple4.Subtract(Center, origin); var tca = Tuple4.DotProduct(l, dir); var d2 = Tuple4.DotProduct(l, l) - tca * tca; if (d2 > radius2) { return(null); } var thc = Math.Sqrt(radius2 - d2); var t0 = tca - thc; var t1 = tca + thc; // Ray originates inside sphere // When t > 0 that is intersection in the direction of the ray // other intersection is in the opposite direction return(new double[] { t0, t1 }); }
public Tuple4 GetNormal(Tuple4 objectPoint) { // hit - Center return(Tuple4.Subtract(objectPoint, Center)); }
public Tuple4 PositionAt(double t) { return(Tuple4.Add(origin, Tuple4.Scale(dir, Tuple4.Point(t, t, t)))); }