示例#1
0
        void Gizmos_DrawEndBoneJoint()
        {
            // Drawing auto end joint offset
            if (FEngineering.VIsZero(EndBoneJointOffset))
            {
                Transform t = _TransformsGhostChain[_TransformsGhostChain.Count - 1];
                Transform p = _TransformsGhostChain[_TransformsGhostChain.Count - 1].parent;

                if (p) // Reference from parent
                {
                    Vector3 worldOffset = t.position - p.position;

                    Handles.color = new Color(0.3f, .3f, 1f, 0.8f);
                    FGUI_Handles.DrawBoneHandle(t.position, t.position + worldOffset, BaseTransform.forward, 1f);
                }
                else // Reference to child
                {
                    if (t.childCount > 0)
                    {
                        Transform ch          = _TransformsGhostChain[0].GetChild(0);
                        Vector3   worldOffset = ch.position - t.position;
                        FGUI_Handles.DrawBoneHandle(t.position, t.position + worldOffset, BaseTransform.forward, 1f);
                    }
                }
            }
            // Drawing custom joint offset
            else
            {
                Transform t = _TransformsGhostChain[_TransformsGhostChain.Count - 1];
                Handles.color = new Color(0.3f, .3f, 1f, 0.8f);
                FGUI_Handles.DrawBoneHandle(t.position, t.position + t.TransformVector(EndBoneJointOffset), BaseTransform.forward, 1f);
            }
        }
            public void AngleLimiting()
            {
                Quaternion localRotation   = Quaternion.Inverse(LastKeyLocalRotation) * transform.localRotation;
                Quaternion limitedRotation = localRotation;

                if (FEngineering.VIsZero(HingeLimits))
                {
                    if (AngleLimit < 180)
                    {
                        limitedRotation = LimitSpherical(limitedRotation);
                    }
                    if (TwistAngleLimit < 180)
                    {
                        limitedRotation = LimitZ(limitedRotation);
                    }
                }
                else
                {
                    limitedRotation = LimitHinge(limitedRotation);
                }

                if (FEngineering.QIsSame(limitedRotation, localRotation))
                {
                    return;
                }

                transform.localRotation = LastKeyLocalRotation * limitedRotation;
            }
示例#3
0
 /// <summary>
 /// Limiting movement of tail bones in selected axis
 /// </summary>
 void Axis2DLimit(TailSegment child)
 {
     child.ProceduralPosition -=
         FEngineering.VAxis2DLimit(
             child.ParentBone.transform,
             child.ParentBone.ProceduralPosition,
             child.ProceduralPosition, Axis2D);
 }
示例#4
0
 /// <summary>
 /// Offsset to default segment position from parent relation
 /// </summary>
 internal Vector3 ParentToFrontOffset()
 {
     return(FEngineering.TransformVector
            (
                ParentBone.LastKeyframeLocalRotation,
                ParentBone.transform.lossyScale,
                LastKeyframeLocalPosition
            ));
 }
示例#5
0
            //public static Vector3 CalculateLocalLook(Transform parent, Transform child)
            //{ return -(parent.InverseTransformPoint(child.position) - parent.InverseTransformPoint(parent.position)).normalized; }


            /// <summary>
            /// Blend toward target position
            /// </summary>
            internal Vector3 BlendMotionWeight(Vector3 newPosition)
            {
                return(Vector3.LerpUnclamped
                       (
                           // Blending from default pose to new position
                           ParentBone.ProceduralPosition + FEngineering.TransformVector(ParentBone.LastKeyframeLocalRotation, ParentBone.transform.lossyScale, LastKeyframeLocalPosition),
                           newPosition,
                           BlendValue
                       ));
            }
            private Quaternion LimitSpherical(Quaternion rotation)
            {
                if (FEngineering.QIsZero(rotation))
                {
                    return(rotation);
                }
                Vector3    currentForward = rotation * ForwardOrientation;
                Quaternion limitAngle     = Quaternion.RotateTowards(Quaternion.identity, Quaternion.FromToRotation(ForwardOrientation, currentForward), AngleLimit);

                return(Quaternion.FromToRotation(currentForward, limitAngle * ForwardOrientation) * rotation);
            }
示例#7
0
        /// <summary>
        /// Processing calculated simple segment position with special effects like limiting / collision / smoothing etc.
        /// Calling methods using bone's parent variables
        /// </summary>
        void TailCalculations_SegmentPreProcessingStack(TailSegment child)
        {
            if (!UseCollision) // Basic motion without collision
            // Different update order with enable/disable collisions to avoid jittering on angle limiting
            {
                // Limit segments angles
                if (AngleLimit < 181)
                {
                    child.ProceduralPosition = AngleLimiting(child, child.ProceduralPosition);
                }

                // Smoothing motion
                if (child.PositionSpeed < 1f)
                {
                    child.ProceduralPosition = TailCalculations_SmoothPosition(child.PreviousPosition /*+ _limiting_influenceOffset*/, child.ProceduralPosition, child);
                }
            }
            else
            {
                // Smoothing motion
                if (child.PositionSpeed < 1f)
                {
                    child.ProceduralPosition = TailCalculations_SmoothPosition(child.PreviousPosition /*+ _limiting_influenceOffset*/, child.ProceduralPosition, child);
                }

                // Computing collision offset as first thing
                TailCalculations_ComputeSegmentCollisions(child, ref child.ProceduralPosition);

                // Limit segments angles
                if (AngleLimit < 181)
                {
                    child.ProceduralPosition = AngleLimiting(child, child.ProceduralPosition);
                }
            }


            // Control stretching
            if (MaxStretching < 1f)
            {
                StretchingLimiting(child);
            }

            // Apply gravity
            if (!FEngineering.VIsZero(child.Gravity) || UseWind)
            {
                CalculateGravityPositionOffsetForSegment(child);
            }

            if (Axis2D > 0)
            {
                Axis2DLimit(child);
            }
        }
