unity UGUI 正交相机实现图片的透视旋转效果

UI透视效果常见的就是绕x轴或y轴旋转,来达到近大远小的效果。正经要做透视UI的话肯定直接用透视相机,如果透视效果用的极少(就一张图)不改动相机类型才按这种思路进行。

最简单直接的想法就是把矩形的图片顶点扭成梯形,在PS里面扭一下很直观的就是透视效果嘛。但是在unity里面不行,一个矩形实际是两个三角面,改了顶点位置之后明显是能看出来扭曲的,所以要按照径向方向再切分,来削弱扭曲效果。

大概切8刀(分成9份)效果就还不错了,当然如果放一个正方形、圆形这种标准图形还是能明显看出来 需要再提高切分次数。

贴出主要思路 要用的话需要再补全一下

public class UIRawImagePerspective : BaseMeshEffect
{
    [SerializeField]
    private float m_DeltaRate = 0.1f;

    [SerializeField]
    private int m_SplitCount = 8;

    // Properties 略

    private Graphic m_Graphic;
    private Vector3 m_LastRotation;

    protected override void OnEnable()
    {
        base.OnEnable();
        m_LastRotation = transform.rotation.eulerAngles;
        m_Graphic = this.GetComponent<Graphic>();
    }

    private void Update()
    {
        if (!IsActive()) return;
        Vector3 rotation = transform.rotation.eulerAngles;
        if (rotation != m_LastRotation)
        {
            m_LastRotation = rotation;
            m_Graphic.SetVerticesDirty();
        }
    }

    private override void ModifyMesh(VertexHelper vh)
    {
        if (!IsActive()) return;
        if (m_SplitCount <= 0) return;

        Vector3 rotation = m_LastRotation;
        if (rotation.x == 0 && rotation.y == 0) return;
        if (vh.currentVertCount > 4)
        {
            // 不是单个矩形的不处理
            return;
        }

        // 这个函数是自定义的,因为直接用GetUIVertexStream()比较讨厌,写法也很别扭,实际逻辑就是取出数据
        List<UIVertex> vertices = vh.GetUIVerticesEx();
        List<int> indices = new List<int>();
        UIVertex v;

        if (rotation.x != 0)
        {
            float left = vertices[0].position.x;
            float right = vertices[2].position.x;

            Vector4 uvLeftBottom = vertices[0].uv0;
            Vector4 uvRightBottom = vertices[3].uv0;

            float delta = Mathf.Sin((rotation.x / 180) * Mathf.PI) * m_DeltaRate;
            float length = right - left;

            UIVertex tempBottom = vertices[0];
            UIVertex tempTop = vertices[1];
            vertices.Clear();

            int parts = m_SplitCount + 1;
            float topLeft = left + delta * length * 0.5f;
            float bottomLeft = left - delta * length * 0.5f;

            for (int i = 0; i < m_SplitCount + 2; i++)
            {
                float partFactor = (float)i / parts;
                float uvx = uvLeftBottom.x + partFactor * (uvRightBottom.x - uvLeftBottom.x);

                v = tempBottom;
                v.position.x = bottomLeft + partFactor * length * (1 + delta);
                v.uv0.x = uvx;
                vertices.Add(v);

                v = tempTop;
                v.position.x = topLeft + partFactor * length * (1 - delta);
                v.uv0.x = uvx;
                vertices.Add(v);

                if (i > 0)
                {
                    int count = vertices.Count;
                    indices.Add(count - 4);
                    indices.Add(count - 3);
                    indices.Add(count - 1);
                    indices.Add(count - 1);
                    indices.Add(count - 2);
                    indices.Add(count - 4);
                }
            }
        }
        else
        {
            // 绕y轴旋转 换个方向再来一遍 略
        }

        vh.Clear();
        // 这个函数是自定义的,也是因为AddUIVertexStream()用起来比较讨厌
        vh.SetFullData(vertices, indices);
    }
}
posted @   lunoctis  阅读(742)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示