2010年12月26日日曜日

かっこいい動画

早いですね、、、1年って。で、最近はまってるのがニコニコ動画の「魔王エンジェル」の動画。

もともとアイマスっていうか、ニコマスの魔王エンジェル系の P さま系はすごすぎて、でも、カメラワークとかむっちゃ参考になるんですよね。

2010年12月4日土曜日

Viewer2 対応 ブーツ

そろそろ 1.x 系のサードパーティ ビューワーでもアルファ マスクのサポートしはじめたし、特にブーツで使われているインビジブルプリムだと、、、場所によっては透けちゃって、きれいじゃないんですよね。
Boots01
ということで、そろそろ Viewer2 対応のブーツを買ってみることにしました。今回は PixelFashion さんのとこの「Ultimate Boots black(SL 2.0 ready)」 550L$ を購入してみることに。

こちらのお店のブーツは以前いくつか購入したことがあり、テクスチャがかなりきれいなブーツでした。ただし、インビジブルプリムを多用して整形しているため、微妙にブーツのまわりに「透ける」部分が出ていました。
それらの SL 2.0 ready がでたら、、、、買いなおすとは思いますが。。。
で、上のブーツを購入して履いた絵がこちら。
Boots02
ですよね~。
お気に入りの BAX の Ankle boots も SL 2.0 readay にならないかなぁ、、、。

[NeurolaB Inc.] Ultimate Boots black (SL 2.0 ready)
https://marketplace.secondlife.com/p/NeurolaB-Inc-Ultimate-Boots-black-SL-20-ready/504191

BAX Ankle Boots Black Patent
https://marketplace.secondlife.com/p/BAX-Ankle-Boots-Black-Patent/424098

[追記] V2.0 アルファマスクサポートの BAX Ankle でましたー
Second Life Marketplace - BAX Ankle Boots Black Leather

2010年11月29日月曜日

Kirstens で被写界深度 リアルタイムで焦点ぼかし

Kirstens Viewer の作者さんのページで最新の KL Viewer の SS を見てたら「?」と。前にもご紹介していた GIMP の Focus Blur を使わずして、リアルタイムに背景がぼけてるように見えるんです。



KL すごいし。。。
環境設定のグラフィックにある [Lighting and Shadows] をオンにすると、、、影だけじゃなくて、ブラ―までもかかるんですね。

Blur001

ちょっと触っただけなので、まだどのような調整ができるかわからないのですが、Viewer もいろいろと進化していることは確かですね。

[追記]
SL Depth of Field 01

Kirstens の場合は設定項目がありますね。
[Graphics] - [Advanced] - [Misc] です。
Camera COC、CameraFNumber、Camera Focal Length です。

焦点距離と絞り、とか、そんなキーワードで検索するといろいろ解説がでます。
カメラが寄った時だけ、背景がぼけるような設定にしておくと、あまりうるさくないかも。

KL Depth Of Field
KL Depth of Field and Shadow Effect

2010年11月8日月曜日

Rigged Mesh すごいですね

敷居は相当高いようなのですが、Rigged Mesh を使ったアバタ―制作の事例が YouTube や個人のブログで公開されはじめていますね。

Rigged Mesh : http://wiki.secondlife.com/wiki/Mesh/Mesh_Walkthrough:_Rigged_Mesh_Upload

Secondlife の先駆者の方々には元々 3DCG のエリアでご活躍されていた方も多くて、その方々にすると「やっと」という感もあるのでしょうが、それでもこの対応の早さは日本のユーザーがとびぬけているようにも思えます。









私には到底無理なんですが、すでにあるモデリングツールの利用や COLLADA データフォーマットの採用といった点がこのようなことを可能にしているんですね。

技術的/非技術的な課題・問題も山積みですが、どこまで進化していくのか楽しみです。セカンドライフ、いろいろ言われ続けていますが、このようなサービスで「もう、やーめた」と言わず継続している数少ないサービスのひとつなので引き続き進化してほしいのと、やっぱり CGM の要素を大切にし続けてほしいですね。

2010年10月16日土曜日

[LSL] 位置と回転について ~ アバタ―にスクリプトはいれられない ~

前回までで、llSetLinkPrimitiveParams を使った子プリムの位置と向きの設定方法をご紹介してきました。また、Link された子プリムを扱うには、与えられた「リンク番号」が重要だ、ということもお伝えしました。
そこで、リンク番号の取得ですが、プリム同士のリンクであれば、それぞれのプリムにスクリプトを入れ、リセット後のタイミングなどで llMessageLinked を使って子プリムのリンク番号をルートのスクリプトに渡すことで、リンク番号管理をしたりします。
llGetLinkNumber() を使って自分のリンク番号をとるわけです。

ここで問題になるのが、プリムにアバタ―が座った時のリンク番号です。ん?と思われるかもしれませんが、アバタ―がプリムに「座る」という行為は、アバタ―がルートプリムにリンクされた、というイベントで管理されるのです。
スクリプトでは CHANGE イベントCHANGED_LINK を使って、アバタ―が座ったかどうかを管理しているのですね。

アバタ―には他の子プリムのようにスクリプトを入れることができません。座った後のアバタ―の位置や回転を操作するのは、リンクされた子プリムの位置と回転を操作するのと同様ですが、リンク番号の取得がプリムのようにできないのです。今回はその対応方法と、椅子に座ったアバタ―の位置や向きを変えるスクリプトを考えてみます。

5. アバタ―にスクリプトはいれられない


まぁ、、、既知、既出といえる比較的有名な話題になります。wiki にも紹介されていますし、過去にも多くの先輩諸氏がブログなどで紹介しているのですが、ポイントをまとめると

a) 多くの場合は CHANGE イベント発生時のリンク番号の最大値がアバタ―のリンク番号
b) 複数のアバタ―が座ったり立ったりする場合は、アバタ―のリンク番号は CHANGE イベントのたびに変わる可能性がある


上記の2つに注意してリンク番号を取得するサンプル スクリプトを書くと以下のようなものになります。
なお、一人しか座らせない場合は、llSitTarget と llAvatorOnSitTarget を使って、アバタ―の key の取得、llGetNumberOfPrims をリンク番号として扱うのが一番簡単です。このスクリプトはオブジェクトに複数のアバタ―が Sit する、という前提で、key や リンク番号などの情報を取得するサンプルになっています。

//--------------------------------------------------------------------------------
// Sit した複数のアバタ―のリンク番号や Key, 名前、ポジション、ローテーションを
// それぞれのリストに取得するサンプルスクリプト
//--------------------------------------------------------------------------------
list keyList;     //Sit しているアバタ―の key をいれます
list nameList; //Sit しているアバタ―の名前をいれます
list posList;    //Sit しているアバタ―のグローバルポジションを入れます
list rotList;     //Sit しているアバタ―のグローバルローテーションを入れます
list numList;   //Sit しているアバタ―のリンク番号をいれます
default{
    state_entry(){
        llSay(0, "Hello, Avatar!");
    }
   
    changed(integer change){
        if(change & CHANGED_LINK){
            integer max = llGetNumberOfPrims();
            integer i = max;
            keyList = nameList = posList = rotList = numList = [];
            for(;i>0;--i){
                list tmp = llGetLinkPrimitiveParams(i,[PRIM_NAME,PRIM_POSITION,PRIM_ROTATION]);
                key tKey= llGetLinkKey(i);
                list objDetails = llGetObjectDetails(tKey,[OBJECT_CREATOR]);
//OBJECT_CREATOR が NULL_KEY の場合はプリムではなくアバタ―です
                key cKey = llList2Key(objDetails,0);
                if(cKey==NULL_KEY){ //リンクされたものがアバタ―かどうかのチェック
                    //アバタ―だったら各情報をリストに格納します

                    tmp = llGetLinkPrimitiveParams(i,[PRIM_NAME,PRIM_POSITION,PRIM_ROTATION]);
                    keyList += tKey;
                    nameList+= llList2String(tmp,0);
                    posList += llList2Vector(tmp,1);
                    rotList += llList2Rot(tmp,2);
                    numList += [i];
                }else{
                    i=0; //アバタ―じゃなくなったら、あとはリンクされたプリムなので終了
                }
            }           
        }
        //アバタ―が座っていれば、その情報を確認用に表示
        integer len = llGetListLength(keyList);
        if(len>0){
            integer i = 0;
            for(;i<len;++i){
                llOwnerSay(llList2String(numList,i)+","+
                           llList2String(nameList,i)+","+
                           llList2String(keyList,i)+","+
                           llList2String(posList,i)+","+
                           llList2String(rotList,i));
            }
        }else{
            llOwnerSay("誰も座っていません。");
        }
    }
}
//------------------------------------------------------------------------

