Ejemplo n.º 1
0
        public TriangleShape(PosVector position, PosVector vb, PosVector vc, BaseMaterial frontMaterial,
                             BaseMaterial backMaterial) : base(position)
        {
            VB             = vb;
            VC             = vc;
            _frontMaterial = frontMaterial;
            _backMaterial  = backMaterial;

            EdgeAb = VB - VA;
            EdgeBc = VC - VB;
            EdgeCa = VA - VC;

            Normal    = EdgeAb.Dot(EdgeBc) < EdgeBc.Dot(EdgeCa) ? EdgeAb.Cross(EdgeBc) : EdgeBc.Cross(EdgeCa);
            Magnitude = Normal.Magnitude();
            if (Magnitude > 0.0)
            {
                Normal = Normal / Magnitude; // unit vector to triangle plane
            }

            PlaneCoefficient = Normal.Dot(VA); // same coeff for all three vertices

            var a    = EdgeAb.MagnitudeSquared();
            var b    = EdgeAb.Dot(EdgeCa);
            var c    = EdgeCa.MagnitudeSquared();
            var dinv = 1.0 / (a * c - b * b);

            a = a * dinv;
            b = b * dinv;
            c = c * dinv;

            Ubeta  = (EdgeAb * c).AddScaled(EdgeCa, -b);
            Ugamma = (EdgeCa * -a).AddScaled(EdgeAb, b);
        }
Ejemplo n.º 2
0
 public KdNode(KdNodePlane plane, PosVector coord, List <IShape> list, KdNode nodeLeft, KdNode nodeRight)
 {
     Plane  = plane;
     Coord  = coord;
     Shapes = list;
     Left   = nodeLeft;
     Right  = nodeRight;
 }
Ejemplo n.º 3
0
        private Ray GetRefractionRay(PosVector p, PosVector n, PosVector v, double refraction)
        {
            var c1 = n.Dot(v);
            var c2 = 1.0 - refraction * refraction * Math.Sqrt(1.0 - c1 * c1);
            var t  = (n * (refraction * c1 - c2) - v * refraction * -1.0).Normalize();

            return(new Ray(p, t));
        }
Ejemplo n.º 4
0
        private PosVector GetVectorPlaneIntersection(Ray ray, KdNodePlane plane, PosVector coord)
        {
            switch (plane)
            {
            case KdNodePlane.XY:
                if (((coord.Z < ray.Position.Z) && (ray.Direction.Z > 0.0)) ||
                    ((coord.Z > ray.Position.Z) && (ray.Direction.Z < 0.0)))
                {
                    return(null);
                }
                else
                {
                    double k = (coord.Z - ray.Position.Z) / ray.Direction.Z;
                    return(new PosVector(
                               ray.Position.X + (ray.Direction.X * k),
                               ray.Position.Y + (ray.Direction.Y * k),
                               coord.Z));
                }

            case KdNodePlane.XZ:
                if (((coord.Y < ray.Position.Y) && (ray.Direction.Y > 0.0)) ||
                    ((coord.Y > ray.Position.Y) && (ray.Direction.Y < 0.0)))
                {
                    return(null);
                }
                else
                {
                    double k = (coord.Y - ray.Position.Y) / ray.Direction.Y;
                    return(new PosVector(
                               ray.Position.X + (ray.Direction.X * k),
                               coord.Y,
                               ray.Position.Z + (ray.Direction.Z * k)));
                }

            case KdNodePlane.YZ:
                if (((coord.X < ray.Position.X) && (ray.Direction.X > 0.0)) ||
                    ((coord.X > ray.Position.X) && (ray.Direction.X < 0.0)))
                {
                    return(null);
                }
                else
                {
                    double k = (coord.X - ray.Position.X) / ray.Direction.X;
                    return(new PosVector(
                               coord.X,
                               ray.Position.Y + (ray.Direction.Y * k),
                               ray.Position.Z + (ray.Direction.Z * k)));
                }

            default:
                throw new InvalidOperationException();
            }
        }
