mesh.verticesの編集(もにょもにょした表現)


ポリゴンの頂点をコード側から動かしてもにょもにょさせるにはどうしたらいいかやってみた。

>>サンプル
すごく簡単で、下記のコードで頂点が取り出せる。

Vector3[] vertices = this.GetComponent<MeshFilter>().mesh.vertices;


MeshFilterコンポーネントの中にメッシュの情報があり、それをMeshRendererが描画し表示される。MeshFilter.meshのなかに頂点情報(vertices)が格納されているのでそれをいじると、頂点が操作できる。
内部的(実行時?)にはすべて三角ポリゴンに変換されているらしいけど、Unity上では三角ポリゴン、四角ポリゴンがサポートされている。例えばCubeであれば、各面に四角ポリゴンがあるので頂点が4つ。その面が6つあるので頂点数は24個。この頂点をランダムに動かしてしまうと面と面がはなれてしまいCubeではなくなってしまうので、同じ座標にある頂点は同じように動かしてあげないと形状が崩れちゃう。見た目のCubeの角頂点座標と、mesh.verticesの頂点の座標の対応表をつくって、それを動かせば面と面が離れることを回避できる。そんな感じでつくったコードはこちら。
>>プロジェクトファイルダウンロード

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

/**
 * 頂点加工のテスト。
 */
public class VerticesTest : MonoBehaviour {
	/**
	 * 揺らぐ距離間。
	 */
	public float swingDistance = 0.1f;

	/**
	 * MeshFilter.
	 */
	private MeshFilter meshFilter;

	/**
	 * メッシュデータの頂点。
	 */
	private Vector3[] vertices;

	/**
	 * 重複のないオリジナル頂点データ。
	 */
	private List<Vector3> originalVertices = new List<Vector3>();

	/**
	 * 現在の重複のない頂点データ。
	 */
	private List<Vector3> currentVertices = new List<Vector3>();

	/**
	 * 動かす際のターゲットとなる重複のない頂点データ。
	 */
	private List<Vector3> targetlVertices = new List<Vector3>();

	/**
	 * 頂点ごとの時間の差。
	 */
	private List<float> timeGap = new List<float>();

	/**
	 * 頂点との対応表。
	 */
	private Dictionary<int, int> correspondenceTable = new Dictionary<int, int>();

	/**
	 * Awake.
	 */
	public void Awake() {
		this.meshFilter = this.GetComponent<MeshFilter>();
		this.vertices = this.meshFilter.mesh.vertices;

		for (int i = 0; i < vertices.Length; ++i) {
			Vector3 vertex = vertices[i];

			if (!this.originalVertices.Contains(vertex)) {
				this.correspondenceTable[i] = this.originalVertices.Count;
				this.originalVertices.Add(vertex);
				this.currentVertices.Add(vertex);
				
				// ランダムな位置を作る
				this.targetlVertices.Add(new Vector3(
					vertex.x + Random.Range(-this.swingDistance, this.swingDistance),
					vertex.y + Random.Range(-this.swingDistance, this.swingDistance),
					vertex.z + Random.Range(-this.swingDistance, this.swingDistance)
				));
			}
			else {
				this.correspondenceTable[i] = this.originalVertices.FindIndex(vec => vec == vertex);
			}
		}

		for (int i = 0; i < this.originalVertices.Count; ++i) {
			this.timeGap.Add(Random.Range(0.0f, 1.0f));
		}
	}

	/**
	 * Update.
	 */
	public void Update() {
		// 現在位置の更新
		for (int i = 0; i < this.currentVertices.Count; ++i) {
			Vector3 originalPos = this.originalVertices[i];
			Vector3 targetPos = this.targetlVertices[i];
			Vector3 currentPos = this.currentVertices[i];

			this.timeGap[i] += Time.deltaTime * 1.6f;
			currentPos = Vector3.Slerp(originalPos, targetPos, Mathf.PingPong(this.timeGap[i], 1.0f));

			this.currentVertices[i] = currentPos;
		}

		// verticesに渡す頂点を作成
		for (int i = 0; i < this.vertices.Length; ++i) {
			int vid = this.correspondenceTable[i];
			this.vertices[i] = this.currentVertices[vid];
		}

		// 回転演出
		this.transform.Rotate(Vector3.up * Time.deltaTime * 12.0f, Space.World);

		// 頂点を渡す
		this.meshFilter.mesh.vertices = this.vertices;
	}
}

コメントを残す