上記スクリプトの入った直方体に2人のアバターが Sit すると llOwnerSay で以下のようなメッセージをオーナーは受け取ることができます。

[00:28]  Object: 2,Snuma Whitfield,d19d8aef-530a-41cc-bc1c-xxxxxxxxxxxx,<210.193100, 234.464900, 2498.686000>,<0.000000, 0.000000, 0.477574, 0.878592>
[00:28]  Object: 3,Alt Beck,a45ad906-fa8e-4fe2-bb3d-xxxxxxxxxxxx,<210.193100, 236.036500, 2498.686000>,<0.000000, 0.000000, -0.934414, 0.356190>


リンク番号3番の Alt さんは一番最後に Sit したアバタ―なのですが、ここでリンク番号 2 番の私が立ち上がったとき、Alt さんのリンク番号がどうなるか。。。答えは 3番ではなく即座に2番になるのです。そのため、changed イベントが発生する毎に、アバタ―のリンク番号の再設定をしなくてはいけません。

リンク番号さえわかっていれば、あとはこれまでお話ししてきた設定方法を使って llSetLinkPrimitiveParams によるアバタ―の位置や回転の指定を行えばいいのです。
llSitTarget で指定するような初期の座る場所を指定したい、、などは上記の考えを拡張する(座った直後に移動させる)か、wiki の llSitTarget にある「着座ポイントを更新」などの応用をためしてみるといいでしょうね。

それでは複数のプリムからなる台座(オブジェクト)に、複数のアバターが座り、台座にタッチすることで表示されるダイアログで自分の位置を変える(前後、左右、上下、回転)、というスクリプトのサンプルが以下です。
ポイントは、

1) CHANGE イベント毎にアバターのリンク番号を更新する
2) ダイアログで移動させるときに、その時点での位置情報を取得し、使用する
3) グローバル座標による差をローカル座標上の差に変換する
4) アバターを回すときは、ルートのローテーションで2回除算する
(または PRIM_ROT_LOCAL を使う)
5) llSitTarget と llAvatarOnSitTarget を使わず、座りたい場所にアバターを座らせ、微調整を可能にする

といったところでしょう。サンプル スクリプトとしてわかりやすくするために一部冗長なコードがあったり、情報確認用の llOwnerSay があったり、ダイアログの扱いについてもあまり汎用的にしていませんので、その辺は臨機応変に変更してみてください。
blogSittingScript

2010年10月14日木曜日

[LSL] 位置と回転について ~クォータニオンと移動量~

前回からの続き、、、ではなくて、ちょっと閑話休題。といっても、今回の一連のお話しの中で、私が勝手に造語的に使っている「移動量」って何?の補足みたいなお話しです。

[LSL] 位置と回転について ~移動量という考え方~ のエントリーで、球体で考える空間と位置指定の概念を説明するのに、地球の話を持ってきて「移動量」の話をしていますが、この移動量っていうのが、やっぱりよくわかんない、、、と感じる方も多いと思います。

移動量(正直、これ私が勝手にそう呼んでいるので、一般的な用語ではないことをご了承ください。)はクォータニオンそのものなんですが、イメージとしては地球上のある地点から他の地点までの最短距離(大圏航路)で、ぐるっ!と地球をまわして、一度の回転でA地点からB地点にいって、回転させる軸の傾きも含めたもの、、、としつこく書いています。

