Exemplo n.º 1
0
    /// <summary>
    /// ミッキー型の花火用Meshを作成
    /// </summary>
    /// <returns>The micky mesh.</returns>
    private Mesh CreateMickyMesh()
    {
        Mesh mesh = new Mesh();

        // 構造体の初期化
        CirclePoints cpoints = new CirclePoints();

        cpoints.vertextList = new List <Vector3>();
        cpoints.indexList   = new List <int>();

        // 頭部
        cpoints = CreateCirclePoints(new Vector3(0, 0, 0), 100, cpoints);

        // 左耳
        cpoints = CreateCirclePoints(new Vector3(100, 100, 0), 70, cpoints);

        // 右耳
        cpoints = CreateCirclePoints(new Vector3(-100, 100, 0), 70, cpoints);

        // Meshの作成
        mesh.RecalculateNormals();                                               // 法線方向を(0,0,1) 固定にしない
        mesh.SetVertices(cpoints.vertextList);                                   //meshに頂点群をセット
        mesh.SetIndices(cpoints.indexList.ToArray(), MeshTopology.Triangles, 0); //メッシュにどの頂点の順番で面を作るかセット

        return(mesh);
    }
Exemplo n.º 2
0
        private ProfilePoint CreatePoint(float t, ref int colliderTri)
        {
            // ReSharper disable once InconsistentNaming
            // B(t) = (1-t)^3 p0 + t(1-t)^2 p1 + t^2(1-t) p2 + t^3 p3
            Vector2 Bt = B(t);

            // ReSharper disable once InconsistentNaming
            // B'(t) = (1-t)^2 (p1-p0) + t(1-t) (p2-p1) + t^2 (p3-p2)
            Vector2 Btdt = Bdt(t);

            // normalized perpendicular to tangent (derivative)
            Vector2 norm = new Vector2(Btdt.y, -Btdt.x / 2f).normalized;

            // Count the number of triangles
            CirclePoints colliderCirc = CirclePoints.ForDiameter(Bt.x, MaxCircleError * 4f, 4, 16);

            colliderTri += (colliderCirc.totVertexes + 1) * 2;

            //Debug.LogWarning(string.Format("Creating profile point t={0:F3} coord=({1:F3}, {2:F3})  normal=({3:F3}, {4:F3})", t, Bt.x, Bt.y, norm.x, norm.y));

            // We can have a maxium of 255 triangles in the collider. Will leave a bit of breathing room at the top.
            return(colliderTri <= 220 ?
                   new ProfilePoint(Bt.x, Bt.y, t, norm, colliderCirc: colliderCirc) :
                   new ProfilePoint(Bt.x, Bt.y, t, norm, inCollider: false));
        }
Exemplo n.º 3
0
        internal override void UpdateShape(bool forceUpdate = true)
        {
            part.CoMOffset = CoMOffset;
            Volume         = CalculateVolume();
            LinkedList <ProfilePoint> points = new LinkedList <ProfilePoint>();

            if (fillet == 0)
            {
                // Reduces down to a cylinder part.
                points.AddLast(new ProfilePoint(diameter, -0.5f * length, 0f, new Vector2(1, 0)));
                points.AddLast(new ProfilePoint(diameter, 0.5f * length, 1f, new Vector2(1, 0)));
            }
            else
            {
                float bodyLength   = length - fillet;
                float endDiameter  = diameter - fillet;
                float bodyDiameter = diameter;

                float filletLength = Mathf.PI * fillet * 0.5f;
                float totLength    = filletLength + bodyLength;
                float s1           = filletLength * 0.5f / totLength;

                CirclePoints cp = CirclePoints.ForDiameter(fillet, MaxCircleError, MinCircleVertexes);

                // We need to be careful with the number of points so we don't blow the 255 point budget for colliders
                CirclePoints collCp   = CirclePoints.ForDiameter(fillet, MaxCircleError, 0, 12);
                CirclePoints collEnds = CirclePoints.ForDiameter(endDiameter, MaxCircleError * 4f, 4, 12);
                CirclePoints collBody = CirclePoints.ForDiameter(bodyDiameter, MaxCircleError * 4f, 4, 16);

                points.AddLast(new ProfilePoint(endDiameter, -0.5f * length, 0f, new Vector2(0, -1), colliderCirc: collEnds));

                foreach (Vector3 xzu in cp.PointsXZU(0.5f, 0.75f))
                {
                    points.AddLast(new ProfilePoint(endDiameter + fillet * xzu.x, -0.5f * (bodyLength - fillet * xzu.y), s1 * Mathf.InverseLerp(0.5f, 0.75f, xzu[2]), xzu, inCollider: false));
                }
                foreach (Vector3 xzu in collCp.PointsXZU(0.5f, 0.75f))
                {
                    points.AddLast(new ProfilePoint(endDiameter + fillet * xzu.x, -0.5f * (bodyLength - fillet * xzu.y), s1 * Mathf.InverseLerp(0.5f, 0.75f, xzu[2]), xzu, inRender: false, colliderCirc: collEnds));
                }

                points.AddLast(new ProfilePoint(bodyDiameter, -0.5f * bodyLength, s1, new Vector2(1, 0), colliderCirc: collBody));
                if (fillet < length)
                {
                    points.AddLast(new ProfilePoint(bodyDiameter, 0.5f * bodyLength, 1f - s1, new Vector2(1, 0), colliderCirc: collBody));
                }

                foreach (Vector3 xzu in cp.PointsXZU(0.75f, 1))
                {
                    points.AddLast(new ProfilePoint(endDiameter + fillet * xzu.x, 0.5f * (bodyLength + fillet * xzu.y), 1f - s1 * Mathf.InverseLerp(1f, 0.75f, xzu[2]), xzu, inCollider: false));
                }
                foreach (Vector3 xzu in collCp.PointsXZU(0.75f, 1))
                {
                    points.AddLast(new ProfilePoint(endDiameter + fillet * xzu.x, 0.5f * (bodyLength + fillet * xzu.y), 1f - s1 * Mathf.InverseLerp(1f, 0.75f, xzu[2]), xzu, inRender: false, colliderCirc: collEnds));
                }
                points.AddLast(new ProfilePoint(endDiameter, 0.5f * length, 1f, new Vector2(0, 1), colliderCirc: collEnds));
            }

            WriteMeshes(points);
        }
