Exemplo n.º 1
0
        public static void findShieldedPartsCylinder(Part basePart, Bounds fairingRenderBounds, List <Part> shieldedParts, float topY, float bottomY, float topRadius, float bottomRadius)
        {
            float height        = topY - bottomY;
            float largestRadius = topRadius > bottomRadius ? topRadius : bottomRadius;

            Vector3 lookupCenterLocal  = new Vector3(0, bottomY + (height * 0.5f), 0);
            Vector3 lookupTopLocal     = new Vector3(0, topY, 0);
            Vector3 lookupBottomLocal  = new Vector3(0, bottomY, 0);
            Vector3 lookupCenterGlobal = basePart.transform.TransformPoint(lookupCenterLocal);

            Ray lookupRay = new Ray(lookupBottomLocal, new Vector3(0, 1, 0));

            List <Part> partsFound = new List <Part>();

            Collider[] foundColliders = Physics.OverlapSphere(lookupCenterGlobal, height * 1.5f, 1);
            foreach (Collider col in foundColliders)
            {
                Part pt = col.gameObject.GetComponentUpwards <Part>();
                if (pt != null && pt != basePart && pt.vessel == basePart.vessel && !partsFound.Contains(pt))
                {
                    partsFound.Add(pt);
                }
            }

            Bounds[] otherPartBounds;
            Vector3  otherPartCenterLocal;

            float partYPos;
            float partYPercent;
            float partYRadius;
            float radiusOffset = topRadius - bottomRadius;

            foreach (Part pt in partsFound)
            {
                //check basic render bounds for containment

                //TODO this check misses the case where the fairing is long/tall, containing a wide part; it will report that the wide part can fit inside
                //of the fairing, due to the relative size of their colliders
                otherPartBounds = pt.GetRendererBounds();
                if (PartGeometryUtil.MergeBounds(otherPartBounds, pt.transform).size.sqrMagnitude > fairingRenderBounds.size.sqrMagnitude)
                {
                    continue;
                }

                Vector3 otherPartCenter = pt.partTransform.TransformPoint(PartGeometryUtil.FindBoundsCentroid(otherPartBounds, pt.transform));
                if (!fairingRenderBounds.Contains(otherPartCenter))
                {
                    continue;
                }

                //check part bounds center point against conic projection of the fairing
                otherPartCenterLocal = basePart.transform.InverseTransformPoint(otherPartCenter);

                //check vs top and bottom of the shielded area
                if (otherPartCenterLocal.y > lookupTopLocal.y || otherPartCenterLocal.y < lookupBottomLocal.y)
                {
                    continue;
                }

                //quick check vs cylinder radius
                float distFromLine = SSTUUtils.distanceFromLine(lookupRay, otherPartCenterLocal);
                if (distFromLine > largestRadius)
                {
                    continue;
                }

                //more precise check vs radius of the cone at that Y position
                partYPos     = otherPartCenterLocal.y - lookupBottomLocal.y;
                partYPercent = partYPos / height;
                partYRadius  = partYPercent * radiusOffset;
                if (distFromLine > (partYRadius + bottomRadius))
                {
                    continue;
                }
                shieldedParts.Add(pt);
            }
        }
