コード例 #1
0
        public static MeshDraft BaselessPyramid(Vector3 baseCenter, Vector3 apex, float radius, int segments,
                                                bool inverted = false)
        {
            float segmentAngle = Mathf.PI * 2 / segments * (inverted ? -1 : 1);
            float currentAngle = 0f;

            var vertices = new Vector3[segments + 1];

            vertices[0] = apex;
            for (var i = 1; i <= segments; i++)
            {
                vertices[i]   = PTUtils.PointOnCircle3(radius, currentAngle) + baseCenter;
                currentAngle += segmentAngle;
            }

            var draft = new MeshDraft {
                name = "BaselessPyramid"
            };

            for (var i = 1; i < segments; i++)
            {
                draft.Add(Triangle(vertices[0], vertices[i], vertices[i + 1]));
            }
            draft.Add(Triangle(vertices[0], vertices[vertices.Length - 1], vertices[1]));
            return(draft);
        }
コード例 #2
0
        public void Simulate()
        {
            PTUtils.Swap(ref _cells, ref copy);
            for (int x = 0; x < config.width; x++)
            {
                for (int y = 0; y < config.height; y++)
                {
                    int aliveCells = CountAliveNeighbourCells(x, y);

                    if (!copy[x, y])
                    {
                        if (config.ruleset.CanSpawn(aliveCells))
                        {
                            cells[x, y] = true;
                        }
                        else
                        {
                            cells[x, y] = false;
                        }
                    }
                    else
                    {
                        if (!config.ruleset.CanSurvive(aliveCells))
                        {
                            cells[x, y] = false;
                        }
                        else
                        {
                            cells[x, y] = true;
                        }
                    }
                }
            }
        }
コード例 #3
0
        /// <summary>
        /// Constructs a icosahedron draft
        /// </summary>
        public static MeshDraft Icosahedron(float radius, bool generateUV = true)
        {
            const float magicAngle   = 26.56505f;
            const float segmentAngle = 72;

            float lowerAngle = 0;
            float upperAngle = segmentAngle / 2;

            var lowerRing = new Vector3[5];
            var upperRing = new Vector3[5];

            for (var i = 0; i < 5; i++)
            {
                lowerRing[i] = PTUtils.PointOnSphere(radius, lowerAngle, -magicAngle);
                upperRing[i] = PTUtils.PointOnSphere(radius, upperAngle, magicAngle);
                lowerAngle  += segmentAngle;
                upperAngle  += segmentAngle;
            }

            var draft = new MeshDraft {
                name = "Icosahedron"
            }
            .AddBaselessPyramid(new Vector3(0, radius, 0), upperRing, generateUV)
            .AddFlatTriangleBand(lowerRing, upperRing, generateUV)
            .AddBaselessPyramid(new Vector3(0, -radius, 0), lowerRing, generateUV, true);

            return(draft);
        }
コード例 #4
0
        /// <summary>
        /// Constructs a pyramid draft
        /// </summary>
        public static MeshDraft Pyramid(float radius, int segments, float height, bool generateUV = true)
        {
            float segmentAngle = 360f / segments;
            float currentAngle = 0;

            var ring = new Vector3[segments];

            for (var i = 0; i < segments; i++)
            {
                ring[i]       = PTUtils.PointOnCircle3XZ(radius, currentAngle);
                currentAngle += segmentAngle;
            }

            var draft = new MeshDraft().AddBaselessPyramid(Vector3.up * height, ring, generateUV);

            if (generateUV)
            {
                var fanUV = new Vector2[segments];
                currentAngle = 0;
                for (var i = 0; i < segments; i++)
                {
                    Vector2 uv = PTUtils.PointOnCircle2(0.5f, currentAngle) + new Vector2(0.5f, 0.5f);
                    uv.x          = 1 - uv.x;
                    fanUV[i]      = uv;
                    currentAngle += segmentAngle;
                }
                draft.AddTriangleFan(ring, Vector3.down, fanUV, true);
            }
            else
            {
                draft.AddTriangleFan(ring, Vector3.down, true);
            }
            draft.name = "Pyramid";
            return(draft);
        }
コード例 #5
0
        /// <summary>
        /// Constructs a dodecahedron draft
        /// </summary>
        public static MeshDraft Dodecahedron(float radius)
        {
            const float magicAngle1  = 52.62263590f;
            const float magicAngle2  = 10.81231754f;
            const float segmentAngle = 72;

            float lowerAngle = 0;
            float upperAngle = segmentAngle / 2;

            var lowerCap  = new Vector3[5];
            var lowerRing = new Vector3[5];
            var upperCap  = new Vector3[5];
            var upperRing = new Vector3[5];

            for (var i = 0; i < 5; i++)
            {
                lowerCap[i]  = PTUtils.PointOnSphere(radius, lowerAngle, -magicAngle1);
                lowerRing[i] = PTUtils.PointOnSphere(radius, lowerAngle, -magicAngle2);
                upperCap[i]  = PTUtils.PointOnSphere(radius, upperAngle, magicAngle1);
                upperRing[i] = PTUtils.PointOnSphere(radius, upperAngle, magicAngle2);
                lowerAngle  += segmentAngle;
                upperAngle  += segmentAngle;
            }

            var draft = new MeshDraft {
                name = "Dodecahedron"
            }
            .AddTriangleFan(upperCap, Vector3.up)
            .AddFlatTriangleBand(upperRing, upperCap, false)
            .AddFlatTriangleBand(lowerRing, upperRing, false)
            .AddFlatTriangleBand(lowerCap, lowerRing, false)
            .AddTriangleFan(lowerCap, Vector3.down, true);

            return(draft);
        }