Exemplo n.º 4
0
 public ProfilePoint(float dia, float y, float v, Vector2 norm, bool inRender = true, bool inCollider = true, CirclePoints circ = null, CirclePoints colliderCirc = null)
 {
     this.dia          = dia;
     this.y            = y;
     this.v            = v;
     this.norm         = norm;
     this.inRender     = inRender;
     this.inCollider   = inCollider;
     this.circ         = inRender ? (circ ?? CirclePoints.ForDiameter(dia, MaxCircleError, MinCircleVertexes)) : null;
     this.colliderCirc = inCollider ? (colliderCirc ?? this.circ ?? CirclePoints.ForDiameter(dia, MaxCircleError, MinCircleVertexes)) : null;
 }
Exemplo n.º 5
0
            public static CirclePoints ForPoints(int vertexes)
            {
                int idx = vertexes / 4 - 1;

                if (idx >= circlePoints.Count)
                {
                    CirclePoints prev = circlePoints.Last();
                    do
                    {
                        circlePoints.Add(prev = new CirclePoints(prev.subdivCount + 1));
                    }while (prev.totVertexes <= vertexes);
                }
                return(circlePoints[idx]);
            }
Exemplo n.º 6
0
    /// <summary>
    /// ハート形のMeshを返す
    /// </summary>
    /// <returns>The circumference mesh.</returns>
    private Mesh CreateHeartMesh(Vector3 theOrigin, float CircleSize, CirclePoints cpoints)
    {
        Mesh mesh = new Mesh();

        // 構造体の初期化
        cpoints.vertextList = new List <Vector3>();
        cpoints.indexList   = new List <int>();

        cpoints = CreateHeartPoints(theOrigin, CircleSize, cpoints);

        // Meshの作成
        mesh.RecalculateNormals();                                               // 法線方向を(0,0,1) 固定にしない
        mesh.SetVertices(cpoints.vertextList);                                   //meshに頂点群をセット
        mesh.SetIndices(cpoints.indexList.ToArray(), MeshTopology.Triangles, 0); //メッシュにどの頂点の順番で面を作るかセット

        return(mesh);
    }
Exemplo n.º 7
0
    /// <summary>
    /// 円を近似する三角形の頂点の座標と、組み合わせを返す
    /// </summary>
    /// 計算方法は、ピザ(三角形)を一切れずつ集めて一枚の丸いピザにするイメージ
    /// <returns>The circle.</returns>
    /// <param name="theOrigin">The origin.</param>
    /// <param name="CircleSize">Circle size.</param>
    /// <param name="cpoints">Cpoints.</param>
    private CirclePoints CreateCirclePoints(Vector3 theOrigin, int CircleSize, CirclePoints cpoints)
    {
        var unit_angle   = 5;
        var triangle_num = 360 / unit_angle;

        // 原点
        cpoints.vertextList.Add(theOrigin);

        // 近似のため、円上の座標を取得
        for (int i = 0; i < triangle_num; i++)
        {
            var sin = Math.Sin(unit_angle * i * (Math.PI / 180));
            var cos = Math.Cos(unit_angle * i * (Math.PI / 180));
            cpoints.vertextList.Add(
                new Vector3((float)cos * CircleSize + theOrigin.x, (float)sin * CircleSize + theOrigin.y, theOrigin.z));
        }

        // 原点の番号を算出
        int initTriangleNumSize = cpoints.indexList.Count / 3 + cpoints.indexList.Count / 3 / triangle_num;

        // 座標と三角形の頂点を対応させる
        for (int i = 0; i < triangle_num; i++)
        {
            // 第0頂点(原点)
            cpoints.indexList.Add(initTriangleNumSize);

            // 第1頂点
            cpoints.indexList.Add(i + 1 + initTriangleNumSize);

            // 第2頂点
            if (i * 3 + 2 < triangle_num * 3 - 1)
            {
                cpoints.indexList.Add(i + 2 + initTriangleNumSize);
            }
            else
            {
                // 最後の三角形は最初の頂点に戻る
                cpoints.indexList.Add(1 + initTriangleNumSize);
            }
        }

        return(cpoints);
    }