示例#8
0
 /// <summary>
 /// Calculations for stiff tail motion reference parent rotation
 /// </summary>
 Quaternion TailSegment_RotationStiff(TailSegment child)
 {
     // Curving feature
     if (!FEngineering.QIsZero(child.Curving))
     {
         return
             (MultiplyQ(child.Curving, child.Index * 2f)  // Curving multiplier
              * child.ParentBone.transform.rotation);     // Parent bone rotation
     }
     else // No Curving
     {
         return(child.ParentBone.transform.rotation);      // Parent bone rotation
     }
 }
示例#9
0
 /// <summary>
 /// Calculations for slithery tail motion reference parent rotation
 /// </summary>
 Quaternion TailSegment_RotationSlithery(TailSegment child)
 {
     if (!FEngineering.QIsZero(child.Curving))
     {
         return(GetSlitheryReferenceRotation(child)            // Back rotation for parent of parent bone
                * child.Curving                                // Curving
                * child.ParentBone.LastKeyframeLocalRotation); // Sync with animator
     }
     else
     {
         return(GetSlitheryReferenceRotation(child)            // Back rotation for parent of parent bone
                * child.ParentBone.LastKeyframeLocalRotation); // Sync with animator
     }
 }
示例#10
0
        void ComputeWind()
        {
            Vector3 newWind;

            if (overrideWind != Vector3.zero)
            {
                newWind = overrideWind;
            }
            else // Procedural wind
            {
                for (int i = 0; i < 4; i++)
                {
                    randTimes[i] += Time.deltaTime * randSpeeds[i] * turbulenceSpeed;
                }

                Quaternion windDir = windOrientation;

                float x = -1f + Mathf.PerlinNoise(randTimes[0], 256f + randTimes[1]) * 2f;
                float y = -1f + Mathf.PerlinNoise(-randTimes[1], 55f + randTimes[2]) * 2f;
                float z = -1f + Mathf.PerlinNoise(-randTimes[3], 55f + randTimes[0]) * 2f;
                windDir *= Quaternion.Euler(new Vector3(0, y, 0) * changesPower);
                windDir  = Quaternion.Euler(x * (changesPower / 6f), windDir.eulerAngles.y, z * (changesPower / 6f));

                smoothWindOrient = FEngineering.SmoothDampRotation(smoothWindOrient, windDir, ref smoothWindOrientHelper, 1f - rapidness, Time.deltaTime);

                transform.rotation = smoothWindOrient;
                newWind            = smoothWindOrient * Vector3.forward;
            }

            // Additional turbulence
            smoothAddTurbulence = Vector3.SmoothDamp(smoothAddTurbulence, GetAddTurbulence() * additionalTurbulence, ref addTurbHelper, 0.05f, Mathf.Infinity, Time.deltaTime);

            // Smooth out
            smoothWind = Vector3.SmoothDamp(smoothWind, newWind, ref windVeloHelper, 0.1f, Mathf.Infinity, Time.deltaTime);

            for (int i = 7; i < 10; i++)
            {
                randTimes[i] += Time.deltaTime * randSpeeds[i] * turbulenceSpeed;
            }

            float turbulencedPower = power * 0.015f;

            turbulencedPower *= 0.5f + Mathf.PerlinNoise(randTimes[7] * 2f, 25 + randTimes[8] * 0.5f);

            finalAddTurbulence = smoothAddTurbulence * turbulencedPower;
            targetWind         = smoothWind * turbulencedPower;
        }
示例#11
0
        /// <summary>
        /// Skinning target mesh with helper vertex datas which you can get with CalculateVertexWeightingData() method
        /// Using transforms as guidement for bones positions and rotations
        /// </summary>
        /// <returns> Skinned mesh can't be returned as 'Mesh' type because skinned mesh is mesh + bones transforms etc. </returns>
        public static SkinnedMeshRenderer SkinMesh(Mesh baseMesh, Transform skinParent, Transform[] bonesStructure, FTail_SkinningVertexData[] vertData)
        {
            Vector3[]    pos = new Vector3[bonesStructure.Length];
            Quaternion[] rot = new Quaternion[bonesStructure.Length];

            // We must reset bones structure to identity space
            for (int i = 0; i < bonesStructure.Length; i++)
            {
                // Transforming from world to local space coords
                pos[i] = skinParent.InverseTransformPoint(bonesStructure[i].position);
                rot[i] = FEngineering.QToLocal(skinParent.rotation, bonesStructure[i].rotation);
            }

            SkinnedMeshRenderer skin = SkinMesh(baseMesh, pos, rot, vertData);

            return(skin);
        }