コード例 #6
0
        /// <summary>
        /// Constructs a tetrahedron draft
        /// </summary>
        public static MeshDraft Tetrahedron(float radius, bool generateUV = true)
        {
            const float tetrahedralAngle = -19.471220333f;

            var vertex0 = new Vector3(0, radius, 0);
            var vertex1 = PTUtils.PointOnSphere(radius, 0, tetrahedralAngle);
            var vertex2 = PTUtils.PointOnSphere(radius, 120, tetrahedralAngle);
            var vertex3 = PTUtils.PointOnSphere(radius, 240, tetrahedralAngle);

            var draft = new MeshDraft {
                name = "Tetrahedron"
            };

            if (generateUV)
            {
                var uv0 = new Vector2(0, 0);
                var uv1 = new Vector2(0.5f, 1);
                var uv2 = new Vector2(1, 0);
                draft.AddTriangle(vertex2, vertex0, vertex1, uv0, uv1, uv2)
                .AddTriangle(vertex2, vertex1, vertex3, uv0, uv1, uv2)
                .AddTriangle(vertex3, vertex0, vertex2, uv0, uv1, uv2)
                .AddTriangle(vertex1, vertex0, vertex3, uv0, uv1, uv2);
            }
            else
            {
                draft.AddTriangle(vertex2, vertex0, vertex1)
                .AddTriangle(vertex2, vertex1, vertex3)
                .AddTriangle(vertex3, vertex0, vertex2)
                .AddTriangle(vertex1, vertex0, vertex3);
            }
            return(draft);
        }
コード例 #7
0
        public static MeshDraft Icosahedron(float radius)
        {
            float magicAngle   = Mathf.PI * 26.56505f / 180;
            float segmentAngle = Mathf.PI * 72 / 180;

            float currentAngle = 0f;
            var   upperRing    = new List <Vector3>(5);

            for (var i = 0; i < 5; i++)
            {
                upperRing.Add(PTUtils.PointOnSphere(radius, currentAngle, magicAngle));
                currentAngle -= segmentAngle;
            }

            currentAngle = segmentAngle / 2;
            var lowerRing = new List <Vector3>(5);

            for (var i = 0; i < 5; i++)
            {
                lowerRing.Add(PTUtils.PointOnSphere(radius, currentAngle, -magicAngle));
                currentAngle -= segmentAngle;
            }

            var draft = BaselessPyramid(new Vector3(0, -radius, 0), lowerRing);

            draft.Add(FlatBand(lowerRing, upperRing));
            upperRing.Reverse();
            draft.Add(BaselessPyramid(new Vector3(0, radius, 0), upperRing));
            draft.name = "Icosahedron";
            return(draft);
        }
コード例 #8
0
        /// <summary>
        /// Computes an intersection of the line and the sphere
        /// </summary>
        public static bool IntersectLineSphere(Vector3 origin, Vector3 direction, Vector3 center, float radius,
                                               out Vector3 pointA, out Vector3 pointB)
        {
            Vector3 toCenter          = center - origin;
            float   toCenterOnLine    = Vector3.Dot(toCenter, direction);
            float   sqrDistanceToLine = toCenter.sqrMagnitude - toCenterOnLine * toCenterOnLine;

            float sqrRadius = radius * radius;

            if (sqrDistanceToLine > sqrRadius)
            {
                pointA = Vector3.zero;
                pointB = Vector3.zero;
                return(false);
            }
            float fromClosestPointToIntersection = Mathf.Sqrt(sqrRadius - sqrDistanceToLine);
            float intersectionA = toCenterOnLine - fromClosestPointToIntersection;
            float intersectionB = toCenterOnLine + fromClosestPointToIntersection;

            if (intersectionA > intersectionB)
            {
                PTUtils.Swap(ref intersectionA, ref intersectionB);
            }

            pointA = origin + intersectionA * direction;
            pointB = origin + intersectionB * direction;
            return(true);
        }
コード例 #9
0
ファイル: Draw.cs プロジェクト: daidaima/study
        /// <summary>
        /// Draws a wireframe cone with position and rotation
        /// </summary>
        public static void WireCone(DebugDrawLine drawLine, Vector3 position, Quaternion rotation, float apexRadius, float angle, float length,
                                    Color color, float duration, bool depthTest)
        {
            Vector3 upperCenter = position + rotation * Vector3.up * length;
            float   upperRadius = Mathf.Tan(angle * Mathf.Deg2Rad) * length + apexRadius;

            WireCircleXZ(drawLine, upperCenter, rotation, upperRadius, color, duration, depthTest);

            Vector3 a2 = upperCenter + rotation * PTUtils.PointOnCircle3XZ(upperRadius, 0);
            Vector3 b2 = upperCenter + rotation * PTUtils.PointOnCircle3XZ(upperRadius, 90);
            Vector3 c2 = upperCenter + rotation * PTUtils.PointOnCircle3XZ(upperRadius, 180);
            Vector3 d2 = upperCenter + rotation * PTUtils.PointOnCircle3XZ(upperRadius, 270);

            if (apexRadius == 0)
            {
                drawLine(position, a2, color, duration, depthTest);
                drawLine(position, b2, color, duration, depthTest);
                drawLine(position, c2, color, duration, depthTest);
                drawLine(position, d2, color, duration, depthTest);
            }
            else
            {
                WireCircleXZ(drawLine, position, rotation, apexRadius, color, duration, depthTest);

                Vector3 a1 = position + rotation * PTUtils.PointOnCircle3XZ(apexRadius, 0);
                Vector3 b1 = position + rotation * PTUtils.PointOnCircle3XZ(apexRadius, 90);
                Vector3 c1 = position + rotation * PTUtils.PointOnCircle3XZ(apexRadius, 180);
                Vector3 d1 = position + rotation * PTUtils.PointOnCircle3XZ(apexRadius, 270);

                drawLine(a1, a2, color, duration, depthTest);
                drawLine(b1, b2, color, duration, depthTest);
                drawLine(c1, c2, color, duration, depthTest);
                drawLine(d1, d2, color, duration, depthTest);
            }
        }