Exemplo n.º 8
0
            public static CirclePoints ForDiameter(float diameter, float maxError, int minVertexes, int maxVertexes = int.MaxValue)
            {
                int idx = circlePoints.FindIndex(v => (v.totVertexes >= minVertexes) && (v.maxError * diameter * 2f) <= maxError);

                switch (idx)
                {
                case 0:
                    return(circlePoints[0]);

                case -1:
                    CirclePoints prev;
                    if (circlePoints.Count == 0)
                    {
                        circlePoints.Add(prev = new CirclePoints(0));
                    }
                    else
                    {
                        prev = circlePoints.Last();
                    }

                    while (prev.totVertexes <= minVertexes)
                    {
                        circlePoints.Add(prev = new CirclePoints(prev.subdivCount + 1));
                    }

                    while (true)
                    {
                        CirclePoints nxt = new CirclePoints(prev.subdivCount + 1);
                        circlePoints.Add(nxt);
                        if (nxt.totVertexes >= maxVertexes || nxt.maxError * diameter * 2 < maxError)
                        {
                            return(prev);
                        }
                        prev = nxt;
                    }
                    throw new InvalidProgramException();

                default:
                    return(circlePoints[Math.Min(idx - 1, maxVertexes / 4 - 1)]);
                }
            }
Exemplo n.º 9
0
        public void Fill(JsonCheckStatusResponse data, ESymbol mySymbol, bool isMyTurn)
        {
            foreach (var p in data.coordinates)
            {
                PointData pd = new PointData()
                {
                    X = p.x, Y = p.y
                };
                if (p.playerId == data.playerCircleId)
                {
                    CirclePoints.Add(pd);
                }
                if (p.playerId == data.playerCrossId)
                {
                    CrossPoints.Add(pd);
                }
            }

            MySymbol = mySymbol;
            IsMyTurn = isMyTurn;
        }
Exemplo n.º 10
0
    /// <summary>
    /// ハート型輪郭線の座標を返す
    /// </summary>
    /// <returns>The circumference points.</returns>
    /// <param name="theOrigin">The origin.</param>
    /// <param name="CircleSize">Circle size.</param>
    /// <param name="cpoints">Cpoints.</param>
    private CirclePoints CreateHeartPoints(Vector3 theOrigin, float CircleSize, CirclePoints cpoints)
    {
        double increment    = 0.0005;
        var    triangle_num = Math.PI * 2 / increment;

        for (double t = -Math.PI / 2; t < 3 * Math.PI / 2; t += increment)
        {
            var x = 16 * Math.Sin(t) * Math.Sin(t) * Math.Sin(t);
            var y = 13 * Math.Cos(t) - 5 * Math.Cos(2 * t) - 2 * Math.Cos(3 * t) - Math.Cos(4 * t);

            cpoints.vertextList.Add(
                new Vector3((float)x * CircleSize, (float)y * CircleSize, 0) + theOrigin
                );
        }

        // 座標と三角形の頂点を対応させる
        for (int i = 0; i < triangle_num; i++)
        {
            cpoints.indexList.Add(i);
        }

        return(cpoints);
    }
Exemplo n.º 11
0
            public static CirclePoints ForDiameter(float diameter, float maxError, int minVertexes, int maxVertexes = int.MaxValue)
            {
                int idx = circlePoints.FindIndex(v => (v.totVertexes >= minVertexes) && (v.maxError * diameter * 2f) <= maxError);
                switch (idx)
                {
                    case 0:
                        return circlePoints[0];
                    case -1:
                        CirclePoints prev;
                        if (circlePoints.Count == 0)
                            circlePoints.Add(prev = new CirclePoints(0));
                        else
                            prev = circlePoints.Last();

                        while (prev.totVertexes <= minVertexes)
                            circlePoints.Add(prev = new CirclePoints(prev.subdivCount + 1));

                        while (true)
                        {
                            CirclePoints nxt = new CirclePoints(prev.subdivCount + 1);
                            circlePoints.Add(nxt);
                            if (nxt.totVertexes >= maxVertexes || nxt.maxError * diameter * 2 < maxError)
                                return prev;
                            prev = nxt;
                        }
                        throw new InvalidProgramException();
                    default:
                        return circlePoints[Math.Min(idx - 1, maxVertexes / 4 - 1)];
                }
            }