ふ~ん、そうなんだ、と思ってくれるといいのですが、「ん~、わかんない」となると、実は先に進めないのも事実。それが2年前の私の状態ですから(笑
イメージ、イメージっていってもしょうがないので、もうちょっと具体的に説明してみたいと思います。ただし、なぜこれまで具体的に説明していないか、、、といえば、最終的には必要になる場合もありますが、最初のほうでは具体的に理解する必要があまりない(というか邪魔な?)知識だと思ったためです。あ、もちろん、ここでも行列計算、虚数といった数学的な話にはなりません。

前のエントリーでも「羽田空港とJFK空港を結ぶ大圏航路でグルッと回す」、それが移動量って言い方をしていますが、一気に回すための傾いた軸って存在しますよね。

クォータニオンからは、まず、その軸の方向を導き出すことができます。その関数が llRot2Axis なんです。そして軸を使ってまわした角度が llRot2Angle なんです。

Rot2AxisAngle2
( 絵心無いわ・・・わかってくれるといいけどw )

この軸の傾き(方向)と回る角度が移動量つまりクォータニオンを構成する要素なんですよね。
実際、Axis のベクターと、Angle の float からクォータニオンを計算する関数が llAxisAngle2Rot になるわけです。これでクォータニオン(移動量)を算出できるのです。

ネットや書籍でクォータニオンを調べると、そもそも LSL で使われる関数などでは説明されませんから、四元数で、実数部分と虚数部分にわかれ、、、、と説明されます。クォータニオンはローテーション型で <x, y, z ,s> の四元数にて LSL でも表現されますが、現実にその x, y, z, s の要素を直接いぢることは、最初の頃はほぼ皆無です。ちなみに2年前に私は ウィキペディアの四元数や、クォータニオンの説明を見てしまい、頭痛&挫折しそうになりましたし、wiki.secondlife.com での llRot2Axis や llRot2Angle の説明では、それらの関数と同じ動きをする llAcos や llFabs, llSqrt, llVecNorm で四元数の要素をいじるユーザー関数を紹介しています。ですが、その特記事項を見ても何を言っているのかわからなかったわけです。

実際はウィキペディアにある内容をもとにクォータニオンは計算され、四元数の各要素となって表現されるのですが、それを理解するためには数学の勉強は必須で、ちょっと敷居が高かったのです。(私にとっては、、、ですが)

このクォータニオンと軸の傾きと回転量の関係がわかっていれば、他のところでも応用可能なような気がしませんか?

回す軸の方向はわかっていて、何度まわしたい、、、ってあるでしょう?おおよそローカル軸が「回す軸の方向」なので、あまり Axis と Angle の関係を理解せずにz軸で回すなら <0.0, 0.0, PI/2> とかにして、llEuler2Rot を使ってクォータニオン(移動量)にして、現在の Rotation に左からかけたりする、、、。でも、ローカルの軸、もしくはグローバルの軸じゃなくても、llAxisAngle2Rot で任意の軸で回すことができる、、、と考えると、ちょっとどこかで使えそうな気がしません?

クォータニオンについては、最初の回で紹介したように、また、何度もしつこくいっているように「球体で考える空間と位置指定」の概念をきちんと持つことで、行列計算や三角関数を深く知らなくても、LSL の関数だけでほとんどの操作は克服できると思っています。その上のステップに行くときに、そこで必要な知識を吸収すればいいわけですよね。

さて、次はオブジェクトに座っているアバタ―を動かす(それも複数のアバタ―)です。

2010年10月12日火曜日

[LSL] 位置と回転について ~ ルートプリムと子プリムたち(2) ~

前回はルートプリムからのローカル座標を使った子プリムの相対位置の算出までご紹介しました。今回は llSetLinkPrimitiveParams の PRIM_ROTATION で指定するローテーションの指定方法をご紹介します。

ですが、、、最初にいっておきます。2010年10月の段階では llSetLinkPrimitiveParams の PRIM_ROTATION の指定には Bug (本当は Bug じゃないかもしれませんが、実装上の不具合というか混乱) があって、適切だろうというローテーション型の数値を渡してもうまく動かないのです。

[追記] コメントいただいたように PRIM_ROT_LOCAL を使うことですべてうまくいきます。    

[JIRA] llSetPrimitiveParams PRIM_ROTATION and llSetRot incorrectly implemented for child prims

回避方法はあります。といっても上記でいう incorrectly implemented (正しくない実装)を使うわけです。ですから将来的にこの回避方法が動かなくなる可能性(期待しない動きにならないこと)があることをご了承ください。


ポイント4 PRIM_ROTATION にはクセがあります

まぁ、、2007年からある問題ですので、ちょっと放置気味ですが、、。(いまさら仕様変更できないのかもしれませんし、JIRA を見るかぎりでは、ほぼみんなあきらめ気味です、、、)

そもそも仕様通りに動かないので、本来あるべき方法を説明しても仕方ないのですが、本来は、llSetLinkPrimitiveParams の PRIM_ROTATION で設定されるべきクォータニオンはルートから見た場合の相対的な回転です。その計算の仕方はグローバル座標軸上における設定すべきクォータニオンから、ルートプリムのローテーションを引いたもの、つまり除算したものになります。
[追記] ルートおよび子プリムのグローバルローテーションによる除算のため、グローバル基準を元にした相対位置となります。そのためもう一度ルートのローテーションで除算しています。これを回避するために、PRIM_ROT_LOCAL を使い、ルートプリムを基準とした相対ローテーションを取得することができるようになりました。

ですが、それを設定しても期待とおりに回転しません。

回避方法は、設定すべき子プリムのローテーションを、ルートプリムのローテーションで2回除算するのです。

なぜか、、、って考えない、考えない。(笑   このエントリーの最後のほうに私なりに考えた「こういう意味?」をまとめました。
また、この方法は llSetPos の wiki の説明でも記載されています。

簡単な例を使ってみてみましょう。
 rotation1
下の平べったい直方体がルートプリムです。直方体の上方向に立方体をリンクしました。これが子プリムになります。この子プリムの立方体を llSetLinkPrimitiveParams の PRIM_ROTATION を使ってまわしてみます。このときに、ルートプリムの直方体を傾けても、期待する動き(回転)をするようにスクリプトを組むのが目的です。

まず、失敗例から。スクリプトは以下になります。
タッチするとローカル Z 軸 45 度立方体が回る、というものです。子プリムのローカル Z 軸なので、期待する動きとしてはルートプリムの直方体が傾いても、直方体にのった状態でくるくる回る感じです。


回転する度に子プリムには自分のローカルローテーションを取得して、llMessageLinked を使い送信、ルートではそのレスポンスをもらったら、子プリムの上に計算したローカルローテーション と llGetLocalRot の値の両方を表示するというものです。

rotation q;
default{
    state_entry(){
        q = ZERO_ROTATION;
    }
    touch_start(integer total_number){
        rotation childRot = llList2Rot(llGetLinkPrimitiveParams(2,
                 [PRIM_ROTATION]),0);     
        vector targetEluer= DEG_TO_RAD*<0.0,0.0,45.0>;
        rotation targetQ = llEuler2Rot(targetEluer);
        q = targetQ*childRot/llGetRootRotation(); //ダメなサンプルですよ!
        llSetLinkPrimitiveParams(2,[PRIM_ROTATION,q]);
        llMessageLinked(LINK_SET,10,"","");
    }
    link_message(integer snd_num,integer num,string str,key id){
        if(num==100){
            llSetLinkPrimitiveParamsFast(2, 
                [PRIM_TEXT,(string)q+"\n"+str,<1.0,1.0,1.0>,1.0]);
        }
    }
}

結果は、ルートに傾きがなければうまくうごきますが、ルートが傾くと以下のようになります。
rot10

そこで、q の計算を


q = targetQ*childRot/llGetRootRotation()/llGetRootRotation();

のようにルートプリムのローテーションで2回除算する、に変えると、ルートが傾いても 45度 ローカルZ軸を中心に回ります。

rot11

画像では小さいですが、ローカルZ軸でまわっていない方の計算したローカルローテーションと、子プリムからもらったローカルローテーションは一致しています。うまくまわっている方は子プリムからもらったローカルローテーションと計算したローカルローテーションが違うのです。たぶん、これが多くのユーザーから Bug と言われる所以でしょう。

つまり、llSetLinkPrimitiveParams で設定したローカルローテーションと、子プリムが回転後に取得したローカルローテーションが違うのです。この例だと「何が問題?」になりますが、たとえば、ある子プリム A の向きと同じ方向を他の子プリム B に適用しようとしたとき、子プリム A のスクリプトでローカルローテーションを取得し、それを使って llSetLinkPrimitiveParams の 子プリムB の PRIM_ROTATION に受け渡してもダメ、、、ということなんです。これは相当悩みます。この場合は、取得したローカルローテーションを、ルートプリムのローテーションで1度だけ除算する必要があります。

ただ、、、これまでの球体で考える空間と位置指定の概念を使ってみると、この2回ルートのローテーションで子プリムのグローバルローテーションを割る、という意味が見えてきます。
子プリムのローテーションをルートプリムのローテーションで除算すると、子プリムとルートプリムの移動量の差分が算出されます。この差分をさらにルートプリムのローテーションで除算するということは、移動量の「基準」をグローバル座標軸に合わせる(ルートを無回転状態にする)、ということです。


つまり、東京からニューヨークの移動量を、東京を緯度0・経度0にしたときの移動量に変換しているのですね。こうするとルートがどの地点にあっても(どんな回転をしていても=東京でなくても)、同じような方向、距離であるルートからの移動量は絶対値的に表現することができます。そうすると、この2回除算するというのは非常に意味のあることだと考えられます。
まぁ、、、最大のハマリポイントでもありますね。

さて、次回はプリムではなくて、椅子(もしくはプリム)に座ったアバターを動かしてみます。

[追記] PRIM_ROT_LOCAL を使うことで上位のように2回の除算をする必要がなくなります。
サンプル スクリプトは以下になります。


rotation q; 
rotation childRot;
default{
    state_entry(){
        q = ZERO_ROTATION;
    }
    touch_start(integer total_number){
        childRot = llList2Rot(llGetLinkPrimitiveParams(2,
                 [PRIM_ROT_LOCAL]),0);      
        vector targetEluer= DEG_TO_RAD*<0.0,0.0,45.0>;
        rotation targetQ = llEuler2Rot(targetEluer);
        q = targetQ*childRot;
        llSetLinkPrimitiveParams(2,[PRIM_ROT_LOCAL,q]);
        llMessageLinked(LINK_SET,10,"","");
    }
    link_message(integer snd_num,integer num,string str,key id){
        if(num==100){
            llSetLinkPrimitiveParamsFast(2, 
                [PRIM_TEXT,(string)q+"\n"+str,<1.0,1.0,1.0>,1.0]);
        }
    }
}


プリム上に表示されるローカル ローテーションも同じものになります。
子プリムのサンプル スクリプトは以下になります。


default
{
    state_entry(){
    }
    link_message(integer send_num,integer num,string str,key id){
        if(num==10){
            llMessageLinked(LINK_SET,100,(string)llGetLocalRot(),"");
        }
    }
}

2010年10月11日月曜日

[LSL] 位置と回転について ~ ルートプリムと子プリムたち

前回ではリージョン座標軸で表現される位置をクォータニオンと球体の中心からの距離で置き換える方法をご紹介しました。空間の概念は X, Y, Z 軸による立方体だけでなく、球体での移動量と球体の中心からの距離で表現できる「球体で考える空間と位置指定」の概念の重要性がご理解いただけたかな、と思います。

ここまででオイラー角による回転について1度も触れていないのは面白いですよね。移動量という言葉を使って「角度」という言葉を使っていないわけです。

プリムをまわす、回転させるときに一番最初に覚えるのは軸を中心とした回転ですよね。わたしもそうでした。Z軸で90度回転させる、なんてことをやるわけで、そのときラジアンによる角度表現が必要である、とか、llEuler2Rot という関数を知ったり、右ねじの法則、グローバル軸を基にした回転と、ローカル軸を基にした回転の違い、その方法を学ぶわけです。

もちろんオイラー角によるプリムの回転で事足りことも多いのですが、スクリプトでいろいろな操作をやろうとすると、はじめから角度がわかっていることって、、、少ないと思います。llGetPosllGetRotllGetObjectDetails, llGetLinkPrimitiveParams などで取れる数値は位置を表すベクター型であり、移動量をあらわすローテーション型のクォータニオンです。なので、位置ベクトルとクォータニオンを駆使して操作することになり、あらかじめ各軸の角度がわかっていれば使えるオイラー角による回転指定は、、、、実は、かぎられるような気がします。

前置きが長くなりましたが、今回は llSetLinkPrimitiveParams などで必須となるルートプリムと子プリムの関係、とくに位置(ローカルポジション)と向き/回転(ローカルローテーション)について考えてみたいと思います。

4. ルートプリムと子プリムたち

複数のプリムをリンクさせるとき、スクリプトを組み込む必要がなければ、あまりルートプリムがどれかを意識しないかもしれませんが、スクリプトをいれてなんらかの操作をしようとすると、ルートプリムがどれか、子プリムでもリンク番号は何番かが非常に重要になります。

基本的なリンク、リンクのさせかたについては wiki の記事や先輩諸氏のブログなどを参照してもらって、ルートプリムに入っているスクリプトから子プリムたちをどのように扱うかを見てみます。

ポイント1 リンクされた子プリムは「ルートだけ」とつながっている

ちょっといきなりハードルが高いかもしれませんが、プリムをリンクさせたとき、子プリムはルートプリムに対してリンクされている、ということを忘れるときがあります。1対1なら直感的ですが、子プリムの数が多くなり、造形的に階層構造のようなオブジェクトになったとき、見た目で土台になっているプリムを動かすと、それに「見た目」でのっているプリムが動きそうな気になるんですよね。

linkedprims

上の絵の緑色のルートプリムを動かせば、リンクされている子プリムたちはすべて追随するのですが、青いプリムを動かしても、見た目その上にある赤や黄色のプリムは動かない、、ということです。上のような単純なオブジェクトだと「当たり前じゃん」と思うでしょうが、造詣をしていって、見た目が子プリム同士関連しているように見えれば見えるほど、ルートだけにしかリンクしていないことを忘れます(笑

それが顕著にでるのが、プリムに座ったアバターを動かすときです。

どうしても座っているプリムを動かせば、座っている(=リンクしている)アバターも動くような気がしてしまいますが、アバターはルートにリンクしているであって、見た目座っているプリムとはリンクしていないのです。

ポイント2 子プリムの位置・回転はルートプリムが「基準」です

ですよね~、と思われるかもしれませんが、わたしも最初にはまった落とし穴は、ルートプリムのローカル座標軸(前後、左右、上下)がグローバル座標軸(東西、南北、天地)と重なっているのがおおよそ Rez した直後の初期値なので、グローバル座標軸を基準とした回転や位置指定を子プリムに対して行い、最初うまく動いている!と誤解してしまうことです。

うまく動いている状態だったのに、オブジェクトの向きを変えたら、予想もしない方向、位置に子プリムが動いた、、、となり、それが予想もつかない動きをするので悩んでしまう、、というものです。

sittingOnChair0

sittingOnChai1

ポイント3 ルートを基準とした位置の算出方法は球体で考える

正直、、、わたしは相当苦労しました。。。前に「位置と回転」について書いたブログが 2008 年のもの、、、当時はクォータニオンを理解しようとして行列計算や、関連しそうなネットの情報、書籍を読んでみて、興味深い内容が多かったものの、それぞれを理解したとはいえませんでした。

最近は wiki.secondlife.com のコンテンツも有志の方による日本語訳が充実してきているので、そこからある程度「こんなものかな」で理解してしまうほうがいいかもしれません。

ルートと子プリムの関係は、これまでご説明してきた「球体で考える空間と位置指定」の概念がわかっていれば比較的簡単に必要な数値の算出が可能になります。(なると思っています、、、)

まず、ルートから見た子プリムの相対位置です。
llGetLinkPrimitiveParams もしくは llGetObjectDetails で子プリムのグローバル座標を取得することができます。ルートプリムのグローバル座標もこの関数以外に llGetPosllGetRootPosition で取得できるので、ルート、子プリムそれぞれのグローバル座標をもとに、ルートプリムからルートのローカル座標(前後、左右、上下)による子プリムまでの「軸上の移動距離」を算出することになります。ただし、この算出の場合も「球体で考える空間と位置指定」を使うことになります。

え?子プリムのグローバル座標からルートプリムのグローバル座標を引けばいいんじゃない?と思いたくなるのですが、その差分はグローバル座標軸における差(東西、南北、天地)であって、ルートプリムからのローカル座標軸(ルートプリムからの前後、左右、上下)での差分ではないのです。グローバル軸とローカル軸が重なっていれば問題ないですが、ずれた(ルートが回転した)瞬間から予期しない動きをしてしまいます。

ルートプリムから見た子プリムのローカル座標上の移動距離を算出する考え方と手順が以下になります。

a) 球体で考える空間と位置指定の概念を使ってルートプリムを球体の中心にもってくるイメージをしてみます

そのときのルートプリムの向きは llGetRot でとったそのままの傾きで、子プリムと一緒に動いてくるイメージです。球体の中心にきた時は、ルートプリムのローカル座標軸とグローバル座標軸はずれている感じです。そしてそのずれは移動量であり、ルートプリムのローテーションになります。

//ルートプリムのクォータニオン
rotation rootRot = llGetRot(); または llGetRootRotation();

b) 中心(ルート)から子プリムまでの直線距離とグローバル座標軸上の移動距離を算出します

グローバル座標軸における2つの位置ベクトル間の距離です。

vector rootPos  = llGetPos(); または llGetRootPosition();
integer linkNum = 2; //ルートは1、それ以降は2~ 
list pList  = llGetLinkPrimitiveParams(linkNum,[PRIM_POSITION]);
vector childPos = llList2Vector(pList,0); 
float dist = llVecDist(rootPos, childPos);

グローバル座標上の子プリムの位置とルートプリムの位置の差分。つまり、ルートプリムが中心のときにグローバル座標上の子プリムの位置ベクトルになります。

vector childVec = childPos-rootPos;

c) ルートプリムをぐるりと回転させて、ルートプリムのローカル座標軸とグローバル座標軸を一致させるイメージを持ってみます

