Example #1
0
File: CSG.cs Project: langerv/osm
        /// <summary>
        /// Cube function, Untested but compiles
        /// </summary>
        /// <param name="center">world space center of the cube</param>
        /// <param name="radius">size of the cube created at center</param>
        /// <returns></returns>
        public static CSG cube(Vector3?center, Vector3?radius)
        {
            Vector3 c = center.GetValueOrDefault(Vector3.Zero);
            Vector3 r = radius.GetValueOrDefault(Vector3.One);

            //TODO: Test if this works
            CsgPolygon[] polygons = new CsgPolygon[6];
            int[][][]    data     = new int[][][] {
                new int[][] { new int[] { 0, 4, 6, 2 }, new int[] { -1, 0, 0 } },
                new int[][] { new int[] { 1, 3, 7, 5 }, new int[] { 1, 0, 0 } },
                new int[][] { new int[] { 0, 1, 5, 4 }, new int[] { 0, -1, 0 } },
                new int[][] { new int[] { 2, 6, 7, 3 }, new int[] { 0, 1, 0 } },
                new int[][] { new int[] { 0, 2, 3, 1 }, new int[] { 0, 0, -1 } },
                new int[][] { new int[] { 4, 5, 7, 6 }, new int[] { 0, 0, 1 } }
            };
            for (int x = 0; x < 6; x++)
            {
                int[][] v      = data[x];
                Vector3 normal = new Vector3(v[1][0], v[1][1], v[1][2]);

                IVertex[] verts = new IVertex[4];
                for (int i = 0; i < 4; i++)
                {
                    verts[i] = new Vertex(
                        new Vector3(
                            c.X + (r.X * (2 * (((v[0][i] & 1) > 0) ? 1 : 0) - 1)),
                            c.Y + (r.Y * (2 * (((v[0][i] & 2) > 0) ? 1 : 0) - 1)),
                            c.Z + (r.Z * (2 * (((v[0][i] & 4) > 0) ? 1 : 0) - 1))),
                        normal
                        );
                }
                polygons[x] = new CsgPolygon(verts);
            }
            return(CSG.fromPolygons(polygons));
        }
Example #2
0
        /// <summary>
        /// Creates a Polygon from an array of points.
        /// </summary>
        /// <param name="points"></param>
        /// <param name="shared"></param>
        /// <returns></returns>
        public static CsgPolygon createPolygon(Vector3[] points, System.Object shared = null)
        {
            if (points.Length < 2)
            {
                return(null);
            }

            List <IVertex> vertices = new List <IVertex>();

            foreach (Vector3 pos in points)
            {
                vertices.Add(new Vertex(pos));
            }
            CsgPolygon polygon = new CsgPolygon(vertices, shared);

            return(polygon);
        }
Example #3
0
        /// <summary>
        /// Extrudes a polygon.
        /// </summary>
        /// <param name="polygon">The polygon to extrude</param>
        /// <param name="distance">Extrusion distance</param>
        /// <param name="normal">Optional normal to extrude along, default is polygon normal</param>
        /// <returns></returns>
        public static List <CsgPolygon> extrudePolygon(CsgPolygon polygon, float distance, Vector3?normal = null)
        {
            normal = normal != null ? normal : polygon.plane.normal;

            Vector3 du = normal.GetValueOrDefault();

            IVertex[]         vertices  = polygon.vertices;
            List <IVertex>    top       = new List <IVertex>();
            List <IVertex>    bot       = new List <IVertex>();
            List <CsgPolygon> polygons  = new List <CsgPolygon>();
            Vector3           invNormal = normal.GetValueOrDefault();

            du        *= distance;
            invNormal *= -1f;

            for (int i = 0; i < vertices.Length; i++)
            {
                int        j     = (i + 1) % vertices.Length;
                Vector3    p1    = vertices[i].pos;
                Vector3    p2    = vertices[j].pos;
                Vector3    p3    = p2 + du;
                Vector3    p4    = p1 + du;
                Plane      plane = Plane.fromPoints(p1, p2, p3);
                Vertex     v1    = new Vertex(p1, plane.normal);
                Vertex     v2    = new Vertex(p2, plane.normal);
                Vertex     v3    = new Vertex(p3, plane.normal);
                Vertex     v4    = new Vertex(p4, plane.normal);
                CsgPolygon poly  = new CsgPolygon(new List <IVertex>(new IVertex[] { v1, v2, v3, v4 }), polygon.shared);
                polygons.Add(poly);
                top.Add(new Vertex(p4, normal.GetValueOrDefault()));
                bot.Insert(0, new Vertex(p1, invNormal));
            }

            polygons.Add(new CsgPolygon(top, polygon.shared));
            polygons.Add(new CsgPolygon(bot, polygon.shared));

            return(polygons);
        }