Exemplo n.º 12
0
        /// <summary>
        /// Generate the compShape from profile points from pt to bottom.
        /// Note that this list will have extra interpolated points added if the change in radius is high to avoid
        /// texture stretching.
        /// </summary>
        /// <param name="pts"></param>
        protected void WriteMeshes(LinkedList <ProfilePoint> pts)
        {
            if (pts == null || pts.Count < 2)
            {
                return;
            }

            // update nodes
            UpdateNodeSize(pts.First(), bottomNodeName);
            UpdateNodeSize(pts.Last(), topNodeName);

            // Move attachments first, before subdividing
            MoveAttachments(pts);

            // Horizontal profile point subdivision
            SubdivHorizontal(pts);

            // Tank stats
            float tankVLength = 0;

            int  nVrt           = 0;
            int  nTri           = 0;
            int  nColVrt        = 0;
            int  nColTri        = 0;
            bool customCollider = false;

            ProfilePoint first = pts.First.Value;
            ProfilePoint last  = pts.Last.Value;

            if (!first.inCollider || !last.inCollider)
            {
                throw new InvalidOperationException("First and last profile points must be used in the collider");
            }

            foreach (ProfilePoint pt in pts)
            {
                customCollider = customCollider || pt.CustomCollider;

                if (pt.inRender)
                {
                    nVrt += pt.circ.totVertexes + 1;
                    // one for above, one for below
                    nTri += 2 * pt.circ.totVertexes;
                }

                if (pt.inCollider)
                {
                    nColVrt += pt.colliderCirc.totVertexes + 1;
                    nColTri += 2 * pt.colliderCirc.totVertexes;
                }
            }
            // Have double counted for the first and last circles.
            nTri    -= first.circ.totVertexes + last.circ.totVertexes;
            nColTri -= first.colliderCirc.totVertexes + last.colliderCirc.totVertexes;

            UncheckedMesh m = new UncheckedMesh(nVrt, nTri);

            float sumDiameters = 0;
            //Debug.LogWarning("Display mesh vert=" + nVrt + " tris=" + nTri);

            bool odd = false;
            {
                ProfilePoint prev = null;
                int          off = 0, prevOff = 0;
                int          tOff = 0;
                foreach (ProfilePoint pt in pts)
                {
                    if (!pt.inRender)
                    {
                        continue;
                    }

                    pt.circ.WriteVertexes(diameter: pt.dia, y: pt.y, v: pt.v, norm: pt.norm, off: off, m: m, odd: odd);
                    if (prev != null)
                    {
                        CirclePoints.WriteTriangles(prev.circ, prevOff, pt.circ, off, m.triangles, tOff * 3, !odd);
                        tOff += prev.circ.totVertexes + pt.circ.totVertexes;

                        // Deprecated: Volume has been moved up to callers. This way we can use the idealized rather than aproximate volume
                        // Work out the area of the truncated cone

                        // integral_y1^y2 pi R(y)^2 dy   where R(y) = ((r2-r1)(y-y1))/(r2-r1) + r1   Integrate circles along a line
                        // integral_y1^y2 pi ( ((r2-r1)(y-y1))/(r2-r1) + r1) ^2 dy                Substituted in formula.
                        // == -1/3 pi (y1-y2) (r1^2+r1*r2+r2^2)                                   Do the calculus
                        // == -1/3 pi (y1-y2) (d1^2/4+d1*d2/4+d2^2/4)                             r = d/2
                        // == -1/12 pi (y1-y2) (d1^2+d1*d2+d2^2)                                  Take out the factor
                        //volume += (Mathf.PI * (pt.y - prev.y) * (prev.dia * prev.dia + prev.dia * pt.dia + pt.dia * pt.dia)) / 12f;

                        float dy = (pt.y - prev.y);
                        float dr = (prev.dia - pt.dia) * 0.5f;

                        //print("dy=" + dy + " dr=" + dr + " len=" + Mathf.Sqrt(dy * dy + dr * dr).ToString("F3"));
                        tankVLength += Mathf.Sqrt(dy * dy + dr * dr);

                        // average diameter weighted by dy
                        sumDiameters += (pt.dia + prev.dia) * dy;
                    }

                    prev    = pt;
                    prevOff = off;
                    off    += pt.circ.totVertexes + 1;
                    odd     = !odd;
                }
            }

            // Use the weighted average diameter across segments to set the ULength
            float tankULength = Mathf.PI * sumDiameters / (last.y - first.y);

            //print("ULength=" + tankULength + " VLength=" + tankVLength);

            // set the texture scale.
            RaiseChangeTextureScale("sides", PPart.SidesMaterial, new Vector2(tankULength, tankVLength));

            m.WriteTo(SidesMesh);

            // The endcaps.
            nVrt = first.circ.totVertexes + last.circ.totVertexes;
            nTri = first.circ.totVertexes - 2 + last.circ.totVertexes - 2;
            m    = new UncheckedMesh(nVrt, nTri);

            first.circ.WriteEndcap(first.dia, first.y, false, 0, 0, m, false);
            last.circ.WriteEndcap(last.dia, last.y, true, first.circ.totVertexes, (first.circ.totVertexes - 2) * 3, m, !odd);

            m.WriteTo(EndsMesh);

            // build the collider mesh at a lower resolution than the visual mesh.
            if (customCollider)
            {
                //Debug.LogWarning("Collider mesh vert=" + nColVrt + " tris=" + nColTri);
                m   = new UncheckedMesh(nColVrt, nColTri);
                odd = false;
                {
                    ProfilePoint prev = null;
                    int          off = 0, prevOff = 0;
                    int          tOff = 0;
                    foreach (ProfilePoint pt in pts)
                    {
                        if (!pt.inCollider)
                        {
                            continue;
                        }
                        //Debug.LogWarning("Collider circ (" + pt.dia + ", " + pt.y + ") verts=" + pt.colliderCirc.totVertexes);
                        pt.colliderCirc.WriteVertexes(diameter: pt.dia, y: pt.y, v: pt.v, norm: pt.norm, off: off, m: m, odd: odd);
                        if (prev != null)
                        {
                            CirclePoints.WriteTriangles(prev.colliderCirc, prevOff, pt.colliderCirc, off, m.triangles, tOff * 3, !odd);
                            tOff += prev.colliderCirc.totVertexes + pt.colliderCirc.totVertexes;
                        }

                        prev    = pt;
                        prevOff = off;
                        off    += pt.colliderCirc.totVertexes + 1;
                        odd     = !odd;
                    }
                }

                if (colliderMesh == null)
                {
                    colliderMesh = new Mesh();
                }

                m.WriteTo(colliderMesh);

                PPart.ColliderMesh = colliderMesh;
            }
            else
            {
                PPart.ColliderMesh = SidesMesh;
            }

            RaiseModelAndColliderChanged();
        }
