Esempio n. 1
0
        /// <summary>
        /// Updates the characterHeightMassRadius after all other changes have been made by the converters
        /// </summary>
        private void UpdateCharacterHeightMassRadius(UMAData umaData, UMASkeleton skeleton, Bounds newBounds)
        {
            float charHeight = newBounds.size.y;
            float charWidth  = newBounds.size.x;

            if (umaData.umaRecipe.raceData.umaTarget == RaceData.UMATarget.Humanoid)
            {
                //adjusting is only about tweaking the result
                if (_adjustHeight || _adjustRadius)
                {
                    float chinHeight = 0f;
                    float headHeight = 0f;
                    float headWidth  = 0f;

                    UpdateMechanimBoneDict(umaData, skeleton);

                    //character needs to be moved into the root again with no rotation applied
                    var  umaTransform        = umaData.transform;
                    var  originalParent      = umaData.transform.parent;
                    var  originalRot         = umaData.transform.localRotation;
                    var  originalPos         = umaData.transform.localPosition;
                    var  umaCollider         = umaData.gameObject.GetComponent <Collider>();
                    bool prevColliderEnabled = umaCollider != null ? umaCollider.enabled : false;

                    //if there is a collider, disable it before we move anything
                    if (umaCollider)
                    {
                        umaCollider.enabled = false;
                    }

                    umaTransform.SetParent(null, false);
                    umaTransform.localRotation = Quaternion.identity;
                    umaTransform.localPosition = Vector3.zero;

                    if (_adjustHeight)
                    {
                        //Classically a human is apprx 7.5 heads tall, but we only know the height to the base of the head bone
                        //usually head bone is actually usually in line with the lips, making the base of the chin, 1/3rd down the neck
                        //so if we have the optional neck bone use that to estimate the base of the chin
                        chinHeight = skeleton.GetRelativePosition(_mechanimBoneDict["Head"]).y;
                        if (skeleton.BoneExists(_mechanimBoneDict["Neck"]))
                        {
                            chinHeight = skeleton.GetRelativePosition(_mechanimBoneDict["Neck"]).y + (((skeleton.GetRelativePosition(_mechanimBoneDict["Head"]).y - skeleton.GetRelativePosition(_mechanimBoneDict["Neck"]).y) / 3f) * 2f);
                        }
                        //apply the headRatio (by default this is 7.5)
                        chinHeight = (chinHeight / 6.5f) * (_headRatio - 1);
                        //so classically chinbase is 6.5 headHeights from the floor so headHeight is..
                        headHeight = (chinHeight / (_headRatio - 1));
                        //but bobble headed charcaters (toons), children or dwarves etc have bigger heads proportionally
                        //so their overall height will greater than (chinHeight / 6.5) * 7.5
                        //If we have the eyes we can use those to calculate the size of the head better because classically the distance from the chin to the eyes will be half the head height
                        if (skeleton.BoneExists(_mechanimBoneDict["LeftEye"]) || skeleton.BoneExists(_mechanimBoneDict["RightEye"]))
                        {
                            var eyeHeight = 0f;
                            //if we have both eyes get the average
                            if (skeleton.BoneExists(_mechanimBoneDict["LeftEye"]) && skeleton.BoneExists(_mechanimBoneDict["RightEye"]))
                            {
                                eyeHeight = (skeleton.GetRelativePosition(_mechanimBoneDict["LeftEye"]).y + skeleton.GetRelativePosition(_mechanimBoneDict["RightEye"]).y) / 2f;
                            }
                            else if (skeleton.BoneExists(_mechanimBoneDict["LeftEye"]))
                            {
                                eyeHeight = skeleton.GetRelativePosition(_mechanimBoneDict["LeftEye"]).y;
                            }
                            else if (skeleton.BoneExists(_mechanimBoneDict["RightEye"]))
                            {
                                eyeHeight = skeleton.GetRelativePosition(_mechanimBoneDict["RightEye"]).y;
                            }

                            headHeight = ((eyeHeight - chinHeight) * 2f);
                            //because we do this the actual headRatio doesnt *feel* right
                            //i.e. with toon the head ratio is more like 3, but the correct value for calcs is 6.5
                            //I'd prefer it if these calcs made 3 deliver the correct result
                        }

                        //So finally
                        //Debug.Log("chinHeight was " + chinHeight+" headHeight was "+headHeight);
                        //Debug.Log("Classical Height from Head = " + (headHeight * 7.5f));
                        //Debug.Log("Classical Height from Chin = " + ((chinHeight / 6.5f) * 7.5f));
                        charHeight = chinHeight + headHeight;
                    }

                    if (_adjustRadius)
                    {
                        float shouldersWidth = Mathf.Abs(skeleton.GetRelativePosition(_mechanimBoneDict["LeftUpperArm"]).x - skeleton.GetRelativePosition(_mechanimBoneDict["RightUpperArm"]).x);
                        //Also female charcaters tend to have hips wider than their shoulders, so check that
                        float hipsWidth = Mathf.Abs(skeleton.GetRelativePosition(_mechanimBoneDict["LeftUpperLeg"]).x - skeleton.GetRelativePosition(_mechanimBoneDict["RightUpperLeg"]).x);
                        //the outerWidth of the hips is larger than this because the thigh muscles are so big so make this 1/3rd bigger
                        hipsWidth = (hipsWidth / 2) * 3;

                        //classically the width of the body is 3* headwidth for a strong character so headwidth will be
                        headWidth = shouldersWidth / 2.75f;
                        //but bobble headed charcaters (toons), children or dwarves etc have bigger heads proportionally and the head can be wider than the shoulders
                        //so if we have eye bones use them to calculate head with
                        if (skeleton.BoneExists(_mechanimBoneDict["LeftEye"]) && skeleton.BoneExists(_mechanimBoneDict["RightEye"]))
                        {
                            //clasically a face is 5* the width of the eyes where the distance between the pupils is 2 * eye width
                            var eyeWidth = Mathf.Abs(skeleton.GetRelativePosition(_mechanimBoneDict["LeftEye"]).x - skeleton.GetRelativePosition(_mechanimBoneDict["RightEye"]).x) / 2;
                            headWidth = eyeWidth * 5f;
                        }
                        charWidth = (shouldersWidth > headWidth || hipsWidth > headWidth) ? (shouldersWidth > hipsWidth ? shouldersWidth : hipsWidth) : headWidth;
                        //we might also want to take into account the z depth between the hips and the head,
                        //because if the character has been made into a horse or something it might be on all fours (and still be mechanim.Humanoid [if that even works!])
                        //capsule colliders break down in this scenario though (switch race to SkyCar to see what I mean), so would we want to change the orientation of the collider or the type?
                        //does the collider orientation have any impact on physics?
                    }
                    //Set the UMA back
                    umaTransform.SetParent(originalParent, false);
                    umaTransform.localRotation = originalRot;
                    umaTransform.localPosition = originalPos;

                    //set any collider to its original setting
                    if (umaCollider)
                    {
                        umaCollider.enabled = prevColliderEnabled;
                    }
                }
            }
            else             //if its a car or a castle or whatever use the bounds
            {
                charHeight = newBounds.size.y;
                charWidth  = newBounds.size.x;
            }

            //get the scale of the overall scale bone if set
            float overallScale = 1f;

            if (skeleton.GetBoneTransform(_scaleBoneHash) != null)
            {
                overallScale = (skeleton.GetScale(_scaleBoneHash)).x;
            }

            if (_adjustHeight)
            {
                //characterHeight is what we calculated plus any radius y the user has added
                umaData.characterHeight = charHeight * (1 + (_radiusAdjustY * 2));
            }
            else
            {
                umaData.characterHeight = charHeight;
            }

            if (_adjustRadius)
            {
                //characterRadius is the average of the width we calculated plus the z-depth from the bounds / 2
                //we need to include the new _radiusAdjust.y (which is now an adjust for the z axis as radiusAdjustY is now its own field (used for heightAdjust)
                umaData.characterRadius = (charWidth + newBounds.size.z * (_radiusAdjust.x * 2)) / 2;
                //Debug.Log("BCM umaData.characterRadius[" + umaData.characterRadius + "] = (charWidth[" + charWidth + "] + newBounds.size.z[" + newBounds.size.z + "] * (radiusAdjust.x[" + _radiusAdjust.x + "] * 2)) / 2;");
            }
            else
            {
                umaData.characterRadius = (charWidth + newBounds.size.z) / 2;
            }

            if (_adjustMass)
            {
                //characterMass is... what? still dont understand this quite
                var massZModified = (umaData.characterRadius * 2) * overallScale;
                var massYModified = ((1 + _radiusAdjustY) * 0.5f) * overallScale;
                umaData.characterMass = (_massAdjust.x * overallScale) + _massAdjust.y * massYModified + _massAdjust.z * massZModified;
            }
            else
            {
                //HUMANMALE umaData.characterMass[66.68236] = raceMass[50] * overallScale[0.907451] + 28f * umaDna.upperWeight[0.5019608] + 22f * umaDna.lowerWeight[0.3176471]
                umaData.characterMass = 66.68236f;                //? Thats the result
            }
            //in the fixed UMA converters HumanMales mass is actually less than HumanFemales, with this thats solved
            //but the characters are lighter than stock by a about 5 when at they standard size and heaver than stock by about 7 when at max height
            //I dont know how much this matters? It can easily be fixed by tweaking the calcs, I just dont know what the numbers mean again...

            //Debug.Log(umaData.transform.gameObject.name + " umaData.characterMass was "+ umaData.characterMass+" characterHeight was " + umaData.characterHeight + " characterRadius was " + umaData.characterRadius);

#if UNITY_EDITOR
            /*if (_heightDebugToolsEnabled)
             *      AddDebugBoxes(umaData, chinHeight, headHeight, headWidth);
             * else
             *      RemoveDebugBoxes(umaData);*/
#endif
        }