コード例 #10
0
ファイル: Draw.cs プロジェクト: daidaima/study
        /// <summary>
        /// Draws a wireframe cone with position and rotation
        /// </summary>
        public static void WireCone(Action <Vector3, Vector3> drawLine, Vector3 position, Quaternion rotation, float apexRadius, float angle,
                                    float length)
        {
            Vector3 baseCenter = position + rotation * Vector3.up * length;
            float   baseRadius = Mathf.Tan(angle * Mathf.Deg2Rad) * length + apexRadius;

            WireCircleXZ(drawLine, baseCenter, rotation, baseRadius);

            Vector3 a2 = baseCenter + rotation * PTUtils.PointOnCircle3XZ(baseRadius, 0);
            Vector3 b2 = baseCenter + rotation * PTUtils.PointOnCircle3XZ(baseRadius, 90);
            Vector3 c2 = baseCenter + rotation * PTUtils.PointOnCircle3XZ(baseRadius, 180);
            Vector3 d2 = baseCenter + rotation * PTUtils.PointOnCircle3XZ(baseRadius, 270);

            if (apexRadius == 0)
            {
                drawLine(position, a2);
                drawLine(position, b2);
                drawLine(position, c2);
                drawLine(position, d2);
            }
            else
            {
                WireCircleXZ(drawLine, position, rotation, apexRadius);

                Vector3 a1 = position + rotation * PTUtils.PointOnCircle3XZ(apexRadius, 0);
                Vector3 b1 = position + rotation * PTUtils.PointOnCircle3XZ(apexRadius, 90);
                Vector3 c1 = position + rotation * PTUtils.PointOnCircle3XZ(apexRadius, 180);
                Vector3 d1 = position + rotation * PTUtils.PointOnCircle3XZ(apexRadius, 270);

                drawLine(a1, a2);
                drawLine(b1, b2);
                drawLine(c1, c2);
                drawLine(d1, d2);
            }
        }
コード例 #11
0
        public static MeshDraft Cylinder(float radius, int segments, float heignt)
        {
            float segmentAngle = 360f / segments;
            float currentAngle = 0;

            var lowerRing = new List <Vector3>(segments);
            var upperRing = new List <Vector3>(segments);

            for (var i = 0; i < segments; i++)
            {
                var point = PTUtils.PointOnCircle3XZ(radius, currentAngle);
                lowerRing.Add(point - Vector3.up * heignt / 2);
                upperRing.Add(point + Vector3.up * heignt / 2);
                currentAngle -= segmentAngle;
            }

            var draft = new MeshDraft {
                name = "Cylinder"
            }
            .AddTriangleFan(lowerRing)
            .Add(Band(lowerRing, upperRing));

            upperRing.Reverse();
            draft.AddTriangleFan(upperRing);
            return(draft);
        }
コード例 #12
0
        /// <summary>
        /// Draws aliased line and calls <paramref name="draw"/> on every pixel
        /// </summary>
        /// <remarks>
        /// https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm
        /// </remarks>
        public static void RasterLine(int x0, int y0, int x1, int y1, Action <int, int> draw)
        {
            bool steep = Math.Abs(y1 - y0) > Math.Abs(x1 - x0);

            if (steep)
            {
                PTUtils.Swap(ref x0, ref y0);
                PTUtils.Swap(ref x1, ref y1);
            }
            if (x0 > x1)
            {
                PTUtils.Swap(ref x0, ref x1);
                PTUtils.Swap(ref y0, ref y1);
            }

            int dx    = x1 - x0;
            int dy    = Math.Abs(y1 - y0);
            int error = dx / 2;
            int ystep = (y0 < y1) ? 1 : -1;
            int y     = y0;

            for (int x = x0; x <= x1; x++)
            {
                draw(steep ? y : x, steep ? x : y);
                error -= dy;
                if (error < 0)
                {
                    y     += ystep;
                    error += dx;
                }
            }
        }
コード例 #13
0
        public static MeshDraft FlatSphere(float radius, int longitudeSegments, int latitudeSegments)
        {
            float longitudeSegmentAngle = Mathf.PI * 2 / longitudeSegments;
            float latitudeSegmentAngle  = Mathf.PI / latitudeSegments;

            float currentLatitude = -Mathf.PI / 2;
            var   rings           = new List <List <Vector3> >(latitudeSegments);

            for (var i = 0; i <= latitudeSegments; i++)
            {
                var currentLongitude = 0f;
                var ring             = new List <Vector3>(longitudeSegments);
                for (int j = 0; j < longitudeSegments; j++)
                {
                    ring.Add(PTUtils.PointOnSphere(radius, currentLongitude, currentLatitude));
                    currentLongitude -= longitudeSegmentAngle;
                }
                rings.Add(ring);
                currentLatitude += latitudeSegmentAngle;
            }

            var draft = new MeshDraft {
                name = "Flat sphere"
            };

            for (int i = 0; i < rings.Count - 1; i++)
            {
                draft.Add(FlatBand(rings[i], rings[i + 1]));
            }
            return(draft);
        }
コード例 #14
0
        /// <summary>
        /// Constructs a cylinder draft
        /// </summary>
        public static MeshDraft Cylinder(float radius, int segments, float height, bool generateUV = true)
        {
            float   segmentAngle = 360f / segments;
            float   currentAngle = 0;
            Vector3 halfHeightUp = Vector3.up * height / 2;

            var draft = new MeshDraft {
                name = "Cylinder"
            };
            var lowerRing    = new List <Vector3>(segments);
            var lowerDiskUV  = new List <Vector2>();
            var upperRing    = new List <Vector3>(segments);
            var upperDiskUV  = new List <Vector2>();
            var strip        = new List <Vector3>();
            var stripNormals = new List <Vector3>();
            var stripUV      = new List <Vector2>();

            for (var i = 0; i < segments; i++)
            {
                Vector3 lowerVertex;
                Vector3 upperVertex;
                AddCylinderPoints(radius, currentAngle, halfHeightUp, generateUV,
                                  ref strip, ref stripUV, ref stripNormals, out lowerVertex, out upperVertex);

                lowerRing.Add(lowerVertex);
                upperRing.Add(upperVertex);
                if (generateUV)
                {
                    Vector2 uv = PTUtils.PointOnCircle2(0.5f, currentAngle) + new Vector2(0.5f, 0.5f);
                    upperDiskUV.Add(uv);
                    uv.x = 1 - uv.x;
                    lowerDiskUV.Add(uv);
                }
                currentAngle += segmentAngle;
            }

            Vector3 lowerSeamVertex;
            Vector3 upperSeamVertex;

            AddCylinderPoints(radius, currentAngle, halfHeightUp, generateUV,
                              ref strip, ref stripUV, ref stripNormals, out lowerSeamVertex, out upperSeamVertex);

            if (generateUV)
            {
                draft.AddTriangleFan(lowerRing, Vector3.down, lowerDiskUV, true);
                draft.AddTriangleFan(upperRing, Vector3.up, upperDiskUV);
                draft.AddTriangleStrip(strip, stripNormals, stripUV);
            }
            else
            {
                draft.AddTriangleFan(lowerRing, Vector3.down, true);
                draft.AddTriangleFan(upperRing, Vector3.up);
            }
            return(draft);
        }