Exemplo n.º 13
0
    /// <summary>
    /// 円周Mesh作成用の座標を返す
    /// </summary>
    /// <returns>The circumference points.</returns>
    /// <param name="theOrigin">The origin.</param>
    /// <param name="CircleSize">Circle size.</param>
    /// <param name="cpoints">Cpoints.</param>
    private CirclePoints CreateCircumferencePoints(Vector3 theOrigin, float CircleSize, CirclePoints cpoints)
    {
        var unit_angle   = 1;
        var triangle_num = 360 / unit_angle;

        // 原点
        //cpoints.vertextList.Add(theOrigin);

        // 近似のため、円上の座標を取得
        for (int i = 0; i < triangle_num; i++)
        {
            var sin = Math.Sin(unit_angle * i * (Math.PI / 180));
            var cos = Math.Cos(unit_angle * i * (Math.PI / 180));
            cpoints.vertextList.Add(
                new Vector3((float)cos * CircleSize + theOrigin.x, (float)sin * CircleSize + theOrigin.y, theOrigin.z));
        }

        // 座標と三角形の頂点を対応させる
        for (int i = 0; i < triangle_num; i++)
        {
            cpoints.indexList.Add(i);
        }

        return(cpoints);
    }
Exemplo n.º 14
0
            /// <summary>
            /// Creates a.vertexes + b.vertexes triangles to cover the surface between circle a and b.
            /// </summary>
            /// <param name="a">the first circle points</param>
            /// <param name="ao">offset into vertex array for a points</param>
            /// <param name="b">the second circle points</param>
            /// <param name="bo">offset into vertex array for b points</param>
            /// <param name="triangles">triangles array for output</param>
            /// <param name="to">offset into triangles array. This must be a multiple of 3</param>
            /// <param name="odd">Is this an odd row</param>
            public static void WriteTriangles(CirclePoints a, int ao, CirclePoints b, int bo, int[] triangles, int to, bool odd)
            {
                int aq = a.subdivCount + 1, bq = b.subdivCount + 1;
                int ai = 0, bi = 0;
                int ad = (odd ? 1 : 0), bd = (odd ? 0 : 1);

                while (ai < aq || bi < bq)
                {
                    float au = (ai < aq) ? a.uCoords[ad][ai] : (a.uCoords[ad][0] + 0.25f);
                    float bu = (bi < bq) ? b.uCoords[bd][bi] : (b.uCoords[bd][0] + 0.25f);

                    if (au < bu)
                    {
                        //MonoBehaviour.print("A-tri #" + ai + " tOff=" + to);
                        triangles[to++] = ao + ai;
                        triangles[to++] = bo + bi;
                        triangles[to++] = ao + ai + 1;
                        //MonoBehaviour.print(" (" + triangles[to - 3] + ", " + triangles[to - 2] + ", " + triangles[to - 1] + ") ");

                        triangles[to++] = ao + ai + aq;
                        triangles[to++] = bo + bi + bq;
                        triangles[to++] = ao + ai + 1 + aq;
                        //MonoBehaviour.print(" (" + triangles[to - 3] + ", " + triangles[to - 2] + ", " + triangles[to - 1] + ") ");

                        triangles[to++] = ao + ai + 2 * aq;
                        triangles[to++] = bo + bi + 2 * bq;
                        triangles[to++] = ao + ai + 1 + 2 * aq;
                        //MonoBehaviour.print(" (" + triangles[to - 3] + ", " + triangles[to - 2] + ", " + triangles[to - 1] + ") ");

                        triangles[to++] = ao + ai + 3 * aq;
                        triangles[to++] = bo + bi + 3 * bq;
                        triangles[to++] = ao + ai + 1 + 3 * aq;
                        //MonoBehaviour.print(" (" + triangles[to - 3] + ", " + triangles[to - 2] + ", " + triangles[to - 1] + ") ");

                        ++ai;
                    }
                    else
                    {
                        //MonoBehaviour.print("B-tri #" + bi + " tOff=" + to);
                        triangles[to++] = bo + bi;
                        triangles[to++] = bo + bi + 1;
                        triangles[to++] = ao + ai;
                        //MonoBehaviour.print(" (" + triangles[to - 3] + ", " + triangles[to - 2] + ", " + triangles[to - 1] + ") ");

                        triangles[to++] = bo + bi + bq;
                        triangles[to++] = bo + bi + 1 + bq;
                        triangles[to++] = ao + ai + aq;
                        //MonoBehaviour.print(" (" + triangles[to - 3] + ", " + triangles[to - 2] + ", " + triangles[to - 1] + ") ");

                        triangles[to++] = bo + bi + 2 * bq;
                        triangles[to++] = bo + bi + 1 + 2 * bq;
                        triangles[to++] = ao + ai + 2 * aq;
                        //MonoBehaviour.print(" (" + triangles[to - 3] + ", " + triangles[to - 2] + ", " + triangles[to - 1] + ") ");

                        triangles[to++] = bo + bi + 3 * bq;
                        triangles[to++] = bo + bi + 1 + 3 * bq;
                        triangles[to++] = ao + ai + 3 * aq;
                        //MonoBehaviour.print(" (" + triangles[to - 3] + ", " + triangles[to - 2] + ", " + triangles[to - 1] + ") ");

                        ++bi;
                    }
                }
            }
