unity 让文字呈现弧度变化

news2025/1/8 5:45:20

 效果:

using UnityEngine;
using TMPro;
using Core;

[ExecuteInEditMode]
public class TMTextWrap : MonoBehaviour
{
    private TMP_Text m_TextComponent;

    public AnimationCurve VertexCurve = new AnimationCurve(new Keyframe(0, 0), new Keyframe(0.5f, 1), new Keyframe(1, 0f));
    public float AngleMultiplier = 1.0f;
    public float SpeedMultiplier = 1.0f;
    public float CurveScale = 1.0f;

    public bool ForceChange = true;
    public bool AlwaysChange = false;
    float m_OldCurveScale;
    AnimationCurve m_OldCurve;

    void Awake()
    {
        m_TextComponent = gameObject.GetComponent<TMP_Text>();
        if (AlwaysChange)
        {
            Log.Error($"{gameObject.name} text wrap set to always change on awake");
        }
    }


    void LateUpdate()
    {
        if (NeedChange() || AlwaysChange)
        {
            WarpText();
        }
    }

    void OnEnable()
    {
        ForceChange = true;
    }

    bool NeedChange()
    {
        if (ForceChange)
        {
            ForceChange = false;
            return true;
        }

        if (m_TextComponent.havePropertiesChanged)
            return true;

        if (Mathf.Abs(m_OldCurveScale - CurveScale) > 0.01f)
            return true;


        if (!m_OldCurve.Equals(VertexCurve))
            return true;

        return false;
    }


    private AnimationCurve CopyAnimationCurve(AnimationCurve curve)
    {
        AnimationCurve newCurve = new AnimationCurve(curve.keys);
        return newCurve;
    }


