MRが楽しい

MRやVRについて学習したことを書き残す

UnityEngineのMeshクラスを読み解く Simple Mesh API その2

本日は Unity の調査枠です。
UnityEngine の Mesh クラスのドキュメントを理解のため、少しずつ読み進めていきます。

前回記事の続きです。
bluebirdofoz.hatenablog.com

Simple Mesh APIクラスのドキュメント

今回は Mesh クラスで利用する Simple Mesh API の以下の関数ドキュメントを読み進めていきます。
docs.unity3d.com
docs.unity3d.com
docs.unity3d.com
docs.unity3d.com

SetNormals

public void SetNormals (Vector3[] inNormals);
public void SetNormals (List inNormals);
public void SetNormals (NativeArray inNormals);

引数説明
inNormals頂点ごとの法線

メッシュの法線を設定します。

public void SetNormals (Vector3[] inNormals, int start, int length);
public void SetNormals (List inNormals, int start, int length);
public void SetNormals (NativeArray inNormals, int start, int length);

引数説明
inNormals頂点ごとの法線
start入力配列から取得する最初の要素のインデックス
lengh入力配列から取得する要素の数

入力配列の一部を使用して、メッシュの法線を設定します。
このメソッドは入力配列の一部を使用して SetNormals を呼び出したかのように動作します。
指定の start インデックスから始まり、指定された length 長が取得されます。
結果のメッシュには length 数の頂点があります。

SetTangents

public void SetTangents (Vector4[] inTangents);
public void SetTangents (List inTangents);
public void SetTangents (NativeArray inTangents);

引数説明
inTangents頂点ごとの接線

メッシュの接線を設定します。

public void SetTangents (Vector4[] inTangents, int start, int length);
public void SetTangents (List inTangents, int start, int length);
public void SetTangents (NativeArray inTangents, int start, int length);

引数説明
inTangents頂点ごとの接線
start入力配列から取得する最初の要素のインデックス
lengh入力配列から取得する要素の数

入力配列の一部を使用して、メッシュの接線を設定します。

このメソッドは入力配列の一部を使用して SetTangents を呼び出したかのように動作します。
指定の start インデックスから始まり、指定された length 長が取得されます。
結果のメッシュには length 数の頂点があります。

SetUVs

public void SetUVs (int channel, Vector2[] uvs);
public void SetUVs (int channel, Vector3[] uvs);
public void SetUVs (int channel, Vector4[] uvs);
public void SetUVs (int channel, List uvs);
public void SetUVs (int channel, List uvs);
public void SetUVs (int channel, List uvs);
public void SetUVs (int channel, NativeArray uvs);

引数説明
channel[0..7]の範囲のUVチャネル(Mesh.uvと対応)
uvs指定されたインデックスに設定するUV

メッシュのUVを設定します。

メッシュUV(テクスチャ座標)をVector2、Vector3、またはVector4のリストとして設定します。
2D(Vector2)テクスチャ座標が最も一般的なケースですが、3Dまたは4Dテクスチャ座標を使用することも可能です。
これは、シェーダーの特殊効果データに最もよく使用されます。

public void SetUVs (int channel、Vector2 [] uvs、int start、int length);
public void SetUVs (int channel、Vector3 [] uvs、int start、int length);
public void SetUVs (int channel、Vector4 [] uvs、int start、int length);
public void SetUVs (int channel、List uvs、int start、int length);
public void SetUVs (int channel、List uvs、int start、int length);
public void SetUVs (int channel、List uvs、int start、int length);
public void SetUVs (int channel、NativeArray uvs、int start、int length);

入力配列の一部を使用して、メッシュのUVを設定します。

このメソッドは入力配列の一部を使用して SetUVs を呼び出したかのように動作します。
指定の start インデックスから始まり、指定された length 長が取得されます。
結果のメッシュには length 数の頂点があります。

SetBoneWeights

public void SetBoneWeights (NativeArray bonesPerVertex, NativeArray weights);

引数説明
bonesPerVertexメッシュの各頂点のボーン数
weights頂点インデックスでソートされた各頂点のBoneWeight1構造体

メッシュのボーンウェイトを設定します。

頂点ごとの可変数のボーンをサポートします。
各頂点のボーンウェイトは最も重いウェイトから順にソートする必要があります。
ウェイト 0 は無視されます。

ウェイトは渡された浮動小数点値よりも低い精度で保存される可能性があります。
Mesh.GetAllBoneWeights を使用して正確な値を取得することは期待しないでください。
使用される最小精度は 16 ビットの正規化された整数です。

