Files
Colosseum/Assets/External/Models/SidekickCharacters/Scripts/Runtime/Prefab/CharacterBlendshapeEditor.cs
dal4segno c265f980db chore: Assets 디렉토리 구조 정리 및 네이밍 컨벤션 적용
- Assets/_Game/ 하위로 게임 에셋 통합
- External/ 패키지 벤더별 분류 (Synty, Animations, UI)
- 에셋 네이밍 컨벤션 확립 및 적용
  (Data_Skill_, Data_SkillEffect_, Prefab_, Anim_, Model_, BT_ 등)
- pre-commit hook으로 네이밍 컨벤션 자동 검사 추가
- RESTRUCTURE_CHECKLIST.md 작성

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-16 19:08:27 +09:00

1737 lines
70 KiB
C#

// Copyright (c) 2024 Synty Studios Limited. All rights reserved.
//
// Use of this software is subject to the terms and conditions of the Synty Studios End User Licence Agreement (EULA)
// available at: https://syntystore.com/pages/end-user-licence-agreement
//
// For additional details, see the LICENSE.MD file bundled with this software.
#if UNITY_EDITOR
using System;
using System.Collections;
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
using System.Linq;
using UnityEditor.UIElements;
using UnityEngine.UIElements;
[ExecuteInEditMode]
public class CharacterBlendshapeEditor : MonoBehaviour
{
[Range(-1, 1)] public float _bodyType;
[Range(-1, 1)] public float _bodySize;
[Range(-1, 1)] public float _musculature;
// Attachment Back values.
public Vector3 _abacFeminineMaxPosOffset = new Vector3(0f, -0.01f, 0f);
public Vector3 _abacFeminineMaxRotOffset = new Vector3(0f, 0f, 0f);
public Vector3 _abacHeavyMaxPosOffset = new Vector3(0f, 0.08f, 0f);
public Vector3 _abacHeavyMaxRotOffset = new Vector3(8f, 0f, 0f);
public Vector3 _abacSkinnyMaxPosOffset = new Vector3(0f, -0.01f, 0f);
public Vector3 _abacSkinnyMaxRotOffset = new Vector3(0f, 0f, 0f);
public Vector3 _abacBulkMaxPosOffset = new Vector3(-0.04f, 0.04f, 0f);
public Vector3 _abacBulkMaxRotOffset = new Vector3(356f, 0f, 0f);
// Attachment Hips Front values.
public Vector3 _ahpfFeminineMaxPosOffset = new Vector3(0f, -0.005f, 0f);
public Vector3 _ahpfFeminineMaxRotOffset = new Vector3(0f, 0f, 0f);
public Vector3 _ahpfHeavyMaxPosOffset = new Vector3(0.06f, 0.15f, 0f);
public Vector3 _ahpfHeavyMaxRotOffset = new Vector3(15f, 0f, 0f);
public Vector3 _ahpfSkinnyMaxPosOffset = new Vector3(0f, -0.007f, 0f);
public Vector3 _ahpfSkinnyMaxRotOffset = new Vector3(0f, 0f, 0f);
public Vector3 _ahpfBulkMaxPosOffset = new Vector3(0f, -0.013f, 0f);
public Vector3 _ahpfBulkMaxRotOffset = new Vector3(2f, 0f, 0f);
// Attachment Hips Back values.
public Vector3 _ahpbFeminineMaxPosOffset = new Vector3(0f, -0.015f, 0f);
public Vector3 _ahpbFeminineMaxRotOffset = new Vector3(3f, 0f, 0f);
public Vector3 _ahpbHeavyMaxPosOffset = new Vector3(0.005f, -0.14f, 0f);
public Vector3 _ahpbHeavyMaxRotOffset = new Vector3(352f, 0f, 0f);
public Vector3 _ahpbSkinnyMaxPosOffset = new Vector3(0f, 0.005f, 0f);
public Vector3 _ahpbSkinnyMaxRotOffset = new Vector3(0f, 0f, 0f);
public Vector3 _ahpbBulkMaxPosOffset = new Vector3(-0.01f, -0.02f, 0f);
public Vector3 _ahpbBulkMaxRotOffset = new Vector3(0f, 0f, 0f);
// Attachment Hips Left values.
public Vector3 _ahplFeminineMaxPosOffset = new Vector3(0f, 0f, 0.005f);
public Vector3 _ahplFeminineMaxRotOffset = new Vector3(0f, 0f, 0f);
public Vector3 _ahplHeavyMaxPosOffset = new Vector3(0f, 0f, 0.13f);
public Vector3 _ahplHeavyMaxRotOffset = new Vector3(0f, 0f, 0f);
public Vector3 _ahplSkinnyMaxPosOffset = new Vector3(0f, 0f, -0.01f);
public Vector3 _ahplSkinnyMaxRotOffset = new Vector3(0f, 0f, 0f);
public Vector3 _ahplBulkMaxPosOffset = new Vector3(0f, 0f, 0.015f);
public Vector3 _ahplBulkMaxRotOffset = new Vector3(0f, 0f, 0f);
// Attachment Hips Right values.
public Vector3 _ahprFeminineMaxPosOffset = new Vector3(0f, 0f, -0.005f);
public Vector3 _ahprFeminineMaxRotOffset = new Vector3(0f, 0f, 0f);
public Vector3 _ahprHeavyMaxPosOffset = new Vector3(0f, 0f, -0.13f);
public Vector3 _ahprHeavyMaxRotOffset = new Vector3(0f, 0f, 0f);
public Vector3 _ahprSkinnyMaxPosOffset = new Vector3(0f, 0f, 0.008f);
public Vector3 _ahprSkinnyMaxRotOffset = new Vector3(0f, 0f, 0f);
public Vector3 _ahprBulkMaxPosOffset = new Vector3(0f, 0f, -0.01f);
public Vector3 _ahprBulkMaxRotOffset = new Vector3(0f, 0f, 0f);
// Attachment Shoulder Left values.
public Vector3 _ashlFeminineMaxPosOffset = new Vector3(0.01f, 0f, -0.015f);
public Vector3 _ashlFeminineMaxRotOffset = new Vector3(0f, 0f, 0f);
public Vector3 _ashlHeavyMaxPosOffset = new Vector3(-0.04f, 0.01f, 0.028f);
public Vector3 _ashlHeavyMaxRotOffset = new Vector3(0f, 0f, 0f);
public Vector3 _ashlSkinnyMaxPosOffset = new Vector3(0.015f, 0f, -0.01f);
public Vector3 _ashlSkinnyMaxRotOffset = new Vector3(0f, 0f, 0f);
public Vector3 _ashlBulkMaxPosOffset = new Vector3(-0.03f, 0f, 0.05f);
public Vector3 _ashlBulkMaxRotOffset = new Vector3(0f, 0f, 0f);
// Attachment Shoulder Right values.
public Vector3 _ashrFeminineMaxPosOffset = new Vector3(0.01f, 0f, -0.015f);
public Vector3 _ashrFeminineMaxRotOffset = new Vector3(0f, 0f, 0f);
public Vector3 _ashrHeavyMaxPosOffset = new Vector3(-0.04f, -0.01f, 0.028f);
public Vector3 _ashrHeavyMaxRotOffset = new Vector3(0f, 0f, 0f);
public Vector3 _ashrSkinnyMaxPosOffset = new Vector3(0.015f, 0f, -0.01f);
public Vector3 _ashrSkinnyMaxRotOffset = new Vector3(0f, 0f, 0f);
public Vector3 _ashrBulkMaxPosOffset = new Vector3(-0.03f, 0f, 0.05f);
public Vector3 _ashrBulkMaxRotOffset = new Vector3(0f, 0f, 0f);
// Attachment Elbow Left values.
public Vector3 _aeblFeminineMaxPosOffset = new Vector3(0f, -0.01f, 0f);
public Vector3 _aeblFeminineMaxRotOffset = new Vector3(0f, 0f, 0f);
public Vector3 _aeblHeavyMaxPosOffset = new Vector3(0f, 0.025f, 0f);
public Vector3 _aeblHeavyMaxRotOffset = new Vector3(0f, 0f, 0f);
public Vector3 _aeblSkinnyMaxPosOffset = new Vector3(0f, -0.015f, 0.01f);
public Vector3 _aeblSkinnyMaxRotOffset = new Vector3(0f, 2f, 0f);
public Vector3 _aeblBulkMaxPosOffset = new Vector3(0f, 0.06f, 0.02f);
public Vector3 _aeblBulkMaxRotOffset = new Vector3(13f, 0f, 0f);
// Attachment Elbow Right values.
public Vector3 _aebrFeminineMaxPosOffset = new Vector3(0f, -0.01f, 0f);
public Vector3 _aebrFeminineMaxRotOffset = new Vector3(0f, 0f, 0f);
public Vector3 _aebrHeavyMaxPosOffset = new Vector3(0f, 0.035f, 0f);
public Vector3 _aebrHeavyMaxRotOffset = new Vector3(0f, 0f, 0f);
public Vector3 _aebrSkinnyMaxPosOffset = new Vector3(0f, -0.015f, 0.01f);
public Vector3 _aebrSkinnyMaxRotOffset = new Vector3(0f, 358f, 0f);
public Vector3 _aebrBulkMaxPosOffset = new Vector3(0f, 0.06f, 0.02f);
public Vector3 _aebrBulkMaxRotOffset = new Vector3(13f, 0f, 0f);
// Attachment Knee Left values.
public Vector3 _aknlFeminineMaxPosOffset = new Vector3(0f, 0f, 0f);
public Vector3 _aknlFeminineMaxRotOffset = new Vector3(0f, 0f, 0f);
public Vector3 _aknlHeavyMaxPosOffset = new Vector3(0f, -0.015f, 0f);
public Vector3 _aknlHeavyMaxRotOffset = new Vector3(0f, 20f, 0f);
public Vector3 _aknlSkinnyMaxPosOffset = new Vector3(0f, 0.01f, 0f);
public Vector3 _aknlSkinnyMaxRotOffset = new Vector3(0f, 0f, 0f);
public Vector3 _aknlBulkMaxPosOffset = new Vector3(0f, -0.002f, 0f);
public Vector3 _aknlBulkMaxRotOffset = new Vector3(0f, 0f, 0f);
// Attachment Knee Right values.
public Vector3 _aknrFeminineMaxPosOffset = new Vector3(0f, 0f, 0f);
public Vector3 _aknrFeminineMaxRotOffset = new Vector3(0f, 0f, 0f);
public Vector3 _aknrHeavyMaxPosOffset = new Vector3(0f, 0.015f, 0f);
public Vector3 _aknrHeavyMaxRotOffset = new Vector3(0f, 0f, 15f);
public Vector3 _aknrSkinnyMaxPosOffset = new Vector3(0f, -0.01f, 0f);
public Vector3 _aknrSkinnyMaxRotOffset = new Vector3(0f, 0f, 0f);
public Vector3 _aknrBulkMaxPosOffset = new Vector3(0f, 0.002f, 0f);
public Vector3 _aknrBulkMaxRotOffset = new Vector3(0f, 0f, 0f);
private List<SkinnedMeshRenderer> _meshRenderers = new List<SkinnedMeshRenderer>();
private Dictionary<SkinnedMeshRenderer, Dictionary<string, int>> _blendshapeIndices;
private readonly Vector3 _minValues = Vector3.zero;
private readonly Vector3 _maxValues = new Vector3(359.9999f, 359.9999f, 359.9999f);
private Dictionary<string, Vector3> _blendShapeRigMovement;
private Dictionary<string, Quaternion> _blendShapeRigRotation;
private Hashtable _boneNameMap;
private static readonly Dictionary<AttachmentType, string> _PART_TYPE_JOINT_MAP = new Dictionary<AttachmentType, string>
{
[AttachmentType.AttachmentBack] = "backAttach",
[AttachmentType.AttachmentHipsFront] = "hipAttachFront",
[AttachmentType.AttachmentHipsBack] = "hipAttachBack",
[AttachmentType.AttachmentHipsLeft] = "hipAttach_l",
[AttachmentType.AttachmentHipsRight] = "hipAttach_r",
[AttachmentType.AttachmentShoulderLeft] = "shoulderAttach_l",
[AttachmentType.AttachmentShoulderRight] = "shoulderAttach_r",
[AttachmentType.AttachmentElbowLeft] = "elbowAttach_l",
[AttachmentType.AttachmentElbowRight] = "elbowAttach_r",
[AttachmentType.AttachmentKneeLeft] = "kneeAttach_l",
[AttachmentType.AttachmentKneeRight] = "kneeAttach_r"
};
// Initial positions of attachment joints, used for applying offsets.
private static readonly Dictionary<string, Vector3> _JOINT_BASE_POSITION_MAP = new Dictionary<string, Vector3>
{
["hipAttach_l"] = new Vector3(-0.06f, -0.02f, 0.16f),
["hipAttach_r"] = new Vector3(-0.06f, -0.02f, -0.16f),
["hipAttachBack"] = new Vector3(-0.08f, -0.10f, 0.00f),
["hipAttachFront"] = new Vector3(-0.02f, 0.14f, 0.00f),
["backAttach"] = new Vector3(-0.19f, 0.14f, 0.00f),
["shoulderAttach_l"] = new Vector3(-0.17f, 0.01f, 0.08f),
["elbowAttach_l"] = new Vector3(0.01f, 0.03f, -0.01f),
["shoulderAttach_r"] = new Vector3(-0.17f, -0.01f, 0.08f),
["elbowAttach_r"] = new Vector3(-0.01f, 0.03f, -0.01f),
["kneeAttach_l"] = new Vector3(-0.01f, -0.05f, -0.01f),
["kneeAttach_r"] = new Vector3(0.01f, 0.05f, 0.01f)
};
// Initial rotations of attachment joints, used for applying offsets.
private static readonly Dictionary<string, Quaternion> _JOINT_BASE_ROTATION_MAP = new Dictionary<string, Quaternion>
{
["hipAttach_l"] = new Quaternion(-0.50000f, 0.50000f, 0.50000f, 0.50000f),
["hipAttach_r"] = new Quaternion(-0.50000f, 0.50000f, 0.50000f, 0.50000f),
["hipAttachBack"] = new Quaternion(-0.50000f, 0.50000f, 0.50000f, 0.50000f),
["hipAttachFront"] = new Quaternion(-0.50000f, 0.50000f, 0.50000f, 0.50000f),
["backAttach"] = new Quaternion(0.49823f, -0.50177f, 0.49822f, 0.50176f),
["shoulderAttach_l"] = new Quaternion(0.69873f, -0.00835f, 0.01867f, 0.71509f),
["elbowAttach_l"] = new Quaternion(0.70711f, 0.00230f, -0.02266f, 0.70674f),
["shoulderAttach_r"] = new Quaternion(0.71507f, -0.01867f, 0.00835f, 0.69875f),
["elbowAttach_r"] = new Quaternion(0.70711f, -0.00230f, 0.02266f, 0.70674f),
["kneeAttach_l"] = new Quaternion(0.70616f, -0.03582f, -0.02210f, 0.70680f),
["kneeAttach_r"] = new Quaternion(-0.00045f, -0.00970f, -0.04096f, 0.99911f)
};
/// <inheritdoc cref="OnEnable"/>
private void OnEnable()
{
UpdateMeshReference();
CacheBlendshapeIndices();
}
/// <inheritdoc cref="OnValidate"/>
private void OnValidate()
{
_abacFeminineMaxRotOffset = MinMaxVector3(_abacFeminineMaxRotOffset);
_abacHeavyMaxRotOffset = MinMaxVector3(_abacHeavyMaxRotOffset);
_abacSkinnyMaxRotOffset = MinMaxVector3(_abacSkinnyMaxRotOffset);
_abacBulkMaxRotOffset = MinMaxVector3(_abacBulkMaxRotOffset);
_ahpfFeminineMaxRotOffset = MinMaxVector3(_ahpfFeminineMaxRotOffset);
_ahpfHeavyMaxRotOffset = MinMaxVector3(_ahpfHeavyMaxRotOffset);
_ahpfSkinnyMaxRotOffset = MinMaxVector3(_ahpfSkinnyMaxRotOffset);
_ahpfBulkMaxRotOffset = MinMaxVector3(_ahpfBulkMaxRotOffset);
_ahpbFeminineMaxRotOffset = MinMaxVector3(_ahpbFeminineMaxRotOffset);
_ahpbHeavyMaxRotOffset = MinMaxVector3(_ahpbHeavyMaxRotOffset);
_ahpbSkinnyMaxRotOffset = MinMaxVector3(_ahpbSkinnyMaxRotOffset);
_ahpbBulkMaxRotOffset = MinMaxVector3(_ahpbBulkMaxRotOffset);
_ahplFeminineMaxRotOffset = MinMaxVector3(_ahplFeminineMaxRotOffset);
_ahplHeavyMaxRotOffset = MinMaxVector3(_ahplHeavyMaxRotOffset);
_ahplSkinnyMaxRotOffset = MinMaxVector3(_ahplSkinnyMaxRotOffset);
_ahplBulkMaxRotOffset = MinMaxVector3(_ahplBulkMaxRotOffset);
_ahprFeminineMaxRotOffset = MinMaxVector3(_ahprFeminineMaxRotOffset);
_ahprHeavyMaxRotOffset = MinMaxVector3(_ahprHeavyMaxRotOffset);
_ahprSkinnyMaxRotOffset = MinMaxVector3(_ahprSkinnyMaxRotOffset);
_ahprBulkMaxRotOffset = MinMaxVector3(_ahprBulkMaxRotOffset);
_ashlFeminineMaxRotOffset = MinMaxVector3(_ashlFeminineMaxRotOffset);
_ashlHeavyMaxRotOffset = MinMaxVector3(_ashlHeavyMaxRotOffset);
_ashlSkinnyMaxRotOffset = MinMaxVector3(_ashlSkinnyMaxRotOffset);
_ashlBulkMaxRotOffset = MinMaxVector3(_ashlBulkMaxRotOffset);
_ashrFeminineMaxRotOffset = MinMaxVector3(_ashrFeminineMaxRotOffset);
_ashrHeavyMaxRotOffset = MinMaxVector3(_ashrHeavyMaxRotOffset);
_ashrSkinnyMaxRotOffset = MinMaxVector3(_ashrSkinnyMaxRotOffset);
_ashrBulkMaxRotOffset = MinMaxVector3(_ashrBulkMaxRotOffset);
_aeblFeminineMaxRotOffset = MinMaxVector3(_aeblFeminineMaxRotOffset);
_aeblHeavyMaxRotOffset = MinMaxVector3(_aeblHeavyMaxRotOffset);
_aeblSkinnyMaxRotOffset = MinMaxVector3(_aeblSkinnyMaxRotOffset);
_aeblBulkMaxRotOffset = MinMaxVector3(_aeblBulkMaxRotOffset);
_aebrFeminineMaxRotOffset = MinMaxVector3(_aebrFeminineMaxRotOffset);
_aebrHeavyMaxRotOffset = MinMaxVector3(_aebrHeavyMaxRotOffset);
_aebrSkinnyMaxRotOffset = MinMaxVector3(_aebrSkinnyMaxRotOffset);
_aebrBulkMaxRotOffset = MinMaxVector3(_aebrBulkMaxRotOffset);
_aknlFeminineMaxRotOffset = MinMaxVector3(_aknlFeminineMaxRotOffset);
_aknlHeavyMaxRotOffset = MinMaxVector3(_aknlHeavyMaxRotOffset);
_aknlSkinnyMaxRotOffset = MinMaxVector3(_aknlSkinnyMaxRotOffset);
_aknlBulkMaxRotOffset = MinMaxVector3(_aknlBulkMaxRotOffset);
_aknrFeminineMaxRotOffset = MinMaxVector3(_aknrFeminineMaxRotOffset);
_aknrHeavyMaxRotOffset = MinMaxVector3(_aknrHeavyMaxRotOffset);
_aknrSkinnyMaxRotOffset = MinMaxVector3(_aknrSkinnyMaxRotOffset);
_aknrBulkMaxRotOffset = MinMaxVector3(_aknrBulkMaxRotOffset);
// Ensure the mesh references are populated before trying to update blend shapes
if (_meshRenderers == null)
{
UpdateMeshReference();
}
// Ensure the blend shape indices are populated before trying to update blend shapes
if (_blendshapeIndices == null)
{
CacheBlendshapeIndices();
}
// Ensure the bone map is populated before trying to move joints.
if (_boneNameMap == null)
{
_boneNameMap = CreateBoneNameMap(gameObject.GetComponentsInChildren<Transform>().First(t => t.name == "root").gameObject);
}
ApplyBlendshapes();
ProcessRigMovementOnBlendShapeChange();
ProcessBoneMovement(_boneNameMap, _blendShapeRigMovement, _blendShapeRigRotation);
}
/// <summary>
/// Updates the reference list of the all skinned meshes on the character.
/// </summary>
private void UpdateMeshReference()
{
if (_meshRenderers.Count < 1)
{
_meshRenderers = gameObject.GetComponentsInChildren<SkinnedMeshRenderer>().ToList();
}
if (_meshRenderers.Count > 0)
{
SkinnedMeshRenderer meshRenderer = _meshRenderers[0];
_boneNameMap = CreateBoneNameMap(meshRenderer.rootBone.gameObject);
}
}
/// <summary>
/// Updates the blend shape indices cache.
/// </summary>
private void CacheBlendshapeIndices()
{
_blendshapeIndices = new Dictionary<SkinnedMeshRenderer, Dictionary<string, int>>();
if (_meshRenderers.Count < 1)
{
return;
}
foreach (SkinnedMeshRenderer meshRenderer in _meshRenderers)
{
if (meshRenderer == null || meshRenderer.sharedMesh == null)
{
continue;
}
Dictionary<string, int> currentIndices = new Dictionary<string, int>();
Mesh mesh = meshRenderer.sharedMesh;
for (int i = 0; i < mesh.blendShapeCount; i++)
{
string blendName = mesh.GetBlendShapeName(i);
currentIndices[blendName] = i;
}
_blendshapeIndices[meshRenderer] = currentIndices;
}
}
/// <summary>
/// Sets the blend shape value for the given blend shape name.
/// </summary>
/// <param name="blendName">The name for the blend shape to be updated.</param>
/// <param name="value">The new value to send for the given blend shape.</param>
private void SetBlendValue(string blendName, float value)
{
foreach (SkinnedMeshRenderer meshRenderer in _meshRenderers)
{
if (_blendshapeIndices.TryGetValue(meshRenderer, out Dictionary<string, int> currentIndices))
{
if (currentIndices.TryGetValue(blendName, out int index))
{
meshRenderer.SetBlendShapeWeight(index, Mathf.Clamp01(value) * 100f);
}
}
}
}
/// <summary>
/// Applies changes to the blend shapes from the changes on the UI sliders.
/// </summary>
private void ApplyBlendshapes()
{
foreach (SkinnedMeshRenderer meshRenderer in _meshRenderers)
{
if (meshRenderer == null)
{
continue;
}
if (_blendshapeIndices.TryGetValue(meshRenderer, out Dictionary<string, int> currentIndices))
{
foreach (KeyValuePair<string, int> pair in currentIndices)
{
string blendName = pair.Key;
float weight = 0f;
if (blendName.EndsWith("masculineFeminine"))
{
weight = _bodyType;
}
else if (blendName.EndsWith("defaultSkinny"))
{
weight = _bodySize < 0 ? -_bodySize : 0;
}
else if (blendName.EndsWith("defaultHeavy"))
{
weight = _bodySize > 0 ? _bodySize : 0;
}
else if (blendName.EndsWith("Buff"))
{
weight = (_musculature + 1) / 2;
}
SetBlendValue(blendName, weight);
}
}
}
}
/// <summary>
/// Ensures that the values in the given Vector3 are within the desired min-max range.
/// </summary>
/// <param name="value">The Vector3 to clamp to the values.</param>
/// <returns>The new Vector3 with clamped values.</returns>
private Vector3 MinMaxVector3(Vector3 value)
{
Vector3 temp = Vector3.Max(value, _minValues);
Vector3 newValue = Vector3.Min(temp, _maxValues);
return newValue;
}
/// <summary>
/// Creates a map between bones and their names.
/// </summary>
/// <param name="currentBone">The Current bone being mapped.</param>
/// <returns>A hashmap between bone names and bones.</returns>
private Hashtable CreateBoneNameMap(GameObject currentBone)
{
Hashtable boneNameMap = new Hashtable
{
{
currentBone.name, currentBone.transform
}
};
for (int i = 0; i < currentBone.transform.childCount; i++)
{
Hashtable childBoneMap = CreateBoneNameMap(currentBone.transform.GetChild(i).gameObject);
foreach (DictionaryEntry entry in childBoneMap)
{
if (!boneNameMap.ContainsKey(entry.Key))
{
boneNameMap.Add(entry.Key, (Transform) entry.Value);
}
}
}
return boneNameMap;
}
/// <summary>
/// Processes the movement of rig joints based on blend shape changes.
/// </summary>
private void ProcessRigMovementOnBlendShapeChange()
{
_blendShapeRigMovement = new Dictionary<string, Vector3>();
_blendShapeRigRotation = new Dictionary<string, Quaternion>();
foreach (KeyValuePair<AttachmentType, string> entry in _PART_TYPE_JOINT_MAP)
{
if (!_boneNameMap.ContainsKey(entry.Value))
{
continue;
}
Transform bone = (Transform) _boneNameMap[entry.Value];
float feminineBlendValue = (_bodyType + 1) / 2;
float heavyBlendValue = _bodySize > 0 ? _bodySize : 0;
float skinnyBlendValue = _bodySize < 0 ? -_bodySize : 0;
float bulkBlendValue = (_musculature + 1) / 2;
Vector3 allMovement = _JOINT_BASE_POSITION_MAP[bone.name]; //bone.localPosition;
Quaternion allRotation = _JOINT_BASE_ROTATION_MAP[bone.name]; //bone.localRotation;
foreach (BlendShapeType blendType in Enum.GetValues(typeof(BlendShapeType)))
{
switch (blendType)
{
case BlendShapeType.Feminine:
allMovement += GetBlendedFeminineOffsetValue(entry.Key, feminineBlendValue);
allRotation *= GetBlendedFeminineRotationValue(entry.Key, feminineBlendValue);
break;
case BlendShapeType.Heavy:
allMovement += GetBlendedHeavyOffsetValue(entry.Key, heavyBlendValue);
allRotation *= GetBlendedHeavyRotationValue(entry.Key, heavyBlendValue);
break;
case BlendShapeType.Skinny:
allMovement += GetBlendedSkinnyOffsetValue(entry.Key, skinnyBlendValue);
allRotation *= GetBlendedSkinnyRotationValue(entry.Key, skinnyBlendValue);
break;
case BlendShapeType.Bulk:
allMovement += GetBlendedBulkOffsetValue(entry.Key, bulkBlendValue);
allRotation *= GetBlendedBulkRotationValue(entry.Key, bulkBlendValue);
break;
}
}
_blendShapeRigMovement[entry.Value] = allMovement;
_blendShapeRigRotation[entry.Value] = allRotation;
}
}
/// <summary>
/// Processes the movement of bones if required for the given movement dictionary.
/// </summary>
/// <param name="boneNameMap">The bone name map that has all the bones of the rig.</param>
/// <param name="movementDictionary">The dictionary of bones to process the movement from.</param>
/// <param name="rotationDictionary">The dictionary of bone rotations to process.</param>
private static void ProcessBoneMovement(Hashtable boneNameMap, Dictionary<string, Vector3> movementDictionary, Dictionary<string, Quaternion>
rotationDictionary)
{
Dictionary<string, Vector3> bonePositionDictionary = new Dictionary<string, Vector3>();
Dictionary<string, Quaternion> boneRotationDictionary = new Dictionary<string, Quaternion>();
Dictionary<string, Vector3> boneMovementDictionary = new Dictionary<string, Vector3>();
foreach (Transform currentBone in boneNameMap.Values)
{
// Store bone positions from rig before processing joints.
bonePositionDictionary.TryAdd(currentBone.name, currentBone.transform.localPosition);
boneRotationDictionary.TryAdd(currentBone.name, currentBone.transform.localRotation);
if (movementDictionary.ContainsKey(currentBone.name))
{
float jointDistance = Vector3.Distance(bonePositionDictionary[currentBone.name], movementDictionary[currentBone.name]);
float rotationDistance = Quaternion.Angle(boneRotationDictionary[currentBone.name], rotationDictionary[currentBone.name]);
// If the bone in the new part is at a different location, move the actual bone to the same position.
if (jointDistance > 0.0001)
{
Vector3 rigMovement = movementDictionary[currentBone.name];
// If an existing joint movement exists, and is further from the standard joint position, use that instead.
if (boneMovementDictionary.TryGetValue(currentBone.name, out Vector3 existingMovement)
&& Math.Abs(Vector3.Distance(bonePositionDictionary[currentBone.name], existingMovement)) > Math.Abs(jointDistance))
{
rigMovement = existingMovement;
}
currentBone.transform.localPosition = rigMovement;
boneMovementDictionary[currentBone.name] = rigMovement;
}
if (rotationDistance > 0.01)
{
Quaternion rigRotation = rotationDictionary[currentBone.name];
if (boneRotationDictionary.TryGetValue(currentBone.name, out Quaternion existingRotation)
&& Math.Abs(Quaternion.Angle(boneRotationDictionary[currentBone.name], existingRotation)) > Math.Abs(rotationDistance))
{
rigRotation = existingRotation;
}
currentBone.transform.localRotation = rigRotation;
boneRotationDictionary[currentBone.name] = rigRotation;
}
}
}
}
/// <summary>
/// Gets the blended offset value for the given attachment type and blend value.
/// </summary>
/// <param name="attachmentType">The attachment type to get the blended offset value for.</param>
/// <param name="blendValue">The blend value to use.</param>
/// <returns>The blended offset value.</returns>
private Vector3 GetBlendedFeminineOffsetValue(AttachmentType attachmentType, float blendValue)
{
switch (attachmentType)
{
case AttachmentType.AttachmentBack:
return Vector3.Lerp(Vector3.zero, _abacFeminineMaxPosOffset, blendValue);
case AttachmentType.AttachmentHipsFront:
return Vector3.Lerp(Vector3.zero, _ahpfFeminineMaxPosOffset, blendValue);
case AttachmentType.AttachmentHipsBack:
return Vector3.Lerp(Vector3.zero, _ahpbFeminineMaxPosOffset, blendValue);
case AttachmentType.AttachmentHipsLeft:
return Vector3.Lerp(Vector3.zero, _ahplFeminineMaxPosOffset, blendValue);
case AttachmentType.AttachmentHipsRight:
return Vector3.Lerp(Vector3.zero, _ahprFeminineMaxPosOffset, blendValue);
case AttachmentType.AttachmentShoulderLeft:
return Vector3.Lerp(Vector3.zero, _ashlFeminineMaxPosOffset, blendValue);
case AttachmentType.AttachmentShoulderRight:
return Vector3.Lerp(Vector3.zero, _ashrFeminineMaxPosOffset, blendValue);
case AttachmentType.AttachmentElbowLeft:
return Vector3.Lerp(Vector3.zero, _aeblFeminineMaxPosOffset, blendValue);
case AttachmentType.AttachmentElbowRight:
return Vector3.Lerp(Vector3.zero, _aebrFeminineMaxPosOffset, blendValue);
case AttachmentType.AttachmentKneeLeft:
return Vector3.Lerp(Vector3.zero, _aknlFeminineMaxPosOffset, blendValue);
case AttachmentType.AttachmentKneeRight:
return Vector3.Lerp(Vector3.zero, _aknrFeminineMaxPosOffset, blendValue);
default:
return Vector3.zero;
}
}
/// <summary>
/// Gets the blended offset value for the given attachment type and blend value.
/// </summary>
/// <param name="attachmentType">The attachment type to get the blended offset value for.</param>
/// <param name="blendValue">The blend value to use.</param>
/// <returns>The blended offset value.</returns>
private Vector3 GetBlendedHeavyOffsetValue(AttachmentType attachmentType, float blendValue)
{
switch (attachmentType)
{
case AttachmentType.AttachmentBack:
return Vector3.Lerp(Vector3.zero, _abacHeavyMaxPosOffset, blendValue);
case AttachmentType.AttachmentHipsFront:
return Vector3.Lerp(Vector3.zero, _ahpfHeavyMaxPosOffset, blendValue);
case AttachmentType.AttachmentHipsBack:
return Vector3.Lerp(Vector3.zero, _ahpbHeavyMaxPosOffset, blendValue);
case AttachmentType.AttachmentHipsLeft:
return Vector3.Lerp(Vector3.zero, _ahplHeavyMaxPosOffset, blendValue);
case AttachmentType.AttachmentHipsRight:
return Vector3.Lerp(Vector3.zero, _ahprHeavyMaxPosOffset, blendValue);
case AttachmentType.AttachmentShoulderLeft:
return Vector3.Lerp(Vector3.zero, _ashlHeavyMaxPosOffset, blendValue);
case AttachmentType.AttachmentShoulderRight:
return Vector3.Lerp(Vector3.zero, _ashrHeavyMaxPosOffset, blendValue);
case AttachmentType.AttachmentElbowLeft:
return Vector3.Lerp(Vector3.zero, _aeblHeavyMaxPosOffset, blendValue);
case AttachmentType.AttachmentElbowRight:
return Vector3.Lerp(Vector3.zero, _aebrHeavyMaxPosOffset, blendValue);
case AttachmentType.AttachmentKneeLeft:
return Vector3.Lerp(Vector3.zero, _aknlHeavyMaxPosOffset, blendValue);
case AttachmentType.AttachmentKneeRight:
return Vector3.Lerp(Vector3.zero, _aknrHeavyMaxPosOffset, blendValue);
default:
return Vector3.zero;
}
}
/// <summary>
/// Gets the blended offset value for the given attachment type and blend value.
/// </summary>
/// <param name="attachmentType">The attachment type to get the blended offset value for.</param>
/// <param name="blendValue">The blend value to use.</param>
/// <returns>The blended offset value.</returns>
private Vector3 GetBlendedSkinnyOffsetValue(AttachmentType attachmentType, float blendValue)
{
switch (attachmentType)
{
case AttachmentType.AttachmentBack:
return Vector3.Lerp(Vector3.zero, _abacSkinnyMaxPosOffset, blendValue);
case AttachmentType.AttachmentHipsFront:
return Vector3.Lerp(Vector3.zero, _ahpfSkinnyMaxPosOffset, blendValue);
case AttachmentType.AttachmentHipsBack:
return Vector3.Lerp(Vector3.zero, _ahpbSkinnyMaxPosOffset, blendValue);
case AttachmentType.AttachmentHipsLeft:
return Vector3.Lerp(Vector3.zero, _ahplSkinnyMaxPosOffset, blendValue);
case AttachmentType.AttachmentHipsRight:
return Vector3.Lerp(Vector3.zero, _ahprSkinnyMaxPosOffset, blendValue);
case AttachmentType.AttachmentShoulderLeft:
return Vector3.Lerp(Vector3.zero, _ashlSkinnyMaxPosOffset, blendValue);
case AttachmentType.AttachmentShoulderRight:
return Vector3.Lerp(Vector3.zero, _ashrSkinnyMaxPosOffset, blendValue);
case AttachmentType.AttachmentElbowLeft:
return Vector3.Lerp(Vector3.zero, _aeblSkinnyMaxPosOffset, blendValue);
case AttachmentType.AttachmentElbowRight:
return Vector3.Lerp(Vector3.zero, _aebrSkinnyMaxPosOffset, blendValue);
case AttachmentType.AttachmentKneeLeft:
return Vector3.Lerp(Vector3.zero, _aknlSkinnyMaxPosOffset, blendValue);
case AttachmentType.AttachmentKneeRight:
return Vector3.Lerp(Vector3.zero, _aknrSkinnyMaxPosOffset, blendValue);
default:
return Vector3.zero;
}
}
/// <summary>
/// Gets the blended offset value for the given attachment type and blend value.
/// </summary>
/// <param name="attachmentType">The attachment type to get the blended offset value for.</param>
/// <param name="blendValue">The blend value to use.</param>
/// <returns>The blended offset value.</returns>
private Vector3 GetBlendedBulkOffsetValue(AttachmentType attachmentType, float blendValue)
{
switch (attachmentType)
{
case AttachmentType.AttachmentBack:
return Vector3.Lerp(Vector3.zero, _abacBulkMaxPosOffset, blendValue);
case AttachmentType.AttachmentHipsFront:
return Vector3.Lerp(Vector3.zero, _ahpfBulkMaxPosOffset, blendValue);
case AttachmentType.AttachmentHipsBack:
return Vector3.Lerp(Vector3.zero, _ahpbBulkMaxPosOffset, blendValue);
case AttachmentType.AttachmentHipsLeft:
return Vector3.Lerp(Vector3.zero, _ahplBulkMaxPosOffset, blendValue);
case AttachmentType.AttachmentHipsRight:
return Vector3.Lerp(Vector3.zero, _ahprBulkMaxPosOffset, blendValue);
case AttachmentType.AttachmentShoulderLeft:
return Vector3.Lerp(Vector3.zero, _ashlBulkMaxPosOffset, blendValue);
case AttachmentType.AttachmentShoulderRight:
return Vector3.Lerp(Vector3.zero, _ashrBulkMaxPosOffset, blendValue);
case AttachmentType.AttachmentElbowLeft:
return Vector3.Lerp(Vector3.zero, _aeblBulkMaxPosOffset, blendValue);
case AttachmentType.AttachmentElbowRight:
return Vector3.Lerp(Vector3.zero, _aebrBulkMaxPosOffset, blendValue);
case AttachmentType.AttachmentKneeLeft:
return Vector3.Lerp(Vector3.zero, _aknlBulkMaxPosOffset, blendValue);
case AttachmentType.AttachmentKneeRight:
return Vector3.Lerp(Vector3.zero, _aknrBulkMaxPosOffset, blendValue);
default:
return Vector3.zero;
}
}
/// <summary>
/// Gets the blended offset value for the given attachment type and blend value.
/// </summary>
/// <param name="attachmentType">The attachment type to get the blended offset value for.</param>
/// <param name="blendValue">The blend value to use.</param>
/// <returns>The blended offset value.</returns>
private Quaternion GetBlendedFeminineRotationValue(AttachmentType attachmentType, float blendValue)
{
switch (attachmentType)
{
case AttachmentType.AttachmentBack:
return Quaternion.Lerp(Quaternion.Euler(Vector3.zero), Quaternion.Euler(_abacFeminineMaxPosOffset), blendValue);
case AttachmentType.AttachmentHipsFront:
return Quaternion.Lerp(Quaternion.Euler(Vector3.zero), Quaternion.Euler(_ahpfFeminineMaxPosOffset), blendValue);
case AttachmentType.AttachmentHipsBack:
return Quaternion.Lerp(Quaternion.Euler(Vector3.zero), Quaternion.Euler(_ahpbFeminineMaxPosOffset), blendValue);
case AttachmentType.AttachmentHipsLeft:
return Quaternion.Lerp(Quaternion.Euler(Vector3.zero), Quaternion.Euler(_ahplFeminineMaxPosOffset), blendValue);
case AttachmentType.AttachmentHipsRight:
return Quaternion.Lerp(Quaternion.Euler(Vector3.zero), Quaternion.Euler(_ahprFeminineMaxPosOffset), blendValue);
case AttachmentType.AttachmentShoulderLeft:
return Quaternion.Lerp(Quaternion.Euler(Vector3.zero), Quaternion.Euler(_ashlFeminineMaxPosOffset), blendValue);
case AttachmentType.AttachmentShoulderRight:
return Quaternion.Lerp(Quaternion.Euler(Vector3.zero), Quaternion.Euler(_ashrFeminineMaxPosOffset), blendValue);
case AttachmentType.AttachmentElbowLeft:
return Quaternion.Lerp(Quaternion.Euler(Vector3.zero), Quaternion.Euler(_aeblFeminineMaxPosOffset), blendValue);
case AttachmentType.AttachmentElbowRight:
return Quaternion.Lerp(Quaternion.Euler(Vector3.zero), Quaternion.Euler(_aebrFeminineMaxPosOffset), blendValue);
case AttachmentType.AttachmentKneeLeft:
return Quaternion.Lerp(Quaternion.Euler(Vector3.zero), Quaternion.Euler(_aknlFeminineMaxPosOffset), blendValue);
case AttachmentType.AttachmentKneeRight:
return Quaternion.Lerp(Quaternion.Euler(Vector3.zero), Quaternion.Euler(_aknrFeminineMaxPosOffset), blendValue);
default:
return Quaternion.Euler(Vector3.zero);
}
}
/// <summary>
/// Gets the blended offset value for the given attachment type and blend value.
/// </summary>
/// <param name="attachmentType">The attachment type to get the blended offset value for.</param>
/// <param name="blendValue">The blend value to use.</param>
/// <returns>The blended offset value.</returns>
private Quaternion GetBlendedHeavyRotationValue(AttachmentType attachmentType, float blendValue)
{
switch (attachmentType)
{
case AttachmentType.AttachmentBack:
return Quaternion.Lerp(Quaternion.Euler(Vector3.zero), Quaternion.Euler(_abacHeavyMaxPosOffset), blendValue);
case AttachmentType.AttachmentHipsFront:
return Quaternion.Lerp(Quaternion.Euler(Vector3.zero), Quaternion.Euler(_ahpfHeavyMaxPosOffset), blendValue);
case AttachmentType.AttachmentHipsBack:
return Quaternion.Lerp(Quaternion.Euler(Vector3.zero), Quaternion.Euler(_ahpbHeavyMaxPosOffset), blendValue);
case AttachmentType.AttachmentHipsLeft:
return Quaternion.Lerp(Quaternion.Euler(Vector3.zero), Quaternion.Euler(_ahplHeavyMaxPosOffset), blendValue);
case AttachmentType.AttachmentHipsRight:
return Quaternion.Lerp(Quaternion.Euler(Vector3.zero), Quaternion.Euler(_ahprHeavyMaxPosOffset), blendValue);
case AttachmentType.AttachmentShoulderLeft:
return Quaternion.Lerp(Quaternion.Euler(Vector3.zero), Quaternion.Euler(_ashlHeavyMaxPosOffset), blendValue);
case AttachmentType.AttachmentShoulderRight:
return Quaternion.Lerp(Quaternion.Euler(Vector3.zero), Quaternion.Euler(_ashrHeavyMaxPosOffset), blendValue);
case AttachmentType.AttachmentElbowLeft:
return Quaternion.Lerp(Quaternion.Euler(Vector3.zero), Quaternion.Euler(_aeblHeavyMaxPosOffset), blendValue);
case AttachmentType.AttachmentElbowRight:
return Quaternion.Lerp(Quaternion.Euler(Vector3.zero), Quaternion.Euler(_aebrHeavyMaxPosOffset), blendValue);
case AttachmentType.AttachmentKneeLeft:
return Quaternion.Lerp(Quaternion.Euler(Vector3.zero), Quaternion.Euler(_aknlHeavyMaxPosOffset), blendValue);
case AttachmentType.AttachmentKneeRight:
return Quaternion.Lerp(Quaternion.Euler(Vector3.zero), Quaternion.Euler(_aknrHeavyMaxPosOffset), blendValue);
default:
return Quaternion.Euler(Vector3.zero);
}
}
/// <summary>
/// Gets the blended offset value for the given attachment type and blend value.
/// </summary>
/// <param name="attachmentType">The attachment type to get the blended offset value for.</param>
/// <param name="blendValue">The blend value to use.</param>
/// <returns>The blended offset value.</returns>
private Quaternion GetBlendedSkinnyRotationValue(AttachmentType attachmentType, float blendValue)
{
switch (attachmentType)
{
case AttachmentType.AttachmentBack:
return Quaternion.Lerp(Quaternion.Euler(Vector3.zero), Quaternion.Euler(_abacSkinnyMaxPosOffset), blendValue);
case AttachmentType.AttachmentHipsFront:
return Quaternion.Lerp(Quaternion.Euler(Vector3.zero), Quaternion.Euler(_ahpfSkinnyMaxPosOffset), blendValue);
case AttachmentType.AttachmentHipsBack:
return Quaternion.Lerp(Quaternion.Euler(Vector3.zero), Quaternion.Euler(_ahpbSkinnyMaxPosOffset), blendValue);
case AttachmentType.AttachmentHipsLeft:
return Quaternion.Lerp(Quaternion.Euler(Vector3.zero), Quaternion.Euler(_ahplSkinnyMaxPosOffset), blendValue);
case AttachmentType.AttachmentHipsRight:
return Quaternion.Lerp(Quaternion.Euler(Vector3.zero), Quaternion.Euler(_ahprSkinnyMaxPosOffset), blendValue);
case AttachmentType.AttachmentShoulderLeft:
return Quaternion.Lerp(Quaternion.Euler(Vector3.zero), Quaternion.Euler(_ashlSkinnyMaxPosOffset), blendValue);
case AttachmentType.AttachmentShoulderRight:
return Quaternion.Lerp(Quaternion.Euler(Vector3.zero), Quaternion.Euler(_ashrSkinnyMaxPosOffset), blendValue);
case AttachmentType.AttachmentElbowLeft:
return Quaternion.Lerp(Quaternion.Euler(Vector3.zero), Quaternion.Euler(_aeblSkinnyMaxPosOffset), blendValue);
case AttachmentType.AttachmentElbowRight:
return Quaternion.Lerp(Quaternion.Euler(Vector3.zero), Quaternion.Euler(_aebrSkinnyMaxPosOffset), blendValue);
case AttachmentType.AttachmentKneeLeft:
return Quaternion.Lerp(Quaternion.Euler(Vector3.zero), Quaternion.Euler(_aknlSkinnyMaxPosOffset), blendValue);
case AttachmentType.AttachmentKneeRight:
return Quaternion.Lerp(Quaternion.Euler(Vector3.zero), Quaternion.Euler(_aknrSkinnyMaxPosOffset), blendValue);
default:
return Quaternion.Euler(Vector3.zero);
}
}
/// <summary>
/// Gets the blended offset value for the given attachment type and blend value.
/// </summary>
/// <param name="attachmentType">The attachment type to get the blended offset value for.</param>
/// <param name="blendValue">The blend value to use.</param>
/// <returns>The blended offset value.</returns>
private Quaternion GetBlendedBulkRotationValue(AttachmentType attachmentType, float blendValue)
{
switch (attachmentType)
{
case AttachmentType.AttachmentBack:
return Quaternion.Lerp(Quaternion.Euler(Vector3.zero), Quaternion.Euler(_abacBulkMaxPosOffset), blendValue);
case AttachmentType.AttachmentHipsFront:
return Quaternion.Lerp(Quaternion.Euler(Vector3.zero), Quaternion.Euler(_ahpfBulkMaxPosOffset), blendValue);
case AttachmentType.AttachmentHipsBack:
return Quaternion.Lerp(Quaternion.Euler(Vector3.zero), Quaternion.Euler(_ahpbBulkMaxPosOffset), blendValue);
case AttachmentType.AttachmentHipsLeft:
return Quaternion.Lerp(Quaternion.Euler(Vector3.zero), Quaternion.Euler(_ahplBulkMaxPosOffset), blendValue);
case AttachmentType.AttachmentHipsRight:
return Quaternion.Lerp(Quaternion.Euler(Vector3.zero), Quaternion.Euler(_ahprBulkMaxPosOffset), blendValue);
case AttachmentType.AttachmentShoulderLeft:
return Quaternion.Lerp(Quaternion.Euler(Vector3.zero), Quaternion.Euler(_ashlBulkMaxPosOffset), blendValue);
case AttachmentType.AttachmentShoulderRight:
return Quaternion.Lerp(Quaternion.Euler(Vector3.zero), Quaternion.Euler(_ashrBulkMaxPosOffset), blendValue);
case AttachmentType.AttachmentElbowLeft:
return Quaternion.Lerp(Quaternion.Euler(Vector3.zero), Quaternion.Euler(_aeblBulkMaxPosOffset), blendValue);
case AttachmentType.AttachmentElbowRight:
return Quaternion.Lerp(Quaternion.Euler(Vector3.zero), Quaternion.Euler(_aebrBulkMaxPosOffset), blendValue);
case AttachmentType.AttachmentKneeLeft:
return Quaternion.Lerp(Quaternion.Euler(Vector3.zero), Quaternion.Euler(_aknlBulkMaxPosOffset), blendValue);
case AttachmentType.AttachmentKneeRight:
return Quaternion.Lerp(Quaternion.Euler(Vector3.zero), Quaternion.Euler(_aknrBulkMaxPosOffset), blendValue);
default:
return Quaternion.Euler(Vector3.zero);
}
}
/// <summary>
/// The attachment types to be offset.
/// </summary>
private enum AttachmentType
{
AttachmentBack,
AttachmentHipsFront,
AttachmentHipsBack,
AttachmentHipsLeft,
AttachmentHipsRight,
AttachmentShoulderLeft,
AttachmentShoulderRight,
AttachmentElbowLeft,
AttachmentElbowRight,
AttachmentKneeLeft,
AttachmentKneeRight
}
/// <summary>
/// The blend shape types to adjust.
/// </summary>
private enum BlendShapeType
{
Feminine,
Heavy,
Skinny,
Bulk
}
}
/// <summary>
/// Custom UI inspector for the script.
/// </summary>
[CustomEditor(typeof(CharacterBlendshapeEditor))]
public class MyCustomInspector : Editor
{
public override VisualElement CreateInspectorGUI()
{
VisualElement root = new VisualElement();
Slider bodyTypeSlider = new Slider
{
bindingPath = "_bodyType",
label = "Body Type",
lowValue = -1,
highValue = 1,
showInputField = true
};
VisualElement bodyTypeLabelContainer = new VisualElement
{
style =
{
flexDirection = new StyleEnum<FlexDirection>(FlexDirection.Row),
width = Length.Percent(100),
height = 20
}
};
Label masculineLabel = new Label
{
text = "Masculine",
style =
{
position = new StyleEnum<Position>(Position.Absolute),
left = 155
}
};
Label feminineLabel = new Label
{
text = "Feminine",
style =
{
position = new StyleEnum<Position>(Position.Absolute),
right = 50
}
};
bodyTypeLabelContainer.Add(masculineLabel);
bodyTypeLabelContainer.Add(feminineLabel);
Slider bodySizeSlider = new Slider
{
bindingPath = "_bodySize",
label = "Body Size",
lowValue = -1,
highValue = 1,
showInputField = true
};
VisualElement bodySizeLabelContainer = new VisualElement
{
style =
{
flexDirection = new StyleEnum<FlexDirection>(FlexDirection.Row),
width = Length.Percent(100),
height = 20
}
};
Label skinnyLabel = new Label
{
text = "Skinny",
style =
{
position = new StyleEnum<Position>(Position.Absolute),
left = 155
}
};
Label heavyLabel = new Label
{
text = "Heavy",
style =
{
position = new StyleEnum<Position>(Position.Absolute),
right = 50
}
};
bodySizeLabelContainer.Add(skinnyLabel);
bodySizeLabelContainer.Add(heavyLabel);
Slider musculatureSlider = new Slider
{
bindingPath = "_musculature",
label = "Musculature",
lowValue = -1,
highValue = 1,
showInputField = true
};
VisualElement musculatureLabelContainer = new VisualElement
{
style =
{
flexDirection = new StyleEnum<FlexDirection>(FlexDirection.Row),
width = Length.Percent(100),
height = 20
}
};
Label leanLabel = new Label
{
text = "Lean",
style =
{
position = new StyleEnum<Position>(Position.Absolute),
left = 155
}
};
Label muscularLabel = new Label
{
text = "Muscular",
style =
{
position = new StyleEnum<Position>(Position.Absolute),
right = 50
}
};
musculatureLabelContainer.Add(leanLabel);
musculatureLabelContainer.Add(muscularLabel);
Foldout offsetContainer = new Foldout
{
text = "Attachment Offsets",
value = false,
style =
{
marginTop = 10
}
};
#region abacControls
Foldout abacContainer = new Foldout
{
text = "Attachment Back",
value = false
};
Vector3Field abacFemOffsetPos = new Vector3Field
{
bindingPath = "_abacFeminineMaxPosOffset",
label = "Feminine Max Position"
};
Vector3Field abacFemOffsetRot = new Vector3Field
{
bindingPath = "_abacFeminineMaxRotOffset",
label = "Feminine Max Rotation"
};
Vector3Field abacHeavyOffsetPos = new Vector3Field
{
bindingPath = "_abacHeavyMaxPosOffset",
label = "Heavy Max Position"
};
Vector3Field abacHeavyOffsetRot = new Vector3Field
{
bindingPath = "_abacHeavyMaxRotOffset",
label = "Heavy Max Rotation"
};
Vector3Field abacSkinnyOffsetPos = new Vector3Field
{
bindingPath = "_abacSkinnyMaxPosOffset",
label = "Skinny Max Position"
};
Vector3Field abacSkinnyOffsetRot = new Vector3Field
{
bindingPath = "_abacSkinnyMaxRotOffset",
label = "Skinny Max Rotation"
};
Vector3Field abacBulkOffsetPos = new Vector3Field
{
bindingPath = "_abacBulkMaxPosOffset",
label = "Bulk Max Position"
};
Vector3Field abacBulkOffsetRot = new Vector3Field
{
bindingPath = "_abacBulkMaxRotOffset",
label = "Bulk Max Rotation"
};
abacContainer.Add(abacFemOffsetPos);
abacContainer.Add(abacFemOffsetRot);
abacContainer.Add(abacHeavyOffsetPos);
abacContainer.Add(abacHeavyOffsetRot);
abacContainer.Add(abacSkinnyOffsetPos);
abacContainer.Add(abacSkinnyOffsetRot);
abacContainer.Add(abacBulkOffsetPos);
abacContainer.Add(abacBulkOffsetRot);
offsetContainer.Add(abacContainer);
#endregion
#region ahpfControls
Foldout ahpfContainer = new Foldout
{
text = "Attachment Hips Front",
value = false
};
Vector3Field ahpfFemOffsetPos = new Vector3Field
{
bindingPath = "_ahpfFeminineMaxPosOffset",
label = "Feminine Max Position"
};
Vector3Field ahpfFemOffsetRot = new Vector3Field
{
bindingPath = "_ahpfFeminineMaxRotOffset",
label = "Feminine Max Rotation"
};
Vector3Field ahpfHeavyOffsetPos = new Vector3Field
{
bindingPath = "_ahpfHeavyMaxPosOffset",
label = "Heavy Max Position"
};
Vector3Field ahpfHeavyOffsetRot = new Vector3Field
{
bindingPath = "_ahpfHeavyMaxRotOffset",
label = "Heavy Max Rotation"
};
Vector3Field ahpfSkinnyOffsetPos = new Vector3Field
{
bindingPath = "_ahpfSkinnyMaxPosOffset",
label = "Skinny Max Position"
};
Vector3Field ahpfSkinnyOffsetRot = new Vector3Field
{
bindingPath = "_ahpfSkinnyMaxRotOffset",
label = "Skinny Max Rotation"
};
Vector3Field ahpfBulkOffsetPos = new Vector3Field
{
bindingPath = "_ahpfBulkMaxPosOffset",
label = "Bulk Max Position"
};
Vector3Field ahpfBulkOffsetRot = new Vector3Field
{
bindingPath = "_ahpfBulkMaxRotOffset",
label = "Bulk Max Rotation"
};
ahpfContainer.Add(ahpfFemOffsetPos);
ahpfContainer.Add(ahpfFemOffsetRot);
ahpfContainer.Add(ahpfHeavyOffsetPos);
ahpfContainer.Add(ahpfHeavyOffsetRot);
ahpfContainer.Add(ahpfSkinnyOffsetPos);
ahpfContainer.Add(ahpfSkinnyOffsetRot);
ahpfContainer.Add(ahpfBulkOffsetPos);
ahpfContainer.Add(ahpfBulkOffsetRot);
offsetContainer.Add(ahpfContainer);
#endregion
#region ahpbControls
Foldout ahpbContainer = new Foldout
{
text = "Attachment Hips Back",
value = false
};
Vector3Field ahpbFemOffsetPos = new Vector3Field
{
bindingPath = "_ahpbFeminineMaxPosOffset",
label = "Feminine Max Position"
};
Vector3Field ahpbFemOffsetRot = new Vector3Field
{
bindingPath = "_ahpbFeminineMaxRotOffset",
label = "Feminine Max Rotation"
};
Vector3Field ahpbHeavyOffsetPos = new Vector3Field
{
bindingPath = "_ahpbHeavyMaxPosOffset",
label = "Heavy Max Position"
};
Vector3Field ahpbHeavyOffsetRot = new Vector3Field
{
bindingPath = "_ahpbHeavyMaxRotOffset",
label = "Heavy Max Rotation"
};
Vector3Field ahpbSkinnyOffsetPos = new Vector3Field
{
bindingPath = "_ahpbSkinnyMaxPosOffset",
label = "Skinny Max Position"
};
Vector3Field ahpbSkinnyOffsetRot = new Vector3Field
{
bindingPath = "_ahpbSkinnyMaxRotOffset",
label = "Skinny Max Rotation"
};
Vector3Field ahpbBulkOffsetPos = new Vector3Field
{
bindingPath = "_ahpbBulkMaxPosOffset",
label = "Bulk Max Position"
};
Vector3Field ahpbBulkOffsetRot = new Vector3Field
{
bindingPath = "_ahpbBulkMaxRotOffset",
label = "Bulk Max Rotation"
};
ahpbContainer.Add(ahpbFemOffsetPos);
ahpbContainer.Add(ahpbFemOffsetRot);
ahpbContainer.Add(ahpbHeavyOffsetPos);
ahpbContainer.Add(ahpbHeavyOffsetRot);
ahpbContainer.Add(ahpbSkinnyOffsetPos);
ahpbContainer.Add(ahpbSkinnyOffsetRot);
ahpbContainer.Add(ahpbBulkOffsetPos);
ahpbContainer.Add(ahpbBulkOffsetRot);
offsetContainer.Add(ahpbContainer);
#endregion
#region ahplControls
Foldout ahplContainer = new Foldout
{
text = "Attachment Hips Left",
value = false
};
Vector3Field ahplFemOffsetPos = new Vector3Field
{
bindingPath = "_ahplFeminineMaxPosOffset",
label = "Feminine Max Position"
};
Vector3Field ahplFemOffsetRot = new Vector3Field
{
bindingPath = "_ahplFeminineMaxRotOffset",
label = "Feminine Max Rotation"
};
Vector3Field ahplHeavyOffsetPos = new Vector3Field
{
bindingPath = "_ahplHeavyMaxPosOffset",
label = "Heavy Max Position"
};
Vector3Field ahplHeavyOffsetRot = new Vector3Field
{
bindingPath = "_ahplHeavyMaxRotOffset",
label = "Heavy Max Rotation"
};
Vector3Field ahplSkinnyOffsetPos = new Vector3Field
{
bindingPath = "_ahplSkinnyMaxPosOffset",
label = "Skinny Max Position"
};
Vector3Field ahplSkinnyOffsetRot = new Vector3Field
{
bindingPath = "_ahplSkinnyMaxRotOffset",
label = "Skinny Max Rotation"
};
Vector3Field ahplBulkOffsetPos = new Vector3Field
{
bindingPath = "_ahplBulkMaxPosOffset",
label = "Bulk Max Position"
};
Vector3Field ahplBulkOffsetRot = new Vector3Field
{
bindingPath = "_ahplBulkMaxRotOffset",
label = "Bulk Max Rotation"
};
ahplContainer.Add(ahplFemOffsetPos);
ahplContainer.Add(ahplFemOffsetRot);
ahplContainer.Add(ahplHeavyOffsetPos);
ahplContainer.Add(ahplHeavyOffsetRot);
ahplContainer.Add(ahplSkinnyOffsetPos);
ahplContainer.Add(ahplSkinnyOffsetRot);
ahplContainer.Add(ahplBulkOffsetPos);
ahplContainer.Add(ahplBulkOffsetRot);
offsetContainer.Add(ahplContainer);
#endregion
#region ahprControls
Foldout ahprContainer = new Foldout
{
text = "Attachment Hips Right",
value = false
};
Vector3Field ahprFemOffsetPos = new Vector3Field
{
bindingPath = "_ahprFeminineMaxPosOffset",
label = "Feminine Max Position"
};
Vector3Field ahprFemOffsetRot = new Vector3Field
{
bindingPath = "_ahprFeminineMaxRotOffset",
label = "Feminine Max Rotation"
};
Vector3Field ahprHeavyOffsetPos = new Vector3Field
{
bindingPath = "_ahprHeavyMaxPosOffset",
label = "Heavy Max Position"
};
Vector3Field ahprHeavyOffsetRot = new Vector3Field
{
bindingPath = "_ahprHeavyMaxRotOffset",
label = "Heavy Max Rotation"
};
Vector3Field ahprSkinnyOffsetPos = new Vector3Field
{
bindingPath = "_ahprSkinnyMaxPosOffset",
label = "Skinny Max Position"
};
Vector3Field ahprSkinnyOffsetRot = new Vector3Field
{
bindingPath = "_ahprSkinnyMaxRotOffset",
label = "Skinny Max Rotation"
};
Vector3Field ahprBulkOffsetPos = new Vector3Field
{
bindingPath = "_ahprBulkMaxPosOffset",
label = "Bulk Max Position"
};
Vector3Field ahprBulkOffsetRot = new Vector3Field
{
bindingPath = "_ahprBulkMaxRotOffset",
label = "Bulk Max Rotation"
};
ahprContainer.Add(ahprFemOffsetPos);
ahprContainer.Add(ahprFemOffsetRot);
ahprContainer.Add(ahprHeavyOffsetPos);
ahprContainer.Add(ahprHeavyOffsetRot);
ahprContainer.Add(ahprSkinnyOffsetPos);
ahprContainer.Add(ahprSkinnyOffsetRot);
ahprContainer.Add(ahprBulkOffsetPos);
ahprContainer.Add(ahprBulkOffsetRot);
offsetContainer.Add(ahprContainer);
#endregion
#region ashlControls
Foldout ashlContainer = new Foldout
{
text = "Attachment Shoulder Left",
value = false
};
Vector3Field ashlFemOffsetPos = new Vector3Field
{
bindingPath = "_ashlFeminineMaxPosOffset",
label = "Feminine Max Position"
};
Vector3Field ashlFemOffsetRot = new Vector3Field
{
bindingPath = "_ashlFeminineMaxRotOffset",
label = "Feminine Max Rotation"
};
Vector3Field ashlHeavyOffsetPos = new Vector3Field
{
bindingPath = "_ashlHeavyMaxPosOffset",
label = "Heavy Max Position"
};
Vector3Field ashlHeavyOffsetRot = new Vector3Field
{
bindingPath = "_ashlHeavyMaxRotOffset",
label = "Heavy Max Rotation"
};
Vector3Field ashlSkinnyOffsetPos = new Vector3Field
{
bindingPath = "_ashlSkinnyMaxPosOffset",
label = "Skinny Max Position"
};
Vector3Field ashlSkinnyOffsetRot = new Vector3Field
{
bindingPath = "_ashlSkinnyMaxRotOffset",
label = "Skinny Max Rotation"
};
Vector3Field ashlBulkOffsetPos = new Vector3Field
{
bindingPath = "_ashlBulkMaxPosOffset",
label = "Bulk Max Position"
};
Vector3Field ashlBulkOffsetRot = new Vector3Field
{
bindingPath = "_ashlBulkMaxRotOffset",
label = "Bulk Max Rotation"
};
ashlContainer.Add(ashlFemOffsetPos);
ashlContainer.Add(ashlFemOffsetRot);
ashlContainer.Add(ashlHeavyOffsetPos);
ashlContainer.Add(ashlHeavyOffsetRot);
ashlContainer.Add(ashlSkinnyOffsetPos);
ashlContainer.Add(ashlSkinnyOffsetRot);
ashlContainer.Add(ashlBulkOffsetPos);
ashlContainer.Add(ashlBulkOffsetRot);
offsetContainer.Add(ashlContainer);
#endregion
#region ashrControls
Foldout ashrContainer = new Foldout
{
text = "Attachment Shoulder Right",
value = false
};
Vector3Field ashrFemOffsetPos = new Vector3Field
{
bindingPath = "_ashrFeminineMaxPosOffset",
label = "Feminine Max Position"
};
Vector3Field ashrFemOffsetRot = new Vector3Field
{
bindingPath = "_ashrFeminineMaxRotOffset",
label = "Feminine Max Rotation"
};
Vector3Field ashrHeavyOffsetPos = new Vector3Field
{
bindingPath = "_ashrHeavyMaxPosOffset",
label = "Heavy Max Position"
};
Vector3Field ashrHeavyOffsetRot = new Vector3Field
{
bindingPath = "_ashrHeavyMaxRotOffset",
label = "Heavy Max Rotation"
};
Vector3Field ashrSkinnyOffsetPos = new Vector3Field
{
bindingPath = "_ashrSkinnyMaxPosOffset",
label = "Skinny Max Position"
};
Vector3Field ashrSkinnyOffsetRot = new Vector3Field
{
bindingPath = "_ashrSkinnyMaxRotOffset",
label = "Skinny Max Rotation"
};
Vector3Field ashrBulkOffsetPos = new Vector3Field
{
bindingPath = "_ashrBulkMaxPosOffset",
label = "Bulk Max Position"
};
Vector3Field ashrBulkOffsetRot = new Vector3Field
{
bindingPath = "_ashrBulkMaxRotOffset",
label = "Bulk Max Rotation"
};
ashrContainer.Add(ashrFemOffsetPos);
ashrContainer.Add(ashrFemOffsetRot);
ashrContainer.Add(ashrHeavyOffsetPos);
ashrContainer.Add(ashrHeavyOffsetRot);
ashrContainer.Add(ashrSkinnyOffsetPos);
ashrContainer.Add(ashrSkinnyOffsetRot);
ashrContainer.Add(ashrBulkOffsetPos);
ashrContainer.Add(ashrBulkOffsetRot);
offsetContainer.Add(ashrContainer);
#endregion
#region aeblControls
Foldout aeblContainer = new Foldout
{
text = "Attachment Elbow Left",
value = false
};
Vector3Field aeblFemOffsetPos = new Vector3Field
{
bindingPath = "_aeblFeminineMaxPosOffset",
label = "Feminine Max Position"
};
Vector3Field aeblFemOffsetRot = new Vector3Field
{
bindingPath = "_aeblFeminineMaxRotOffset",
label = "Feminine Max Rotation"
};
Vector3Field aeblHeavyOffsetPos = new Vector3Field
{
bindingPath = "_aeblHeavyMaxPosOffset",
label = "Heavy Max Position"
};
Vector3Field aeblHeavyOffsetRot = new Vector3Field
{
bindingPath = "_aeblHeavyMaxRotOffset",
label = "Heavy Max Rotation"
};
Vector3Field aeblSkinnyOffsetPos = new Vector3Field
{
bindingPath = "_aeblSkinnyMaxPosOffset",
label = "Skinny Max Position"
};
Vector3Field aeblSkinnyOffsetRot = new Vector3Field
{
bindingPath = "_aeblSkinnyMaxRotOffset",
label = "Skinny Max Rotation"
};
Vector3Field aeblBulkOffsetPos = new Vector3Field
{
bindingPath = "_aeblBulkMaxPosOffset",
label = "Bulk Max Position"
};
Vector3Field aeblBulkOffsetRot = new Vector3Field
{
bindingPath = "_aeblBulkMaxRotOffset",
label = "Bulk Max Rotation"
};
aeblContainer.Add(aeblFemOffsetPos);
aeblContainer.Add(aeblFemOffsetRot);
aeblContainer.Add(aeblHeavyOffsetPos);
aeblContainer.Add(aeblHeavyOffsetRot);
aeblContainer.Add(aeblSkinnyOffsetPos);
aeblContainer.Add(aeblSkinnyOffsetRot);
aeblContainer.Add(aeblBulkOffsetPos);
aeblContainer.Add(aeblBulkOffsetRot);
offsetContainer.Add(aeblContainer);
#endregion
#region aebrControls
Foldout aebrContainer = new Foldout
{
text = "Attachment Elbow Right",
value = false
};
Vector3Field aebrFemOffsetPos = new Vector3Field
{
bindingPath = "_aebrFeminineMaxPosOffset",
label = "Feminine Max Position"
};
Vector3Field aebrFemOffsetRot = new Vector3Field
{
bindingPath = "_aebrFeminineMaxRotOffset",
label = "Feminine Max Rotation"
};
Vector3Field aebrHeavyOffsetPos = new Vector3Field
{
bindingPath = "_aebrHeavyMaxPosOffset",
label = "Heavy Max Position"
};
Vector3Field aebrHeavyOffsetRot = new Vector3Field
{
bindingPath = "_aebrHeavyMaxRotOffset",
label = "Heavy Max Rotation"
};
Vector3Field aebrSkinnyOffsetPos = new Vector3Field
{
bindingPath = "_aebrSkinnyMaxPosOffset",
label = "Skinny Max Position"
};
Vector3Field aebrSkinnyOffsetRot = new Vector3Field
{
bindingPath = "_aebrSkinnyMaxRotOffset",
label = "Skinny Max Rotation"
};
Vector3Field aebrBulkOffsetPos = new Vector3Field
{
bindingPath = "_aebrBulkMaxPosOffset",
label = "Bulk Max Position"
};
Vector3Field aebrBulkOffsetRot = new Vector3Field
{
bindingPath = "_aebrBulkMaxRotOffset",
label = "Bulk Max Rotation"
};
aebrContainer.Add(aebrFemOffsetPos);
aebrContainer.Add(aebrFemOffsetRot);
aebrContainer.Add(aebrHeavyOffsetPos);
aebrContainer.Add(aebrHeavyOffsetRot);
aebrContainer.Add(aebrSkinnyOffsetPos);
aebrContainer.Add(aebrSkinnyOffsetRot);
aebrContainer.Add(aebrBulkOffsetPos);
aebrContainer.Add(aebrBulkOffsetRot);
offsetContainer.Add(aebrContainer);
#endregion
#region aknlControls
Foldout aknlContainer = new Foldout
{
text = "Attachment Knee Left",
value = false
};
Vector3Field aknlFemOffsetPos = new Vector3Field
{
bindingPath = "_aknlFeminineMaxPosOffset",
label = "Feminine Max Position"
};
Vector3Field aknlFemOffsetRot = new Vector3Field
{
bindingPath = "_aknlFeminineMaxRotOffset",
label = "Feminine Max Rotation"
};
Vector3Field aknlHeavyOffsetPos = new Vector3Field
{
bindingPath = "_aknlHeavyMaxPosOffset",
label = "Heavy Max Position"
};
Vector3Field aknlHeavyOffsetRot = new Vector3Field
{
bindingPath = "_aknlHeavyMaxRotOffset",
label = "Heavy Max Rotation"
};
Vector3Field aknlSkinnyOffsetPos = new Vector3Field
{
bindingPath = "_aknlSkinnyMaxPosOffset",
label = "Skinny Max Position"
};
Vector3Field aknlSkinnyOffsetRot = new Vector3Field
{
bindingPath = "_aknlSkinnyMaxRotOffset",
label = "Skinny Max Rotation"
};
Vector3Field aknlBulkOffsetPos = new Vector3Field
{
bindingPath = "_aknlBulkMaxPosOffset",
label = "Bulk Max Position"
};
Vector3Field aknlBulkOffsetRot = new Vector3Field
{
bindingPath = "_aknlBulkMaxRotOffset",
label = "Bulk Max Rotation"
};
aknlContainer.Add(aknlFemOffsetPos);
aknlContainer.Add(aknlFemOffsetRot);
aknlContainer.Add(aknlHeavyOffsetPos);
aknlContainer.Add(aknlHeavyOffsetRot);
aknlContainer.Add(aknlSkinnyOffsetPos);
aknlContainer.Add(aknlSkinnyOffsetRot);
aknlContainer.Add(aknlBulkOffsetPos);
aknlContainer.Add(aknlBulkOffsetRot);
offsetContainer.Add(aknlContainer);
#endregion
#region aknrControls
Foldout aknrContainer = new Foldout
{
text = "Attachment Knee Right",
value = false
};
Vector3Field aknrFemOffsetPos = new Vector3Field
{
bindingPath = "_aknrFeminineMaxPosOffset",
label = "Feminine Max Position"
};
Vector3Field aknrFemOffsetRot = new Vector3Field
{
bindingPath = "_aknrFeminineMaxRotOffset",
label = "Feminine Max Rotation"
};
Vector3Field aknrHeavyOffsetPos = new Vector3Field
{
bindingPath = "_aknrHeavyMaxPosOffset",
label = "Heavy Max Position"
};
Vector3Field aknrHeavyOffsetRot = new Vector3Field
{
bindingPath = "_aknrHeavyMaxRotOffset",
label = "Heavy Max Rotation"
};
Vector3Field aknrSkinnyOffsetPos = new Vector3Field
{
bindingPath = "_aknrSkinnyMaxPosOffset",
label = "Skinny Max Position"
};
Vector3Field aknrSkinnyOffsetRot = new Vector3Field
{
bindingPath = "_aknrSkinnyMaxRotOffset",
label = "Skinny Max Rotation"
};
Vector3Field aknrBulkOffsetPos = new Vector3Field
{
bindingPath = "_aknrBulkMaxPosOffset",
label = "Bulk Max Position"
};
Vector3Field aknrBulkOffsetRot = new Vector3Field
{
bindingPath = "_aknrBulkMaxRotOffset",
label = "Bulk Max Rotation"
};
aknrContainer.Add(aknrFemOffsetPos);
aknrContainer.Add(aknrFemOffsetRot);
aknrContainer.Add(aknrHeavyOffsetPos);
aknrContainer.Add(aknrHeavyOffsetRot);
aknrContainer.Add(aknrSkinnyOffsetPos);
aknrContainer.Add(aknrSkinnyOffsetRot);
aknrContainer.Add(aknrBulkOffsetPos);
aknrContainer.Add(aknrBulkOffsetRot);
offsetContainer.Add(aknrContainer);
#endregion
root.Add(bodyTypeSlider);
root.Add(bodyTypeLabelContainer);
root.Add(bodySizeSlider);
root.Add(bodySizeLabelContainer);
root.Add(musculatureSlider);
root.Add(musculatureLabelContainer);
root.Add(offsetContainer);
return root;
}
}
#endif