この時の移動量は a) の rootRot だけ「戻る」感じですよね。
ただし、このとき「移動」するのは実は子プリムなんです。ルートプリムは中心にいるので一切「移動」しないわけです。
なので、動かす前の子プリムの移動量を算出します。これは子プリムの向きを表すローテーションではありません。球体で考える空間の話を思い出してください。球体の中心(=ルートプリム)とX軸基準 <1.0, 0.0, 0.0> と自分のグローバル座標上の位置ベクトルから算出する移動量です。自分の位置ベクトルはグローバル座標上の XYZ であり、ルートプリムは球体の中心にきていますから、b) で算出した childVec になります。

rotation childRot = llRotBetween(<1.0,0.0,0.0>,childVec);

そして、ルートのローカル軸をグローバル軸にあわせるために、子プリムの移動量からルートの傾き分の移動量を引きます。(ルートプリムがぐるりとまわって元に戻る感じです。)ローテーションでの計算では除算します。ここがルートと子プリムの関係の最大のポイントです。

rotation q = childRot/rootRot;

これで移動量 q は、ルートのローカル軸、グローバル軸が重なった時点での球体上の子プリムの移動量となります。

d) ローカル座標の位置ベクトルを算出します

ローカル座標とグローバル座標は一致しているので、<1.0, 0.0, 0.0> と llRot2Fwd と使ったこれまでと同じ方法で算出します。