using UnityEngine;
using System.Collections;
using Unity.Collections;

public class ExampleClass : MonoBehaviour
{
    void Start()
    {
        gameObject.AddComponent<Animation>();
        gameObject.AddComponent<SkinnedMeshRenderer>();
        SkinnedMeshRenderer rend = GetComponent<SkinnedMeshRenderer>();
        Animation anim = GetComponent<Animation>();

        // 基本的なメッシュを作成する
        Mesh mesh = new Mesh();
        mesh.vertices = new Vector3[] { new Vector3(-1, 0, 0), new Vector3(1, 0, 0), new Vector3(-1, 5, 0), new Vector3(1, 5, 0) };
        mesh.uv = new Vector2[] { new Vector2(0, 0), new Vector2(1, 0), new Vector2(0, 1), new Vector2(1, 1) };
        mesh.triangles = new int[] { 0, 1, 2, 1, 3, 2 };
        mesh.RecalculateNormals();

        // マテリアルをスキンメッシュレンダラーに割り当てます
        rend.material = new Material(Shader.Find("Diffuse"));

        // ボーンウェイトをメッシュに割り当てます
        byte[] bonesPerVertex = new byte[4] { 1, 2, 2, 1 };
        BoneWeight1[] weights = new BoneWeight1[6];

        // 頂点 0
        weights[0].boneIndex = 0;
        weights[0].weight = 1;

        // 頂点 1
        weights[1].boneIndex = 0;
        weights[1].weight = 0.5f;

        weights[2].boneIndex = 1;
        weights[2].weight = 0.5f;

        // 頂点 2
        weights[3].boneIndex = 0;
        weights[3].weight = 0.5f;

        weights[4].boneIndex = 1;
        weights[4].weight = 0.5f;

        // 頂点 3
        weights[5].boneIndex = 1;
        weights[5].weight = 1;

        // ボーンウェイトを作成します
        var bonesPerVertexArray = new NativeArray<byte>(bonesPerVertex, Allocator.Temp);
        var weightsArray = new NativeArray<BoneWeight1>(weights, Allocator.Temp);

        // メッシュにボーンウェイトを設定します
        mesh.SetBoneWeights(bonesPerVertexArray, weightsArray);

        // ボーントランスフォームとバインドポーズ(デフォルト位置)を作成します
        Transform[] bones = new Transform[2];
        Matrix4x4[] bindPoses = new Matrix4x4[2];

        bones[0] = new GameObject("Lower").transform;
        bones[0].parent = transform;

        // 親オブジェクトに対して相対的な位置を設定します
        bones[0].localRotation = Quaternion.identity;
        bones[0].localPosition = Vector3.zero;

        // バインドポーズはボーンの逆変換行列です
        // この場合、行列はルートオブジェクトに関連させて作成します
        // これにより、ルートオブジェクトを自由に移動できるようにします
        bindPoses[0] = bones[0].worldToLocalMatrix * transform.localToWorldMatrix;

        bones[1] = new GameObject("Upper").transform;
        bones[1].parent = transform;
        
        // 親オブジェクトに対して相対的な位置を設定します
        bones[1].localRotation = Quaternion.identity;
        bones[1].localPosition = new Vector3(0, 5, 0);

        // バインドポーズはボーンの逆変換行列です
        // この場合、行列はルートオブジェクトに関連させて作成します
        // これにより、ルートオブジェクトを自由に移動できるようにします
        bindPoses[1] = bones[1].worldToLocalMatrix * transform.localToWorldMatrix;

        // bindPoses 配列を、メッシュの bindposes 配列に割り当て、デフォルトポーズをバインドします
        mesh.bindposes = bindPoses;

        // スキンメッシュレンダラーにボーンとメッシュを割り当てます
        rend.bones = bones;
        rend.sharedMesh = mesh;

        // シンプルなアニメーションカーブ(0.0f -> 3.0f -> 0.0f)を作成します
        AnimationCurve curve = new AnimationCurve();
        curve.keys = new Keyframe[] { new Keyframe(0, 0, 0, 0), new Keyframe(10, 3, 0, 0), new Keyframe(20, 0, 0, 0) };

        // アニメーションカーブで"Lower"オブジェクトのZ軸座標を移動させるクリップを作成します
        AnimationClip clip = new AnimationClip();
        clip.legacy = true;
        clip.SetCurve("Lower", typeof(Transform), "m_LocalPosition.z", curve);

        // クリップを反映して再生します
        anim.AddClip(clip, "test");
        anim.Play("test");
    }
}

f:id:bluebirdofoz:20200805054830j:plain