示例#12
0
        protected virtual void OnSceneGUI()
        {
            if (Application.isPlaying)
            {
                return;
            }
            if (!Get.DrawGizmos)
            {
                return;
            }

            if (Get._Editor_Category == TailAnimator2.ETailCategory.Setup)
            {
                if (Get.BaseTransform)
                {
                    if (!FEngineering.VIsZero(Get.EndBoneJointOffset))
                    {
                        Get.RefreshTransformsList();

                        if (Get._TransformsGhostChain.Count > 0)
                        {
                            Undo.RecordObject(Get, "Changing position of tail joint offset");
                            Transform root = Get._TransformsGhostChain[Get._TransformsGhostChain.Count - 1];

                            Vector3 off         = root.TransformVector(Get.EndBoneJointOffset);
                            Vector3 pos         = root.position + off;
                            Vector3 transformed = FEditor_TransformHandles.PositionHandle(pos, Get.BaseTransform.rotation, .3f, true, false);

                            if (Vector3.Distance(transformed, pos) > 0.00001f)
                            {
                                Vector3 diff = transformed - pos;
                                Get.EndBoneJointOffset = root.InverseTransformVector(off + diff);
                                SerializedObject obj = new SerializedObject(Get);
                                if (obj != null)
                                {
                                    obj.ApplyModifiedProperties(); obj.Update();
                                }
                            }
                        }
                    }
                }
            }
        }
示例#13
0
        /// <summary>
        /// Begin update operations for additionaly genrated child bone of chain
        /// </summary>
        public void TailCalculations_UpdateArtificialChildBone(TailSegment child)
        {
            // Pre processing with limiting, gravity etc.
            //TailCalculations_SegmentPreProcessingStack(lastChild);

            //// Blending animation weight
            //TailSegment_PreRotationPositionBlend(lastChild);

            TailSegment_BaseSwingProcessing(child);

            if (child.PositionSpeed < 1f)
            {
                child.ProceduralPosition = TailCalculations_SmoothPosition(child.PreviousPosition /*+ _limiting_influenceOffset*/, child.ProceduralPosition, child);
            }

            if (MaxStretching < 1f)
            {
                StretchingLimiting(child);
            }

            if (!FEngineering.VIsZero(child.Gravity) || UseWind)
            {
                CalculateGravityPositionOffsetForSegment(child);
            }

            if (Axis2D > 0)
            {
                Axis2DLimit(child);
            }

            child.CollisionContactRelevancy = -1f;

            // Blending or just setting target position
            if (child.BlendValue * conditionalWeight < 1f)
            {
                child.ProceduralPositionWeightBlended = Vector3.LerpUnclamped(
                    child.ParentBone.transform.TransformPoint(child.LastKeyframeLocalPosition), child.ProceduralPosition, child.BlendValue * conditionalWeight);
            }
            else
            {
                child.ProceduralPositionWeightBlended = child.ProceduralPosition;
            }
        }
示例#14
0
            /// <summary>
            /// Checking for null keyframes to prevent spinning error
            /// </summary>
            public void ZeroKeyframeCheck()
            {
                // Null keyframe detected
                if (FEngineering.QIsSame(lastFinalLocalRotation, transform.localRotation))
                {
                    transform.localRotation = lastKeyframeRotation;
                }
                else // Remembering rotation to check for null keyframe
                {
                    lastKeyframeRotation = transform.localRotation;
                }

                if (FEngineering.VIsSame(lastFinalLocalPosition, transform.localPosition))
                {
                    transform.localPosition = lastKeyframePosition;
                }
                else // Remembering position to check for null keyframe
                {
                    lastKeyframePosition = transform.localPosition;
                }
            }