vector offset = llRot2Fwd(q)*dist;

この offset ベクターがルートプリムからの相対位置になります。
どうです?三角関数とか意識しなくても出せるような気がしませんか?
重要なのはイメージなんですよね。

と、、、ちょっと長くなったので、ルートプリムから見た子プリムの向きについては次回にします。

2010年10月10日日曜日

[LSL] 位置と回転について ~ 基準はどこにあるの? ~

前回では移動量(クォータニオン)と高さを使えば空間のあらゆる位置を表現できる、という方法を説明してみました。ただし、その場合でもある地点を「基準」として考えたら、、、という前提があったことを思い出してください。

この基準、、、というのが難しいのです。

3. 基準はどこにあるの?

地球上の位置を考えたとき、よく例にでるのがイギリスにあるグリニッジ天文台の子午線ですが、前回ではそれに赤道も加え、経度0度の子午線と緯度0度の赤道の交点がギニア湾上にある、ということを紹介しました。その位置は「緯度0度、経度0度」の位置です。

そして、その位置は地球の中心から見て「地球の半径」の高さ(あえていえば、海抜 0 m もしくは標高 0 m)を加えることで「ピンポイント」で地球の表面上の位置の特定が可能になります。

そして以下の絵でご説明したように、回転であらわした「移動量」が同じでも、地球の半径に相当する R の距離(もしくは高さ)を変えることで違う位置をさすことが可能だということも理解できたと思います。

rotation

Secondlife のインワールドで移動量と半径Rで空間内のすべての位置を表現するには、考えなくてはならない「基準」が球体の中心 <0.0,0.0,0.0> だけではないのがミソなんです。

地球でいう緯度0度、経度0度、標高 0m の地点はどこにあるのでしょうか。

これ、、、実は明確には無いのです。(今のわたしの理解では^^;)

複数の SIM からなる SecondLife なので、他の SIM をぜーんぶひっくるめて「地球」のような感覚になりがちですが、位置の特定にかぎっていえば 1 つの SIM がすべてです。この1つの SIM で、球体の中心を <0.0, 0.0, 0.0> におき、さらに、LSL で扱いやすくするために、地球上のギニア湾上にある緯度0度、経度0度、標高0m(地球の半径)のような「基準」をグローバル座標で以下の地点だと「仮定」します。

<1.0, 0.0, 0.0>

上の絵で、<0.0, 0.0, 0.0> の球体の中心点からグローバル座標の X 軸上で 1m いった地点。これを緯度0度、経度0度、標高0m と同じように扱ってみるのです。ここが絵でいうピンクの線の基準。

ええ、、、でも、たとえば自分が <100.0, 82.0, 36.0> のグローバル座標の位置にいて、それで <1.0, 0.0, 0.0> の基準点(もしくは基準ベクトル)をつかって何がわかるの?となりますよね。ただ、もう一度思い出してください。同心円(もしくは同じ球面)にいなくても、移動量(クォータニオン)は 上の図でいえば A1, A2, A3 は同じ、B1, B2, B3 も同じ、、、ということを。そうすると、半径 1.0 m の球面上で、上の絵の中の線で言えば赤い直線、青い直線上の地点への移動量がわかれば、あとはどれだけ中心から離れているかの組み合わせで、<100.0, 82.0, 36.0> の地点を示すのと同じことができるのです。

そのための便利な関数が llRotBetween() なのです。

wiki の説明では llRotBetween の引数には単位ベクトル的な数値(x や y や z が 1.0) しか入れていませんが、この関数が本領発揮してくれるのは単位ベクトル以外のベクトルをいれても、2つの位置間の「移動量」を計算してくれるのです。

上の絵でいうと、A2 と B3 の間の移動量を出してくれる、ということです。同心円上の A2 と B2 の移動量も、同心円上にない A2 と B3 の移動量は同じことはもう理解できますよね。違うのは中心からの距離、半径 R なのです。

なので、グローバル座標上の <100.0, 82.0, 36.0> を移動量(クォータニオン)と <0.0,0.0,0.0> からの距離で表すと

移動量(クォータニオン)r は、
rotation r = llRotBetween(<1.0, 0.0, 0.0>,<100.0,82.0,36.0>);

<0.0, 0.0, 0.0>から<100.0, 82.0, 36.0>までの距離は
float d = llVecMag(<100.0, 82.0, 36.0>);
または
float d = llVecDist(<0.0,0.0,0.0>,<100.0,82.0,36.0>);

となります。この r と d でグローバル座標上の位置の計算は以下で可能です。

vector v = llRot2Fwd(r)*d; //注1) なぜ llRot2Fwd か理解できない人は最後の(注1)を参照してみてください。

これで、v の値は自分の位置の <100.0, 82.0, 36.0> になるのです。

この基準の考え方を応用すると、リンクされた子プリムのルートプリムからの相対位置を計算することができます。ルートに対する相対とは「ルートから見て(ルートを中心として)」どのくらい差分があるか、ということで、特に llSetLinkPrimitiveParams() で子プリムの位置や傾きを設定する PRIM_POSITION や PRIM_ROTATION で使用できます。子プリムがルートからみてどの位置にあるか、どんな傾きになっているかを算出してはじめて llSetLinkPrimitiveParams が使えるようになるわけです。そのときルートプリムは自分が傾いているなんて考えていません。また自分がグローバル座標のどの位置にいても、「自分からみてどのくらいの距離にいるか、自分から見て前後・左右・上下のどのくらいの位置にいるか」が重要となります。

次はここまでの知識を元にルートプリムと子プリムの関係について考えてみたいと思います。

(注1)llRot2Fwd を使ったのは、基準となる位置(ベクトル)を <1.0, 0.0, 0.0> と仮定したためです。X 軸は東西であると同時に前後になります。<0.0, 0.0, 0.0> から前に1歩進んだ状態で、移動量によってくるりと回転した状態からさらにベクトルを伸ばそうとするので前に進む、なので llRot2Fwd を使います。

もし基準となる位置(ベクトル)を <0.0,1.0,0.0> としたら、<0.0,0.0,0.0>から左に一歩分横に移動したようなものです。この状態で移動量分くるりとまわし、ベクトルを伸ばそうとすると、今度は llRot2Fwd ではなく llRot2Left を使って左に進むことでベクトル算出をすることになります。

2010年10月9日土曜日

[LSL] 位置と回転について ~ 移動量という考え方 ~

前回、位置を表すには2つの方法があって、そのうちのひとつに地球を例にとって球体における位置の指定についてご紹介しました。

今回はその球体における位置指定について具体的に見ていきたいと思います。

2. 移動量という考え方

前回では成田空港と JFK 空港の位置は「緯度」と「経度」で指定できることをご紹介しました。緯度、経度が何か、、、はここでは詳しく説明しませんが、数値データで表現されるこの緯度、経度、、、それぞれの数値が 0 のところってどこでしょう?そしてそれはどんな意味を持つのか考えてみます。

lat0longi0

緯度0度(つまり赤道上)で、経度0度(つまり、イギリスのグリニッジ天文台を通過する子午線)が交わる地球上の位置は残念ながら海上です。アフリカのガーナの下、ギニア湾上にありました。(上の Google Map の 青いマーカーです)