Exemplo n.º 15
0
        protected override void UpdateShape(bool force)
        {
            // ReSharper disable CompareOfFloatsByEqualityOperator
            if (!force && oldDiameter == diameter && oldLength == length && oldFillet == fillet)
            {
                return;
            }

            if (HighLogic.LoadedSceneIsFlight)
            {
                Volume = CalcVolume();
            }
            else if (HighLogic.LoadedSceneIsEditor)
            {
                if (filletEdit == null)
                {
                    filletEdit = (UI_FloatEdit)Fields["fillet"].uiControlEditor;
                }

                if (length != oldLength)
                {
                    if (length < oldLength && fillet > length)
                    {
                        fillet = length;
                    }

                    float volExcess = MaxMinVolume();
                    if (volExcess != 0)
                    {
                        // Again using alpha, solve the volume equation below equation for l
                        // v = 1/24 pi (6 d^2 l+3 (pi-4) d f^2+(10-3 pi) f^3) for l
                        // l = (-3 (pi-4) pi d f^2+pi (3 pi-10) f^3+24 v)/(6 pi d^2)
                        length = (-3f * (Pi - 4f) * Pi * diameter * pow(fillet, 2) + Pi * (3f * Pi - 10f) * pow(fillet, 3) + 24f * Volume) / (6f * Pi * pow(diameter, 2));
                        length = (float)Math.Round(length, 3);

                        // We could iterate here with the fillet and push it back up if it's been pushed down
                        // but it's altogether too much bother. User will just have to suck it up and not be
                        // so darn agressive with short lengths. I mean, seriously... :)
                    }

                    filletEdit.maxValue = Mathf.Min(length, useEndDiameter ? PPart.diameterMax : diameter);
                }
                else if (diameter != oldDiameter)
                {
                    if (useEndDiameter)
                    {
                        if (diameter + fillet < PPart.diameterMin)
                        {
                            fillet = PPart.diameterMin - diameter;
                        }
                        else if (diameter + fillet > PPart.diameterMax)
                        {
                            fillet = PPart.diameterMax - diameter;
                        }
                    }
                    else
                    {
                        if (diameter < oldDiameter && fillet > diameter)
                        {
                            fillet = diameter;
                        }
                    }

                    float volExcess = MaxMinVolume();
                    if (volExcess != 0)
                    {
                        // Unfortunatly diameter is not as easily isolated, but its still possible.

                        // v = 1/24 pi (6 d^2 l+3 (pi-4) d f^2+(10-3 pi) f^3) for d
                        // simplify d = ((-3 pi^2 f^2+12 pi f^2) ± sqrt(3 pi) sqrt(3 pi^3 f^4-24 pi^2 f^4+48 pi f^4+24 pi^2 f^3 l-80 pi f^3 l+192 l v))/(12 pi l)
                        // d = (-3 (pi-4) pi f^2 ± sqrt(3 pi) sqrt(3 (pi-4)^2 pi f^4+8 pi (3 pi-10) f^3 l+192 l v)) / (12 pi l)

                        float t1 = -3 * (Pi - 4f) * Pi * fillet * fillet;
                        float t2 = sqrt(3f * Pi) * sqrt(3f * pow(Pi - 4f, 2) * Pi * pow(fillet, 4) + 8f * Pi * (3f * Pi - 10f) * pow(fillet, 3) * length + 192f * length * Volume);
                        float de = (12f * Pi * length);

                        // I'm pretty sure only the +ve value is required, but make the -ve possible too.
                        diameter = (t1 + t2) / de;
                        if (diameter < 0)
                        {
                            diameter = (t1 - t2) / de;
                        }

                        diameter = (float)Math.Round(diameter, 3);
                    }

                    filletEdit.maxValue = Mathf.Min(length, useEndDiameter ? PPart.diameterMax : diameter);
                }
                else if (fillet != oldFillet)
                {
                    if (useEndDiameter)
                    {
                        // Keep diameter + fillet within range.
                        if (diameter + fillet < PPart.diameterMin)
                        {
                            diameter = PPart.diameterMin - fillet;
                        }
                        else if (diameter + fillet > PPart.diameterMax)
                        {
                            diameter = PPart.diameterMax - fillet;
                        }
                    }

                    // Will do an iterative process for finding the value.
                    // The equation is far too complicated plug this into alpha and you'll see what I mean:
                    // v = 1/24 pi (6 d^2 l+3 (pi-4) d f^2+(10-3 pi) f^3) for f

                    float vol = CalcVolume();
                    float inc;

                    if (vol < PPart.volumeMin)
                    {
                        Volume = PPart.volumeMin;
                        inc    = -0.001f;
                    }
                    else if (vol > PPart.volumeMax)
                    {
                        Volume = PPart.volumeMax;
                        inc    = 0.001f;
                    }
                    else
                    {
                        Volume = vol;
                        goto goldilocks;
                    }

                    float lVol;
                    float lFillet;
                    do
                    {
                        lVol    = vol;
                        lFillet = fillet;
                        fillet += inc;
                        vol     = CalcVolume();
                    }while (Mathf.Abs(vol - Volume) < Mathf.Abs(lVol - Volume));
                    fillet = (float)Math.Round(lFillet, 3);
                    goldilocks :;
                }
            }

            LinkedList <ProfilePoint> points = new LinkedList <ProfilePoint>();

            if (fillet == 0)
            {
                // Reduces down to a cylinder part.
                points.AddLast(new ProfilePoint(diameter, -0.5f * length, 0f, new Vector2(1, 0)));
                points.AddLast(new ProfilePoint(diameter, 0.5f * length, 1f, new Vector2(1, 0)));
            }
            else
            {
                float bodyLength   = length - fillet;
                float endDiameter  = useEndDiameter ? diameter : (diameter - fillet);
                float bodyDiameter = useEndDiameter ? (fillet + diameter) : diameter;

                float filletLength = Mathf.PI * fillet * 0.5f;
                float totLength    = filletLength + bodyLength;
                float s1           = filletLength * 0.5f / totLength;

                CirclePoints cp = CirclePoints.ForDiameter(fillet, MaxCircleError, MinCircleVertexes);

                // We need to be careful with the number of points so we don't blow the 255 point budget for colliders
                CirclePoints collCp   = CirclePoints.ForDiameter(fillet, MaxCircleError, 0, 12);
                CirclePoints collEnds = CirclePoints.ForDiameter(endDiameter, MaxCircleError * 4f, 4, 12);
                CirclePoints collBody = CirclePoints.ForDiameter(bodyDiameter, MaxCircleError * 4f, 4, 16);

                points.AddLast(new ProfilePoint(endDiameter, -0.5f * length, 0f, new Vector2(0, -1), colliderCirc: collEnds));

                foreach (Vector3 xzu in cp.PointsXZU(0.5f, 0.75f))
                {
                    points.AddLast(new ProfilePoint(endDiameter + fillet * xzu.x, -0.5f * (bodyLength - fillet * xzu.y), s1 * Mathf.InverseLerp(0.5f, 0.75f, xzu[2]), xzu, inCollider: false));
                }
                foreach (Vector3 xzu in collCp.PointsXZU(0.5f, 0.75f))
                {
                    points.AddLast(new ProfilePoint(endDiameter + fillet * xzu.x, -0.5f * (bodyLength - fillet * xzu.y), s1 * Mathf.InverseLerp(0.5f, 0.75f, xzu[2]), xzu, inRender: false, colliderCirc: collEnds));
                }

                points.AddLast(new ProfilePoint(bodyDiameter, -0.5f * bodyLength, s1, new Vector2(1, 0), colliderCirc: collBody));
                if (fillet < length)
                {
                    points.AddLast(new ProfilePoint(bodyDiameter, 0.5f * bodyLength, 1f - s1, new Vector2(1, 0), colliderCirc: collBody));
                }

                foreach (Vector3 xzu in cp.PointsXZU(0.75f, 1))
                {
                    points.AddLast(new ProfilePoint(endDiameter + fillet * xzu.x, 0.5f * (bodyLength + fillet * xzu.y), 1f - s1 * Mathf.InverseLerp(1f, 0.75f, xzu[2]), xzu, inCollider: false));
                }
                foreach (Vector3 xzu in collCp.PointsXZU(0.75f, 1))
                {
                    points.AddLast(new ProfilePoint(endDiameter + fillet * xzu.x, 0.5f * (bodyLength + fillet * xzu.y), 1f - s1 * Mathf.InverseLerp(1f, 0.75f, xzu[2]), xzu, inRender: false, colliderCirc: collEnds));
                }
                points.AddLast(new ProfilePoint(endDiameter, 0.5f * length, 1f, new Vector2(0, 1), colliderCirc: collEnds));
            }

            WriteMeshes(points);

            oldDiameter = diameter;
            oldLength   = length;
            oldFillet   = fillet;
            // ReSharper restore CompareOfFloatsByEqualityOperator
            //RefreshPartEditorWindow();
            UpdateInterops();
        }
