public void Setup()
        {
            #region Mesh Generation
            mesh.Clear();

            #region Vertices
            List <Vector3>    vertices    = new List <Vector3>();
            List <BoneWeight> boneWeights = new List <BoneWeight>();

            // Top Hemisphere.
            vertices.Add(new Vector3(0, 0, 0));
            boneWeights.Add(new BoneWeight()
            {
                boneIndex0 = 0, weight0 = 1
            });
            for (int ringIndex = 1; ringIndex < settings.Segments / 2; ringIndex++)
            {
                float percent      = (float)ringIndex / (settings.Segments / 2);
                float ringRadius   = settings.Radius * Mathf.Sin(90f * percent * Mathf.Deg2Rad);
                float ringDistance = settings.Radius * (-Mathf.Cos(90f * percent * Mathf.Deg2Rad) + 1f);

                for (int i = 0; i < settings.Segments; i++)
                {
                    float angle = i * 360f / settings.Segments;

                    float x = ringRadius * Mathf.Cos(angle * Mathf.Deg2Rad);
                    float y = ringRadius * Mathf.Sin(angle * Mathf.Deg2Rad);
                    float z = ringDistance;

                    vertices.Add(new Vector3(x, y, z));
                    boneWeights.Add(new BoneWeight()
                    {
                        boneIndex0 = 0, weight0 = 1f
                    });
                }
            }

            // Middle Cylinder.
            for (int ringIndex = 0; ringIndex < settings.Rings * data.bones.Count; ringIndex++)
            {
                float boneIndexFloat = (float)ringIndex / settings.Rings;
                int   boneIndex      = Mathf.FloorToInt(boneIndexFloat);

                float bonePercent = boneIndexFloat - boneIndex;

                int boneIndex0 = (boneIndex > 0) ? boneIndex - 1 : 0;
                int boneIndex2 = (boneIndex < data.bones.Count - 1) ? boneIndex + 1 : data.bones.Count - 1;
                int boneIndex1 = boneIndex;

                float weight0 = (boneIndex > 0) ? (1f - bonePercent) * 0.5f : 0f;
                float weight2 = (boneIndex < data.bones.Count - 1) ? bonePercent * 0.5f : 0f;
                float weight1 = 1f - (weight0 + weight2);

                for (int i = 0; i < settings.Segments; i++)
                {
                    float angle = i * 360f / settings.Segments;

                    float x = settings.Radius * Mathf.Cos(angle * Mathf.Deg2Rad);
                    float y = settings.Radius * Mathf.Sin(angle * Mathf.Deg2Rad);
                    float z = ringIndex * settings.Length / settings.Rings;

                    vertices.Add(new Vector3(x, y, settings.Radius + z));
                    boneWeights.Add(new BoneWeight()
                    {
                        boneIndex0 = boneIndex0,
                        boneIndex1 = boneIndex1,
                        boneIndex2 = boneIndex2,
                        weight0    = weight0,
                        weight1    = weight1,
                        weight2    = weight2
                    });
                }
            }

            // Bottom Hemisphere.
            for (int ringIndex = 0; ringIndex < settings.Segments / 2; ringIndex++)
            {
                float percent      = (float)ringIndex / (settings.Segments / 2);
                float ringRadius   = settings.Radius * Mathf.Cos(90f * percent * Mathf.Deg2Rad);
                float ringDistance = settings.Radius * Mathf.Sin(90f * percent * Mathf.Deg2Rad);

                for (int i = 0; i < settings.Segments; i++)
                {
                    float angle = i * 360f / settings.Segments;

                    float x = ringRadius * Mathf.Cos(angle * Mathf.Deg2Rad);
                    float y = ringRadius * Mathf.Sin(angle * Mathf.Deg2Rad);
                    float z = ringDistance;

                    vertices.Add(new Vector3(x, y, settings.Radius + (settings.Length * data.bones.Count) + z));
                    boneWeights.Add(new BoneWeight()
                    {
                        boneIndex0 = data.bones.Count - 1, weight0 = 1
                    });
                }
            }
            vertices.Add(new Vector3(0, 0, 2f * settings.Radius + (settings.Length * data.bones.Count)));
            boneWeights.Add(new BoneWeight()
            {
                boneIndex0 = data.bones.Count - 1, weight0 = 1
            });

            mesh.vertices    = vertices.ToArray();
            mesh.boneWeights = boneWeights.ToArray();
            #endregion

            #region Triangles
            List <int> triangles = new List <int>();

            // Top Cap.
            for (int i = 0; i < settings.Segments; i++)
            {
                int seamOffset = i != settings.Segments - 1 ? 0 : settings.Segments;

                triangles.Add(0);
                triangles.Add(i + 2 - seamOffset);
                triangles.Add(i + 1);
            }

            // Main.
            int rings = (settings.Rings * data.bones.Count) + (2 * (settings.Segments / 2 - 1));
            for (int ringIndex = 0; ringIndex < rings; ringIndex++)
            {
                int ringOffset = 1 + ringIndex * settings.Segments;

                for (int i = 0; i < settings.Segments; i++)
                {
                    int seamOffset = i != settings.Segments - 1 ? 0 : settings.Segments;

                    triangles.Add(ringOffset + i);
                    triangles.Add(ringOffset + i + 1 - seamOffset);
                    triangles.Add(ringOffset + i + 1 - seamOffset + settings.Segments);

                    triangles.Add(ringOffset + i + 1 - seamOffset + settings.Segments);
                    triangles.Add(ringOffset + i + settings.Segments);
                    triangles.Add(ringOffset + i);
                }
            }

            // Bottom Cap.
            int topIndex = 1 + (rings + 1) * settings.Segments;
            for (int i = 0; i < settings.Segments; i++)
            {
                int seamOffset = i != settings.Segments - 1 ? 0 : settings.Segments;

                triangles.Add(topIndex);
                triangles.Add(topIndex - i - 2 + seamOffset);
                triangles.Add(topIndex - i - 1);
            }

            mesh.triangles = triangles.ToArray();
            #endregion

            #region UV
            List <Vector2> uv = new List <Vector2>();

            uv.Add(Vector2.zero);
            for (int ringIndex = 0; ringIndex < rings + 1; ringIndex++)
            {
                float v = ringIndex / (float)rings;
                for (int i = 0; i < settings.Segments; i++)
                {
                    float u = i / (float)(settings.Segments - 1);
                    uv.Add(new Vector2(u, v * (data.bones.Count + 1)));
                }
            }
            uv.Add(Vector2.one);

            mesh.uv8 = uv.ToArray(); // Store copy of UVs in mesh.
            #endregion

            #region Bones
            Transform[] boneTransforms = new Transform[data.bones.Count];
            Matrix4x4[] bindPoses      = new Matrix4x4[data.bones.Count];
            Vector3[]   deltaZeroArray = new Vector3[vertices.Count];
            for (int vertIndex = 0; vertIndex < vertices.Count; vertIndex++)
            {
                deltaZeroArray[vertIndex] = Vector3.zero;
            }

            for (int boneIndex = 0; boneIndex < data.bones.Count; boneIndex++)
            {
                boneTransforms[boneIndex] = root.GetChild(boneIndex);

                #region Bind Pose
                boneTransforms[boneIndex].localPosition = Vector3.forward * (settings.Radius + settings.Length * (0.5f + boneIndex));
                boneTransforms[boneIndex].localRotation = Quaternion.identity;
                bindPoses[boneIndex] = boneTransforms[boneIndex].worldToLocalMatrix * transform.localToWorldMatrix;
                #endregion

                #region Hinge Joint
                if (boneIndex > 0)
                {
                    HingeJoint hingeJoint = boneTransforms[boneIndex].GetComponent <HingeJoint>();
                    hingeJoint.anchor        = new Vector3(0, 0, -settings.Length / 2f);
                    hingeJoint.connectedBody = boneTransforms[boneIndex - 1].GetComponent <Rigidbody>();
                }
                #endregion

                #region Blend Shapes
                Vector3[] deltaVertices = new Vector3[vertices.Count];
                for (int vertIndex = 0; vertIndex < vertices.Count; vertIndex++)
                {
                    // Round
                    //float distanceToBone = Mathf.Clamp(Vector3.Distance(vertices[vertIndex], boneTransforms[boneIndex].localPosition), 0, 2f * settings.Length);
                    //Vector3 directionToBone = (vertices[vertIndex] - boneTransforms[boneIndex].localPosition).normalized;

                    //deltaVertices[vertIndex] = directionToBone * (2f * settings.Length - distanceToBone);


                    // Smooth - https://www.desmos.com/calculator/wmpvvtmor8
                    float maxDistanceAlongBone = settings.Length * 2f;
                    float maxHeightAboveBone   = settings.Radius * 2f;

                    float displacementAlongBone = vertices[vertIndex].z - boneTransforms[boneIndex].localPosition.z;

                    float x = Mathf.Clamp(displacementAlongBone / maxDistanceAlongBone, -1, 1);
                    float a = maxHeightAboveBone;
                    float b = 1f / a;

                    float heightAboveBone = (Mathf.Cos(x * Mathf.PI) / b + a) / 2f;

                    deltaVertices[vertIndex] = new Vector2(vertices[vertIndex].x, vertices[vertIndex].y).normalized *heightAboveBone;
                }
                mesh.AddBlendShapeFrame("Bone." + boneIndex, 0, deltaZeroArray, deltaZeroArray, deltaZeroArray);
                mesh.AddBlendShapeFrame("Bone." + boneIndex, 100, deltaVertices, deltaZeroArray, deltaZeroArray);

                Scroll scroll = boneTransforms[boneIndex].GetComponent <Scroll>();
                int    index  = boneIndex;
                scroll.OnScrollUp.RemoveAllListeners();
                scroll.OnScrollDown.RemoveAllListeners();
                scroll.OnScrollUp.AddListener(delegate
                {
                    audioSource.PlayOneShot(sizeAudioClip);

                    AddWeight(index, 5f);
                });
                scroll.OnScrollDown.AddListener(delegate
                {
                    audioSource.PlayOneShot(sizeAudioClip);

                    RemoveWeight(index, 5f);
                });
                #endregion
            }

            mesh.bindposes            = bindPoses;
            skinnedMeshRenderer.bones = boneTransforms;
            #endregion

            mesh.RecalculateNormals();
            #endregion

            #region Mesh Deformation
            for (int boneIndex = 0; boneIndex < data.bones.Count; boneIndex++)
            {
                boneTransforms[boneIndex].position = data.bones[boneIndex].Position;
                boneTransforms[boneIndex].rotation = data.bones[boneIndex].Rotation;
                SetWeight(boneIndex, data.bones[boneIndex].Size);
            }

            UpdateMeshCollider();
            #endregion
        }
        protected override void Start()
        {
            base.Start();

            hover.OnEnter.AddListener(delegate
            {
                if (!Input.GetMouseButton(0))
                {
                    SetToolsVisibility(true);
                }
            });
            hover.OnExit.AddListener(delegate
            {
                if (!Input.GetMouseButton(0))
                {
                    SetToolsVisibility(false);
                }
            });

            Drag.OnRelease.AddListener(delegate
            {
                UpdateMeshCollider();
                FlippedLimb.UpdateMeshCollider();

                if (!hover.IsOver)
                {
                    SetToolsVisibility(false);
                }
            });
            Drag.OnDrag.AddListener(delegate
            {
                FlippedLimb.bones[bones.Length - 1].position = new Vector3(-bones[bones.Length - 1].position.x, bones[bones.Length - 1].position.y, bones[bones.Length - 1].position.z);
            });

            scroll.OnScrollUp.RemoveAllListeners();
            scroll.OnScrollDown.RemoveAllListeners();

            for (int i = 2; i < bones.Length; i++)
            {
                int index = i;

                Transform bone        = bones[index];
                Transform flippedBone = FlippedLimb.bones[index];

                #region Interact
                Hover boneHover = bone.GetComponentInChildren <Hover>();
                boneHover.OnEnter.AddListener(delegate
                {
                    if (!Input.GetMouseButton(0))
                    {
                        CreatureCreator.Instance.CameraOrbit.Freeze();
                        SetToolsVisibility(true);
                    }
                });
                boneHover.OnExit.AddListener(delegate
                {
                    if (!Input.GetMouseButton(0))
                    {
                        CreatureCreator.Instance.CameraOrbit.Unfreeze();
                        SetToolsVisibility(false);
                    }
                });

                Drag boneDrag = bone.GetComponentInChildren <Drag>();
                boneDrag.OnPress.AddListener(delegate
                {
                    CreatureCreator.Instance.CameraOrbit.Freeze();

                    SetToolsVisibility(true);
                });
                boneDrag.OnDrag.AddListener(delegate
                {
                    flippedBone.position = new Vector3(-bone.position.x, bone.position.y, bone.position.z);
                });
                boneDrag.OnRelease.AddListener(delegate
                {
                    CreatureCreator.Instance.CameraOrbit.Unfreeze();

                    if (!boneHover.IsOver && !hover.IsOver)
                    {
                        SetToolsVisibility(false);
                    }

                    UpdateMeshCollider();
                    FlippedLimb.UpdateMeshCollider();
                });

                Scroll boneScroll = bone.GetComponentInChildren <Scroll>();
                if (boneScroll)
                {
                    boneScroll.OnScrollUp.AddListener(delegate
                    {
                        bone.localScale       += Vector3.one * Time.deltaTime * scrollWeigth;
                        bone.localScale        = bone.localScale.Clamp(minSize, maxSize);
                        flippedBone.localScale = bone.localScale;
                    });
                    boneScroll.OnScrollDown.AddListener(delegate
                    {
                        bone.localScale       -= Vector3.one * Time.deltaTime * scrollWeigth;
                        bone.localScale        = bone.localScale.Clamp(minSize, maxSize);
                        flippedBone.localScale = bone.localScale;
                    });
                }

                #endregion
            }

            UpdateMeshCollider();
            SetToolsVisibility(false);
        }