Ejemplo n.º 5
0
        private static (BoundingBox, BoundingBox) SplitBoundingBox(
            BoundingBox bbox,
            KdNodePlane plane,
            PosVector coord)
        {
            BoundingBox bboxLeft;
            BoundingBox bboxRight;

            switch (plane)
            {
            case KdNodePlane.XY:
                bboxLeft = new BoundingBox(
                    new Bound(bbox.BoxMin.X, bbox.BoxMax.X),
                    new Bound(bbox.BoxMin.Y, bbox.BoxMax.Y),
                    new Bound(bbox.BoxMin.Z, coord.Z));
                bboxRight = new BoundingBox(
                    new Bound(bbox.BoxMin.X, bbox.BoxMax.X),
                    new Bound(bbox.BoxMin.Y, bbox.BoxMax.Y),
                    new Bound(coord.Z, bbox.BoxMax.Z));
                break;

            case KdNodePlane.XZ:
                bboxLeft = new BoundingBox(
                    new Bound(bbox.BoxMin.X, bbox.BoxMax.X),
                    new Bound(bbox.BoxMin.Y, coord.Y),
                    new Bound(bbox.BoxMin.Z, bbox.BoxMax.Z));
                bboxRight = new BoundingBox(
                    new Bound(bbox.BoxMin.X, bbox.BoxMax.X),
                    new Bound(coord.Y, bbox.BoxMax.Y),
                    new Bound(bbox.BoxMin.Z, bbox.BoxMax.Z));
                break;

            case KdNodePlane.YZ:
                bboxLeft = new BoundingBox(
                    new Bound(bbox.BoxMin.X, coord.X),
                    new Bound(bbox.BoxMin.Y, bbox.BoxMax.Y),
                    new Bound(bbox.BoxMin.Z, bbox.BoxMax.Z));
                bboxRight = new BoundingBox(
                    new Bound(coord.X, bbox.BoxMax.X),
                    new Bound(bbox.BoxMin.Y, bbox.BoxMax.Y),
                    new Bound(bbox.BoxMin.Z, bbox.BoxMax.Z));
                break;

            default:
                throw new InvalidOperationException();
            }

            return(bboxLeft, bboxRight);
        }
Ejemplo n.º 6
0
        private ColorVector GetLightingColor(PosVector point, PosVector normal)
        {
            var lightColor = new ColorVector();

            foreach (var light in Scene.Lights)
            {
                // if not shaded
                if (IsViewable(light.Position, point))
                {
                    var lightVector = light.Position - point;
                    lightColor = lightColor + (light.Color * Math.Abs(PosVector.CosVectors(normal, lightVector)));
                }
            }

            return(lightColor);
        }
Ejemplo n.º 7
0
        private bool IsViewable(PosVector targetPoint, PosVector startingPoint)
        {
            var    dir        = targetPoint - startingPoint;
            double targetDist = dir.Magnitude();

            var intInfo = Scene.KdTree.FindIntersectionTree(new Ray(startingPoint, dir));

            if (intInfo.IsHit)
            {
                // check if intersection point is closer than target point
                return(targetDist < intInfo.Distance);
            }

            // ray doesn't intersect any of scene objects
            return(true);
        }
Ejemplo n.º 8
0
        public Camera(PosVector pos, PosVector lookAt, PosVector up, double fov)
        {
            Position = pos;
            LookAt   = lookAt;
            Up       = up;
            Fov      = fov;

            _a3 = (LookAt - Position).Normalize();
            _a1 = _a3.Cross(up).Normalize();
            _a2 = _a1.Cross(_a3).Normalize();
            var viewAngleRadians = Fov * 0.017453239;

            _dval = Math.Cos(viewAngleRadians / 2.0) / Math.Sin(viewAngleRadians / 2.0);

            _center = _a3 * _dval;
        }
Ejemplo n.º 9
0
        private ColorVector GetSpecularColor(Ray ray, double p)
        {
            var lightColor = new ColorVector();

            foreach (var light in Scene.Lights)
            {
                // if not shaded
                if (IsViewable(light.Position, ray.Position))
                {
                    var lightSourceVector = light.Position - ray.Position;
                    var cosLightSource    = PosVector.CosVectors(ray.Direction, lightSourceVector);
                    if (cosLightSource > double.Epsilon)
                    {
                        lightColor = lightColor * p; // + (light.Color * Math.Pow(cosLightSource, p));
                    }
                }
            }

            return(lightColor);
        }
Ejemplo n.º 10
0
 public BoundingBox(PosVector boxMin, PosVector boxMax)
 {
     BoxMin = boxMin;
     BoxMax = boxMax;
 }
Ejemplo n.º 11
0
 private static KdNode MakeLeaf(List <IShape> shapes)
 {
     return(new KdNode(KdNodePlane.NoPlane, PosVector.NewDefault(), shapes, null, null));
 }