Exemplo n.º 16
0
 public ProfilePoint(float dia, float y, float v, Vector2 norm, bool inRender = true, bool inCollider = true, CirclePoints circ = null, CirclePoints colliderCirc = null)
 {
     this.dia = dia;
     this.y = y;
     this.v = v;
     this.norm = norm;
     this.inRender = inRender;
     this.inCollider = inCollider;
     this.circ = inRender ? (circ ?? CirclePoints.ForDiameter(dia, maxCircleError, minCircleVertexes)) : null;
     this.colliderCirc = inCollider ? (colliderCirc ?? this.circ ?? CirclePoints.ForDiameter(dia, maxCircleError, minCircleVertexes)) : null;
 }
Exemplo n.º 17
0
            /// <summary>
            /// Creates a.vertexes + b.vertexes triangles to cover the surface between circle a and b.
            /// </summary>
            /// <param name="a">the first circle points</param>
            /// <param name="ao">offset into vertex array for a points</param>
            /// <param name="b">the second circle points</param>
            /// <param name="bo">offset into vertex array for b points</param>
            /// <param name="triangles">triangles array for output</param>
            /// <param name="to">offset into triangles array. This must be a multiple of 3</param>
            public static void WriteTriangles(CirclePoints a, int ao, CirclePoints b, int bo, int[] triangles, int too, bool odd)
            {
                int to = too;

                int aq = a.subdivCount + 1, bq = b.subdivCount + 1;
                int ai = 0, bi = 0;
                int ad = (odd ? 1 : 0), bd = (odd ? 0 : 1);

                while (ai < aq || bi < bq)
                {
                    float au = (ai < aq) ? a.uCoords[ad][ai] : (a.uCoords[ad][0] + 0.25f);
                    float bu = (bi < bq) ? b.uCoords[bd][bi] : (b.uCoords[bd][0] + 0.25f);

                    if (au < bu)
                    {
                        //MonoBehaviour.print("A-tri #" + ai + " tOff=" + to);
                        triangles[to++] = ao + ai;
                        triangles[to++] = bo + bi;
                        triangles[to++] = ao + ai + 1;
                        //MonoBehaviour.print(" (" + triangles[to - 3] + ", " + triangles[to - 2] + ", " + triangles[to - 1] + ") ");

                        triangles[to++] = ao + ai + aq;
                        triangles[to++] = bo + bi + bq;
                        triangles[to++] = ao + ai + 1 + aq;
                        //MonoBehaviour.print(" (" + triangles[to - 3] + ", " + triangles[to - 2] + ", " + triangles[to - 1] + ") ");

                        triangles[to++] = ao + ai + 2 * aq;
                        triangles[to++] = bo + bi + 2 * bq;
                        triangles[to++] = ao + ai + 1 + 2 * aq;
                        //MonoBehaviour.print(" (" + triangles[to - 3] + ", " + triangles[to - 2] + ", " + triangles[to - 1] + ") ");

                        triangles[to++] = ao + ai + 3 * aq;
                        triangles[to++] = bo + bi + 3 * bq;
                        triangles[to++] = ao + ai + 1 + 3 * aq;
                        //MonoBehaviour.print(" (" + triangles[to - 3] + ", " + triangles[to - 2] + ", " + triangles[to - 1] + ") ");

                        ++ai;
                    }
                    else
                    {
                        //MonoBehaviour.print("B-tri #" + bi + " tOff=" + to);
                        triangles[to++] = bo + bi;
                        triangles[to++] = bo + bi + 1;
                        triangles[to++] = ao + ai;
                        //MonoBehaviour.print(" (" + triangles[to - 3] + ", " + triangles[to - 2] + ", " + triangles[to - 1] + ") ");

                        triangles[to++] = bo + bi + bq;
                        triangles[to++] = bo + bi + 1 + bq;
                        triangles[to++] = ao + ai + aq;
                        //MonoBehaviour.print(" (" + triangles[to - 3] + ", " + triangles[to - 2] + ", " + triangles[to - 1] + ") ");

                        triangles[to++] = bo + bi + 2 * bq;
                        triangles[to++] = bo + bi + 1 + 2 * bq;
                        triangles[to++] = ao + ai + 2 * aq;
                        //MonoBehaviour.print(" (" + triangles[to - 3] + ", " + triangles[to - 2] + ", " + triangles[to - 1] + ") ");

                        triangles[to++] = bo + bi + 3 * bq;
                        triangles[to++] = bo + bi + 1 + 3 * bq;
                        triangles[to++] = ao + ai + 3 * aq;
                        //MonoBehaviour.print(" (" + triangles[to - 3] + ", " + triangles[to - 2] + ", " + triangles[to - 1] + ") ");

                        ++bi;
                    }
                }
            }