この緯度・経度が 0 の地点から「ある移動量で動いた地点」をクォータニオンで表すことができるのです。クォータニオンはプリム/オブジェクトの「回転」で出てくる重要な要素ですが、前回ご紹介した大圏航路をつかってある地点、たとえば成田空港まで(球面上で)緯度0度、経度0度の地点から線を引く時、地球を「ぐるっ」と斜めになっている軸で回すと、それも1回の回転だけで青のマーカーを成田空港のある位置まで「移動させる」ことが想像できると思います。(今は軸が何度傾いて、、、とかは考えないようにします。地球を回すと成田空港も逃げちゃうよ、、という突っ込みはなしで^^; 気になる人は成田空港があった位置まで、、、とでも置き換えてください。)

googlemap
緯度0度、経度0度から成田空港へは地球の裏側にいくので、成田とJFKで大圏航路を。。。。

この斜めの軸でぐるっと回し移動させる傾きも含めた「量」を移動量として理解します。そして、その移動量は回転なのでクォータニオンで表現できる、、、と覚えます。
そうすると、緯度0度、経度0度を基準点とした成田空港地点への移動量(クォータニオン)は、成田空港の位置そのものをあらわしていると言えます。

なんとなく、基準点さえ決まっていれば移動量を用いて場所の特定ができそうかな、、、と思ってもらえればいいのですが。

ただ、ここで疑問が湧きます。Seondlife のインワールドではグローバル座標による位置の指定は直観的で、<24.0, 120.0, 30.0> であれば <0.0, 0.0, 0.0> から X 軸のプラス方向に 24 m 進んで、Y 軸のプラス方向に 120m 進んで、Z 軸のプラス方向に 30m 上がれば、そこが指定されている位置だということはわかります。クォータニオンを使った場合、球体の中心は、、、えっと、SIM が 256m X 256m X 256m の立方体だから、その中心は 128m x 128m x 128m、、、あ、でも高さはもっと何千メートルもあるから、、、あれ、中心ってどこだろう????と思います。私も最初のころは、これでつまづいていたんです。

クォータニオンを使った位置指定の重要なポイントは、上の疑問にあるように「球体の中心」をどこにもってくるか、、、なのですが、グローバル座標(リージョン座標)で考えるときは、そのものズバリ <0.0, 0.0, 0.0> を球の中心として考えるのです。
ん~、それですべての位置の表現ができるの?と思いますよね。クォータニオンによる位置の指定は直観的ではないので、もうすこし我慢してお付き合いください。

いきなり3次元だとつらいので、ちょっと高さは考えないで平面で移動量(クォータニオン)と位置についての関係を見てみたのが以下の絵です。

rotation 

いわゆる同心円のお話しですが、ピンクの線を基準として青い線分だけ回ったとします。青い線の回転量は R1 の円上でも、R2 の円上でも、R3 の円上でも同じですよね。ただし、R に相当する半径の長さが違うので、A1, A2, A3 は違う位置をさしている、、、ということです。赤い線上の B1 ~ B3 についても同じことが言えます。回した角度(移動量)は同じでも、半径が違えば指し示す位置が違う、ということで、地球上の高さ/標高が違う同じ緯度・経度の位置の指定方法をイメージするとわかりやすいと思います。

移動量、つまりクォータニオンと、上述の半径 R、地球上でいえば標高の組み合わせで、空間上のすべての位置を指し示すことができる、ということになります。

グローバル座標では <0.0,0.0,0.0> を球体の中心として考えてもよさそう、、、と思いますが、上の例でのピンクの線の「基準」はいったいどれか、、、、基準とした中心が <0.0,0.0,0.0> 以外の場合は、、、など、もう少しこのあいまいそうな「基準」について考えることで、グローバル(絶対)位置とローカル(相対)位置の理解が深まるはずです。

次回は「基準」について考えてみます。

2010年10月6日水曜日

[LSL] 位置と回転について ~ 位置を表す二つの方法 ~

何年やってもなかなか理解し難いのがオブジェクトの位置と回転の扱い方という方は多いように思います。
多くの先輩諸氏がブログなどに Secondlife や LSL での「位置」と「回転」に関する情報を残してくれていますが、前提とする知識のレベルが高かったり、専門的であったりして、自分のレベルに合う情報をなかなか見つけることが難しいエリア、話題ですよね。
私もちょっと避けてきたのですが、この数ヶ月やらなきゃいけない課題があり、ようやく、というか、なんとなく、、理解できたような気がしたので、自分の勉強も兼ねてまとめてみようと思います。
今のところ以下の6回にわけて、Secondlife と LSL による位置と回転(向き)の考え方をまとめてみようと思います。最終的な目標は複数プリムからなるオブジェクトにアバタ―が座った時に、そのアバタ―を自分の思い通りにスクリプトで動かすことができるようにしたいと考えています。

1. 位置を表す二つの方法
2. 移動量という考え方
3. 基準はどこにあるの?
4. ルートプリムと子プリムたち
5. アバターにスクリプトはいれられない
6. スクリプト連携による方法

これらの投稿の課題として、なるべく数学的な要素を省き、三角関数や行列計算、虚数などの深い理解を必要としない形でオブジェクトやアバタ―を動かすことができればいいな、その内容を伝えられたらいいな、と思っています。

1. 位置を表す二つの方法
3次元空間における位置と向きの指定が難しいのは、もしかすると最初の出だしに問題がありそうな気がしました。それは空間の概念です。簡単すぎてあまり深く考えていませんでしたが、二つの方法 (グローバルとローカルじゃないですよ) があることをしっかり理解したほうがあとあと楽になりそうです。

私たちが最初に理解するのは XYZ 軸を使った位置の指定方法です。SIMの中で東西南北天地直交した軸に沿っていきたい場所、今いる場所を特定できます。
同じように XYZ 軸を使って東西、南北、天地に関係なく、いま自分が向いている方向で前後左右上下直交する軸に沿っていきたい場所を指定することもできます。それぞれをグローバル座標軸(もしくはリージョン座標軸)、ローカル座標軸を使った位置の指定と呼びます。
このあたりは、この話題にご興味を持たれた方はすでにご存知かと思います。
また、私のブログでもかなり前に触れています。(混乱を避けるために、以下の私のブログは読まなくてもいいです。)

位置と回転を理解したい1
位置と回転を理解したい2
位置と回転を理解したい3

過去に書いたこの上記3つのブログでも意識していなかった空間の概念というが、位置の指定方法における別のやり方です。それがクォータニオンを使った位置の指定です。えっ?クォータニオンって回転じゃないの?と思われるでしょう。私もつい最近までそうでした。(^_^)

クォータニオンが何かを数学的に理解するのは正直時間がかかります。行列計算、三角関数、複素数、虚数、ジンバルロック、、、などなど。でも、数学的な理解が目的ではないので、ここではクォータニオンをある点からある点への「移動量」として理解してみようと思います。ここでは移動量が何か、何で構成されるのかは考えず、とにかく位置 A から位置 B に移動するのにクォータニオンという「移動量」を使えば移動できる、と考えるわけです。また位置 A や位置 B についてもクォータニオンで表現できる、と覚えます。

この移動量による位置指定の概念を理解するのに一番良い、第一歩として「地球」上の位置を考えてみます。

たとえば、東京からニューヨークに移動するとします。よりわかりやすくするために、成田空港から JFK 空港に直行便があって、それらの空港間を移動すると考えます。一番最短な距離で成田から JFK にいくには「大圏航路(たいけんこうろ)」という最短距離を飛ぶのが理想とされています。途中 LAX (ロサンゼルス)やアンカレッジに寄り燃料補給せずに直接行けるなら、この大圏航路を使えばいいのです。とにかく、大圏航路は地球上の2点を結ぶ最短距離で、それは1つしかない、と理解してみます。
googlemap
また成田空港という場所の指定を地球上でやろうとすると、、、日本の住所もありますが、地球規模で考えると緯度と経度を使いますよね。(緯度35.763983, 経度140.384644) JFK 空港も同様に緯度・経度で位置を指し示すことが可能です。(緯度40.6444122, 経度 -73.782745)つまり、、、地球上の「どこ」でも緯度と経度で位置を指定できます。

