読者です 読者をやめる 読者になる 読者になる

テラシュールブログ

旧テラシュールウェアブログUnity記事。主にUnityのTipsやAR・VR、ニコニコ動画についてのメモを残します。

テクスチャのUV移動について

スプライトアニメーションを行おうと思ったら、概ね2つの方法が考えられる。

一つは「テクスチャを差し替えてしまう」方法、もう一つは「テクスチャのUVを変化させる」方法だ。

ぶっちゃけ簡単なのは「テクスチャを差し替える」方法で、実際殆どの人はこの方法で問題ないと思う。が、もっとガチで作りたい場合は後者となる。


で、スプライトのUV座標を変化させる方法でよく紹介されているのはマテリアルの値を変化させる方法だ。これなら簡単にUVアニメーションを行ったり背景スクロールを行う事ができるが、一つ問題がある。

というのも、Unityはマテリアルの値を変更するとマテリアルインスタンスを新規で作り、それを変更する。つまり、オブジェクト毎にアニメーションを行う場合はマテリアルインスタンスがオブジェクト毎に生成され、ドローコール=オブジェクトの数となる。

【Unity】ゲームエフェクトで必須テクニック1 UVアニメーション
http://amano-kiyoyuki.hateblo.jp/entry/2013/02/24/135132

参照先ページが非公開になってた。下のような感じで記述する。

public class UV : MonoBehaviour
{
public Rect rect;

private Material _material;
private int textureWidth, textureHeight;

void Start ()
{
_material = renderer.material;
Texture texture = _material.mainTexture;
textureWidth = texture.width;
textureHeight = texture.height;

Debug.Log(textureWidth + "/" + textureHeight);
}

void Update ()
{
Vector2 offset, scale;

offset = new Vector2( rect.x / textureWidth, rect.y / textureHeight);
scale = new Vector2( rect.width / textureWidth, rect.height / textureHeight);
_material.SetTextureOffset("_MainTex", offset);
_material.SetTextureScale("_MainTex", scale);
}
}

これの単純な対策としては、マテリアルデータベースを作っておき、uv情報に従ってマテリアルを取得する方法だ。これならばバッチが効く。

スクリーンショット 2014-01-14 12.12.28

この処理はOrthello系で使われている気がするので、自作するならOrthello使ったほうが良いと思う。車輪の再発明は良くない。

[Unity3D]無料の2Dフレームワーク!Orthello
http://terasur.blog.fc2.com/blog-entry-193.html


もう一つの方法としては、メッシュ自体のUVを変化させてしまう方法がある。
こちらの場合は、マテリアルをインスタンス化している訳ではないので、バッチが効く。

また、Unity 4.2からQuadが追加されたので、割と楽にuv設定が出来る。

MeshFilter meshFilter = GetComponent<MeshFilter>();
Mesh mesh = meshFilter.mesh;

float width = scale.x / textureScale.x;
float height = scale.y / textureScale.y;

float x = offset.x/ textureScale.x;
float y = offset.y / textureScale.y;

mesh.uv = new Vector2[]{
new Vector2(x, y) ,
new Vector2(x + width , y + height),
new Vector2(x + width, y ),
new Vector2(x, y + height),
};

但し、標準quadを使う場合はmesh情報を上書きしてしまう関係上、エディタから確認する事ができない。

なので、オブジェクト毎にランタイムでquadメッシュを作成してしまう感じで行うと良さげ。そうすればshardMeshでも文句言われない。

NGUIとかはもう少し高度な事をしてた気がする。