//Alternate mirroring function where the getter is a reference to an actual corner instead of a corner location identifier
        void MirrorCorner(ColliderCorner getter, ColliderCorner.CornerId setter, int xFactor, int yFactor, int zFactor)
        {
            ColliderCorner setCorner = GetCornerAtLocation(setter);

            setCorner.localPos.Set(xFactor * getter.localPos.x, yFactor * getter.localPos.y, zFactor * getter.localPos.z);
            setCorner.axleRadii     = getter.axleRadii;
            setCorner.radiusOffsets = getter.radiusOffsets;
        }
Пример #2
0
        }                           //Empty constructor

        //Creates a new collider corner by copying an existing one
        public ColliderCorner(ColliderCorner cc)
        {
            cornerLocation           = cc.cornerLocation;
            normalizedCornerLocation = cc.normalizedCornerLocation;
            localPos      = cc.localPos;
            axleRadii     = cc.axleRadii;
            radiusOffsets = cc.radiusOffsets;
        }
        //Sets corner positions based on box properties, called by the editor window after editing box properties
        public void SetCornerPositionsFromBox()
        {
            //Corner positioning based on boxSize and boxCenter
            if (cornerPositionMode == CornerPositionEditMode.BoxCenter)
            {
                for (int i = 0; i < corners.Length; i++)
                {
                    corners[i].localPos = Vector3.Scale(corners[i].normalizedCornerLocation, boxSize) * 0.5f + boxOffset;
                }
            }
            //Corner positioning based on boxSidesPos and boxSidesNeg
            else if (cornerPositionMode == CornerPositionEditMode.BoxSides)
            {
                for (int i = 0; i < corners.Length; i++)
                {
                    ColliderCorner curCorner = corners[i];
                    switch (curCorner.cornerLocation)
                    {
                    case ColliderCorner.CornerId.FrontTopRight:
                        curCorner.localPos = boxSidesPos;
                        break;

                    case ColliderCorner.CornerId.FrontTopLeft:
                        curCorner.localPos = new Vector3(boxSidesNeg.x, boxSidesPos.y, boxSidesPos.z);
                        break;

                    case ColliderCorner.CornerId.FrontBottomRight:
                        curCorner.localPos = new Vector3(boxSidesPos.x, boxSidesNeg.y, boxSidesPos.z);
                        break;

                    case ColliderCorner.CornerId.FrontBottomLeft:
                        curCorner.localPos = new Vector3(boxSidesNeg.x, boxSidesNeg.y, boxSidesPos.z);
                        break;

                    case ColliderCorner.CornerId.BackTopRight:
                        curCorner.localPos = new Vector3(boxSidesPos.x, boxSidesPos.y, boxSidesNeg.z);
                        break;

                    case ColliderCorner.CornerId.BackTopLeft:
                        curCorner.localPos = new Vector3(boxSidesNeg.x, boxSidesPos.y, boxSidesNeg.z);
                        break;

                    case ColliderCorner.CornerId.BackBottomRight:
                        curCorner.localPos = new Vector3(boxSidesPos.x, boxSidesNeg.y, boxSidesNeg.z);
                        break;

                    case ColliderCorner.CornerId.BackBottomLeft:
                        curCorner.localPos = boxSidesNeg;
                        break;
                    }
                }
            }
        }
        //Resets the corners to form a basic box shape
        public void ResetCorners()
        {
            boxSize     = Vector3.one;
            boxOffset   = Vector3.zero;
            boxSidesPos = Vector3.one * 0.5f;
            boxSidesNeg = Vector3.one * -0.5f;

            for (int i = 0; i < corners.Length; i++)
            {
                ColliderCorner curCorner = corners[i];
                curCorner.localPos = Vector3.Scale(curCorner.normalizedCornerLocation, boxSize) * 0.5f + boxOffset;
                curCorner.ResetRadii();
            }
        }
        //Copies properties from another GeneratorProps instance
        //If copyPreset is true, it will also copy the linked preset reference from the other instance
        public void CopyProperties(GeneratorProps gp, bool copyPreset)
        {
            if (copyPreset)
            {
                linkedPreset = gp.linkedPreset;
            }

            meshAssetPath      = gp.meshAssetPath;
            cornerPositionMode = gp.cornerPositionMode;
            cornerRadiusMode   = gp.cornerRadiusMode;
            cornerOffsetMode   = gp.cornerOffsetMode;
            cornerDetailMode   = gp.cornerDetailMode;
            boxSize            = gp.boxSize;
            boxOffset          = gp.boxOffset;
            boxSidesPos        = gp.boxSidesPos;
            boxSidesNeg        = gp.boxSidesNeg;
            for (int i = 0; i < corners.Length; i++)
            {
                corners[i] = new ColliderCorner(gp.corners[i]);
            }

            for (int i = 0; i < cornerDetails.Length; i++)
            {
                cornerDetails[i] = gp.cornerDetails[i];
            }

            topSegments             = gp.topSegments;
            bottomSegments          = gp.bottomSegments;
            XYDetail                = gp.XYDetail;
            YZDetail                = gp.YZDetail;
            XZDetail                = gp.XZDetail;
            detailSmoothness        = gp.detailSmoothness;
            stripDistribution1      = gp.stripDistribution1;
            stripDistribution2      = gp.stripDistribution2;
            bypassPolyTest          = gp.bypassPolyTest;
            polyTestMode            = gp.polyTestMode;
            detailReduction         = gp.detailReduction;
            detailReductionAttempts = gp.detailReductionAttempts;
            boxedCorners            = gp.boxedCorners;
            hooks = new DeformHook[gp.hooks.Length];

            for (int i = 0; i < hooks.Length; i++)
            {
                hooks[i] = new DeformHook(gp.hooks[i]);
            }
        }
        }                        //Empty constructor

        //Constructor with properties to use
        public VertexStrip(VertexStripProps setProps)
        {
            props = setProps;
            Vector3 center      = Vector3.zero;     //Center of each corner
            Vector3 nextCenter  = Vector3.zero;     //Center of subsequent corner
            Vector3 newVertex   = Vector3.zero;     //Current vertex being added
            Vector3 nextVertex  = Vector3.zero;     //Next vertex along strip
            float   increment   = 0.0f;             //Angle between vertices in each corner
            float   angle       = 0.0f;             //Current angle of the vertex in a corner
            int     iteration   = 0;                //Current being generated
            float   radiusScale = 1.0f;             //Scale of each corner
            float   sqrtTwo     = Mathf.Sqrt(2.0f); //Constant used to avoid repeat calculations

            //Looping through each corner
            while (iteration < 4)
            {
                //Vertex angle is incremented based on corner detail
                increment = props.cornerDetails[iteration] > 0 ?
                            (Mathf.PI * 0.5f) / props.cornerDetails[iteration] :
                            Mathf.PI * 0.25f;

                angle = Mathf.PI * 0.5f * iteration;//Starting angle in a corner

                int            curCornerIndex = (props.isTop ? iteration + 4 : iteration);
                ColliderCorner curCorner      = props.corners[curCornerIndex];
                ColliderCorner nextCorner     = props.corners[(iteration == 3 ? (props.isTop ? 4 : 0) : curCornerIndex + 1)];

                center      = curCorner.localPos + curCorner.axleRadii.y * (props.isTop ? Vector3.up : Vector3.down) * (props.flat ? 1.0f : props.cornerProgress);
                nextCenter  = nextCorner.localPos + nextCorner.axleRadii.y * (props.isTop ? Vector3.up : Vector3.down) * (props.flat ? 1.0f : props.cornerProgress);
                radiusScale = Mathf.Sqrt(1.0f - Mathf.Pow(Mathf.Clamp01(props.cornerProgress), 2.0f));//Implicit formula of unit circle solved for y above x-axis, x^2 + y^2 = 1 => y = sqrt(1 - x^2)

                Vector3 curRadiusOffset  = curCorner.GetOffset();
                Vector3 nextRadiusOffset = nextCorner.GetOffset();

                if (props.cornerDetails[iteration] == 0)
                {
                    //If corners are right angles
                    angle       += increment;
                    radiusScale *= sqrtTwo;//This is to keep the collider the same size when the corner detail is zero. Pythagorean Theorem: 1 + 1 = c^2 => sqrt(2) = c
                    newVertex    = center - curRadiusOffset + new Vector3(curCorner.axleRadii.x * radiusScale * Mathf.Cos(angle), 0.0f, curCorner.axleRadii.z * radiusScale * Mathf.Sin(angle));
                    verts.Add(newVertex);
                    nextVertex = nextCenter - nextRadiusOffset + new Vector3(nextCorner.axleRadii.x * radiusScale * Mathf.Cos(angle + increment * 2.0f), 0.0f, nextCorner.axleRadii.z * radiusScale * Mathf.Sin(angle + increment * 2.0f));
                }
                else
                {
                    //If corners are round
                    for (int i = 0; i < props.cornerDetails[iteration] + 1; i++)
                    {
                        newVertex = center - curRadiusOffset + new Vector3(curCorner.axleRadii.x * radiusScale * Mathf.Cos(angle), 0.0f, curCorner.axleRadii.z * radiusScale * Mathf.Sin(angle));
                        verts.Add(newVertex);
                        angle += increment;
                    }
                    nextVertex = nextCenter - nextRadiusOffset + new Vector3(nextCorner.axleRadii.x * radiusScale * Mathf.Cos(Mathf.PI * (iteration + 1) * 0.5f), 0.0f, nextCorner.axleRadii.z * radiusScale * Mathf.Sin(Mathf.PI * (iteration + 1) * 0.5f));
                }

                if (props.XYDetail > 0 && (iteration == 1 || iteration == 3))
                {
                    //Adding detail along sides of strip orthogonal to the X-Y plane
                    int curDetail = 1;
                    while (curDetail < props.XYDetail + 1)
                    {
                        float progress    = ((curDetail * 1.0f) / ((props.XYDetail + 1) * 1.0f));
                        float smoothPower = Mathf.Pow(progress, 2.0f - progress * 2.0f);
                        verts.Add(Vector3.Lerp(Vector3.Lerp(newVertex, nextVertex, progress),
                                               new Vector3(Mathf.Lerp(newVertex.x, nextVertex.x, smoothPower),
                                                           Mathf.Lerp(newVertex.y, nextVertex.y, smoothPower),
                                                           Mathf.Lerp(newVertex.z, nextVertex.z, progress)),
                                               props.detailSmoothness));
                        curDetail++;
                    }
                }

                if (props.YZDetail > 0 && (iteration == 0 || iteration == 2))
                {
                    //Adding detail along sides of strip orthogonal to the Y-Z plane
                    int curDetail = 1;
                    while (curDetail < props.YZDetail + 1)
                    {
                        float progress    = ((curDetail * 1.0f) / ((props.YZDetail + 1) * 1.0f));
                        float smoothPower = Mathf.Pow(progress, 2.0f - progress * 2.0f);
                        verts.Add(Vector3.Lerp(Vector3.Lerp(newVertex, nextVertex, progress),
                                               new Vector3(Mathf.Lerp(newVertex.x, nextVertex.x, progress),
                                                           Mathf.Lerp(newVertex.y, nextVertex.y, smoothPower),
                                                           Mathf.Lerp(newVertex.z, nextVertex.z, smoothPower)),
                                               props.detailSmoothness));
                        curDetail++;
                    }
                }

                iteration++;
            }
            verts.Add(verts[0]);//Extra copy of first vertex to close the strip
        }
        //Function for flipping corners
        //cids must be a list of corner ID pairs where each pair represents corners being swapped
        void FlipOperation(ColliderCorner.CornerId[] cids, ref DeformHook[] mHooks, int xFactor, int yFactor, int zFactor)
        {
            if (cids.Length != 8)
            {
                Debug.LogError("Mirror operation failed, corner input array must contain 8 corners (4 pairs of corners being mirrored).");
                return;
            }

            //Temporary corners for swapping
            ColliderCorner[] tempCorners = new ColliderCorner[4]
            {
                new ColliderCorner(GetCornerAtLocation(cids[1])), new ColliderCorner(GetCornerAtLocation(cids[3])),
                new ColliderCorner(GetCornerAtLocation(cids[5])), new ColliderCorner(GetCornerAtLocation(cids[7]))
            };

            //First part of flipping by mirroring
            MirrorCorner(cids[0], cids[1], xFactor, yFactor, zFactor);
            MirrorCorner(cids[2], cids[3], xFactor, yFactor, zFactor);
            MirrorCorner(cids[4], cids[5], xFactor, yFactor, zFactor);
            MirrorCorner(cids[6], cids[7], xFactor, yFactor, zFactor);

            //Second part of flipping by mirroring temporary corners
            MirrorCorner(tempCorners[0], cids[0], xFactor, yFactor, zFactor);
            MirrorCorner(tempCorners[1], cids[2], xFactor, yFactor, zFactor);
            MirrorCorner(tempCorners[2], cids[4], xFactor, yFactor, zFactor);
            MirrorCorner(tempCorners[3], cids[6], xFactor, yFactor, zFactor);

            //Flipping hooks
            for (int i = 0; i < mHooks.Length; i++)
            {
                DeformHook curHook = mHooks[i];
                curHook.localPos.Set(xFactor * curHook.localPos.x, yFactor * curHook.localPos.y, zFactor * curHook.localPos.z);

                Vector3 forwardDir = curHook.localRot * Vector3.forward;
                Vector3 upDir      = curHook.localRot * Vector3.up;
                if (curHook.hookType != DeformHook.HookType.Twist)
                {
                    //Flipping rules for pull and expand hook types
                    Vector3 flippedForwardDir = new Vector3(xFactor * forwardDir.x, yFactor * forwardDir.y, zFactor * forwardDir.z);
                    Vector3 flippedUpDir      = new Vector3(xFactor * upDir.x, yFactor * upDir.y, zFactor * upDir.z);
                    curHook.localRot = Quaternion.LookRotation(flippedForwardDir, flippedUpDir);
                }
                else
                {
                    //Special rules for flipping twist hook types
                    if (xFactor == -1)
                    {
                        Vector3 flippedForwardDir = new Vector3(xFactor * forwardDir.x, yFactor * forwardDir.y, zFactor * forwardDir.z);
                        Vector3 flippedUpDir      = new Vector3(xFactor * upDir.x, yFactor * upDir.y, zFactor * upDir.z);
                        curHook.localRot = Quaternion.LookRotation(flippedForwardDir, flippedUpDir);
                    }
                    else if (yFactor == -1)
                    {
                        Vector3 flippedForwardDir = new Vector3(xFactor * forwardDir.x, yFactor * forwardDir.y, zFactor * forwardDir.z);
                        Vector3 flippedUpDir      = new Vector3(yFactor * upDir.x, upDir.y, yFactor * upDir.z);
                        curHook.localRot = Quaternion.LookRotation(flippedForwardDir, flippedUpDir);
                    }
                    else if (zFactor == -1)
                    {
                        Vector3 flippedForwardDir = new Vector3(zFactor * forwardDir.x, zFactor * forwardDir.y, forwardDir.z);
                        Vector3 flippedUpDir      = new Vector3(zFactor * upDir.x, yFactor * upDir.y, zFactor * upDir.z);
                        curHook.localRot = Quaternion.LookRotation(flippedForwardDir, flippedUpDir);
                    }
                }
                curHook.localEulerRot = curHook.localRot.eulerAngles;
            }
        }