    /// <summary>
    ///  Method to curve text along a Unity animation curve.
    /// </summary>
    /// <param name="textComponent"></param>
    /// <returns></returns>
    void WarpText()
    {
        VertexCurve.preWrapMode = WrapMode.Clamp;
        VertexCurve.postWrapMode = WrapMode.Clamp;

        m_OldCurve = CopyAnimationCurve(VertexCurve);
        m_OldCurveScale = CurveScale;

        //Mesh mesh = m_TextComponent.textInfo.meshInfo[0].mesh;

        Vector3[] vertices;
        Matrix4x4 matrix;

        m_TextComponent.ForceMeshUpdate(); // Generate the mesh and populate the textInfo with data we can use and manipulate.

        TMP_TextInfo textInfo = m_TextComponent.textInfo;
        int characterCount = textInfo.characterCount;


        if (characterCount == 0) return;

        //vertices = textInfo.meshInfo[0].vertices;
        //int lastVertexIndex = textInfo.characterInfo[characterCount - 1].vertexIndex;

        float boundsMinX = m_TextComponent.bounds.min.x;  //textInfo.meshInfo[0].mesh.bounds.min.x;
        float boundsMaxX = m_TextComponent.bounds.max.x;  //textInfo.meshInfo[0].mesh.bounds.max.x;



        for (int i = 0; i < characterCount; i++)
        {
            if (!textInfo.characterInfo[i].isVisible)
                continue;

            int vertexIndex = textInfo.characterInfo[i].vertexIndex;

            // Get the index of the mesh used by this character.
            int materialIndex = textInfo.characterInfo[i].materialReferenceIndex;

            vertices = textInfo.meshInfo[materialIndex].vertices;

            // Compute the baseline mid point for each character
            Vector3 offsetToMidBaseline = new Vector2((vertices[vertexIndex + 0].x + vertices[vertexIndex + 2].x) / 2, textInfo.characterInfo[i].baseLine);
            //float offsetY = VertexCurve.Evaluate((float)i / characterCount + loopCount / 50f); // Random.Range(-0.25f, 0.25f);

            // Apply offset to adjust our pivot point.
            vertices[vertexIndex + 0] += -offsetToMidBaseline;
            vertices[vertexIndex + 1] += -offsetToMidBaseline;
            vertices[vertexIndex + 2] += -offsetToMidBaseline;
            vertices[vertexIndex + 3] += -offsetToMidBaseline;

            // Compute the angle of rotation for each character based on the animation curve
            float x0 = (offsetToMidBaseline.x - boundsMinX) / (boundsMaxX - boundsMinX); // Character's position relative to the bounds of the mesh.
            float x1 = x0 + 0.0001f;
            float y0 = VertexCurve.Evaluate(x0) * CurveScale;
            float y1 = VertexCurve.Evaluate(x1) * CurveScale;

            Vector3 horizontal = new Vector3(1, 0, 0);
            //Vector3 normal = new Vector3(-(y1 - y0), (x1 * (boundsMaxX - boundsMinX) + boundsMinX) - offsetToMidBaseline.x, 0);
            Vector3 tangent = new Vector3(x1 * (boundsMaxX - boundsMinX) + boundsMinX, y1) - new Vector3(offsetToMidBaseline.x, 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;

            matrix = Matrix4x4.TRS(new Vector3(0, y0, 0), Quaternion.Euler(0, 0, angle), Vector3.one);

            vertices[vertexIndex + 0] = matrix.MultiplyPoint3x4(vertices[vertexIndex + 0]);
            vertices[vertexIndex + 1] = matrix.MultiplyPoint3x4(vertices[vertexIndex + 1]);
            vertices[vertexIndex + 2] = matrix.MultiplyPoint3x4(vertices[vertexIndex + 2]);
            vertices[vertexIndex + 3] = matrix.MultiplyPoint3x4(vertices[vertexIndex + 3]);

            vertices[vertexIndex + 0] += offsetToMidBaseline;
            vertices[vertexIndex + 1] += offsetToMidBaseline;
            vertices[vertexIndex + 2] += offsetToMidBaseline;
            vertices[vertexIndex + 3] += offsetToMidBaseline;
        }

        // Upload the mesh with the revised information
        m_TextComponent.UpdateVertexData();
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2257301.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

java抽奖系统(一)2.0

1. 项⽬介绍 1.1 背景 随着数字营销的兴起&#xff0c;企业越来越重视通过在线活动来吸引和留住客⼾。抽奖活动作为⼀种有效的营 销⼿段&#xff0c;能够显著提升⽤⼾参与度和品牌曝光率。于是我们就开发了以抽奖活动作为背景的Spring Boot项⽬&#xff0c;通过这个项⽬提供⼀…

【5G】Spectrum 频谱

频谱是移动运营商的关键资产&#xff0c;可用的频谱是定义移动网络容量和覆盖范围的重要因素。本章讨论了5G的不同频谱选项、它们的特性以及5G早期部署阶段的预期频谱。5G是首个旨在利用大约400 MHz到90 GHz之间所有频段的移动无线系统。5G还设计用于在许可、共享和非许可频谱带…

复现论文:PromptTA: Prompt-driven Text Adapter for Source-freeDomain Generalization

github&#xff1a;zhanghr2001/PromptTA: Source-free Domain Generalization 论文&#xff1a;[2409.14163] PromptTA: Prompt-driven Text Adapter for Source-free Domain Generalization 自己标注&#xff1a;PromptTA: Prompt-driven Text Adapter for Source-free Domai…

电子应用设计方案-43:智能手机充电器系统方案设计

智能手机充电器系统方案设计 一、引言 随着智能手机的广泛应用&#xff0c;对充电器的性能、效率和安全性提出了更高的要求。本方案旨在设计一款高效、安全、兼容多种快充协议的智能手机充电器。 二、系统概述 1. 系统目标 - 提供快速、稳定、安全的充电功能。 - 兼容主流的智…

基于springboot+vue实现的项目评审系统 (源码+L文+ppt)4-116

摘 要 相比于以前的传统手工管理方式&#xff0c;智能化的管理方式可以大幅降低运营人员成本&#xff0c;实现了项目评审系统的标准化、制度化、程序化的管理&#xff0c;有效地防止了项目评审的随意管理&#xff0c;提高了信息的处理速度和精确度&#xff0c;能够及时、准确…

深入了解架构中常见的4种缓存模式及其实现

4种缓存模式 随着应用程序的复杂性日益增加&#xff0c;缓存管理变得至关重要。缓存不仅能有效减轻数据库负载&#xff0c;还能显著提升数据访问速度。选择合适的缓存模式能够在不同的业务场景下发挥出最佳效果。 本文将详细介绍四种常见的缓存模式&#xff1a;Cache-Aside (…

【论文阅读】处理器芯片敏捷设计方法:问题与挑战

作者&#xff1a;包云岗老师 包云岗老师是计算机体系结构方向的大牛&#xff0c;推动了体系结构方面的开源事业! 欢迎对本栏目感兴趣的人学习"一生一芯"~ 学习体会&#xff1a; 已有的软硬件生态系统和开发成本制约了对新结构的探索。但目前仍在几种路线上做尝试~ 1…

Android记单词app(包含数据库)

一、功能与要求 实现功能:设计与开发记单词系统的,系统功能包括用户登录、用户注册、单词操作(单词的添加、查询、修改及删除)以及忘记密码等。 指标要求:通过用户登录、用户注册、单词操作、忘记密等功能的设计与开发,掌握Android常用布局、控件的使用、监听器的设置以及…

数据结构与算法学习笔记----树与图的深度优先遍历

数据结构与算法学习笔记----树与图的深度优先遍历 author: 明月清了个风 first publish time: 2024.12.9 pa⭐️这里只有一道题哈哈。 Acwing 846.树的重心 给定一棵树&#xff0c;树中包含 n n n个节点&#xff08;编号 1 ∼ n 1 \sim n 1∼n&#xff09;和 n − 1 n - 1 n…

TSWIKI知识库软件

TSWIKI 知识库软件介绍 推荐一个适合本地化部署、自托管的知识库软件 TSWIKI介绍 tswiki 是一个适合小团队、个人的知识库、资料管理的软件&#xff0c;所有数据均本地化存储。可以本地化、私有云部署&#xff0c;安装简单。在线预览。 主要功能说明 1、简化的软件依赖和安…

mid360使用cartorapher进行3d建图导航

1. 添加urdf配置文件&#xff1a; 添加IMU配置关节点和laser关节点 <!-- imu livox --> <joint name"livox_frame_joint" type"fixed"> <parent link"base_link" /> <child link"livox_frame" /> <o…

第四十六篇 Vision Transformer论文翻译

论文连接:https://arxiv.org/abs/2010.11929 GitHub:https://github.com/google-research/vision_transformer 摘要 虽然Transformer架构已成为自然语言处理任务的实际标准,但其在计算机视觉中的应用仍然有限。在计算机视觉中,注意力机制要么与卷积网络结合使用,要么在保…

【VUE2】纯前端播放海康视频录像回放,视频格式为rtsp格式,插件使用海康视频插件

一、需求 1、后端从海康平台拉流视频回放数据&#xff0c;前端进行页面渲染播放&#xff0c;视频格式为rtsp eg&#xff1a; 基本格式&#xff1a;rtsp://<username>:<password><ip_addr>:<port>/<path>参数说明&#xff1a; username&#xff…

STL库中list的使用与迭代器的实现

STL库中list的使用与迭代器的实现 1.使用list中的部分函数assignspliceremoveuniquemeger 2.list的部分功能实现&#xff08;重点&#xff09;框架迭代器的实现 1.使用list中的部分函数 assign 功能一&#xff1a;当前链表的节点全部销毁&#xff0c;替换成迭代区间的值 功能二…

2024年华中杯数学建模C题基于光纤传感器的平面曲线重建算法建模解题全过程文档及程序

2024年华中杯数学建模 C题 基于光纤传感器的平面曲线重建算法建模 原题再现 光纤传感技术是伴随着光纤及光通信技术发展起来的一种新型传感器技术。它是以光波为传感信号、光纤为传输载体来感知外界环境中的信号&#xff0c;其基本原理是当外界环境参数发生变化时&#xff0c…

ETCD的封装和测试

etcd是存储键值数据的服务器 客户端通过长连接watch实时更新数据 场景&#xff1a; 当主机A给服务器存储 name&#xff1a; 小王 主机B从服务器中查name ,得到name-小王 当主机A更改name 小李 服务器实时通知主机B name 已经被更改成小李了。 应用&#xff1a;服务注册与发…

Cesium 问题: 添加billboard后移动或缩放地球,标记点位置会左右偏移

文章目录 问题分析原先的:添加属性——解决漂移移动问题产生新的问题:所选的经纬度坐标和应放置的位置有偏差解决坐标位置偏差的问题完整代码问题 添加 billboard 后, 分析 原先的: // 图标加载 function addStation ({lon, lat, el, testName

进入 Dystopia:第九周游戏指南

本指南将为大家详细说明在第八周的每个体验中可以获得的奖励。 在杂草丛生的反乌托邦废墟中生存&#xff0c;随着大自然重新开垦这片土地&#xff0c;文明已陷入绝望。穿越高耸入云、摇摇欲坠的摩天大楼&#xff0c;抵御末世社会的各种危险。适应这个文明与荒野之间的界限已经消…

leetcode 面试经典 150 题:验证回文串

链接验证回文串题序号125类型字符串解题方法双指针法难度简单 题目 如果在将所有大写字符转换为小写字符、并移除所有非字母数字字符之后&#xff0c;短语正着读和反着读都一样。则可以认为该短语是一个 回文串 。 字母和数字都属于字母数字字符。 给你一个字符串 s&#xf…

Android 屏幕采集并编码为H.264

前言 我们前面基于摄像机的图像采集以及编解码已经完成了&#xff0c;那么接下来计划后面的三篇博文分别实现Android屏幕采集实现并进行H.264编解码、MIC音频采集并编码为AAC以及AAC解码播放&#xff0c;希冀可以通过这六篇博文能够对Android上面的音视频编解码有一个初步的学…