Esempio n. 2
0
        /// <summary>
        /// Builds a dictionary of mechanim bones that can be used when doing the characterHeight/Radius/Mass calculations
        /// </summary>
        private void UpdateMechanimBoneDict(UMAData umaData, UMASkeleton skeleton)
        {
            //"Head" is obligatory for mechanim so we can check that too to tell us when we have switched back to this race and the skeleton was rebuilt but this Behaviour hadnt been garbage collected yet
            if ((_lastRace == null || umaData.umaRecipe.raceData.raceName != _lastRace) || (!_mechanimBoneDict.ContainsKey("Head") || !skeleton.BoneExists(_mechanimBoneDict["Head"])) && umaData.umaRecipe.raceData.umaTarget == RaceData.UMATarget.Humanoid)
            {
                _lastRace = umaData.umaRecipe.raceData.raceName;

                _mechanimBoneDict.Clear();

                var umaTPose = umaData.umaRecipe.raceData.TPose;
                if (umaTPose == null)
                {
                    _lastRace = null;
                    return;
                }
                _mechanimBoneDict.Add("Head", UMAUtils.StringToHash((Array.Find(umaTPose.humanInfo, entry => entry.humanName == "Head").boneName)));
                _mechanimBoneDict.Add("LeftEye", UMAUtils.StringToHash((Array.Find(umaTPose.humanInfo, entry => entry.humanName == "LeftEye").boneName)));          //optionalBone
                _mechanimBoneDict.Add("RightEye", UMAUtils.StringToHash((Array.Find(umaTPose.humanInfo, entry => entry.humanName == "RightEye").boneName)));        //optionalBone
                _mechanimBoneDict.Add("Hips", UMAUtils.StringToHash((Array.Find(umaTPose.humanInfo, entry => entry.humanName == "Hips").boneName)));
                _mechanimBoneDict.Add("Neck", UMAUtils.StringToHash((Array.Find(umaTPose.humanInfo, entry => entry.humanName == "Neck").boneName)));                //OptionalBone
                _mechanimBoneDict.Add("LeftUpperArm", UMAUtils.StringToHash((Array.Find(umaTPose.humanInfo, entry => entry.humanName == "LeftUpperArm").boneName)));
                _mechanimBoneDict.Add("RightUpperArm", UMAUtils.StringToHash((Array.Find(umaTPose.humanInfo, entry => entry.humanName == "RightUpperArm").boneName)));
                _mechanimBoneDict.Add("LeftUpperLeg", UMAUtils.StringToHash((Array.Find(umaTPose.humanInfo, entry => entry.humanName == "LeftUpperLeg").boneName)));
                _mechanimBoneDict.Add("RightUpperLeg", UMAUtils.StringToHash((Array.Find(umaTPose.humanInfo, entry => entry.humanName == "RightUpperLeg").boneName)));
            }
        }