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); }