Exemplo n.º 2
0
        //TODO clean this up to be easier to read/understand now that it is optimized for cylinder check only
        public static void findShieldedPartsCylinder(Part basePart, List <Part> shieldedParts, float topY, float bottomY, float topRadius, float bottomRadius)
        {
            float height        = topY - bottomY;
            float largestRadius = topRadius > bottomRadius ? topRadius : bottomRadius;

            Vector3 lookupCenterLocal  = new Vector3(0, bottomY + (height * 0.5f), 0);
            Vector3 lookupTopLocal     = new Vector3(0, topY, 0);
            Vector3 lookupBottomLocal  = new Vector3(0, bottomY, 0);
            Vector3 lookupCenterGlobal = basePart.transform.TransformPoint(lookupCenterLocal);

            Ray lookupRay = new Ray(lookupBottomLocal, new Vector3(0, 1, 0));

            List <Part> partsFound = new List <Part>();

            //do a basic sphere check vs the maximal size of the cylinder
            Collider[] foundColliders = Physics.OverlapSphere(lookupCenterGlobal, height * 1.5f, 1);
            foreach (Collider col in foundColliders)
            {
                Part pt = col.gameObject.GetComponentUpwards <Part>();
                if (pt != null && pt != basePart && pt.vessel == basePart.vessel && !partsFound.Contains(pt))
                {
                    partsFound.Add(pt);
                }
            }

            Vector3 otherPartCenterLocal;

            float partYPos;
            float partYPercent;
            float partYRadius;
            float radiusOffset = topRadius - bottomRadius;

            foreach (Part pt in partsFound)
            {
                Vector3 otherPartCenter = pt.partTransform.TransformPoint(PartGeometryUtil.FindBoundsCentroid(pt.GetRendererBounds(), pt.transform));
                //check part bounds center point against conic projection of the fairing
                otherPartCenterLocal = basePart.transform.InverseTransformPoint(otherPartCenter);

                //check vs top and bottom of the shielded area
                if (otherPartCenterLocal.y > lookupTopLocal.y || otherPartCenterLocal.y < lookupBottomLocal.y)
                {
                    continue;
                }

                //quick check vs cylinder radius
                float distFromLine = SSTUUtils.distanceFromLine(lookupRay, otherPartCenterLocal);
                if (distFromLine > largestRadius)
                {
                    continue;
                }

                //more precise check vs radius of the cone at that Y position
                partYPos     = otherPartCenterLocal.y - lookupBottomLocal.y;
                partYPercent = partYPos / height;
                partYRadius  = partYPercent * radiusOffset;
                if (distFromLine > (partYRadius + bottomRadius))
                {
                    continue;
                }
                shieldedParts.Add(pt);
                //print("Shielding part: " + pt);
            }
        }
        void enableShielding()
        {
            disableShielding();

            var attached = getFairingParams();

            if (!sideFairing)
            {
                return;
            }

            //  Get all parts in range.

            var parts = new List <Part>();

            var colliders = Physics.OverlapSphere(part.transform.TransformPoint(lookupCenter), lookupRad, 1);

            for (int i = colliders.Length - 1; i >= 0; --i)
            {
                var p = colliders [i].gameObject.GetComponentUpwards <Part>();

                if (p != null)
                {
                    parts.AddUnique(p);
                }
            }

            //  Filter parts.

            float sizeSqr       = lookupRad * lookupRad * 4;
            float boundCylRadSq = boundCylRad * boundCylRad;

            bool isInline  = (sideFairing.inlineHeight > 0);
            bool topClosed = false;

            Matrix4x4 w2l = Matrix4x4.identity, w2lb = Matrix4x4.identity;

            Bounds topBounds = default(Bounds);

            if (isInline)
            {
                w2l  = part.transform.worldToLocalMatrix;
                w2lb = w2l;

                for (int i = 0; i < 3; ++i)
                {
                    for (int j = 0; j < 3; ++j)
                    {
                        w2lb [i, j] = Mathf.Abs(w2lb [i, j]);
                    }
                }

                topBounds = new Bounds(new Vector3(0, boundCylY1, 0), new Vector3(sideFairing.topRad * 2, sideFairing.sideThickness, sideFairing.topRad * 2));
            }

            for (int pi = 0; pi < parts.Count; ++pi)
            {
                var pt = parts [pi];

                //  Check special cases.

                if (pt == part)
                {
                    shieldedParts.Add(pt);

                    continue;
                }

                bool isSide = false;

                for (int i = 0; i < attached.Length; ++i)
                {
                    if (attached [i].attachedPart == pt)
                    {
                        isSide = true;

                        break;
                    }
                }

                if (isSide)
                {
                    continue;
                }

                //  Check if the top is closed in the inline case.

                var bounds = pt.GetRendererBounds();

                var box = PartGeometryUtil.MergeBounds(bounds, pt.transform);

                if (isInline && !topClosed && pt.vessel == vessel)
                {
                    var wb = box; wb.Expand(sideFairing.sideThickness * 4);

                    var b = new Bounds(w2l.MultiplyPoint3x4(wb.center), w2lb.MultiplyVector(wb.size));

                    if (b.Contains(topBounds.min) && b.Contains(topBounds.max))
                    {
                        topClosed = true;
                    }
                }

                //  Check if the centroid is within the fairing bounds.

                var c = part.transform.InverseTransformPoint(PartGeometryUtil.FindBoundsCentroid(bounds, null));

                float y = c.y;

                if (y < boundCylY0 || y > boundCylY1)
                {
                    continue;
                }

                float xsq = new Vector2(c.x, c.z).sqrMagnitude;

                if (xsq > boundCylRadSq)
                {
                    continue;
                }

                //  Accurate centroid check.

                float x = Mathf.Sqrt(xsq);

                bool inside = false;

                for (int i = 1; i < shape.Length; ++i)
                {
                    var p0 = shape [i - 1];
                    var p1 = shape [i];

                    if (p0.y > p1.y)
                    {
                        var p = p0;

                        p0 = p1;
                        p1 = p;
                    }

                    if (y < p0.y || y > p1.y)
                    {
                        continue;
                    }

                    float dy = p1.y - p0.y, r;

                    if (dy <= 1e-6f)
                    {
                        r = (p0.x + p1.x) * 0.5f;
                    }
                    else
                    {
                        r = (p1.x - p0.x) * (y - p0.y) / dy + p0.x;
                    }

                    if (x > r)
                    {
                        continue;
                    }

                    inside = true;

                    break;
                }

                if (!inside)
                {
                    continue;
                }

                shieldedParts.Add(pt);
            }

            if (isInline && !topClosed)
            {
                disableShielding();

                return;
            }

            //  Add shielding.

            for (int i = 0; i < shieldedParts.Count; ++i)
            {
                shieldedParts [i].AddShield(this);
            }

            numShieldedDisplay = shieldedParts.Count;

            var fbase = part.GetComponent <ProceduralFairingBase>();

            if (fbase != null)
            {
                fbase.onShieldingEnabled(shieldedParts);
            }
        }