Ejemplo n.º 12
0
        /*
         * Using Surface Area Heuristic (SAH) for finding best split pane
         * SAH = 0.5 * voxel_surface_area * number_of_objects_in_voxel
         * splitted_SAH = split_cost
         *                + 0.5 * left_voxel_surface_area * number_of_objects_in_left_voxel
         *                + 0.5 * right_voxel_surface_area * number_of_objects_in_right_voxel
         * Finding coordinate of split plane (XY, XZ or YZ) which minimizing SAH
         * If can't find optimal split plane - returns NONE
         * see: http://stackoverflow.com/a/4633332/653511
         */
        private static (KdNodePlane, PosVector) FindPlane(List <IShape> shapes, BoundingBox bbox, int depth)
        {
            var finalPlane = KdNodePlane.NoPlane;
            var finalPos   = PosVector.NewDefault();

            if (depth >= MaxTreeDepth || shapes.Count <= NumObjectsInLeaf)
            {
                return(KdNodePlane.NoPlane, PosVector.NewDefault());
            }

            double hx = bbox.BoxMax.X - bbox.BoxMin.X;
            double hy = bbox.BoxMax.Y - bbox.BoxMin.Y;
            double hz = bbox.BoxMax.Z - bbox.BoxMin.Z;

            // calculate square of each side of initial bounding box
            double sxy = hx * hy;
            double sxz = hx * hz;
            double syz = hy * hz;

            double ssum = sxy + sxz + syz;

            // normalize square of each side of initial bounding box to satisfy following relationship:
            // sxy + sxz + syz = 1
            sxy = sxy / ssum;
            sxz = sxz / ssum;
            syz = syz / ssum;

            int    maxSplits = 5; // max splits of bounding box
            double splitCost = 5.0;

            // assum that at beginning best SAH has initial bounding box
            // SAH = 0.5 * square * objectsCount
            // square of initial bounding box is sxy + sxz + syz = 1
            double bestSah = Convert.ToDouble(shapes.Count);

            // initial bounding box doesn't have split plane
            finalPlane = KdNodePlane.NoPlane;

            var currentSplitCoord = PosVector.NewDefault();

            // find split surface which have the least SAH

            // trying to minimize SAH by splitting across XY plane
            double sSplit    = sxy;
            double sNonSplit = sxz + syz;

            for (int i = 1; i < maxSplits; i++)
            {
                double l = Convert.ToDouble(i) / Convert.ToDouble(maxSplits);
                double r = 1.0 - l;

                // current coordinate of split surface
                currentSplitCoord = new PosVector(currentSplitCoord.X, currentSplitCoord.Y, bbox.BoxMin.Z + l * hz);

                var(vl, vr) = SplitBoundingBox(bbox, KdNodePlane.XY, currentSplitCoord);

                var currentSah = (sSplit + l * sNonSplit) * Convert.ToDouble(NumShapesInBoundingBox(shapes, vl)) +
                                 (sSplit + r * sNonSplit) * Convert.ToDouble(NumShapesInBoundingBox(shapes, vr)) +
                                 splitCost;

                if (currentSah < bestSah)
                {
                    bestSah    = currentSah;
                    finalPlane = KdNodePlane.XY;
                    finalPos   = currentSplitCoord;
                }
            }

            // trying to minimize SAH by splitting across XZ plane
            sSplit    = sxz;
            sNonSplit = sxy + syz;
            for (int i = 1; i < maxSplits; i++)
            {
                double l = Convert.ToDouble(i) / Convert.ToDouble(maxSplits);
                double r = 1.0 - l;

                // current coordinate of split surface
                currentSplitCoord = new PosVector(currentSplitCoord.X, bbox.BoxMin.Y + l * hy, currentSplitCoord.Z);

                var(vl, vr) = SplitBoundingBox(bbox, KdNodePlane.XZ, currentSplitCoord);

                var currentSah = (sSplit + l * sNonSplit) * Convert.ToDouble(NumShapesInBoundingBox(shapes, vl)) +
                                 (sSplit + r * sNonSplit) * Convert.ToDouble(NumShapesInBoundingBox(shapes, vr)) +
                                 splitCost;

                if (currentSah < bestSah)
                {
                    bestSah    = currentSah;
                    finalPlane = KdNodePlane.XZ;
                    finalPos   = currentSplitCoord;
                }
            }

            // trying to minimize SAH by splitting across YZ plane
            sSplit    = syz;
            sNonSplit = sxy + sxz;
            for (int i = 1; i < maxSplits; i++)
            {
                double l = Convert.ToDouble(i) / Convert.ToDouble(maxSplits);
                double r = 1.0 - l;

                // current coordinate of split surface
                currentSplitCoord = new PosVector(bbox.BoxMin.X + l * hy, currentSplitCoord.Y, currentSplitCoord.Z);

                var(vl, vr) = SplitBoundingBox(bbox, KdNodePlane.YZ, currentSplitCoord);

                var currentSah = (sSplit + l * sNonSplit) * Convert.ToDouble(NumShapesInBoundingBox(shapes, vl)) +
                                 (sSplit + r * sNonSplit) * Convert.ToDouble(NumShapesInBoundingBox(shapes, vr)) +
                                 splitCost;

                if (currentSah < bestSah)
                {
                    bestSah    = currentSah;
                    finalPlane = KdNodePlane.YZ;
                    finalPos   = currentSplitCoord;
                }
            }

            return(finalPlane, finalPos);
        }
