예제 #1
0
파일: KdTree.cs 프로젝트: MarkZuber/raynet
 private static KdNode MakeLeaf(List <IShape> shapes)
 {
     return(new KdNode(KdNodePlane.NoPlane, PosVector.NewDefault(), shapes, null, null));
 }
예제 #2
0
파일: KdTree.cs 프로젝트: MarkZuber/raynet
        /*
         * 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);
        }
예제 #3
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)));
        }