internal override void UpdateShape(bool force = true)
 {
     Volume        = CalculateVolume();
     OuterDiameter = InnerDiameter / OuterToInnerFactor;
     GenerateMeshes();
     // WriteMeshes in AbstractSoRShape typically does UpdateNodeSize, UpdateProps, RaiseModelAndColliderChanged
     UpdateNodeSize(TopNodeName);
     UpdateNodeSize(BottomNodeName);
     PPart.UpdateProps();
     RaiseModelAndColliderChanged();
 }
Пример #2
0
        internal override void UpdateShape(bool force = true)
        {
            part.CoMOffset = CoMOffset;
            Volume         = CalculateVolume();
            GenerateMeshes(outerDiameter / 2, innerDiameter / 2, length, numSides);

            GenerateColliders();
            // WriteMeshes in AbstractSoRShape typically does UpdateNodeSize, UpdateProps, RaiseModelAndColliderChanged
            UpdateNodeSize(TopNodeName);
            UpdateNodeSize(BottomNodeName);
            PPart.UpdateProps();
            RaiseModelAndColliderChanged();
        }
Пример #3
0
        private void GenerateColliderMesh()
        {
            var mesh = new UncheckedMesh(CornerCount * 2, SideTriangles + 2 * TrianglesPerCap);

            GenerateCapVertices(mesh, -HalfHeight, 0);
            GenerateCapVertices(mesh, HalfHeight, CornerCount);
            GenerateSideTriangles(mesh, CornerCount, 1);
            GenerateCapTriangles(mesh, false, SideTriangles);
            GenerateCapTriangles(mesh, true, SideTriangles + TrianglesPerCap);

            var colliderMesh = new Mesh();

            mesh.WriteTo(colliderMesh);

            PPart.UpdateOrReplaceSingleCollider(colliderMesh);
        }
Пример #4
0
        private void GenerateColliders()
        {
            PPart.ClearColliderHolder();
            // The first corner is at angle=0.
            // We want to start the colliders in between the corners.
            float offset = (360f / numSides) / 2 - 90f;

            for (int i = 0; i < numSides; i++)
            {
                var go   = new GameObject($"Mesh_Collider_{i}");
                var coll = go.AddComponent <MeshCollider>();
                go.transform.SetParent(PPart.ColliderHolder.transform, false);
                coll.convex     = true;
                coll.sharedMesh = GenerateColliderMesh();
                var orientation = Quaternion.AngleAxis(90 + offset + (360f * i / numSides), Vector3.up);
                go.transform.localRotation *= orientation;
                go.transform.localPosition  = Vector3.zero;
            }
        }
Пример #5
0
        private void GenerateColliders()
        {
            PPart.ClearColliderHolder();
            // The first corner is at angle=0.
            // We want to start the capsules in between the corners.
            float   offset   = (360f / numSides) / 2;
            Vector3 refPoint = new Vector3(MajorRadius, 0, 0);

            for (int i = 0; i < numSides; i++)
            {
                var go   = new GameObject($"Mesh_Collider_{i}");
                var coll = go.AddComponent <MeshCollider>();
                go.transform.SetParent(PPart.ColliderHolder.transform, false);
                coll.convex     = true;
                coll.sharedMesh = GenerateColliderMesh();
                var prevCornerOrient = Quaternion.AngleAxis(360f * i / numSides, Vector3.up);
                var prevCornerPos    = prevCornerOrient * refPoint;
                var nextCornerOrient = Quaternion.AngleAxis(360f * (i + 1) / numSides, Vector3.up);
                var nextCornerPos    = nextCornerOrient * refPoint;
                var orientation      = Quaternion.AngleAxis(90 + offset + (360f * i / numSides), Vector3.up);
                go.transform.localRotation *= orientation;
                go.transform.localPosition  = (prevCornerPos + nextCornerPos) / 2;
            }
        }
Пример #6
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);

            lastProfile = 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.legacyTextureHandler.SidesMaterial, new Vector2(tankULength, tankVLength));



            if (HighLogic.LoadedScene == GameScenes.LOADING)
            {
                m.WriteTo(PPart.SidesIconMesh);
            }
            else
            {
                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);



            if (HighLogic.LoadedScene == GameScenes.LOADING)
            {
                m.WriteTo(PPart.EndsIconMesh);
            }
            else
            {
                m.WriteTo(EndsMesh);
            }

            // build the collider mesh at a lower resolution than the visual mesh.
            //Debug.LogWarning("Collider mesh vert=" + nColVrt + " tris=" + nColTri);

            // collider endcaps
            ProfilePoint firstColPt, lastColPt;

            firstColPt = pts.First(x => x.inCollider);
            lastColPt  = pts.Last(x => x.inCollider);

            int nColEndVrt = firstColPt.colliderCirc.totVertexes + lastColPt.colliderCirc.totVertexes;
            int nColEndTri = firstColPt.colliderCirc.totVertexes - 2 + lastColPt.colliderCirc.totVertexes - 2;

            m   = new UncheckedMesh(nColVrt + nColEndVrt, nColTri + nColEndTri);
            odd = false;
            {
                ProfilePoint prev = null;
                int          off = 0, prevOff = 0;
                int          tOff = 0;

                foreach (ProfilePoint pt in pts)
                {
                    if (!pt.inCollider)
                    {
                        continue;
                    }

                    if (prev == null)
                    {
                        pt.colliderCirc.WriteEndcap(pt.dia, pt.y, false, 0, 0, m, odd);
                        off  = firstColPt.colliderCirc.totVertexes;
                        tOff = (firstColPt.colliderCirc.totVertexes - 2);
                    }
                    //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;
                }

                prev.colliderCirc.WriteEndcap(prev.dia, prev.y, true, off, tOff * 3, m, odd);
            }

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

            m.WriteTo(colliderMesh);
            //m.WriteTo(SidesMesh);
            if (colliderMesh.triangles.Length / 3 > 255)
            {
                Debug.LogWarning("Collider mesh contains " + colliderMesh.triangles.Length / 3 + " triangles. Maximum allowed triangles: 255");
            }

            PPart.ColliderMesh = colliderMesh;

            PPart.UpdateProps();

            RaiseModelAndColliderChanged();
        }