示例#15
0
        /// <summary>
        /// Calculating base vertices datas for provided bones setup
        /// </summary>
        /// <param name="baseMesh"> Mesh to be weighted </param>
        /// <param name="bonesCoords"> Required local positions and rotations for bones </param>
        /// <param name="spreadOffset"> Origin weighting offset which can be helpful in some cases, it can be Vector3.zero in most cases </param>
        /// <param name="weightBoneLimit"> To how many bones vertex can be weighted to create smooth weight effect </param>
        /// <param name="spreadValue"> Smoothing weights on the edges of bones if lower then more smooth but don't oversmooth it </param>
        /// <param name="spreadPower"> Making smoothing more sharp on edges </param>
        public static FTail_SkinningVertexData[] CalculateVertexWeightingData(Mesh baseMesh, Transform[] bonesCoords, Vector3 spreadOffset, int weightBoneLimit = 2, float spreadValue = 0.8f, float spreadPower = 0.185f)
        {
            Vector3[]    pos = new Vector3[bonesCoords.Length];
            Quaternion[] rot = new Quaternion[bonesCoords.Length];

            //for (int i = 0; i < bonesCoords.Length; i++)
            //{
            //    pos[i] = bonesCoords[i].position;
            //    rot[i] = bonesCoords[i].rotation;
            //}

            // We must reset bones structure to identity space
            for (int i = 0; i < bonesCoords.Length; i++)
            {
                // Transforming from world to local space coords
                pos[i] = bonesCoords[0].parent.InverseTransformPoint(bonesCoords[i].position);
                rot[i] = FEngineering.QToLocal(bonesCoords[0].parent.rotation, bonesCoords[i].rotation);
            }

            return(CalculateVertexWeightingData(baseMesh, pos, rot, spreadOffset, weightBoneLimit, spreadValue, spreadPower));
        }
 void Shaping_UpdateGravity()
 {
     if (!FEngineering.VIsZero(Gravity))
     {
         if (UseGravityCurve) // Operations with curve
         {
             if (!FEngineering.VIsSame(Gravity, lastGravity) || KeysChanged(GravityCurve.keys, lastGravityKeys))
             {
                 for (int i = 0; i < TailSegments.Count; i++)
                 {
                     TailSegments[i].Gravity  = Gravity * GetValueFromCurve(i, GravityCurve) / 40f;
                     TailSegments[i].Gravity *= (1 + ((TailSegments[i].Index / 2f) * (1f - TailSegments[i].Slithery)));
                 }
             }
         }
         else // Operations without curve
         {
             if (!FEngineering.VIsSame(Gravity, lastGravity))
             {
                 for (int i = 0; i < TailSegments.Count; i++)
                 {
                     TailSegments[i].Gravity  = Gravity / 40f;
                     TailSegments[i].Gravity *= (1 + ((TailSegments[i].Index / 2f) * (1f - TailSegments[i].Slithery)));
                 }
             }
         }
     }
     else // Gravity reset
     {
         if (!FEngineering.VIsSame(Gravity, lastGravity))
         {
             for (int i = 0; i < TailSegments.Count; i++)
             {
                 TailSegments[i].Gravity           = Vector3.zero;
                 TailSegments[i].GravityLookOffset = Vector3.zero;
             }
         }
     }
 }
示例#17
0
            public void CheckForZeroKeyframes()
            {
                if (FEngineering.QIsSame(lastFinalLocalRotation, Transform.localRotation))
                {
                    Transform.localRotation = lastKeyframeLocalRotation;
                    compensatedRotation     = Transform.rotation;
                }
                else
                {
                    lastKeyframeLocalRotation = Transform.localRotation;
                }

                if (FEngineering.VIsSame(lastFinalLocalPosition, Transform.localPosition))
                {
                    Transform.localPosition = lastKeyframeLocalPosition;
                    compensatedPosition     = Transform.position;
                }
                else
                {
                    lastKeyframeLocalPosition = Transform.localPosition;
                }
            }
 void Shaping_UpdateCurving()
 {
     if (!FEngineering.QIsZero(Curving))
     {
         if (UseCurvingCurve) // Operations with curve
         {
             if (!FEngineering.QIsSame(Curving, lastCurving) || KeysChanged(CurvCurve.keys, lastCurvingKeys))
             {
                 for (int i = 0; i < TailSegments.Count; i++)
                 {
                     TailSegments[i].Curving = Quaternion.LerpUnclamped(Quaternion.identity, Curving, GetValueFromCurve(i, CurvCurve));
                 }
             }
         }
         else // Operations without curve
         {
             if (!FEngineering.QIsSame(Curving, lastCurving))
             {
                 for (int i = 0; i < TailSegments.Count; i++)
                 {
                     TailSegments[i].Curving = Curving;
                 }
             }
         }
     }
     else // Curving reset
     {
         if (!FEngineering.QIsSame(Curving, lastCurving))
         {
             for (int i = 0; i < TailSegments.Count; i++)
             {
                 TailSegments[i].Curving = Quaternion.identity;
             }
         }
     }
 }
示例#19
0
        public override void RefreshColliderData()
        {
            if (IsStatic)
            {
                return;             // No need to refresh collider data if it is static
            }
            if (Collider2D == null) // 3D Refresh
            {
                bool diff = false;

                if (!FEngineering.VIsSame(Transform.position, previousPosition))
                {
                    diff = true;
                }
                else
                if (!FEngineering.QIsSame(Transform.rotation, previousRotation))
                {
                    diff = true;
                }

                if (diff)
                {
                    right   = Box.transform.TransformVector((Vector3.right / 2f) * Box.size.x);
                    up      = Box.transform.TransformVector((Vector3.up / 2f) * Box.size.y);
                    forward = Box.transform.TransformVector((Vector3.forward / 2f) * Box.size.z);

                    rightN   = right.normalized;
                    upN      = up.normalized;
                    forwardN = forward.normalized;

                    boxCenter = GetBoxCenter(Box);

                    scales = Vector3.Scale(Box.size, Box.transform.lossyScale);
                    scales.Normalize();
                }
            }
            else // 2D Refresh
            {
                bool diff = false;

                if (Vector2.Distance(Transform.position, previousPosition) > Mathf.Epsilon)
                {
                    diff = true;
                }
                else
                if (!FEngineering.QIsSame(Transform.rotation, previousRotation))
                {
                    diff = true;
                }

                if (diff)
                {
                    right = Box2D.transform.TransformVector((Vector3.right / 2f) * Box2D.size.x);
                    up    = Box2D.transform.TransformVector((Vector3.up / 2f) * Box2D.size.y);

                    rightN = right.normalized;
                    upN    = up.normalized;

                    boxCenter   = GetBoxCenter(Box2D);
                    boxCenter.z = 0f;

                    Vector3 scale = Transform.lossyScale; scale.z = 1f;
                    scales = Vector3.Scale(Box2D.size, scale);
                    scales.Normalize();
                }
            }

            base.RefreshColliderData();

            previousPosition = Transform.position;
            previousRotation = Transform.rotation;
        }
