コンストレイント（位置、回転、スケール）


－加筆中－
Houdini習得の壁の１つに位置、回転、スケールを追従させるコンストレイントがある。他のソフトでは当たり前な機能だがHoudiniは自分で実装しないといけない。方法も様々あって迷いやすいところなので整理しておく。

#位置コンストレイント
##➀ Expression

コンストレイントしたいメッシュのポイント番号をExpressionのpointに指定して移動させる。
シンプルで使いやすい。

![bandicam 2020-04-26 23-26-20-040.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/615517/705ca06e-78b5-01af-a2a1-224d62aee8cc.jpeg)


サンプルは、ポイント番号が３、最後の0,1,2はvectorなのでx,y,zの意味。

```c#:Expression
point("../transform1",3,"P",0)
point("../transform1",3,"P",1)
point("../transform1",3,"P",2)
```

##➁ copytopoints

コンストレイントしたいポイントにcopytopointsでコピー。

![bandicam 2020-04-27 00-13-43-085.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/615517/091182ec-474c-f73d-d252-ea25112caa97.jpeg)

##③ wrangle

コンストレイントしたいポイントをwrangleに入力してpoint関数で位置をコピー

![bandicam 2020-04-27 09-46-44-776.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/615517/d7323a84-2b23-07c2-bfe0-158c15ee6ebd.jpeg)

point関数でwrangleの２番目の入力から位置をコピー

```
@P += point(1, 'P', 0);
```

##④ packed

primintrinsicの配列から位置をコピー。
packしたメッシュは、モデルの中心に基点がかわる。
この方法は使わないがpackオブジェクトのprimintrinsicの知識として入れてみた。

![bandicam 2020-04-27 01-42-09-314.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/615517/1db230b1-8af3-9dea-3a4e-c383f7338472.jpeg)

```
matrix mat = primintrinsic(1, "packedfulltransform", @ptnum);
@P += set(getcomp(mat,4,0), getcomp(mat,4,1), getcomp(mat,4,2));
```
##⑤ matrix

maketransformで移動量の3x3マトリックスを作ってポジションに乗算
![bandicam 2020-07-23 16-31-58-067.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/615517/25f80556-fba1-77c2-a9ac-0937e72bf671.jpeg)

```
int pnum = chi("point_number");
vector point = point(1, "P", pnum);
vector center = getbbox_center(0);
@P *= maketransform(0,0,point-center ,set( 0, 0, 0 ),{ 1, 1, 1 },center);
```
#回転コンストレイント

![bandicam 2020-07-25 20-33-32-487.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/615517/a978d429-6684-a0da-b961-7daea061606f.gif)

Houdiniには非常に沢山の回転に関する機能が用意されているが大別するとXYZ軸回転（オイラー）と姿勢回転（クオータニオン）の２種類に集約される。
XYZ軸回転は、位置、回転、スケールの情報の入った3x3のmatirxを@Pに乗算することで変換するシンプルな方法。ただし、数学的な知識が必須なのでデザイナーには扱いずらい。
一方、姿勢回転は、向きと角度からなるquaternionをアトリビュートで扱いcopy to pointsノード（以降copyノード）で変換する方法。こちらはアトリビュートだけで制御ができるのでデザイナー向き。ただし、細かい制御をするとなるとmatrixを使う事になる。

扱いやすく応用範囲が広く実践的なのは姿勢回転なので、copyノードを利用したケースを中心に説明を進めていく。
姿勢回転は、向きと角度の２軸で回転を表す考え方で飛行機に例えると進む方向が向き(N)、上を示す垂直尾翼が角度(up)となる。２軸で事足りるのは、３軸目となる２つのベクトルの垂直方向は、外積（cross）で求められるからであり、X,Y,Zに相当するのがcross, up, Nである。

![回転方向.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/615517/28486447-8c31-2d3a-2a56-7e73c9c1d0df.jpeg)