コード例 #15
0
 /// <summary>
 /// Reverses winding order of mesh triangles
 /// </summary>
 public static void FlipTriangles(this Mesh mesh)
 {
     for (int i = 0; i < mesh.subMeshCount; i++)
     {
         var triangles = mesh.GetTriangles(i);
         for (int j = 0; j < triangles.Length; j += 3)
         {
             PTUtils.Swap(ref triangles[j], ref triangles[j + 1]);
         }
         mesh.SetTriangles(triangles, i);
     }
 }
コード例 #16
0
 public static void DrawLine(this Texture2D texture, int x0, int y0, int x1, int y1, Color color, bool AA = false)
 {
     if (AA)
     {
         Action <int, int, float> draw =
             (x, y, t) => texture.SetPixel(x, y, Color.Lerp(texture.GetPixel(x, y), color, t));
         PTUtils.WuLine(x0, y0, x1, y1, draw);
     }
     else
     {
         Action <int, int> draw = (x, y) => texture.SetPixel(x, y, color);
         PTUtils.BresenhamLine(x0, y0, x1, y1, draw);
     }
 }
コード例 #17
0
        public static MeshDraft Sphere(float radius, int longitudeSegments, int latitudeSegments)
        {
            var draft = new MeshDraft {
                name = "Sphere"
            };

            float longitudeSegmentAngle = Mathf.PI * 2 / longitudeSegments;
            float latitudeSegmentAngle  = Mathf.PI / latitudeSegments;

            float currentLatitude = -Mathf.PI / 2;

            for (var ring = 0; ring <= latitudeSegments; ring++)
            {
                var currentLongitude = 0f;
                for (int i = 0; i < longitudeSegments; i++)
                {
                    var point = PTUtils.PointOnSphere(radius, currentLongitude, currentLatitude);
                    draft.vertices.Add(point);
                    draft.normals.Add(point.normalized);
                    draft.uv.Add(new Vector2((float)i / longitudeSegments, (float)ring / latitudeSegments));
                    currentLongitude -= longitudeSegmentAngle;
                }
                currentLatitude += latitudeSegmentAngle;
            }

            int i0, i1, i2, i3;

            for (int ring = 0; ring < latitudeSegments; ring++)
            {
                for (int i = 0; i < longitudeSegments - 1; i++)
                {
                    i0 = ring * longitudeSegments + i;
                    i1 = (ring + 1) * longitudeSegments + i;
                    i2 = ring * longitudeSegments + i + 1;
                    i3 = (ring + 1) * longitudeSegments + i + 1;
                    draft.triangles.AddRange(new[] { i0, i1, i2 });
                    draft.triangles.AddRange(new[] { i2, i1, i3 });
                }

                i0 = (ring + 1) * longitudeSegments - 1;
                i1 = (ring + 2) * longitudeSegments - 1;
                i2 = ring * longitudeSegments;
                i3 = (ring + 1) * longitudeSegments;
                draft.triangles.AddRange(new[] { i0, i1, i2 });
                draft.triangles.AddRange(new[] { i2, i1, i3 });
            }

            return(draft);
        }
コード例 #18
0
ファイル: MeshE.cs プロジェクト: zhaojinwei/ProceduralToolkit
 /// <summary>
 /// Reverses winding order of mesh triangles
 /// </summary>
 public static void FlipTriangles(this Mesh mesh)
 {
     if (mesh == null)
     {
         throw new ArgumentNullException("mesh");
     }
     for (int i = 0; i < mesh.subMeshCount; i++)
     {
         var triangles = mesh.GetTriangles(i);
         for (int j = 0; j < triangles.Length; j += 3)
         {
             PTUtils.Swap(ref triangles[j], ref triangles[j + 1]);
         }
         mesh.SetTriangles(triangles, i);
     }
 }
コード例 #19
0
        /// <summary>
        /// Draws anti-aliased line and calls <paramref name="draw"/> on every pixel
        /// </summary>
        /// <remarks>
        /// https://en.wikipedia.org/wiki/Xiaolin_Wu%27s_line_algorithm
        /// </remarks>
        public static void RasterAALine(int x0, int y0, int x1, int y1, Action <int, int, float> draw)
        {
            bool steep = Math.Abs(y1 - y0) > Math.Abs(x1 - x0);

            if (steep)
            {
                PTUtils.Swap(ref x0, ref y0);
                PTUtils.Swap(ref x1, ref y1);
            }
            if (x0 > x1)
            {
                PTUtils.Swap(ref x0, ref x1);
                PTUtils.Swap(ref y0, ref y1);
            }

            if (steep)
            {
                draw(y0, x0, 1);
                draw(y1, x1, 1);
            }
            else
            {
                draw(x0, y0, 1);
                draw(x1, y1, 1);
            }
            float dx       = x1 - x0;
            float dy       = y1 - y0;
            float gradient = dy / dx;
            float y        = y0 + gradient;

            for (var x = x0 + 1; x <= x1 - 1; x++)
            {
                if (steep)
                {
                    draw((int)y, x, 1 - (y - (int)y));
                    draw((int)y + 1, x, y - (int)y);
                }
                else
                {
                    draw(x, (int)y, 1 - (y - (int)y));
                    draw(x, (int)y + 1, y - (int)y);
                }
                y += gradient;
            }
        }