示例#20
0
        private void Tab_DrawShaping()
        {
            FGUI_Inspector.VSpace(-2, -4);
            GUILayout.BeginVertical(FGUI_Resources.ViewBoxStyle);
            GUILayout.BeginVertical(FGUI_Resources.BGInBoxBlankStyle);

            GUILayout.Space(2f);
            EditorGUIUtility.labelWidth = 120;

            if (FEngineering.QIsZero(Get.RotationOffset))
            {
                GUI.color = defaultValC;
            }
            else
            {
                GUI.color = c;
            }

            EditorGUI.BeginChangeCheck();
            Get.RotationOffset = Quaternion.Euler(EditorGUILayout.Vector3Field(new GUIContent(sp_tailRotOff.displayName, sp_tailRotOff.tooltip), FEngineering.WrapVector(Get.RotationOffset.eulerAngles)));
            if (EditorGUI.EndChangeCheck())
            {
                serializedObject.ApplyModifiedProperties();
                GetSelectedTailAnimators();
                for (int i = 0; i < lastSelected.Count; i++)
                {
                    lastSelected[i].RotationOffset = Get.RotationOffset; new SerializedObject(lastSelected[i]).ApplyModifiedProperties();
                }
            }

            // Curving Tail
            GUILayout.Space(2f);
            if (FEngineering.QIsZero(Get.Curving) && !Get.UseCurlingCurve)
            {
                GUI.color = defaultValC;
            }
            else
            {
                GUI.color = c;
            }

            EditorGUILayout.BeginHorizontal();

            EditorGUI.BeginChangeCheck();
            Get.Curving = Quaternion.Euler(EditorGUILayout.Vector3Field(new GUIContent(sp_curving.displayName, sp_curving.tooltip), FEngineering.WrapVector(Get.Curving.eulerAngles)));
            if (EditorGUI.EndChangeCheck())
            {
                serializedObject.ApplyModifiedProperties();
                GetSelectedTailAnimators();
                for (int i = 0; i < lastSelected.Count; i++)
                {
                    lastSelected[i].Curving = Get.Curving; new SerializedObject(lastSelected[i]).ApplyModifiedProperties();
                }
            }

            if (Get.UseCurvingCurve)
            {
                EditorGUILayout.LabelField(new GUIContent("*", "Curving offset value weight for tail segments multiplied by curve"), GUILayout.Width(9));
                EditorGUILayout.PropertyField(sp_CurvCurve, new GUIContent("", sp_curving.tooltip), GUILayout.MaxWidth(32));
            }
            else
            {
                GUILayout.Space(4f);
            }

            EditorGUI.BeginChangeCheck();
            SwitchButton(ref Get.UseCurvingCurve, "Spread curving rotation offset weight over tail segments", curveIcon);
            if (EditorGUI.EndChangeCheck())
            {
                GetSelectedTailAnimators(); for (int i = 0; i < lastSelected.Count; i++)
                {
                    lastSelected[i].UseCurvingCurve = Get.UseCurvingCurve; new SerializedObject(lastSelected[i]).ApplyModifiedProperties();
                }
            }
            EditorGUILayout.EndHorizontal();

            GUILayout.Space(3f);

            // Length Stretch
            if (Get.LengthMultiplier == 1f && !Get.UseLengthMulCurve)
            {
                GUI.color = defaultValC;
            }
            else
            {
                GUI.color = c;
            }

            EditorGUILayout.BeginHorizontal();

            if (!Get.UseLengthMulCurve)
            {
                EditorGUILayout.PropertyField(sp_LengthMultiplier);
                GUILayout.Space(4f); EditorGUI.BeginChangeCheck();
                SwitchButton(ref Get.UseLengthMulCurve, "Spread length multiplier weight over tail segments", curveIcon);
                if (EditorGUI.EndChangeCheck())
                {
                    GetSelectedTailAnimators(); for (int i = 0; i < lastSelected.Count; i++)
                    {
                        lastSelected[i].UseLengthMulCurve = Get.UseLengthMulCurve; new SerializedObject(lastSelected[i]).ApplyModifiedProperties();
                    }
                }
            }
            else
            {
                EditorGUILayout.PropertyField(sp_LengthMulCurve, new GUIContent(sp_LengthMultiplier.displayName, sp_LengthMultiplier.tooltip));
                GUILayout.Space(4f); EditorGUI.BeginChangeCheck();
                SwitchButton(ref Get.UseLengthMulCurve, "Spread length multiplier weight over tail segments", curveIcon);
                if (EditorGUI.EndChangeCheck())
                {
                    GetSelectedTailAnimators(); for (int i = 0; i < lastSelected.Count; i++)
                    {
                        lastSelected[i].UseLengthMulCurve = Get.UseLengthMulCurve; new SerializedObject(lastSelected[i]).ApplyModifiedProperties();
                    }
                }
            }

            EditorGUILayout.EndHorizontal();

            EditorGUIUtility.labelWidth = 0;
            GUILayout.EndVertical();
            GUILayout.EndVertical();
        }
        /// <summary>
        /// Method to initialize component, to have more controll than waiting for Start() method, init can be executed before or after start, as programmer need it.
        /// </summary>
        protected virtual void Init()
        {
            if (initialized)
            {
                return;
            }


            // Checking if we have transform to create tail chain from
            if (_TransformsGhostChain == null || _TransformsGhostChain.Count == 0)
            {
                _TransformsGhostChain = new List <Transform>();
                GetGhostChain();
            }


            // Generating tail instances for procedural animation
            TailSegments = new List <TailSegment>();

            for (int i = 0; i < _TransformsGhostChain.Count; i++)
            {
                if (_TransformsGhostChain[i] == null)
                {
                    Debug.Log("[Tail Animator] Null bones in " + name + " !");
                    continue;
                }

                TailSegment b = new TailSegment(_TransformsGhostChain[i]);
                b.SetIndex(i, _TransformsGhostChain.Count);
                TailSegments.Add(b);
            }


            // Checking correctness
            if (TailSegments.Count == 0)
            {
                Debug.Log("[Tail Animator] Could not create tail bones chain in " + name + " !");
                return;
            }


            _TC_TailLength = 0f;
            _baseTransform = _TransformsGhostChain[0];

            //if (_baseTransform.parent)
            //    _baseTransform = _baseTransform.parent;
            //else
            //    IncludeParent = false;


            // Setting parent-child relation for tail logics
            for (int i = 0; i < TailSegments.Count; i++)
            {
                TailSegment current = TailSegments[i];
                TailSegment parent;

                #region Defining Parent Bones

                if (i == 0)
                {
                    if (current.transform.parent)
                    {
                        // Creating parent and setting safety parent
                        parent = new TailSegment(current.transform.parent);
                        parent.SetParentRef(new TailSegment(parent.transform.parent));
                    }
                    else
                    #region If first bone is parentless
                    {
                        parent = new TailSegment(current.transform);

                        Vector3 toStartDir;

                        if (_TransformsGhostChain.Count > 1)
                        {
                            toStartDir = _TransformsGhostChain[0].position - _TransformsGhostChain[1].position;
                            if (toStartDir.magnitude == 0)
                            {
                                toStartDir = transform.position - _TransformsGhostChain[1].position;
                            }
                        }
                        else
                        {
                            toStartDir = current.transform.position - _TransformsGhostChain[0].position;
                        }

                        if (toStartDir.magnitude == 0)
                        {
                            toStartDir = transform.position - _TransformsGhostChain[0].position;
                        }
                        if (toStartDir.magnitude == 0)
                        {
                            toStartDir = transform.forward;
                        }

                        parent.LocalOffset = parent.transform.InverseTransformPoint(parent.transform.position + toStartDir);
                        parent.SetParentRef(new TailSegment(current.transform));
                    }
                    #endregion

                    //current.InitialLocalRotation = Quaternion.Inverse(current.transform.localRotation);
                    GhostParent = parent;
                    GhostParent.Validate();
                    current.SetParentRef(GhostParent);
                }
                else // i != 0
                {
                    parent = TailSegments[i - 1];
                    // If bones are removed manually from chain we support custom length of bone undependent from transform parenting chain structure
                    current.ReInitializeLocalPosRot(parent.transform.InverseTransformPoint(current.transform.position), current.transform.localRotation);
                }


                #endregion


                #region Defining Last Child Bone

                if (i == TailSegments.Count - 1)
                {
                    Transform childT = null;
                    if (current.transform.childCount > 0)
                    {
                        childT = current.transform.GetChild(0);
                    }

                    GhostChild = new TailSegment(childT);

                    // Scale ref for ghosting object position offset
                    Vector3 scaleDir;

                    if (FEngineering.VIsZero(EndBoneJointOffset))
                    {
                        if (current.transform.parent)
                        {
                            scaleDir = current.transform.position - current.transform.parent.position;
                        }
                        else
                        if (current.transform.childCount > 0)
                        {
                            scaleDir = current.transform.GetChild(0).position - current.transform.position;
                        }
                        else
                        {
                            scaleDir = current.transform.TransformDirection(Vector3.forward) * 0.05f;
                        }
                    }
                    else
                    {
                        scaleDir = current.transform.TransformVector(EndBoneJointOffset);
                    }


                    GhostChild.ProceduralPosition = current.transform.position + scaleDir;
                    GhostChild.ProceduralPositionWeightBlended = GhostChild.ProceduralPosition;
                    GhostChild.PreviousPosition             = GhostChild.ProceduralPosition;
                    GhostChild.PosRefRotation               = Quaternion.identity;
                    GhostChild.PreviousPosReferenceRotation = Quaternion.identity;
                    GhostChild.ReInitializeLocalPosRot(current.transform.InverseTransformPoint(GhostChild.ProceduralPosition), Quaternion.identity);
                    GhostChild.RefreshFinalPos(GhostChild.ProceduralPosition);
                    GhostChild.RefreshFinalRot(GhostChild.PosRefRotation);
                    GhostChild.TrueTargetRotation = GhostChild.PosRefRotation;
                    current.TrueTargetRotation    = current.transform.rotation;

                    current.SetChildRef(GhostChild);
                    GhostChild.SetParentRef(current);
                }
                else
                {
                    current.SetChildRef(TailSegments[i + 1]);
                }

                #endregion


                current.SetParentRef(parent);

                _TC_TailLength += Vector3.Distance(current.ProceduralPosition, parent.ProceduralPosition);
            }


            // List with ghosts for curves etc.
            GhostParent.SetIndex(-1, TailSegments.Count);
            GhostChild.SetIndex(TailSegments.Count, TailSegments.Count);
            GhostParent.SetChildRef(TailSegments[0]);

            previousWorldPosition = BaseTransform.position;
            WavingRotationOffset  = Quaternion.identity;

            if (CollidersDataToCheck == null)
            {
                CollidersDataToCheck = new List <FImp_ColliderData_Base>();
            }

            DynamicAlwaysInclude = new List <Component>();
            if (UseCollision)
            {
                SetupSphereColliders();
            }

            // List instance for deflection feature
            if (_defl_source == null)
            {
                _defl_source = new List <TailSegment>();
            }

            Waving_Initialize();

            if (DetachChildren)
            {
                DetachChildrenTransforms();
            }

            initialized = true;

            if (TailSegments.Count == 1)
            {
                if (TailSegments[0].transform.parent == null)
                {
                    Debug.Log("[Tail Animator] Can't initialize one-bone length chain on bone which don't have any parent!");
                    Debug.LogError("[Tail Animator] Can't initialize one-bone length chain on bone which don't have any parent!");
                    TailAnimatorAmount = 0f;
                    initialized        = false;
                    return;
                }
            }

            if (UseWind)
            {
                TailAnimatorWind.Refresh(this);
            }

            if (PostProcessingNeeded())
            {
                if (!_pp_initialized)
                {
                    InitializePostProcessing();
                }
            }

            #region Prewarming tail to target state

            if (Prewarm)
            {
                ShapingParamsUpdate();
                ExpertParamsUpdate();

                Update();
                LateUpdate();

                justDelta      = rateDelta;
                secPeriodDelta = 1f;
                deltaForLerps  = secPeriodDelta;
                rateDelta      = 1f / 60f;

                CheckIfTailAnimatorShouldBeUpdated();

                if (updateTailAnimator)
                {
                    int loopCount = 60 + TailSegments.Count / 2;

                    for (int d = 0; d < loopCount; d++)
                    {
                        PreCalibrateBones();
                        LateUpdate();
                    }
                }
            }

            #endregion
        }
        public override void RefreshColliderData()
        {
            if (IsStatic)
            {
                return;           // No need to refresh collider data if it is static
            }
            bool diff = false;

            if (!FEngineering.VIsSame(previousPosition, Transform.position))
            {
                diff = true;
            }
            else
            if (!FEngineering.QIsSame(Transform.rotation, previousRotation))
            {
                diff = true;
            }
            else
            {
                if (Is2D == false)
                {
                    if (preRadius != Capsule.radius || !FEngineering.VIsSame(previousScale, Transform.lossyScale))
                    {
                        CalculateCapsuleParameters(Capsule, ref Direction, ref radius, ref scaleFactor);
                    }
                }
                else
                {
                    if (preRadius != GetCapsule2DRadius(Capsule2D) || !FEngineering.VIsSame(previousScale, Transform.lossyScale))
                    {
                        CalculateCapsuleParameters(Capsule2D, ref Direction, ref radius, ref scaleFactor);
                    }
                }
            }

            if (diff)
            {
                if (Is2D == false)
                {
                    GetCapsuleHeadsPositions(Capsule, ref Top, ref Bottom, Direction, radius, scaleFactor);
                }
                else
                {
                    GetCapsuleHeadsPositions(Capsule2D, ref Top, ref Bottom, Direction, radius, scaleFactor);
                }
            }

            base.RefreshColliderData();

            previousPosition = Transform.position;
            previousRotation = Transform.rotation;
            previousScale    = Transform.lossyScale;

            if (Is2D == false)
            {
                preRadius = Capsule.radius;
            }
            else
            {
                preRadius = GetCapsule2DRadius(Capsule2D);
            }
        }
