Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
7
Help us understand the problem. What is going on with this article?
@Chocogake_sanQ

UnityでスクリプトからUVを操作する

More than 3 years have passed since last update.

初めに

 例えば、キャラクタの表情をテクスチャで貼って、UV座標を変更することで表情を変える、というようなケースがあるかと思います。最近、このようなものに取り組んでいたのですが、自分が引っ掛かった点をご紹介いたします。

1.ボーンの入ったキャラクタはSkinnedMeshRendererのsharedMeshを使う。
2.インスタンス化したsharedMeshを使う。
という2点です。

MeshRendererがアタッチされているオブジェクトの場合

 例えば、CubeのようなプリミティブをUnityのエディタ上で作成すると、このようにMesh FilterとMeshRendererが自動的にアタッチされています。201803282220.png
 この場合は、MeshFilterコンポーネントからmeshを取得することができます。meshクラスのメンバにUVがVector2の配列として定義されているので、それを操作すればよいです。

meshUV.cs
一部抜粋
private Mesh myM;
void Start () {
        myMesh = gameObject.GetComponent<MeshFilter>().mesh;
}
void Update(){
        Vector2[] nUV = myMesh.uv;
        for (int i=0; i < myMesh.uv.Length; i++)
        {
            nUV[i].x *= 0.99f;
            nUV[i].y *= 0.99f;
        }
        myMesh.uv = nUV;
}

201803282256.png
201803282257.png
このように貼られたテクスチャが変化していきます。

SkinnedMeshRendererがアタッチされているオブジェクトの場合

 多くの場合、キャラクターとして使用したいオブジェクトはボーンで動かすものです。例えば、キャラクターのFBXファイルをインポートして、そのメッシュオブジェクトを見ると、先ほどのMeshFilterやMeshRendererは見当たりません。201803282242.png
よって、先ほどのように、MeshFilterのMeshからUVを操作することはできません。
そのかわり、ボーンで変形されるキャラクタでは、このSkinnedMeshRendererが用いられます。SkinnedMeshRendererからSharedMeshを取得することができ、このSharedMeshのメンバにUVがあるので、それを操作します。

meshUV.cs
    private Mesh myM;
    private Mesh Imesh;
    // Use this for initialization
    void Start()
    {
        myMesh = gameObject.GetComponent<SkinnedMeshRenderer>().sharedMesh;
    }

    // Update is called once per frame
    void Update()
    {
        Vector2[] nUV = myMesh.uv;
        for (int i = 0; i < myMesh.uv.Length; i++)
        {
            nUV[i].x *= 0.99f;
            nUV[i].y *= 0.99f;
        }
        myMesh.uv = nUV;
    }

ところが今回は、このようにUVを操作すると問題が起きます。
UVを操作できるのですが、スクリプトを実行して一度UVを変更してしまうと、実行を停止しても元には戻りません。先ほどのCubeの場合は停止して再実行するとスクリプトによるUVの変更がリセットされているのですが、SkinnedMeshRendererの場合はそうはいかないようです。

インスタンス化したものを使用することで、元のデータを操作せずに保存しておく

 そこで、先ほどのスクリプトに少し手を加えます。

meshUV.cs
    private Mesh myM;
    private Mesh Imesh;
    // Use this for initialization
    void Start()
    {
        myMesh = gameObject.GetComponent<SkinnedMeshRenderer>().sharedMesh;
        Imesh = Instantiate(myMesh);
        gameObject.GetComponent<SkinnedMeshRenderer>().sharedMesh = Imesh;
    }

    // Update is called once per frame
    void Update()
    {
        Vector2[] nUV = Imesh.uv;
        for (int i = 0; i < Imesh.uv.Length; i++)
        {
            nUV[i].x *= 0.99f;
            nUV[i].y *= 0.99f;
        }
        Imesh.uv = nUV;
    }

sharedMeshをInstantiate()でインスタンス化して、sharedMeshの参照先をインスタンスに変更します。
こうしてから、インスタンスを操作すれば先ほどのような問題は起こらず、実行を停止すれば、UVへの変更はリセットされます。
 余談ですが、これで、UVだけでなく頂点も弄り放題です。
 また、UVを変更する場合に限らず、色々な場合に応用できると思われます。

7
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Chocogake_sanQ
Unityでゲームを作っています。 アクションゲーム「ペンギンスレッド」開発中。

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
7
Help us understand the problem. What is going on with this article?