19 using System.Collections.Generic;
46 this.Intensity = intensity;
47 this.Direction = direction;
55 public void Deconstruct(out
double intensity, out NormalizedVector3D direction)
85 double GetObstruction(Point3D point, IEnumerable<Triangle3DElement> shadowingTriangles);
117 public double GetObstruction(Point3D point, IEnumerable<Triangle3DElement> shadowingTriangles)
165 public double GetObstruction(Point3D point, IEnumerable<Triangle3DElement> shadowingTriangles)
167 foreach (Triangle3DElement triangle
in shadowingTriangles)
169 Point3D? projected = triangle.ProjectOnThisPlane(point,
ReverseDirection,
true,
double.PositiveInfinity);
171 if (projected !=
null && Intersections3D.PointInTriangle(projected.Value, triangle.Point1, triangle.Point2, triangle.Point3))
233 public double GetObstruction(Point3D point, IEnumerable<Triangle3DElement> shadowingTriangles)
235 Vector3D reverseDir = this.
Position - point;
236 double maxD = reverseDir.Modulus;
237 NormalizedVector3D reverseDirNorm =
new NormalizedVector3D(reverseDir.X / maxD, reverseDir.Y / maxD, reverseDir.Z / maxD,
false);
239 foreach (Triangle3DElement triangle
in shadowingTriangles)
241 Point3D? projected = triangle.ProjectOnThisPlane(point, reverseDirNorm,
true, maxD);
243 if (projected !=
null && Intersections3D.PointInTriangle(projected.Value, triangle.Point1, triangle.Point2, triangle.Point3))
304 public SpotlightLightSource(
double intensity, Point3D position, NormalizedVector3D direction,
double beamWidthAngle,
double cutoffAngle)
319 angle -= 2 * Math.PI;
321 angle = Math.Abs(angle);
362 public double GetObstruction(Point3D point, IEnumerable<Triangle3DElement> shadowingTriangles)
364 Vector3D reverseDir = this.
Position - point;
365 double maxD = reverseDir.Modulus;
366 NormalizedVector3D reverseDirNorm =
new NormalizedVector3D(reverseDir.X / maxD, reverseDir.Y / maxD, reverseDir.Z / maxD,
false);
368 foreach (Triangle3DElement triangle
in shadowingTriangles)
370 Point3D? projected = triangle.ProjectOnThisPlane(point, reverseDirNorm,
true, maxD);
372 if (projected !=
null && Intersections3D.PointInTriangle(projected.Value, triangle.Point1, triangle.Point2, triangle.Point3))
410 private List<Point3D[]> TriangulatedMask {
get; }
437 public MaskedLightSource(
double intensity, Point3D position, NormalizedVector3D direction,
double distance,
GraphicsPath mask,
double maskOrientation,
double triangulationResolution) : this(intensity, position, direction, distance, mask.Triangulate(triangulationResolution, true), maskOrientation)
451 public MaskedLightSource(
double intensity, Point3D position, NormalizedVector3D direction,
double distance, IEnumerable<GraphicsPath> triangulatedMask,
double maskOrientation)
459 double[,] rotation = Matrix3D.RotationToAlignWithZ(direction).Inverse();
461 double[,] rotation2 = Matrix3D.RotationAroundAxis(direction, maskOrientation);
463 List<Point3D[]> maskList =
new List<Point3D[]>();
467 Point3D[] triangle =
new Point3D[3];
469 List<Point> points = trianglePath.
GetPoints().First();
471 for (
int i = 0; i < 3; i++)
473 triangle[i] = (Point3D)((Vector3D)(rotation2 * (rotation *
new Point3D(points[i].X, points[i].Y, 0))) +
Origin);
476 maskList.Add(triangle);
479 this.TriangulatedMask = maskList;
488 bool contained =
false;
490 foreach (Point3D[] triangle
in TriangulatedMask)
492 if (Intersections3D.PointInTriangle(pt, triangle[0], triangle[1], triangle[2]))
525 angle -= 2 * Math.PI;
528 if (Math.Abs(angle) < Math.PI / 2)
530 angle = Math.Abs(angle) / Math.PI * 2;
534 intensity *= 1 - angle;
556 public double GetObstruction(Point3D point, IEnumerable<Triangle3DElement> shadowingTriangles)
558 Vector3D reverseDir = this.
Position - point;
559 double maxD = reverseDir.Modulus;
560 NormalizedVector3D reverseDirNorm =
new NormalizedVector3D(reverseDir.X / maxD, reverseDir.Y / maxD, reverseDir.Z / maxD,
false);
562 foreach (Triangle3DElement triangle
in shadowingTriangles)
564 Point3D? projected = triangle.ProjectOnThisPlane(point, reverseDirNorm,
true, maxD);
566 if (projected !=
null && Intersections3D.PointInTriangle(projected.Value, triangle.Point1, triangle.Point2, triangle.Point3))
589 private Point3D VirtualSource {
get; }
631 private Point3D[] ShadowSamplingPoints {
get; }
643 public AreaLightSource(
double intensity, Point3D center,
double radius,
double penumbraRadius, NormalizedVector3D direction,
double sourceDistance,
int shadowSamplingPointCount)
645 if (shadowSamplingPointCount < 1)
647 throw new ArgumentOutOfRangeException(nameof(shadowSamplingPointCount), shadowSamplingPointCount,
"The number of shadow sampling points must be greater than or equal to 1!");
661 NormalizedVector3D yAxis;
663 if (Math.Abs(
new Vector3D(0, 1, 0) * this.
Direction) < 1)
665 yAxis = (
new Vector3D(0, 1, 0) - (
new Vector3D(0, 1, 0) * this.
Direction) * this.
Direction).Normalize();
669 yAxis = (
new Vector3D(0, 0, 1) - (
new Vector3D(0, 0, 1) * this.
Direction) * this.
Direction).Normalize();
672 NormalizedVector3D xAxis = (this.
Direction ^ yAxis).Normalize();
674 this.ShadowSamplingPoints =
new Point3D[shadowSamplingPointCount - 1];
676 for (
int i = 0; i < shadowSamplingPointCount - 1; i++)
678 double r = ((double)i / (shadowSamplingPointCount - 2)) * this.
Radius;
679 double theta = (double)i / (shadowSamplingPointCount - 2) * 2 * Math.PI * ((shadowSamplingPointCount - 1) / 3.7);
681 double x = r * Math.Cos(theta);
682 double y = r * Math.Sin(theta);
684 Point3D pt = this.
Center + x * xAxis + y * yAxis;
685 this.ShadowSamplingPoints[i] = pt;
692 double denom = ((point - this.VirtualSource) * this.
Direction);
696 return new LightIntensity(0, (point - this.VirtualSource).Normalize());
701 Point3D pt = this.VirtualSource + d * (point - this.VirtualSource);
702 double distSq = (pt.X - this.
Center.X) * (pt.X -
this.Center.X) + (pt.Y - this.
Center.Y) * (pt.Y -
this.Center.Y) + (pt.Z - this.
Center.Z) * (pt.Z -
this.Center.Z);
713 intensity =
Intensity / ((point.X - this.VirtualSource.X) * (point.X -
this.VirtualSource.X) + (point.Y - this.VirtualSource.Y) * (point.Y -
this.VirtualSource.Y) + (point.Z - this.VirtualSource.Z) * (point.Z -
this.VirtualSource.Z));
717 intensity =
Intensity / Math.Pow((point.X -
this.VirtualSource.X) * (point.X - this.VirtualSource.X) + (point.Y -
this.VirtualSource.Y) * (point.Y - this.VirtualSource.Y) + (point.Z -
this.VirtualSource.Z) * (point.Z - this.VirtualSource.Z), 0.5 *
DistanceAttenuationExponent);
720 return new LightIntensity(intensity, (point - this.VirtualSource).Normalize());
731 intensity =
Intensity / ((point.X - this.VirtualSource.X) * (point.X -
this.VirtualSource.X) + (point.Y - this.VirtualSource.Y) * (point.Y -
this.VirtualSource.Y) + (point.Z - VirtualSource.Z) * (point.Z -
this.VirtualSource.Z));
735 intensity =
Intensity / Math.Pow((point.X -
this.VirtualSource.X) * (point.X - this.VirtualSource.X) + (point.Y -
this.VirtualSource.Y) * (point.Y - this.VirtualSource.Y) + (point.Z -
this.VirtualSource.Z) * (point.Z - this.VirtualSource.Z), 0.5 *
DistanceAttenuationExponent);
744 double factor = (Math.Sqrt(distSq) - this.
Radius) / (this.PenumbraRadius - this.Radius);
745 intensity *= 1 - factor;
749 double factor = (Math.Sqrt(distSq) - this.
Radius) / (this.PenumbraRadius - this.Radius);
753 return new LightIntensity(intensity, (point - this.VirtualSource).Normalize());
757 return new LightIntensity(0, (point - this.VirtualSource).Normalize());
763 public double GetObstruction(Point3D point, IEnumerable<Triangle3DElement> shadowingTriangles)
765 double totalObstruction = 0;
769 Vector3D reverseDir = this.VirtualSource - point;
771 double denom = (reverseDir * this.
Direction);
781 Point3D pt = this.VirtualSource + d * reverseDir;
783 double maxD = (point - pt).Modulus;
784 NormalizedVector3D reverseDirNorm =
new NormalizedVector3D(reverseDir.X / maxD, reverseDir.Y / maxD, reverseDir.Z / maxD,
false);
788 foreach (Triangle3DElement triangle
in shadowingTriangles)
790 Point3D? projected = triangle.ProjectOnThisPlane(point, reverseDirNorm,
true, maxD);
792 if (projected !=
null && Intersections3D.PointInTriangle(projected.Value, triangle.Point1, triangle.Point2, triangle.Point3))
794 totalObstruction += 1;
810 for (
int i = 0; i < ShadowSamplingPoints.Length; i++)
812 Vector3D reverseDir = ShadowSamplingPoints[i] - point;
814 double maxD = reverseDir.Modulus;
815 NormalizedVector3D reverseDirNorm =
new NormalizedVector3D(reverseDir.X / maxD, reverseDir.Y / maxD, reverseDir.Z / maxD,
false);
819 foreach (Triangle3DElement triangle
in shadowingTriangles)
821 Point3D? projected = triangle.ProjectOnThisPlane(point, reverseDirNorm,
true, maxD);
823 if (projected !=
null && Intersections3D.PointInTriangle(projected.Value, triangle.Point1, triangle.Point2, triangle.Point3))
825 totalObstruction += 1;
839 return totalObstruction / sampleCount;