コード例 #20
0
        /// <summary>
        /// Constructs a prism draft
        /// </summary>
        public static MeshDraft Prism(float radius, int segments, float height, bool generateUV = true)
        {
            float   segmentAngle = 360f / segments;
            float   currentAngle = 0;
            Vector3 halfHeightUp = Vector3.up * height / 2;

            var lowerRing   = new List <Vector3>(segments);
            var lowerDiskUV = new List <Vector2>();
            var upperRing   = new List <Vector3>(segments);
            var upperDiskUV = new List <Vector2>();

            for (var i = 0; i < segments; i++)
            {
                var point = PTUtils.PointOnCircle3XZ(radius, currentAngle);
                lowerRing.Add(point - halfHeightUp);
                upperRing.Add(point + halfHeightUp);

                if (generateUV)
                {
                    Vector2 uv = PTUtils.PointOnCircle2(0.5f, currentAngle) + new Vector2(0.5f, 0.5f);
                    upperDiskUV.Add(uv);
                    uv.x = 1 - uv.x;
                    lowerDiskUV.Add(uv);
                }
                currentAngle += segmentAngle;
            }

            var draft = new MeshDraft {
                name = "Prism"
            }
            .AddFlatQuadBand(lowerRing, upperRing, generateUV);

            if (generateUV)
            {
                draft.AddTriangleFan(upperRing, Vector3.up, upperDiskUV)
                .AddTriangleFan(lowerRing, Vector3.down, lowerDiskUV, true);
            }
            else
            {
                draft.AddTriangleFan(upperRing, Vector3.up)
                .AddTriangleFan(lowerRing, Vector3.down, true);
            }
            return(draft);
        }
コード例 #21
0
        /// <summary>
        /// Constructs a bipyramid draft
        /// </summary>
        public static MeshDraft BiPyramid(float radius, int segments, float height, bool generateUV = true)
        {
            float segmentAngle = 360f / segments;
            float currentAngle = 0;

            var ring = new Vector3[segments];

            for (var i = 0; i < segments; i++)
            {
                ring[i]       = PTUtils.PointOnCircle3XZ(radius, currentAngle);
                currentAngle += segmentAngle;
            }

            var draft = new MeshDraft {
                name = "Bipyramid"
            }
            .AddBaselessPyramid(Vector3.up * height / 2, ring, generateUV)
            .AddBaselessPyramid(Vector3.down * height / 2, ring, generateUV, true);

            return(draft);
        }
コード例 #22
0
        public static MeshDraft Dodecahedron(float radius)
        {
            const float magicAngle1  = 52.62263590f;
            const float magicAngle2  = 10.81231754f;
            const float segmentAngle = 72;
            float       currentAngle = 0;
            var         lowerCap     = new List <Vector3>();
            var         lowerRing    = new List <Vector3>();

            for (var i = 0; i < 5; i++)
            {
                lowerCap.Add(PTUtils.PointOnSphere(radius, currentAngle, -magicAngle1));
                lowerRing.Add(PTUtils.PointOnSphere(radius, currentAngle, -magicAngle2));
                currentAngle -= segmentAngle;
            }

            currentAngle = -segmentAngle / 2;
            var upperCap  = new List <Vector3>();
            var upperRing = new List <Vector3>();

            for (var i = 0; i < 5; i++)
            {
                upperCap.Add(PTUtils.PointOnSphere(radius, currentAngle, magicAngle1));
                upperRing.Add(PTUtils.PointOnSphere(radius, currentAngle, magicAngle2));
                currentAngle -= segmentAngle;
            }

            var draft = new MeshDraft {
                name = "Dodecahedron"
            }
            .AddTriangleFan(lowerCap)
            .Add(FlatBand(lowerCap, lowerRing))
            .Add(FlatBand(lowerRing, upperRing))
            .Add(FlatBand(upperRing, upperCap));

            upperCap.Reverse();
            draft.AddTriangleFan(upperCap);
            return(draft);
        }
コード例 #23
0
        private static void AddCylinderPoints(float radius, float currentAngle, Vector3 halfHeightUp, bool generateUV,
                                              ref List <Vector3> vertices, ref List <Vector2> uv, ref List <Vector3> normals,
                                              out Vector3 lowerVertex, out Vector3 upperVertex)
        {
            Vector3 normal = PTUtils.PointOnCircle3XZ(1, currentAngle);
            Vector3 point  = normal * radius;

            lowerVertex = point - halfHeightUp;
            upperVertex = point + halfHeightUp;

            vertices.Add(upperVertex);
            normals.Add(normal);
            vertices.Add(lowerVertex);
            normals.Add(normal);

            if (generateUV)
            {
                float u = 1 - currentAngle / 360;
                uv.Add(new Vector2(u, 1));
                uv.Add(new Vector2(u, 0));
            }
        }
コード例 #24
0
        public static MeshDraft Dodecahedron(float radius)
        {
            float magicAngle1  = Mathf.PI * 52.62263590f / 180;
            float magicAngle2  = Mathf.PI * 10.81231754f / 180;
            float segmentAngle = Mathf.PI * 2 / 5;
            float currentAngle = 0f;
            var   lowerCap     = new List <Vector3>();
            var   lowerRing    = new List <Vector3>();

            for (var i = 0; i <= 5; i++)
            {
                lowerCap.Add(PTUtils.PointOnSphere(radius, currentAngle, -magicAngle1));
                lowerRing.Add(PTUtils.PointOnSphere(radius, currentAngle, -magicAngle2));
                currentAngle -= segmentAngle;
            }

            currentAngle = -segmentAngle / 2;
            var upperCap  = new List <Vector3>();
            var upperRing = new List <Vector3>();

            for (var i = 0; i <= 5; i++)
            {
                upperCap.Add(PTUtils.PointOnSphere(radius, currentAngle, magicAngle1));
                upperRing.Add(PTUtils.PointOnSphere(radius, currentAngle, magicAngle2));
                currentAngle -= segmentAngle;
            }

            var draft = TriangleFan(lowerCap);

            draft.Add(FlatBand(lowerCap, lowerRing));
            draft.Add(FlatBand(lowerRing, upperRing));
            draft.Add(FlatBand(upperRing, upperCap));
            upperCap.Reverse();
            draft.Add(TriangleFan(upperCap));
            draft.name = "Dodecahedron";
            return(draft);
        }
