【第008问 Unity中什么是UV?】

本文详细解析了Unity中UV纹理坐标的概念,包括其作为纹理和物体坐标映射关系的重要性。通过实例分析,阐述了如何设置和调整UV坐标以实现不同渲染效果,并提供了源代码展示动态改变UV坐标的部分。内容涵盖了UV坐标的取值范围、映射规则以及在游戏开发中的实际应用。
摘要由CSDN通过智能技术生成

视频讲解

Unity中对UV的理解

一、什么是UV

UV是什么?UV其实就纹理坐标轴的另外一种定义;
比如平时我们说的Transform的坐标,就是说该Transform在笛卡尔坐标系中的具体位置,描述该位置的形象表示用(x,y,z);所以平时我们说到物体的坐标的时候,潜意识就会想到(x,y,z);

为什么纹理也会有坐标呢?
比如下面这张图片:
在这里插入图片描述
从这张图片我们可以通过查看它的信息,知道这张图片的大小是多少,尺寸是多少,什么时候创建的,但是我们并不会去关心这张图片的坐标,因为这个时候我们并不会用上它的坐标,但是它却是存在的。

当我们把上面这张纹理放置在一个Quad上面的时候的时候,就需要用到纹理的坐标:看下面效果:
在这里插入图片描述
上面的是图片上Unity运行的效果,其中有5个大小相等Quad,但是它们使用同一张纹理得到的结果是不一样的;这就是因为每个Quad所获取的纹理的UV坐标范围不一样,导致Quad渲染的结果不一样;

二、实例分析

UV坐标存在的意义就是在于和物体坐标之间的一个映射关系;
比如上图中的纹理大小是512x512,我们不能用512*512这个大小去进行映射,如果我们是映射到同样大小的物体上,它们是1对1的关系,也就是每个物体的坐标点和纹理的UV坐标点是对应上的;否则映射过程上非常麻烦的;

那么什么是物体坐标呢?
看看下面的一个Quad的图片:
在这里插入图片描述
上图中物体Pivot和Center都在中心,在线框模式可以看到该物体有4个顶点,2个三角形;要想把一个纹理的全部或者部分完全在这个quad上面正确显示出来,就需要用到uv坐标,需要以下几个步骤

  • 找到该Quad的三角形的渲染方式,是逆时针还是顺时针;会得到正面或者反面的图片
  • 找到该Quad的4个UV坐标的先后顺序,也就是确认uv[0]、uv[1]、uv[2]、uv[3]和顶点坐标vertext[0]、vertext[1]、vertext[2]、vertext[3]的对应关系,正确的对应关系才能得到正确的结果;这里你可以用UV坐标的任意合理范围的4个uv坐标点来对应顶点坐标,这样就可以得到纹理中部分或者全部渲染到quad上;
  • uv坐标的取值范围都会转换到0-1之间;比如512大小图片范围就会转为:uv(0/512,0/512)-(512/512,512/512)的取值范围,根据图片大小进行转换;
  • 最后重新设置对象的UV坐标即可;

UV是纹理坐标的别称,UV坐标就是xy坐标,只是为了便于在描述过程中的区别才有这个说法;所以处理uv坐标就是处理笛卡尔坐标系;可以把一个纹理看作一个笛卡尔坐标系中的第一象限,左下角就是(0,0)坐标,该坐标的第一象限的最大取值范围就是0-1之间;

纹理和对象之间的映射就是纹理坐标和物体坐标之间的映射关系,纹理坐标的正确映射可以得到物体正确的外观效果。

三、源码

using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

public class ValakiShowUvPartDemos : MonoBehaviour
{
    enum ShowUVPartType
    {
        None=0,
        LeftTop,
        LeftBottom,
        Center,
        RightTop,
        RightBottom
    };

    List<Vector2> uvs;
    Vector2[] backUv;
    Mesh mesh; 
    [SerializeField] ShowUVPartType showUVPartType;

    [SerializeField] bool isPlayRandomUvPart;

    ShowUVPartType currentUvPartType = ShowUVPartType.None;
    private void Awake()
    {
        mesh = GetComponent<MeshFilter>().mesh;
        uvs = mesh.uv.ToList();
        backUv = mesh.uv;
    }

    float totalTime;
    private void LateUpdate()
    {
        if (isPlayRandomUvPart)
        {

            totalTime += Time.deltaTime;
            if(totalTime >= 0.7f)
            {
                totalTime = 0;
                int random = Random.Range(1, 6);
                showUVPartType = (ShowUVPartType)random;
            }
          
        }

        if (currentUvPartType != showUVPartType)
        {
            currentUvPartType = showUVPartType;
            switch (showUVPartType)
            {
                case ShowUVPartType.Center:
                    mesh.SetUVs(0, backUv);
                    break;
                case ShowUVPartType.LeftBottom:
                    ShowLeftBottomUvPart();
                    break;
                case ShowUVPartType.LeftTop:
                    ShowLeftTopUvPart();
                    break;
                case ShowUVPartType.RightBottom:
                    ShowRightBottomUvPart();
                    break;
                case ShowUVPartType.RightTop:
                    ShowRightTopUvPart();
                    break;
            }
        }
    }

   


    void ShowLeftTopUvPart()
    {
        //左-右下-左上-右上
        uvs[0] = new Vector2(0, 0.75f);
        uvs[1] = new Vector2(0.25f, 0.75f); 
        uvs[2] = new Vector2(0, 1);
        uvs[3] = new Vector2(0.25f, 1); 
       
        mesh.SetUVs(0, uvs);
    }


    void ShowRightTopUvPart()
    {
        
        uvs[0] = new Vector2(0.75f, 0.75f);
        uvs[1] = new Vector2(1, 0.75f);
        uvs[2] = new Vector2(0.75f, 1);
        uvs[3] = new Vector2(1, 1);

        mesh.SetUVs(0, uvs);
    }


    void ShowLeftBottomUvPart()
    {
        
        uvs[0] = new Vector2(0, 0);
        uvs[1] = new Vector2(0.25f, 0);
        uvs[2] = new Vector2(0, 0.25f);
        uvs[3] = new Vector2(0.25f, 0.25f);

        mesh.SetUVs(0, uvs);
    }


    void ShowRightBottomUvPart()
    {

        uvs[0] = new Vector2(0.75f, 0);
        uvs[1] = new Vector2(1, 0);
        uvs[2] = new Vector2(0.75f, 0.25f);
        uvs[3] = new Vector2(1, 0.25f);

        mesh.SetUVs(0, uvs);
    }


}

结语:

别问我段位多少,我只是混子而已valaki

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值