[[Spr1の使い方/マニュアル]]
*目次 [#pc308a5e]
#contents
*準備 [#e08ec593]
ソースを読むために,基本のクラスをいくつか覚える必要があります.
**UTRef<T> [[参照カウンタ]]と参照ポインタ [#cc8174f9]
参照カウンタ式のスマートポインタ.
UTRef<クラス名>が参照ポインタ.UTRefCountが[[参照カウンタ]]です.
UTRefCountを基本クラスにもつクラスAがあるとして,次にように使えます.
 UTRef<A> p;
 for(int i=0; i10; ++i){
   p = new A;
   p->Aのメソッド()
 }
new したのにdeleteしていません.さらに,pに10回もnewして代入しています.
でもメモリリークは起きません. 詳しくは[[参照カウンタ]]を見てください.

**線形代数 [#x02328c0]
***[[Spr::Vec3f ( Spr::TVec3<float> ) / Spr::Vec3d ( Spr::TVec3<double> ):http://springhead.info/src/html/ja/classSpr_1_1TVec3.html]] [#h24f9b5e]
-3次元のベクトル。
-DirectX周りではVec3f、物理エンジン周りではVec3dが使われてる.物理には精度が必要なんだ.

 Spr::Vec3f vec(x, y, z); //初期化。
 Spr::Vec3f vec= Spr::Vec3f(x, y, z); //上と同じ意味。
 vec[0]= x2; //各要素に代入。添え字は0,1,2。
 Spr::Vec3f vec2= vec+Spr::Vec3f(x, y, z); //足し算とか。
size()はベクトルの次元.norm()がノルム(大きさ).square()がノルム^2.
unit()で正規化(0割注意)..X() .Y() .Z() で要素にアクセス.~
実は任意サイズのベクトル[[class PTM::TVector<N, T>:http://springhead.info/src/html/ja/classPTM_1_1TVector.html]]の親戚.他にも[[VVector:http://springhead.info/src/html/ja/classPTM_1_1VVector.html]]とか[[EVector:http://springhead.info/src/html/ja/classPTM_1_1ConstEVector.html]]がある.

***[[Spr::Affinef ( Spr::TAffine<float> ):http://springhead.info/src/html/ja/classSpr_1_1TAffine.html]] [#wcc64f12]
-Affine行列(4*4行列)。

 Spr::Affinef trn= Spr::Affinef::Trn(x, y, z); //平行移動を表すAffine行列。
 Spr::Affinef rot= Spr::Affinef::Rot(rad, 'x'); //X軸周りの回転を表すAffine行列。
 Spr::Affinef aff= trn*rot; //Affine行列同士の掛け算。
 aff.Pos()= Spr::Vec3f(x, y, z); //平行移動成分に代入。
 aff.Rot()= Spr::Matrix3f(xx,xy,xz,yx,yy,yz,zx,zy,zz); //回転成分の代入.
 aff[0][0]= 1.0; //各要素に代入。添え字は0,1,2,3.
 aff.Ex() = Vec3f(1,0,0); 回転行列部のx軸基底(縦ベクトル)に代入.
 aff.ExX() = 2.0f; Ex().X() と同じ.
 Spr::Vec3f vec1= …;
 Spr::Vec3f vec2= aff*vec1; //	3次ベクトルをAffine変換.vec1[3]は1と仮定して演算.

:[[LookAt(to), LookAt(to, up), LookAtGL(to), LookAtGL(to, up):http://springhead.info/src/html/ja/classSpr_1_1TAffine.html]] |toを見て,upが上になるような視点行列になるように自分を回転させる.
:[[static Unit(), Trn (px, py, pz), Rot(th, axis), Scale (sx, sy, sz):http://springhead.info/src/html/ja/classSpr_1_1TAffine.html]]|単位行列,平行移動行列,回転行列,拡大行列を返す.Affinef af=Affinef::Trn(1,2,3) のように使う.
:[[static ProjectionGL (Vec3f screen, Vec2f size, front=1.0f, back=10000.0f), ProjectionD3D(..):http://springhead.info/src/html/ja/classSpr_1_1TAffine.html]]|OpenGL, Direct3Dのプロジェクション行列を返す.screenが視点から見たスクリーンの位置,sizeがスクリーンのサイズ.front, back はクリッピングプレーン.

[[逆行列inv(), 転置trans(), 行列式det(), 方程式の解 solve(), ガウスの消去法 gauss(), コレスキー法 cholesky() :http://springhead.info/src/html/ja/classPTM_1_1MatrixImp.html]]~
実は任意サイズの行列[[PTM::TMatrixCol< H, W, T, Z, U >:http://springhead.info/src/html/ja/classPTM_1_1TMatrixCol.html]]の親戚.他にも[[VMatrixCol:http://springhead.info/src/html/ja/classPTM_1_1VMatrixCol.html]]や[[EMatrixCol:http://springhead.info/src/html/ja/classPTM_1_1EMatrixCol.html]]がある.

***[[Spr::Quaternionf (TQuaternion<float>):http://springhead.info/src/html/ja/classSpr_1_1TQuaternion.html]] [#nce99749]
- Quaternion 4元数.
- 回転をあらわす方法の一つ.Matrix3fの変わりに使える.
 Qutaternionf qt;
 qt.from_matrix(Matrix3f::Rot(Rad(30), 'y')); // 行列から初期化できる.
 Vec3f r = qt.rotation(); // 回転ベクトル(unit:回転軸, norm:回転角)
 Vec3f p = qt * Vec3f(1,0,0); // 位置ベクトルを回転させる.

4次元ベクトル [[TVector<4, float>:http://springhead.info/src/html/ja/classPTM_1_1TVector.html]] の親戚.

*シーングラフ上のオブジェクト [#u5aad312]
SpringheadのSceneGraphは次のような構造になっている.
 +Scene         //  シーンオブジェクト(FWD3DApp app; (Viewが持っています)のメンバ)
  +Frame        //  物のデータ
   +Frame
    +CDMesh     //  衝突判定用
    +D3Mesh     //  描画用
    +GRMesh     //  元のメッシュデータ
   +Light       //  光源
  +BehaviorEngines      //  物の振る舞いについての記述
   +PHSolidContainer    //  剛体の入れ物,自由物体の積分もここでやっています.
    +PHSolid solid1
    +PHSolid solid2
    +PHSolid solid3
   +PHContactEngine     //  接触エンジン
    +floor
    +solid1
    +solid2
    +solid3
   +PHJointEngine       //  ジョイントエンジン
    +PHJoint root       //  ルートジョイント
     +PHJoint joint1    //  ジョイント1
      +solid1
      +joint2
       +solid2
       +joint2
        +solid3
これらへのポインタを手に入れて,メンバメソッドを呼び出したり,メンバ変数を
書き換えることで,物を動かしたり,関節に力を加えたり出来る.

*剛体に力を加える. [#xc0f7f92]
力を加えるときは剛体に力を加えます.
 Vec3d f, Vec3d r;
 PHSolid* so;
 scene->FindObject(so, "solid1"); // 名前からオブジェクトのポインタを得る
 if (so) so->AddForec(f, r); //< 力fを 位置r(World系) に加える
**どこで呼び出すか [#b64c1d98]
BehaviorEngineには,実行の優先順位があり,SceneGraph/SGBehaviorEngine.h にあるように,
    enum SGBehaviorPriority{
        //初期化モジュール
        SGBP_INITIALIZER            = 100,
        SGBP_CLEARFORCE,
        //力生成モジュール
        SGBP_FORCEGENERATOR         = 200,
            SGBP_GRAVITYENGINE,
            SGBP_COLLISIONENGINE,
            SGBP_PENALTYENGINE,
        //積分の対象
        SGBP_DYNAMICALSYSTEM        = 300,
            SGBP_JOINTENGINE,
            SGBP_SOLIDCONTAINER,
        //
        SGBP_MOTION                 = 400,
            SGBP_CHANGEOBJECT,
            SGBP_CONSTRAINT,
        //他のエンジンのリスナ
        SGBP_LISTENER               = 500,
            SGBP_CONTACTENGINE,
            SGBP_STICKENGINE,
            SGBP_WARPENGINE,
    };
となっています.scene には,全部のエンジンを呼び出す
    /// シーンの時刻を進める ClearForce(); GenerateForce(); Integrate(); と同じ
    void Step();
以外に,個別に呼び出す
    /// シーンの時刻を進める(力のクリア)
    void ClearForce();
    /// シーンの時刻を進める(力の生成)
    void GenerateForce();
    /// シーンの時刻を進める(力と速度を積分して,速度と位置を更新)
    void Integrate();
があります.プログラムで力を加えるためには,個別に呼び出して,
タイミングよく(たとえばGenerateForce()の直後で)力を加えなければなりません.

DynaHapticが使っている,FWD3DApp app の app.Step()は,
scene->Step()を呼び出してしまいます.
FWD3DAppを派生させてMyAppを作ってFWD3DAppの代わりに使い,
MyApp::Step()の中で,個別に呼び出したり,力を加えるのが良いと思います.

*BehaviorEngineのポインタの取得 [#gb86863f]
 PHContactEngine* ce=NULL;
 scene->GetBehaviors().Find(ce);
 if(ce) ce->bDraw = true;
これで,ce にシーングラフのなかの PHContactEngineを取得して,bDraw フラグを true にしています.

関節エンジンも,
 PHJointEngine* je=NULL;
 scene->GetBehaviors().Find(je);
でとれますが,目当てのJointへのポインタを手に入れるためには,そのあと階層を追って,
GetChildObject(int)を呼び出さなければなりません.

こんなときは,名前をつけておくと簡単です.特定の名前のジョイントと接続するには,
 PHJoint1D* jnt1;
 scene->FindObject(jnt1, "jnt1");
 PHJointPid* pid1 = PHJointPid::Find(jnt1, scene);
 static double th=0.0;
 th = th += 0.1;
 pid1->goal = Rad(th);
のようにすればできます.