コード例 #25
0
        public static MeshDraft Prism(float radius, int segments, float heignt)
        {
            float segmentAngle = Mathf.PI * 2 / segments;

            float currentAngle = 0f;
            var   lowerRing    = new List <Vector3>(segments);
            var   upperRing    = new List <Vector3>(segments);

            for (var i = 0; i < segments; i++)
            {
                var point = PTUtils.PointOnCircle3(radius, currentAngle);
                lowerRing.Add(point - Vector3.up * heignt / 2);
                upperRing.Add(point + Vector3.up * heignt / 2);
                currentAngle -= segmentAngle;
            }

            var draft = TriangleFan(lowerRing);

            draft.Add(FlatBand(lowerRing, upperRing));
            upperRing.Reverse();
            draft.Add(TriangleFan(upperRing));
            draft.name = "Prism";
            return(draft);
        }
コード例 #26
0
        public static MeshDraft Tetrahedron(float radius)
        {
            float tetrahedralAngle = Mathf.PI * -19.471220333f / 180;
            float segmentAngle     = Mathf.PI * 2 / 3;
            float currentAngle     = 0f;

            var vertices = new List <Vector3>(4)
            {
                new Vector3(0, radius, 0)
            };

            for (var i = 1; i < 4; i++)
            {
                vertices.Add(PTUtils.PointOnSphere(radius, currentAngle, tetrahedralAngle));
                currentAngle += segmentAngle;
            }
            var draft = Triangle(vertices[0], vertices[1], vertices[2]);

            draft.Add(Triangle(vertices[1], vertices[3], vertices[2]));
            draft.Add(Triangle(vertices[0], vertices[2], vertices[3]));
            draft.Add(Triangle(vertices[0], vertices[3], vertices[1]));
            draft.name = "Tetrahedron";
            return(draft);
        }
コード例 #27
0
        public static MeshDraft Tetrahedron(float radius)
        {
            const float tetrahedralAngle = -19.471220333f;
            const float segmentAngle     = 120;
            float       currentAngle     = 0;

            var vertices = new List <Vector3>(4)
            {
                new Vector3(0, radius, 0)
            };

            for (var i = 1; i < 4; i++)
            {
                vertices.Add(PTUtils.PointOnSphere(radius, currentAngle, tetrahedralAngle));
                currentAngle += segmentAngle;
            }
            return(new MeshDraft {
                name = "Tetrahedron"
            }
                   .AddTriangle(vertices[0], vertices[1], vertices[2])
                   .AddTriangle(vertices[1], vertices[3], vertices[2])
                   .AddTriangle(vertices[0], vertices[2], vertices[3])
                   .AddTriangle(vertices[0], vertices[3], vertices[1]));
        }
