using UnityEngine; using TMPro; //根据Unity动画曲线来变形 public class TMP_AnimationCurve : TMP_Curve { public AnimationCurve animationCurveY = new AnimationCurve(new Keyframe(0, -1f), new Keyframe(0.5f, 0f), new Keyframe(1, -1f)); public AnimationCurve animationCurveZ = new AnimationCurve(new Keyframe(0, 0), new Keyframe(0.25f, .5f), new Keyframe(0.5f, 1.0f), new Keyframe(0.75f, .5f), new Keyframe(1, 0f)); public float curveScaleY = 1.0f; public float useForWidth = 10; private float cacheScaleY = 1.0f; private float cacheUseForWidth = 10f; public float curveScaleZ = 1.0f; public bool enableZ; protected override bool ParametersHaveChanged() { if (cacheScaleY != curveScaleY || cacheUseForWidth != useForWidth) { cacheScaleY = curveScaleY; cacheUseForWidth = useForWidth; return true; } return false; } protected override Matrix4x4 ComputeTransformationMatrix(Vector3 charMidBaselinePos, float zeroToOnePos, TMP_TextInfo textInfo, int charIdx, float totalLength) { animationCurveY.preWrapMode = WrapMode.Clamp; animationCurveY.postWrapMode = WrapMode.Clamp; animationCurveZ.preWrapMode = WrapMode.Clamp; animationCurveZ.postWrapMode = WrapMode.Clamp; float ty, ry, tz, rz; GetUpTR(charMidBaselinePos, zeroToOnePos, totalLength,out ty, out ry); GetForwardTR(charMidBaselinePos, zeroToOnePos, totalLength,out tz, out rz); return Matrix4x4.TRS(new Vector3(0, ty, -tz), Quaternion.Euler(0, rz, ry), Vector3.one); } private void GetUpTR(Vector3 charMidBaselinePos, float zeroToOnePos, float total, out float t, out float r) { //float boundsMinX = m_TextComponent.bounds.min.x; //float boundsMaxX = m_TextComponent.bounds.max.x; // Compute the angle of rotation for each character based on the animation curve float x0 = 0f; if (zeroToOnePos >= 0.5f) { x0 = (0.5f * useForWidth + (zeroToOnePos - 0.5f) * total) / useForWidth; } else if (zeroToOnePos < 0.5f) { x0 = ((useForWidth - total) *0.5f + zeroToOnePos * total) / useForWidth; } float x1 = x0 + 0.0001f; float y0 = animationCurveY.Evaluate(x0) * curveScaleY; float y1 = animationCurveY.Evaluate(x1) * curveScaleY; Vector3 horizontal = new Vector3(1, 0, 0); //Vector3 tangent = new Vector3(x1 * total, y1) - new Vector3(charMidBaselinePos.x, y0); Vector3 tangent = new Vector3(x1 * curveScaleY, y1) - new Vector3(x0 * curveScaleY, y0); float dot = Mathf.Acos(Vector3.Dot(horizontal, tangent.normalized)) * 57.2957795f; Vector3 cross = Vector3.Cross(horizontal, tangent); float angle = cross.z > 0 ? dot : 360 - dot; t = y0; r = angle; } private void GetForwardTR(Vector3 charMidBaselinePos, float zeroToOnePos, float total, out float t, out float r) { if (!enableZ) { t = r = 0; return; } float boundsMinX = m_TextComponent.bounds.min.x; float boundsMaxX = m_TextComponent.bounds.max.x; // Compute the angle of rotation for each character based on the animation curve float x0 = 0f; if (zeroToOnePos >= 0.5f) { x0 = (0.5f * useForWidth + (zeroToOnePos - 0.5f) * total) / useForWidth; } else if (zeroToOnePos < 0.5f) { x0 = ((useForWidth - total) *0.5f + zeroToOnePos * total) / useForWidth; } // Character's position relative to the bounds of the mesh. float x1 = x0 + 0.0001f; float z0 = animationCurveZ.Evaluate(x0) * curveScaleZ; float z1 = animationCurveZ.Evaluate(x1) * curveScaleZ; Vector3 horizontal = new Vector3(1, 0, 0); //Vector3 normal = new Vector3(-(y1 - y0), (x1 * (boundsMaxX - boundsMinX) + boundsMinX) - charMidBaselinePos.x, 0); Vector3 tangent = new Vector3(x1 * (boundsMaxX - boundsMinX) + boundsMinX, z1) - new Vector3(charMidBaselinePos.x, z0); float dot = Mathf.Acos(Vector3.Dot(horizontal, tangent.normalized)) * 57.2957795f; Vector3 cross = Vector3.Cross(horizontal, tangent); float angle = cross.z > 0 ? dot : 360 - dot; t = z0; r = angle; } }