Example #4
0
        /// <summary>
        /// Split `polygon` by this plane if needed, then put the polygon or polygon
        /// fragments in the appropriate lists. Coplanar polygons go into either
        /// `coplanarFront` or `coplanarBack` depending on their orientation with
        /// respect to this plane. Polygons in front or in back of this plane go into
        /// either `front` or `back`
        /// </summary>
        /// <param name="polygon"></param>
        /// <param name="coplanarFront"></param>
        /// <param name="coplanarBack"></param>
        /// <param name="front"></param>
        /// <param name="back"></param>
        public void splitPolygon(CsgPolygon polygon,
                                 ref List <CsgPolygon> coplanarFront,
                                 ref List <CsgPolygon> coplanarBack,
                                 ref List <CsgPolygon> front,
                                 ref List <CsgPolygon> back)
        {
            //Debug.Log("splitPolygon: " + polygon.vertices[0].pos + ", " + polygon.vertices[1].pos + ", " + polygon.vertices[2].pos);

            IVertex[]  vertices    = polygon.vertices;
            int        polygonType = 0;
            List <int> types       = new List <int>();
            int        type;
            double     t;
            int        i;

            for (i = 0; i < vertices.Length; i++)
            {
                t = Vector3.Dot(this.normal, vertices[i].pos) - this.w;
                if (t < -Plane.EPSILON)
                {
                    type = BACK;
                }
                else if (t > Plane.EPSILON)
                {
                    type = FRONT;
                }
                else
                {
                    type = COPLANAR;
                }
                polygonType |= type;
                types.Add(type);
            }

            // Put the polygon in the correct list, splitting it when necessary.
            switch (polygonType)
            {
            case COPLANAR:
                if (Vector3.Dot(this.normal, polygon.plane.normal) > 0)
                {
                    coplanarFront.Add(polygon);
                }
                else
                {
                    coplanarBack.Add(polygon);
                }
                break;

            case FRONT:
                front.Add(polygon);
                break;

            case BACK:
                back.Add(polygon);
                break;

            default:
            case SPANNING:
                List <IVertex> f = new List <IVertex>();
                List <IVertex> b = new List <IVertex>();
                for (i = 0; i < vertices.Length; i++)
                {
                    int     j  = (i + 1) % vertices.Length;
                    int     ti = types[i];
                    int     tj = types[j];
                    IVertex vi = vertices[i];
                    IVertex vj = vertices[j];
                    if (ti != BACK)
                    {
                        f.Add(vi);
                    }
                    if (ti != FRONT)
                    {
                        b.Add(ti != BACK ? vi.clone() : vi);
                    }
                    if ((ti | tj) == SPANNING)
                    {
                        t = (this.w - Vector3.Dot(this.normal, vi.pos)) / Vector3.Dot(this.normal, vj.pos - vi.pos);
                        IVertex v = vi.interpolate(vj, t);
                        f.Add(v);
                        b.Add(v.clone());
                    }
                }

                if (f.Count >= 3)
                {
                    front.Add(new CsgPolygon(f, polygon.shared));
                }

                if (b.Count >= 3)
                {
                    back.Add(new CsgPolygon(b, polygon.shared));
                }
                break;
            }
        }
Example #5
0
File: CSG.cs Project: langerv/osm
        public Mesh toMesh()
        {
            List <CsgPolygon> trisFromPolygons = new List <CsgPolygon>();

            // triangulate polygons
            for (int i = this.polygons.Count - 1; i >= 0; i--)
            {
                if (this.polygons[i].vertices.Length > 3)
                {
                    for (int vi = 1; vi < this.polygons[i].vertices.Length - 1; vi++)
                    {
                        IVertex[] tri = new IVertex[] {
                            this.polygons[i].vertices[0],
                            this.polygons[i].vertices[vi],
                            this.polygons[i].vertices[vi + 1]
                        };
                        trisFromPolygons.Add(new CsgPolygon(tri));
                    }
                    // the original polygon is replaced by a set of triangles
                    this.polygons.RemoveAt(i);
                }
            }
            this.polygons.AddRange(trisFromPolygons);

            // TODO: Simplify mesh - the boolean CSG algorithm leaves lots of coplanar
            //       polygons that share an edge that could be simplified.

            // At this point, we have a soup of triangles without regard for shared vertices.
            // We index these to combine any vertices with identical positions & normals
            // (and maybe later UVs & vertex colors)

            List <Vertex> vertices = new List <Vertex>();

            int[] tris = new int[this.polygons.Count * 3];
            for (int pi = 0; pi < this.polygons.Count; pi++)
            {
                CsgPolygon tri = this.polygons[pi];
                for (int vi = 0; vi < 3; vi++)
                {
                    Vertex vertex = tri.vertices[vi] as Vertex;
                    bool   equivalentVertexAlreadyInList = false;
                    for (int i = 0; i < vertices.Count; i++)
                    {
                        if (MathHelper.AlmostEqual(vertices[i].pos, vertex.pos) &&
                            MathHelper.AlmostEqual(vertices[i].normal, vertex.normal))
                        {
                            equivalentVertexAlreadyInList = true;
                            vertex.index = vertices[i].index;
                        }
                    }
                    if (!equivalentVertexAlreadyInList)
                    {
                        vertices.Add(vertex);
                        vertex.index = vertices.Count - 1;
                    }
                    tris[(pi * 3) + vi] = vertex.index;
                }
            }

            Vector3[] verts   = new Vector3[this.polygons.Count * 3];
            Vector3[] normals = new Vector3[this.polygons.Count * 3];
            Mesh      m       = new Mesh();

            for (int i = 0; i < vertices.Count; i++)
            {
                verts[i]   = vertices[i].pos;
                normals[i] = vertices[i].normal;
            }
            m.Vertices = verts;
            m.Normals  = normals;
            m.Faces    = tris;
            //m.RecalculateBounds();
            //m.RecalculateNormals();
            //m.Optimize();
            return(m);
        }