public void TupleDotProductTest()
        {
            var t1 = new Tuple4(-1, 7, 3, TupleFlavour.Vector);
            var t2 = new Tuple4(4, 5, 6, TupleFlavour.Vector);

            Assert.Equal(49.0, Tuple4.DotProduct(t1, t2));
        }
        protected override Intersection[] GetBaseIntersections(Ray ray)
        {
            var dir_cross_e2 = Tuple4.CrossProduct(ray.dir, E2);
            var det          = Tuple4.DotProduct(E1, dir_cross_e2);

            if (Constants.EpsilonZero(Math.Abs(det)))
            {
                return(null);
            }

            var f            = 1.0 / det;
            var p1_to_origin = Tuple4.Subtract(ray.origin, P1);
            var u            = f * Tuple4.DotProduct(p1_to_origin, dir_cross_e2);

            if ((u < 0.0) || (u > 1.0))
            {
                return(null);
            }

            var origin_cross_e1 = Tuple4.CrossProduct(p1_to_origin, E1);
            var v = f * Tuple4.DotProduct(ray.dir, origin_cross_e1);

            if ((v < 0.0) || ((u + v) > 1.0))
            {
                return(null);
            }

            var t = f * Tuple4.DotProduct(E2, origin_cross_e1);

            return(new Intersection[] { new Intersection(t, this) });
        }
예제 #3
0
        public static double Schlick(HitResult hit, double refractiveIndexEntering, double refractiveIndexExiting)
        {
            // find the cosine of the angle between the eye and normal vectors
            double cosI = Tuple4.DotProduct(hit.EyeVector, hit.SurfaceNormal);

            // total internal reflection can only occur if n1 > n2
            if (refractiveIndexEntering > refractiveIndexExiting)
            {
                double ration    = refractiveIndexEntering / refractiveIndexExiting;
                double sinTheta2 = ration * ration * (1.0 - cosI * cosI);
                if (sinTheta2 > 1.0)
                {
                    return(1.0);
                }

                // compute cosine of theta_t using trig identity
                var cosTheta = Math.Sqrt(1.0 - sinTheta2);
                // when n1 > n2, use cos(theta_t) instead
                cosI = cosTheta;
            }

            var r0 = Math.Pow((refractiveIndexEntering - refractiveIndexExiting) / (refractiveIndexEntering + refractiveIndexExiting), 2);

            return(r0 + (1 - r0) * Math.Pow((1 - cosI), 5));
        }
예제 #4
0
        private static Lighting GetIntensity(IMaterial material, Tuple4 lightDirection, double intensity, Tuple4 eyeVector, Tuple4 pointOnSurface, Tuple4 surfaceNormal)
        {
            var diffuse  = 0.0;
            var specular = 0.0;

            var cosine = Tuple4.DotProduct(lightDirection, surfaceNormal);

            if (cosine >= 0)
            {
                diffuse = cosine * material.Diffuse;

                if (material.IsShining())
                {
                    // var reflected = Tuple4.Subtract(Tuple4.Scale(surfaceNormal, 2 * Tuple4.DotProduct(surfaceNormal, lightDirection)), lightDirection);
                    var reflected       = Tuple4.Reflect(Tuple4.Negate(lightDirection), surfaceNormal);
                    var reflectedDotDir = Tuple4.DotProduct(reflected, eyeVector);
                    if (reflectedDotDir > 0)
                    {
                        specular = material.Specular * Math.Pow(reflectedDotDir / (reflected.Length() * eyeVector.Length()), material.Shininess);
                    }
                }
            }

            return(diffuse, specular, intensity);
        }
예제 #5
0
        public virtual HitResult[] AllHits(Tuple4 origin, Tuple4 dir)
        {
            var intersections = GetIntersections(new Ray(origin, dir));

            if (intersections == null)
            {
                return(new HitResult[] { HitResult.NoHit });
            }

            var result = new HitResult[intersections.Length];

            for (int i = 0; i < intersections.Length; ++i)
            {
                var figure         = intersections[i].figure;
                var distance       = intersections[i].t;
                var pointOnSurface = Tuple4.Geometry3D.MovePoint(origin, dir, distance); // orig + dir*dist
                // TODO: Remove this cast to BaseFigure
                (var surfaceNormal, var objectPoint) = ((BaseFigure)figure).GetTransformedNormal(figure, pointOnSurface, intersections[i].u, intersections[i].v);
                var eyeVector = Tuple4.Negate(dir);
                var isInside  = false;
                if (Tuple4.DotProduct(surfaceNormal, eyeVector) < 0)
                {
                    isInside      = true;
                    surfaceNormal = Tuple4.Negate(surfaceNormal);
                }
                var pointOverSurface  = Tuple4.Add(pointOnSurface, Tuple4.Scale(surfaceNormal, Constants.Epsilon));
                var pointUnderSurface = Tuple4.Subtract(pointOnSurface, Tuple4.Scale(surfaceNormal, Constants.Epsilon));
                var reflectionVector  = Tuple4.Reflect(dir, surfaceNormal);

                result[i] = new HitResult(true,
                                          figure,
                                          distance,
                                          intersections[i].u,
                                          intersections[i].v,
                                          objectPoint,
                                          pointOnSurface,
                                          pointOverSurface,
                                          pointUnderSurface,
                                          surfaceNormal,
                                          eyeVector,
                                          reflectionVector,
                                          isInside);
            }

            return(result);
        }
예제 #6
0
        private Tuple4 CalculateRefractedColorAt(HitResult hit, double refractiveIndexEntering, double refractiveIndexExiting, int remaining)
        {
            if (!hit.IsHit || remaining <= 0)
            {
                return(colors.Black);
            }

            var material = hit.Figure.Material;

            if (Constants.EpsilonZero(material.Transparency))
            {
                return(colors.Black);
            }

            // Calculations are based on Snell's law

            var ration = refractiveIndexEntering / refractiveIndexExiting;
            var cosI   = Tuple4.DotProduct(hit.EyeVector, hit.SurfaceNormal);

            // sin(t) * sin(t) = (ration * ration) * (1 - cos(I) * cos(I))
            var sinTheta2 = ration * ration * (1 - cosI * cosI);

            if (sinTheta2 > 1.0)
            {
                // Total internal reflection
                return(colors.Black);
            }

            var cosTheta = Math.Sqrt(1 - sinTheta2);
            var dir      = Tuple4.Subtract(Tuple4.Scale(hit.SurfaceNormal, ration * cosI - cosTheta),
                                           Tuple4.Scale(hit.EyeVector, ration));

            var refractedRay   = new Ray(hit.PointUnderSurface, dir);
            var refractedColor = CastRay(refractedRay, remaining - 1);

            return(Tuple4.Scale(refractedColor, material.Transparency));
        }
예제 #7
0
 public void Then_dot(string a, string b, double expected)
 {
     Assert.True(Constants.EpsilonCompare(expected, Tuple4.DotProduct(cache[a], cache[b])));
 }