copyノードは、transformに関わる以下のアトリビュートを使ってオブジェクトを変換する(他にも多くのアトリビュートがある)。

v@N　　　　法線（Z軸）
v@up　　　 upベクトル（Y軸）
f@pscale　均一なスケール
v@scale　 各軸を個別にスケール
p@orient　向きをquaterniondで定義
p@rot 　　回転をquaternionで定義

copyノードは、アトリビュートの@Nの向きと@upの角度の２軸があれば回転ができ、これらはNormalとPolyFrameノードで求めることができる。
![bandicam 2020-07-25 23-53-58-306.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/615517/28d30140-06bf-802a-4c6c-921ce7d6a381.jpeg)
![bandicam 2020-07-25 23-54-10-634.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/615517/a3b8f8a3-7414-7d56-f64f-57ae56977757.jpeg)

ここで注意しないといけないのは、copyノードは@Nの１軸だけでも回転ができ問題ないように見えることだが、ある角度になると反転して制御不能になるのでキチンと２軸を指定しないといけない。


##➀ copytopoints (orientアトリビュート)

copyノードを使った向きと角度だけの一番単純な回転コンストレイント。面に対してそのまま回転コンストレイントするだけならこれで十分。

![bandicam 2020-07-25 21-07-58-978.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/615517/12203424-272e-90e9-8e94-8c7cd5aa31aa.jpeg)


```
@orient = quaternion(maketransform(@N, @up));
```

##➁ copytopoints (rotアトリビュート)

copyノードを使った３軸の調整が可能な回転コンストレイント。各軸のradiansに角度を入れて自由な回転を追加できる。

![bandicam 2020-07-25 21-09-51-280.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/615517/5581e998-c403-7032-c050-9d44320e6164.jpeg)



```
matrix3 matx = ident() , maty = ident() , matz = ident();
vector4 @rot;

float anglex = radians(0);
vector     x = cross(normalize(v@up),normalize(v@N));
rotate(matx, anglex, x);

float angley = radians(0);
vector     y = cross(normalize(v@up),normalize(x));
rotate(maty, angley, y);

float anglez = radians(0);
vector     z = cross(normalize(x),normalize(y));
rotate(maty, anglez, z);

matrix3 mat=matx*maty*matz;
@rot= quaternion(mat);
```

##➂ matrix

①のcopyノードの方法をmatrixに切り替えた方法。学習用に作ったものなので実際に使うことはないかも。

![bandicam 2020-07-25 21-10-21-625.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/615517/0529744a-33c9-c646-1b7f-e355373b51e6.jpeg)


```
vector N = point(1, "N", 0);
vector up = point(1, "up", 0);
vector P = point(1, "P", 0);
vector x = cross(normalize(up),normalize(N));
vector y = cross(normalize(up),normalize(x));
vector z = cross(normalize(x),normalize(y));
vector center = P;

matrix m = set(x, y, z, center);
@P*=m;
```

##④ copytopoints (位置、回転、スケール　ローカル軸対応)

copyノードを使った一番実践的な回転コンストレイント。コンストレイントした面のローカル軸で位置、回転、スケールの調整が可能。
このサンプルではやっていないがノイズを使って個別に回転を変えることも可能。

![bandicam 2020-07-25 21-22-03-746.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/615517/c910bbe8-4ed1-8fc2-0332-5c11a2dfacf6.gif)

##⑤ matrix (位置、回転、スケール　ローカル軸対応)

④のcopyノードを使った方法をmatrixに切り替えた方法。複雑になってしまうので１つの面のコンストレイントにしている。
学習用に作ったものなので実際に使うことはないかも。

![bandicam 2020-07-25 21-34-35-827.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/615517/fe074f8b-fc60-60fa-e0f8-267f1b3b13d2.gif)



## HIPファイル
データの動作環境:
Houdini Apprentice 18.0.348

ダウンロード先リンク(Github):
https://github.com/DefultVFX/houdini/blob/master/constraint.v2.hipnc