ちょっと、まって、、、「地表」ならともかく、地球上には「高さ」があるわけだから、富士山の頂上と、道路の上では「位置」は違うじゃん、と思いますよね。でも、その違いは「標高」や「高度」、「海抜」で表現すればいいのです。
よって、地球上では「緯度」「経度」「高さ」の3つの数字があればどんな位置でも特定が可能なのが、なんとなく想像つくと思います。

位置を表す二つの方法の言い換えると、「立方体で考える空間と位置指定」「球体で考える空間と位置指定」と考えることもできます。

次回はとくに球体で考える空間における「移動量」とクォータニオンをインワールドに適用したときの考えについてまとめてみようと思います。

2010年9月18日土曜日

Electrogram2010 Siva

2010年9月11日~12日に行われた Electrogram2010 Sive。会場のクロス SIM ダンスパネルと、VectorChaos スクリプトスタッフ兼ビデオスタッフとして参加させていただきました。
そのときの模様の SS からお気に入りをご紹介。

赤を基調とした会場 (とりあえずポーズ(w) 
The event is coming soon...

ぷーちゃん制作の特別ステージ
Electrogram 2010 Siva

ぷーちゃ、、、もといシバ
Electrogram2010-P

RMO
RMO

Soleil
Soleil

Hiroshi Kumaki
Hiroshi Kumaki

Chouchou
Chouchou

mkIISR
=?utf-8?q?mk=E2=85=A1SR_-Rebuild-?=

V.L.T.G
V.L.T.G

Vector Chaos with P-Size
VectorChaos

そして、サプライズ イベント
Extra - Electrogram 2010
RMO の matsuken さんの祝福の歌が感動的でした。

って、、、パソコン変えたらなんか SS 綺麗にとれるようになったかも?

そのほかの SS は私の flickr photostream で見ることができます。

みんな、お疲れ様~。
でも、わたしの Electrogram2010 はまだ終わっていないのでありました・・・
Vector Chaos の SS が少ないのはビデオを撮っていたから・・・で、素材だけで、当日分7GB、リハ含めると 24GB もあるよ~。(笑
もうちょっと待ってね~。

[追記] VectorChaos with P-Size “Don’t Stop Your Dance” あがりました~。

2010年8月21日土曜日

BareRose 5yr Photo Contest

たまたま前に Filckr に投稿したフォトが BareRose のスタッフさんの目にとまり、B@R のフリッカーグループに招待されていたのですが、今回、BareRose の5周年記念フォトコンテストへの参加のお招きをいただき以下のフォトを投稿したら、、、3位もらっちゃいました。

B@R from Inferno

コスチュームは左からいずれも BareRose の DoctressQ, NIGHT MISTRESS そして BLACK BRIZARD になります。お友達作成のお墓セットがあったので、それでスカイを作っての撮影で、画像は Windlight の設定のみで霧の雰囲気をだして、フレームのレイヤーを上からかぶせただけ、、というもので、、、正直他の方の作品に比べると恥ずかしいくらいだったんです。

最初はレタッチして HDR っぽい、色を鮮やかにしたフォトだったのですが、お墓の雰囲気ならもっと暗めにして、霧みたいな感じがいいんじゃない?というアドバイスをお友達からもらってその通りにしたのが幸いだったようです。HDR のような鮮やかできれいなフォトのエントリーが多かった分、逆に目立ったのかな?

1st Prize をゲットした作品はこちらです。Ocean Blackthrone さんの作品です。

Bare@Rose 5th Anniversary Submission

2nd は Jill Black さん。
[追記] Jill Black さん、Flickr から退会されたようで写真がなくなりました。

3rd は私の他にお二人いらっしゃって、Bella Slade さんと Wakapa Hermit さん。

Third Place Winner - B@R 5YA Photo Contest

ね、、、、ちょっと3位いただいたのが不思議ちゃん(笑

2010年8月19日木曜日

新しい Viewer – Official 2.1.1

なんか人知れず 2.1.1 出てます。
ビューワーとかにもアテンションでないし、オフシャルブログにも特に書かれていないようなのですが。。。

V211SL

http://wiki.secondlife.com/wiki/Release_Notes/Second_Life_Release/2.1.1

そして、なんか不安定とかいうブログの書きこも散見されていますが、、、それ見る前にダウンロード&インストールしっちゃいました。><
ですが、どうやら、私はなんとか動いているようで、、、ちょっと不安な方は様子見したほうがいいかも。。。

[追記 2010.8.21]
うーん、やっぱり調子悪いかも。最初の立ち上がりでフリーズして、ビューワー落として再度立ち上げると、、、やっとまともに? うーん。

2010年8月2日月曜日

一夜限りのステージ

セカンドライフ内の日本踊り子協同組合という集まり(コミュニティ?)がございまして、半年に1度くらい「踊り子組合ダンス会」なるものが開催されます。
ダンス会は組合参加者およびその親族もとい ^^; その友人のみが会場に入ることができるクローズな会なのですが、組合自体はだれでも参加できるので、実質はオープンなんですけどね。

今週の土曜日に第4回踊り子組合ダンス会が開催されます。ステージは規格がきまっていて、それにあったものを各ダンサーが用意するんです。

今回、私たち(プリンダンス部)はアニメのマクロスFをモチーフにした内容で(え、どこがダンス?という突っ込みはなしで・・・)参加しますが、うちの部の大道具さんがステージ作ってくれました。

Rehearsal

一夜限りのステージです。もったいないくらい素敵に仕上がっています。
スカルプでモノづくりできる人尊敬します。ほんとに。
で、、、照明・効果がまだ最終形になってない~(スクリプト要素が強いので、私とパーティクル担当のそんちょのお仕事。でも、私が遅くてね、、、)

がんばります~。

で、前回ご紹介した llLinkParticleSystem ですが、こういった舞台に組み込んでいくと、当然のようにリンク番号が変わるわけです。なので、Link番号を決め打ちしてると思いもよらぬところからパーティクルがでるわけですよね。

それを回避するためにエミッターさせたいプリムにスクリプトを入れて、llGetLinkNumber でとった値を llMessageLinked でメインプリムのスクリプトに渡し、、、、舞台に他のプリムが新たにリンクされたらその値の受け渡しを再度行い、、、、

あれれ、こんなことやるんだったら、最初から llParticleSystem をエミッタさせたいプリムにいれて llMessageLinked で開始させたほうが楽じゃない?

Link 番号って変わるから、こういうステージにリンク、、、なんてことがあるなら、ちょっと使わないほうがよかったんでしょう。

と、、、使ってみて、こういう失敗して、覚えていくのでしょうね。

[追記] ラスト リハーサルの模様
Reha Last

2010年7月6日火曜日

[LSL] Link 系ファンクション

ひさしぶりに、Linden Script ネタです。
Link に関連するファンクションが増えてますね。

たとえば、llSetLinkPrimitiveParamsFast などはプリムのリンクを多用している人にとっては待ちに待った機能ですね。メインのスクリプトから子プリムたちの操作に遅延が発生しないからです。遅延以外は llSetLinkPrimitiveParams とまったく同じです。

llSetLinkTextureAnim も最近追加された Link 系のファンクションですね。これも子プリムの面に対して Texture Animation (アニメーションGIFみたいな動く画像)を貼り付けることができるようになりました。

おもしろいのは llLinkParticleSystem です。
パーティクルってなかなかむずかしいのですが、wiki にはとても詳しくその仕様について日本語ページに書かれています。(関係者・翻訳者のみなさん、本当におつかれさま&ありがとうございます)

ポイントは、パーティクルのエミッター(発生源とでもいいましょうか)はプリム1個に対して1つしか作ることができない、ということ。パーティクルを発生させるスクリプトを複数、1つのプリムにいれても、挙動がおかしくなるのはそのせいです。

もちろん、llParticleSystem によってパーティクルを発生させるスクリプトをそれぞれのプリムにいれて、それらを Link し、llMessageLinked で各プリムにメッセージを送って操作するやり方も可能でしたが、llLinkParticleSystem を使った複数のスクリプトをルートのプリムにいれて、llMessageLinked であったり、touch_start, listen などのイベントを各スクリプトが拾うことで、一斉・同時に違うパーティクルを出すことが可能になりました。ここのプリムにスクリプトが分散されていない分、スクリプトの修正やメンテナンスが楽になっていると思います。

パーティクルの色や形を変えたものを同時に出そうとすると、この llLinkParticleSystem はとても使い勝手がよいわけです。

kira

llLinkParticleSystem 利用の注意点としては、もし、パーティクルに画像を指定した場合は、発生源である(子)プリムにその画像が存在していないと、デフォルトのパーティクルが使われるようです。もしかすると Key 指定だと存在しなくても OK かもしれませんが、string による画像名指定だとだめでした。

あと、これら Link 系のスクリプトを使う場合は、ルートプリムはどれか、子プリムはいったいいくつ Link されているのか、といったことを常に意識しなくてはなりません。

llGetNumberOfPrims その時点で Link されているプリムの数を取得します
llGetLinkNumber 自分の Link 番号を取得します
llGetLinkKey Link 番号を指定して Key を取得します
llGetLinkPrimitiveParams Link 番号を指定してプリムの情報を取得します
llSetLinkPrimitiveParamsFast Link 番号を指定して、リンクオブジェクトの設定を変えます

llGetLinkNumber は子プリム内でしか使えませんが、ルートのメインスクリプトと子プリムのスクリプトなどを llMessageLinked で複合させて使うことで、今いくつ Link されていて、Link 番号の 2 は何で、3は、、、とチェックすることができます。
スクリプトによる Link  番号決め打ちでもいいのですが、その際は Link させる順番に細心の注意を払うことになります。特に HUD などを作るときは Link させる順番に気を付けるか、スクリプトにより Link 番号とプリムのマッチングを行わせる、といった方法がありますね。また、プリムに座ったアバターを操作するときなども上述の関数を多用します。

2010年7月2日金曜日

YOUR WORLD, YOUR IMAGINATION, YOUR LIFE

お友達の日記に紹介されていた印象的な vimeo のビデオです。

Breathe 2 "it's a wonderful Second Life" from samlowry on Vimeo.

これ、公式にしてもいいんじゃない?(笑
M Linden のアナウンスでは、よりソーシャルな機能をいれていく、としてるけど、facebook や mixi と同じ方向を目指しても違うような気がしていたんですが、このビデオを見て、はっ、と気づきました。そうそう、YOUR WORLD, YOUR IMAGINATION, YOUR LIFE って、Secondlife はじめた最初のころよく見ていたフレーズだったことを思い出しました。

メインランドの Sandbox ではじめてべニア板のプリムを Rez したときの感覚、他の人の作品、SIM の世界観をみて感動したこと、こんなの作ってみたい!と思ったことなど、、、。

そして何より、このビデオで紹介されている SIM のクリエーターに日本の人が多いこと。

バタ臭くて日本じゃはやらない、と散々揶揄されましたが、日本人のクリエーターはその部分を自らのイマジネーションと作品をつくる技術でカバーしてきましたね。

創業者のフィリップが CEO として Linden に戻りました。原点回帰的ながらも、さらなる進化があれば、まだまだ楽しめると思ったのでした。

2010年6月30日水曜日

Server 1.40.2 と Viewer 2.1 ベータ

サーバーが 1.40 になって Havok7 が!なんて喜んで、物理玉(でも、一時オブジェクト)をブンブン rez して遊んでいたのですが、気が付いたら 1.3x に戻ってました、、なんてことがありました。

リンデンのオフィシャルブログによると、1.40 の改良版である 1.40.2 に6月29日から7月1日でサーバーがアップデートされるとのこと。

オフィシャルブログ Server 1.40.2 Deploy

リリースノートみると、やっぱり、Havok7 のせいなのか、はたまた関係ないのか、リンク、コリジョン関連で不具合があったようですね。乗り物系(VEHICLE) での不具合はすぐに報告あがりやすいですし。

あと Viewer 2.1 がベータになりましたね。
まえに試したときは表示上スクリプトのソースの改行がなくなっていて、スクリプトを扱うことができなかったので、すぐに使うのをあきらめましたが、今度は治っているようですね。
また、以前は Viewer の XML 設定ファイルをいぢらないとだめだった「チャット入力ボックスの幅」なんかも、ドラックして広げたり、狭めたりできるようです。これはうれしいかも。
このあたりの紹介は Torley がビデオでしてるので、ぜひ見てみてください。


サイドバーが嫌い、使いづらい、といわれている Viewer2 ですが、私はどちらかといえば Viewer2 に慣れてしまって、逆に今エメラルドを使うと戸惑うこともしばしば。

慣れると使いやすいと思いますよ~^^

2010年6月13日日曜日

The STREET4 – June 14th!!!!

Studio 4D さんの the street4、6月14日に発売決定~
そして以下の PV が!

かっこいい~

2010年5月24日月曜日

THE STREET4 coming soon!

Studio4D さんのブログに来月発表新作の告知が!
それも人気シリーズ STREET ですよ!

street4

まだ発売日などは公開されていませんが、Studio4 さんのブログをチェックしてくださいね~。

2010年4月29日木曜日

VMD Viewer で Shift-jis...の対処方法

Secondlife のサーバーがメンテ(正確には障害みたい)なので、MMD –> SL でたまにあるトラブルというか対処方法をご紹介。以前の投稿でもちょっとだけ触れた件です。

MMD  (MikuMikuDance) のモーションデータの VMD ファイルを mio の VMD VIEWER で読み込もうとしたとき、以下のようなダイアログが表示されて変換できないことがたまにあります。

vmdviewer load error1

‘Shift_jis’ codec can’t decode byte 0x90 in position... というメッセージなので日本語関係かな、と推測がつくのですが、このメッセージは多くの場合、オリジナルの vmd ファイルが日本語で、それを英数字に名前変更して読み込ませたときに起こるようです。ただし、名前変更だけでもうまくいく場合もあります。

こんなときは、その VMD ファイルを MikuMikuDance に読みこませて、あらためてモーションの保存をするとき英数字の名前にしてあげると回避できます。
もちろん、MikuMikuDance がインストールされているのが前提です。MMD のインストールは VPVP Wiki を参考にしてください。

1. MMD でモデルを読み込む
MikuMikuDance を立ち上げて、画面中央下の [モデル操作] の [読込] をおして、モデルを読み込みます。この場合、どのモデルを選んでもかまいません。モデル読み込み

2. モーション データを読み込む
メニューバーの [ファイル] から [モーションデータ読込] を選択します。
vmdload

モーションデータ対象のモデルと、読み込んでいたモデルが違う場合は以下のダイアログがでますが、[OK] を押して続行します。
vmdload_dialog

モーションが読みこまれると、ちゃんとモーションデータの最初のポーズをします。
vmdload2

ものすごくモーションデータが大きいときは以下のように (応答なし) なんて状態になりますが、あわてず待ちましょう。12分のモーション(!!)は読み込むまでに 5分かかりました、、、。
vmdload8

画面右下の [再生] ボタンを押せば、モーションの確認ができます。スカートや髪などはモデルによって違うので、微妙な動きをしていてもそこは無視します。
vmdload3

3. モーションデータを保存する
上記 2 で [ファイル] - [モーションデータ読込] をしましたが、その下に [モーションデータ保存] があるので、それをクリックして、英数字の名前でモーションデータを保存します。

これで VMD Viewer で読み込むことが可能になります。