示例#23
0
        /// <summary>
        /// If segment rotation is in too big angle we straighten it
        /// </summary>
        protected Vector3 AngleLimiting(TailSegment child, Vector3 targetPos)
        {
            float angleFactor = 0f;

            _limiting_limitPosition = targetPos;


            _limiting_angle_ToTargetRot = (
                Quaternion.FromToRotation
                (
                    child.ParentBone.transform.TransformDirection(child.LastKeyframeLocalPosition),
                    targetPos - child.ParentBone.ProceduralPosition)
                )
                                          * child.ParentBone.transform.rotation;

            _limiting_angle_targetInLocal = FEngineering.QToLocal(child.ParentBone.transform.rotation, _limiting_angle_ToTargetRot); // Quaternion.Inverse(child.ParentBone.PreviousRotation) * _limiting_angle_ToTargetRot;


            // Limiting all axis or one
            float angleDiffToInitPose = 0f;

            if (AngleLimitAxis.sqrMagnitude == 0f) // All axis limit angle
            {
                angleDiffToInitPose = Quaternion.Angle(_limiting_angle_targetInLocal, child.LastKeyframeLocalRotation);
            }
            else // Selective axis
            {
                #region Selective axis limits

                AngleLimitAxis.Normalize();

                if (LimitAxisRange.x == LimitAxisRange.y)
                {
                    angleDiffToInitPose = Mathf.DeltaAngle(
                        Vector3.Scale(child.InitialLocalRotation.eulerAngles, AngleLimitAxis).magnitude,
                        Vector3.Scale(_limiting_angle_targetInLocal.eulerAngles, AngleLimitAxis).magnitude);

                    if (angleDiffToInitPose < 0f)
                    {
                        angleDiffToInitPose = -angleDiffToInitPose;
                    }
                }
                else
                {
                    angleDiffToInitPose = Mathf.DeltaAngle(
                        Vector3.Scale(child.InitialLocalRotation.eulerAngles, AngleLimitAxis).magnitude,
                        Vector3.Scale(_limiting_angle_targetInLocal.eulerAngles, AngleLimitAxis).magnitude);

                    if (angleDiffToInitPose > LimitAxisRange.x && angleDiffToInitPose < LimitAxisRange.y)
                    {
                        angleDiffToInitPose = 0f;
                    }
                    if (angleDiffToInitPose < 0)
                    {
                        angleDiffToInitPose = -angleDiffToInitPose;
                    }
                }

                #endregion
            }


            #region Debug
            //Debug.Log("Atarget in local = " +
            //    FEngineering.WrapVector(_limiting_angle_targetInLocal.eulerAngles) + " last key local = " +
            //    FEngineering.WrapVector(child.lastKeyframeLocalRotation.eulerAngles) + " angle = " + angleDiffToInitPose);
            #endregion

            // Finding rotate back to limited angle coordinates
            if (angleDiffToInitPose > AngleLimit)
            {
                float exceededAngle = Mathf.Abs(Mathf.DeltaAngle(angleDiffToInitPose, AngleLimit));
                angleFactor = Mathf.InverseLerp(0f, AngleLimit, exceededAngle); // percentage value (0-1) from target rotation to limit

                #region Debug

                //Debug.DrawLine(child.ParentBone.ParentBone.transform.position + child.ParentBone.ParentBone.ProceduralRotation * child.ParentBone.transform.localPosition,
                //child.ProceduralPosition, Color.red, 1f);

                //Debug.Log("[" + child.Index + "] diff = "
                //    + angleDiffToInitPose + " exc =  "
                //    + exceededAngle + " fact = "
                //    + angleFactor);

                #endregion


                if (LimitSmoothing > Mathf.Epsilon)
                {
                    float smooth = Mathf.Lerp(55f, 15f, LimitSmoothing);
                    _limiting_angle_newLocal = Quaternion.SlerpUnclamped(_limiting_angle_targetInLocal, child.LastKeyframeLocalRotation, deltaForLerps * smooth * angleFactor);
                }
                else
                {
                    _limiting_angle_newLocal = Quaternion.SlerpUnclamped(_limiting_angle_targetInLocal, child.LastKeyframeLocalRotation, angleFactor);
                }


                _limiting_angle_ToTargetRot = FEngineering.QToWorld(child.ParentBone.transform.rotation, _limiting_angle_newLocal);
                _limiting_limitPosition     = child.ParentBone.ProceduralPosition + _limiting_angle_ToTargetRot * Vector3.Scale(child.transform.lossyScale, child.LastKeyframeLocalPosition);
            }

            if (angleFactor > Mathf.Epsilon)
            {
                return(_limiting_limitPosition);
            }
            else
            {
                return(targetPos);
            }
        }
示例#24
0
 /// <summary> Smoothing rotation for _tc_bone with smooth damp method changing _tc_smoothRot variable in iteration towards _tc_targetRot </summary>
 Quaternion TailCalculations_SmoothRotationSmoothDamp(Quaternion from, Quaternion to, ref Quaternion velo, float speed)
 {
     return(FEngineering.SmoothDampRotation(from, to, ref velo, Mathf.LerpUnclamped(0.25f, 0.0001f, Mathf.Sqrt(Mathf.Sqrt(speed))), rateDelta));
 }
示例#25
0
 /// <summary>
 /// Refreshing position for additionaly generated parent bone
 /// </summary>
 public void Editor_TailCalculations_RefreshArtificialParentBone()
 {
     GhostParent.ProceduralPosition = GhostParent.transform.position + FEngineering.TransformVector(GhostParent.transform.rotation, GhostParent.transform.lossyScale, GhostParent.LocalOffset);
 }