コード例 #28
0
        /// <summary>
        /// Returns the distance between the closest points on the ray and the segment
        /// </summary>
        public static float RaySegment(Vector2 rayOrigin, Vector2 rayDirection, Vector2 segmentA, Vector2 segmentB)
        {
            Vector2 segmentAToOrigin = rayOrigin - segmentA;
            Vector2 segmentDirection = segmentB - segmentA;
            float   denominator      = VectorE.PerpDot(rayDirection, segmentDirection);
            float   perpDotA         = VectorE.PerpDot(rayDirection, segmentAToOrigin);
            // Normalized direction gives more stable results
            float perpDotB = VectorE.PerpDot(segmentDirection.normalized, segmentAToOrigin);

            if (Mathf.Abs(denominator) < Geometry.Epsilon)
            {
                // Parallel
                float   segmentAProjection = -Vector2.Dot(rayDirection, segmentAToOrigin);
                Vector2 originToSegmentB   = segmentB - rayOrigin;
                float   segmentBProjection = Vector2.Dot(rayDirection, originToSegmentB);
                if (Mathf.Abs(perpDotA) > Geometry.Epsilon || Mathf.Abs(perpDotB) > Geometry.Epsilon)
                {
                    // Not collinear
                    if (segmentAProjection > -Geometry.Epsilon)
                    {
                        float distanceSqr = segmentAToOrigin.sqrMagnitude - segmentAProjection * segmentAProjection;
                        // distanceSqr can be negative
                        return(distanceSqr <= 0 ? 0 : Mathf.Sqrt(distanceSqr));
                    }
                    if (segmentBProjection > -Geometry.Epsilon)
                    {
                        float distanceSqr = originToSegmentB.sqrMagnitude - segmentBProjection * segmentBProjection;
                        // distanceSqr can be negative
                        return(distanceSqr <= 0 ? 0 : Mathf.Sqrt(distanceSqr));
                    }

                    if (segmentAProjection > segmentBProjection)
                    {
                        return(Vector2.Distance(rayOrigin, segmentA));
                    }
                    return(Vector2.Distance(rayOrigin, segmentB));
                }
                // Collinear
                if (segmentAProjection > -Geometry.Epsilon || segmentBProjection > -Geometry.Epsilon)
                {
                    // Point or segment intersection
                    return(0);
                }
                // No intersection
                return(segmentAProjection > segmentBProjection ? -segmentAProjection : -segmentBProjection);
            }

            // Not parallel
            float rayDistance     = perpDotB / denominator;
            float segmentDistance = perpDotA / denominator;

            if (rayDistance < -Geometry.Epsilon ||
                segmentDistance < -Geometry.Epsilon || segmentDistance > 1 + Geometry.Epsilon)
            {
                // No intersection
                bool    codirected = Vector2.Dot(rayDirection, segmentDirection) > 0;
                Vector2 segmentBToOrigin;
                if (!codirected)
                {
                    PTUtils.Swap(ref segmentA, ref segmentB);
                    segmentDirection = -segmentDirection;
                    segmentBToOrigin = segmentAToOrigin;
                    segmentAToOrigin = rayOrigin - segmentA;
                    segmentDistance  = 1 - segmentDistance;
                }
                else
                {
                    segmentBToOrigin = rayOrigin - segmentB;
                }

                float segmentAProjection = -Vector2.Dot(rayDirection, segmentAToOrigin);
                float segmentBProjection = -Vector2.Dot(rayDirection, segmentBToOrigin);
                bool  segmentAOnRay      = segmentAProjection > -Geometry.Epsilon;
                bool  segmentBOnRay      = segmentBProjection > -Geometry.Epsilon;
                if (segmentAOnRay && segmentBOnRay)
                {
                    if (segmentDistance < 0)
                    {
                        Vector2 rayPoint     = rayOrigin + rayDirection * segmentAProjection;
                        Vector2 segmentPoint = segmentA;
                        return(Vector2.Distance(rayPoint, segmentPoint));
                    }
                    else
                    {
                        Vector2 rayPoint     = rayOrigin + rayDirection * segmentBProjection;
                        Vector2 segmentPoint = segmentB;
                        return(Vector2.Distance(rayPoint, segmentPoint));
                    }
                }
                else if (!segmentAOnRay && segmentBOnRay)
                {
                    if (segmentDistance < 0)
                    {
                        Vector2 rayPoint     = rayOrigin;
                        Vector2 segmentPoint = segmentA;
                        return(Vector2.Distance(rayPoint, segmentPoint));
                    }
                    else if (segmentDistance > 1 + Geometry.Epsilon)
                    {
                        Vector2 rayPoint     = rayOrigin + rayDirection * segmentBProjection;
                        Vector2 segmentPoint = segmentB;
                        return(Vector2.Distance(rayPoint, segmentPoint));
                    }
                    else
                    {
                        Vector2 rayPoint         = rayOrigin;
                        float   originProjection = Vector2.Dot(segmentDirection, segmentAToOrigin);
                        Vector2 segmentPoint     = segmentA + segmentDirection * originProjection / segmentDirection.sqrMagnitude;
                        return(Vector2.Distance(rayPoint, segmentPoint));
                    }
                }
                else
                {
                    // Not on ray
                    Vector2 rayPoint         = rayOrigin;
                    float   originProjection = Vector2.Dot(segmentDirection, segmentAToOrigin);
                    float   sqrSegmentLength = segmentDirection.sqrMagnitude;
                    if (originProjection < 0)
                    {
                        return(Vector2.Distance(rayPoint, segmentA));
                    }
                    else if (originProjection > sqrSegmentLength)
                    {
                        return(Vector2.Distance(rayPoint, segmentB));
                    }
                    else
                    {
                        Vector2 segmentPoint = segmentA + segmentDirection * originProjection / sqrSegmentLength;
                        return(Vector2.Distance(rayPoint, segmentPoint));
                    }
                }
            }
            // Point intersection
            return(0);
        }