Ejemplo n.º 13
0
 public SphereShape(PosVector position, double radius, BaseMaterial material) : base(position)
 {
     Radius    = radius;
     _material = material;
 }
Ejemplo n.º 14
0
        public static NffParserResult ParseFile(string path, int numThreads, int rayTraceDepth, int resolutionX,
                                                int resolutionY)
        {
            var background = new Background(new ColorVector(0.0, 0.0, 0.0), 0.0);
            var lights     = new List <Light>();
            var shapes     = new List <Shape>();
            var cameraAt   = PosVector.NewDefault();
            var cameraFrom = PosVector.NewDefault();
            var cameraUp   = PosVector.NewDefault();

            var lookingFor = LookingFor.Instruction;

            var currentMaterial = new SolidMaterial(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, new ColorVector(0.0, 0.0, 0.0));

            var polyVectors        = new List <PosVector>();
            var currentItemCounter = 0;

            var lines = File.ReadAllLines(path);

            foreach (var line in lines)
            {
                var split = line.Split(' ', '\t');

                switch (lookingFor)
                {
                case LookingFor.Instruction:
                {
                    var instruction = split[0];

                    if (instruction == "b")
                    {
                        // background color
                        background =
                            new Background(new ColorVector(double.Parse(split[1]), double.Parse(split[2]), double.Parse(split[3])),
                                           0.0);
                    }
                    else if (instruction == "v")
                    {
                        // viewpoint location
                        lookingFor = LookingFor.ViewpointFrom;
                    }
                    else if (instruction == "l")
                    {
                        // positional light
                        var colorVector = split.Length == 7
                ? new ColorVector(double.Parse(split[4]), double.Parse(split[5]), double.Parse(split[6]))
                : new ColorVector(1.0, 1.0, 1.0);
                        lights.Add(
                            new PointLight(new PosVector(double.Parse(split[1]), double.Parse(split[2]), double.Parse(split[3])),
                                           colorVector));
                    }
                    else if (instruction == "f")
                    {
                        // println!("reading f: {}", num);
                        // object material properties
                        // "f" red green blue Kd Ks Shine T index_of_refraction
                        // Kd Diffuse component
                        // Ks Specular
                        // Shine Phong cosine power for highlights
                        // T Transmittance (fraction of contribution of the transmitting ray).
                        // Usually, 0 <= Kd <= 1 and 0 <= Ks <= 1, though it is not required that Kd + Ks = 1. Note that transmitting objects (T > 0) are considered to have two sides for algorithms that need these (normally, objects have one side).
                        // todo: i don't think i'm assigning the correct values into my solidmaterial yet
                        currentMaterial = new SolidMaterial(
                            0.0,                    // kAmbient
                            double.Parse(split[4]), // kDiffuse
                            double.Parse(split[5]), // kSpecular
                            double.Parse(split[7]), // kReflection
                            double.Parse(split[8]), // kTransparent
                            double.Parse(split[8]), // refraction    -- todo: which is which here?
                            double.Parse(split[6]), // gloss
                            new ColorVector(double.Parse(split[1]), double.Parse(split[2]), double.Parse(split[3]))
                            );
                    }
                    else if (instruction == "c")
                    {
                        // cone or cylinder
                    }
                    else if (instruction == "s")
                    {
                        // sphere
                        shapes.Add(new SphereShape(
                                       new PosVector(double.Parse(split[1]), double.Parse(split[2]), double.Parse(split[3])),
                                       double.Parse(split[4]),
                                       currentMaterial
                                       ));
                    }
                    else if (instruction == "p")
                    {
                        // polygon
                        currentItemCounter = int.Parse(split[1]);
                        polyVectors        = new List <PosVector>();
                        lookingFor         = LookingFor.Polygon;
                    }
                    else if (instruction == "pp")
                    {
                        // polygon patch
                    }
                    else if (instruction == "#")
                    {
                        // comment
                    }
                }
                break;

                case LookingFor.Polygon:
                {
                    if (currentItemCounter > 0)
                    {
                        currentItemCounter--;
                        polyVectors.Add(new PosVector(double.Parse(split[0]), double.Parse(split[1]), double.Parse(split[2])));
                    }

                    if (currentItemCounter == 0)
                    {
                        if (polyVectors.Count >= 3)
                        {
                            var firstVert = polyVectors[0];
                            var prevVert  = polyVectors[1];
                            var thisVert  = polyVectors[2];
                            shapes.Add(new TriangleShape(firstVert, prevVert, thisVert, currentMaterial, currentMaterial));

                            for (var i = 3; i < polyVectors.Count; i++)
                            {
                                prevVert = thisVert;
                                thisVert = polyVectors[i];
                                shapes.Add(new TriangleShape(firstVert, prevVert, thisVert, currentMaterial, currentMaterial));
                            }
                        }

                        lookingFor = LookingFor.Instruction;
                    }
                }
                break;

                case LookingFor.ViewpointFrom:
                {
                    cameraFrom = new PosVector(double.Parse(split[1]), double.Parse(split[2]), double.Parse(split[3]));
                    lookingFor = LookingFor.ViewpointAt;
                }
                break;

                case LookingFor.ViewpointAt:
                {
                    cameraAt   = new PosVector(double.Parse(split[1]), double.Parse(split[2]), double.Parse(split[3]));
                    lookingFor = LookingFor.ViewpointUp;
                }
                break;

                case LookingFor.ViewpointUp:
                {
                    cameraUp   = new PosVector(double.Parse(split[1]), double.Parse(split[2]), double.Parse(split[3]));
                    lookingFor = LookingFor.ViewpointAngle;
                }
                break;

                case LookingFor.ViewpointAngle:
                {
                    // todo: implement
                    lookingFor = LookingFor.ViewpointHither;
                }
                break;

                case LookingFor.ViewpointHither:
                {
                    // todo: implement
                    lookingFor = LookingFor.ViewpointResolution;
                }
                break;

                case LookingFor.ViewpointResolution:
                {
                    //resolutionX = int.Parse(split[1]);
                    //resolutionY = int.Parse(split[2]);

                    lookingFor = LookingFor.Instruction;
                }
                break;
                }
            }

            return(new NffParserResult(Scene.Create(background, shapes, lights),
                                       new RenderData(resolutionX, resolutionY, rayTraceDepth, numThreads, true),
                                       new Camera(cameraFrom, cameraAt, cameraUp, 50.0)));
        }