Exemplo n.º 18
0
 public static CirclePoints ForPoints(int vertexes)
 {
     int idx = vertexes / 4 - 1;
     if (idx >= circlePoints.Count)
     {
         CirclePoints prev = circlePoints.Last();
         do
         {
             circlePoints.Add(prev = new CirclePoints(prev.subdivCount + 1));
         }
         while (prev.totVertexes <= vertexes);
     }
     return circlePoints[idx];
 }
Exemplo n.º 19
0
 internal void Clear()
 {
     CirclePoints.Clear();
     CrossPoints.Clear();
 }
Exemplo n.º 20
0
        public Segment(Snake snake, Vector3 globalPosition, Vector3 globalRotation)
        {
            position = globalPosition;
            int offset = snake.segments.Count;

            // Create the new set of vertices.
            Vector3[] calculatedPoints = CirclePoints.getPointsOnCircle(BODY_DIAMETER, VERTEX_COUNT);
            Vector3[] rotatedPoints    = CirclePoints.rotatePointsAroundAxis(calculatedPoints, globalRotation);
            Vector3[] vertices         = new Vector3[VERTEX_COUNT];
            Vector2[] uvs = new Vector2[VERTEX_COUNT];

            //makes a ring of 8 points at the same point as the snake head
            for (int i = 0; i < VERTEX_COUNT; i++)
            {
                vertices[i] = globalPosition + rotatedPoints[i];
                uvs[i]      = new Vector2(i * (1 / VERTEX_COUNT), 0 + SEGMENT_DISTANCE * snake.segmentTicker);
            }

            snake.segmentTicker++;

            snake.vertices.AddRange(vertices);
            snake.uvs.AddRange(uvs);

            if (snake.segments.Count > 0)
            {
                int[] triangles = new int[VERTEX_COUNT * 6];

                int vertexOffset;

                for (int i = 0, j = 0; i < VERTEX_COUNT; i++, j += 6)
                {
                    vertexOffset = i + offset * VERTEX_COUNT;

                    int lastVertex;
                    if (vertexOffset + 1 == snake.vertices.Count)
                    {
                        lastVertex = snake.vertices.Count - VERTEX_COUNT;
                    }
                    else
                    {
                        lastVertex = vertexOffset + 1;
                    }

                    int finalFinalVertex;
                    if (j + 5 == triangles.Length - 1)
                    {
                        finalFinalVertex = vertexOffset - (VERTEX_COUNT * 2) + 1;
                    }
                    else
                    {
                        finalFinalVertex = vertexOffset - VERTEX_COUNT + 1;
                    }

                    // Face 1
                    triangles[j]     = vertexOffset - VERTEX_COUNT;
                    triangles[j + 1] = lastVertex;
                    triangles[j + 2] = vertexOffset;

                    // Face 2
                    triangles[j + 3] = finalFinalVertex;
                    triangles[j + 4] = lastVertex;
                    triangles[j + 5] = vertexOffset - VERTEX_COUNT;
                }

                snake.triangles.AddRange(triangles);
            }

            /*
             *          Debug.Log("SEGS: "+ snake.segments.Count);
             *          Debug.Log("VERTS: ");
             *          for (int i = 0; i < snake.vertices.Count; i++) Debug.Log("["+i+"] "+snake.vertices[i]);
             *          Debug.Log("TRIS: ");
             *          for (int i = 0; i < snake.triangles.Count; i++) Debug.Log("["+i+"] "+snake.triangles[i]);
             *          Debug.Log("");
             */
        }