コード例 #29
0
        /// <summary>
        /// Returns the distance between the closest points on the segments
        /// </summary>
        public static float SegmentSegment(Vector2 segment1A, Vector2 segment1B, Vector2 segment2A, Vector2 segment2B)
        {
            Vector2 from2ATo1A     = segment1A - segment2A;
            Vector2 direction1     = segment1B - segment1A;
            Vector2 direction2     = segment2B - segment2A;
            float   segment1Length = direction1.magnitude;
            float   segment2Length = direction2.magnitude;

            bool segment1IsAPoint = segment1Length < Geometry.Epsilon;
            bool segment2IsAPoint = segment2Length < Geometry.Epsilon;

            if (segment1IsAPoint && segment2IsAPoint)
            {
                return(Vector2.Distance(segment1A, segment2A));
            }
            if (segment1IsAPoint)
            {
                direction2.Normalize();
                return(PointSegment(segment1A, segment2A, segment2B, direction2, segment2Length));
            }
            if (segment2IsAPoint)
            {
                direction1.Normalize();
                return(PointSegment(segment2A, segment1A, segment1B, direction1, segment1Length));
            }

            direction1.Normalize();
            direction2.Normalize();
            float denominator = VectorE.PerpDot(direction1, direction2);
            float perpDot1    = VectorE.PerpDot(direction1, from2ATo1A);
            float perpDot2    = VectorE.PerpDot(direction2, from2ATo1A);

            if (Mathf.Abs(denominator) < Geometry.Epsilon)
            {
                // Parallel
                if (Mathf.Abs(perpDot1) > Geometry.Epsilon || Mathf.Abs(perpDot2) > Geometry.Epsilon)
                {
                    // Not collinear
                    float segment2AProjection = -Vector2.Dot(direction1, from2ATo1A);
                    if (segment2AProjection > -Geometry.Epsilon &&
                        segment2AProjection < segment1Length + Geometry.Epsilon)
                    {
                        float distanceSqr = from2ATo1A.sqrMagnitude - segment2AProjection * segment2AProjection;
                        // distanceSqr can be negative
                        return(distanceSqr <= 0 ? 0 : Mathf.Sqrt(distanceSqr));
                    }

                    Vector2 from1ATo2B          = segment2B - segment1A;
                    float   segment2BProjection = Vector2.Dot(direction1, from1ATo2B);
                    if (segment2BProjection > -Geometry.Epsilon &&
                        segment2BProjection < segment1Length + Geometry.Epsilon)
                    {
                        float distanceSqr = from1ATo2B.sqrMagnitude - segment2BProjection * segment2BProjection;
                        // distanceSqr can be negative
                        return(distanceSqr <= 0 ? 0 : Mathf.Sqrt(distanceSqr));
                    }

                    if (segment2AProjection < 0 && segment2BProjection < 0)
                    {
                        if (segment2AProjection > segment2BProjection)
                        {
                            return(Vector2.Distance(segment1A, segment2A));
                        }
                        return(Vector2.Distance(segment1A, segment2B));
                    }
                    if (segment2AProjection > 0 && segment2BProjection > 0)
                    {
                        if (segment2AProjection < segment2BProjection)
                        {
                            return(Vector2.Distance(segment1B, segment2A));
                        }
                        return(Vector2.Distance(segment1B, segment2B));
                    }
                    float   segment1AProjection = Vector2.Dot(direction2, from2ATo1A);
                    Vector2 segment2Point       = segment2A + direction2 * segment1AProjection;
                    return(Vector2.Distance(segment1A, segment2Point));
                }
                // Collinear

                bool codirected = Vector2.Dot(direction1, direction2) > 0;
                if (codirected)
                {
                    // Codirected
                    float segment2AProjection = -Vector2.Dot(direction1, from2ATo1A);
                    if (segment2AProjection > -Geometry.Epsilon)
                    {
                        // 1A------1B
                        //     2A------2B
                        return(SegmentSegmentCollinear(segment1A, segment1B, segment2A));
                    }
                    else
                    {
                        //     1A------1B
                        // 2A------2B
                        return(SegmentSegmentCollinear(segment2A, segment2B, segment1A));
                    }
                }
                else
                {
                    // Contradirected
                    float segment2BProjection = Vector2.Dot(direction1, segment2B - segment1A);
                    if (segment2BProjection > -Geometry.Epsilon)
                    {
                        // 1A------1B
                        //     2B------2A
                        return(SegmentSegmentCollinear(segment1A, segment1B, segment2B));
                    }
                    else
                    {
                        //     1A------1B
                        // 2B------2A
                        return(SegmentSegmentCollinear(segment2B, segment2A, segment1A));
                    }
                }
            }

            // Not parallel
            float distance1 = perpDot2 / denominator;
            float distance2 = perpDot1 / denominator;

            if (distance1 < -Geometry.Epsilon || distance1 > segment1Length + Geometry.Epsilon ||
                distance2 < -Geometry.Epsilon || distance2 > segment2Length + Geometry.Epsilon)
            {
                // No intersection
                bool    codirected = Vector2.Dot(direction1, direction2) > 0;
                Vector2 from1ATo2B;
                if (!codirected)
                {
                    PTUtils.Swap(ref segment2A, ref segment2B);
                    direction2 = -direction2;
                    from1ATo2B = -from2ATo1A;
                    from2ATo1A = segment1A - segment2A;
                    distance2  = segment2Length - distance2;
                }
                else
                {
                    from1ATo2B = segment2B - segment1A;
                }
                Vector2 segment1Point;
                Vector2 segment2Point;

                float segment2AProjection = -Vector2.Dot(direction1, from2ATo1A);
                float segment2BProjection = Vector2.Dot(direction1, from1ATo2B);

                bool segment2AIsAfter1A  = segment2AProjection > -Geometry.Epsilon;
                bool segment2BIsBefore1B = segment2BProjection < segment1Length + Geometry.Epsilon;
                bool segment2AOnSegment1 = segment2AIsAfter1A && segment2AProjection < segment1Length + Geometry.Epsilon;
                bool segment2BOnSegment1 = segment2BProjection > -Geometry.Epsilon && segment2BIsBefore1B;
                if (segment2AOnSegment1 && segment2BOnSegment1)
                {
                    if (distance2 < -Geometry.Epsilon)
                    {
                        segment1Point = segment1A + direction1 * segment2AProjection;
                        segment2Point = segment2A;
                    }
                    else
                    {
                        segment1Point = segment1A + direction1 * segment2BProjection;
                        segment2Point = segment2B;
                    }
                }
                else if (!segment2AOnSegment1 && !segment2BOnSegment1)
                {
                    if (!segment2AIsAfter1A && !segment2BIsBefore1B)
                    {
                        segment1Point = distance1 < -Geometry.Epsilon ? segment1A : segment1B;
                    }
                    else
                    {
                        // Not on segment
                        segment1Point = segment2AIsAfter1A ? segment1B : segment1A;
                    }
                    float segment1PointProjection = Vector2.Dot(direction2, segment1Point - segment2A);
                    segment1PointProjection = Mathf.Clamp(segment1PointProjection, 0, segment2Length);
                    segment2Point           = segment2A + direction2 * segment1PointProjection;
                }
                else if (segment2AOnSegment1)
                {
                    if (distance2 < -Geometry.Epsilon)
                    {
                        segment1Point = segment1A + direction1 * segment2AProjection;
                        segment2Point = segment2A;
                    }
                    else
                    {
                        segment1Point = segment1B;
                        float segment1PointProjection = Vector2.Dot(direction2, segment1Point - segment2A);
                        segment1PointProjection = Mathf.Clamp(segment1PointProjection, 0, segment2Length);
                        segment2Point           = segment2A + direction2 * segment1PointProjection;
                    }
                }
                else
                {
                    if (distance2 > segment2Length + Geometry.Epsilon)
                    {
                        segment1Point = segment1A + direction1 * segment2BProjection;
                        segment2Point = segment2B;
                    }
                    else
                    {
                        segment1Point = segment1A;
                        float segment1PointProjection = Vector2.Dot(direction2, segment1Point - segment2A);
                        segment1PointProjection = Mathf.Clamp(segment1PointProjection, 0, segment2Length);
                        segment2Point           = segment2A + direction2 * segment1PointProjection;
                    }
                }
                return(Vector2.Distance(segment1Point, segment2Point));
            }

            // Point intersection
            return(0);
        }
コード例 #30
0
 /// <summary>
 /// Returns a point on the sphere at the given coordinates
 /// </summary>
 public Vector3 GetPoint(float horizontalAngle, float verticalAngle)
 {
     return(center + PTUtils.PointOnSphere(radius, horizontalAngle, verticalAngle));
 }