Ejemplo n.º 15
0
 public static double CosVectors(PosVector v1, PosVector v2)
 {
     return(v1.Dot(v2) / Math.Sqrt(v1.MagnitudeSquared() * v2.MagnitudeSquared()));
 }
Ejemplo n.º 16
0
 public PosVector AddScaled(PosVector b, double scale)
 {
     return(new PosVector(X + scale * b.X, Y + scale * b.Y, Z + scale * b.Z));
 }
Ejemplo n.º 17
0
 public PosVector Cross(PosVector b)
 {
     return(new PosVector(Y * b.Z - Z * b.Y, Z * b.X - X * b.Z, X * b.Y - Y * b.X));
 }
Ejemplo n.º 18
0
 public double Dot(PosVector b)
 {
     return(X * b.X + Y * b.Y + Z * b.Z);
 }
Ejemplo n.º 19
0
 public bool IsPointInside(PosVector pos)
 {
     return(IsWithinX(pos.X) &&
            IsWithinY(pos.Y) &&
            IsWithinZ(pos.Z));
 }
Ejemplo n.º 20
0
 private Ray ReflectRay(Ray sourceRay, PosVector normal)
 {
     return(new Ray(
                sourceRay.Position,
                sourceRay.Direction + normal * 2.0 * -normal.Dot(sourceRay.Direction)));
 }
Ejemplo n.º 21
0
        private Ray GetReflectionRay(PosVector p, PosVector n, PosVector v)
        {
            var rl = v + n * 2.0 * -n.Dot(v);

            return(new Ray(p, rl));
        }