2008年08月07日
パーティクルの復習^^ ほたるの光^^

ほんとひさしぶりぶりに、ものづくり^^
テレビで蛍を復活させる特集みたいなのやっていて、思った以上に蛍の光って明るいこと知って、急に作りたくなりました^^ ほんとは蛍作って、おしりだけ光らせるのもいいんだけど、今回はパーティクルってことで。
実は、かなり忘れてました。急遽自分のブログ見直しました>< 去年パーティクルについて書いたとき、かなり調べて、ほぼ完璧って自分じゃ思ってたんだけど>< まあ、今もそんなに変更はしてないだろうということで、去年の11月17日のブログを参考にしました。今は、スクリプトエディタの画面で、日本語が表示されるようになったので、すごい楽です。
で、ほたるのひかりです。
default{
state_entry(){
llParticleSystem([]);
}
touch_start(integer detected){
if(llDetectedKey(0)==llGetOwner()){
state start;
}
}
}
state start{
state_entry(){
llParticleSystem([
PSYS_SRC_PATTERN,PSYS_SRC_PATTERN_EXPLODE
,PSYS_PART_FLAGS,(0
| PSYS_PART_EMISSIVE_MASK
| PSYS_PART_INTERP_COLOR_MASK
| PSYS_PART_INTERP_SCALE_MASK
// | PSYS_PART_WIND_MASK
)
//各設定
//パーティクル開始時の透明度、0~1(0が透明)(float)
,PSYS_PART_START_ALPHA,1.0
//パーティクル消滅時の透明度、0~1(float)
,PSYS_PART_END_ALPHA,0.2
//パーティクル生成時の色、0~1(vector)
,PSYS_PART_START_COLOR,<0.0,1.0,0.0>
//パーティクル消滅時の色、0~1(vector)
,PSYS_PART_END_COLOR,<0.0,1.0,0.0>
//パーティクル開始時のサイズ、0.03125~4m、XとYの2次元(vector)Z値は無視される
,PSYS_PART_START_SCALE,<0.04,0.04,0.04>
//パーティクル消滅時のサイズ、0または、0.03125~4メートル、XとYの2次元(vector)Z値は無視される
,PSYS_PART_END_SCALE,<0.5,0.5,0.2>
//1つのパーティクルの寿命、30秒まで(float)
,PSYS_PART_MAX_AGE,8.0
//視界に入ってからのパーティクルシステムの有効時間(噴射し続ける時間)
,PSYS_SRC_MAX_AGE,0.0
//パーティクルの加速度(vector)m/s 擬似的な重力 0 または 0.007815~100
,PSYS_SRC_ACCEL,<0.0,0.0,0.005>
//1回の噴射あたりのパーティクル生成数(integer)
,PSYS_SRC_BURST_PART_COUNT,3
//パーティクル生成地点の中心からの距離、メートル(float)PSYS_SRC_PATTERN_DROPには使えない
,PSYS_SRC_BURST_RADIUS,2.0
//噴射の間隔、秒(float),0秒で連続
,PSYS_SRC_BURST_RATE,5.0
//噴射するときの最小スピード(float)
,PSYS_SRC_BURST_SPEED_MIN,0.05
//噴射するときの最大スピード(float)
,PSYS_SRC_BURST_SPEED_MAX,0.1
]);
}
touch_start(integer detected){
if(llDetectedKey(0)==llGetOwner()){
state default;
}
}
}
オーナーがタッチすると、パーティクル(蛍の光)を発光します。もう一度タッチでとまります。
去年2回にわたって、パーティクルについては書いてあるので、それを、見返していただいて、あとは個々の説明を読みながら値を変更して確かめてるうちにマスターできると思います。
あしたで、SLに生まれてちょうど1年というきりのいい日になるので、これを公開するとともに、フリーの商品としてしばらくの間お店に置くことにします。ねこねこ屋の場所はプロフィールのところにあります。(パッケージングはあしたやります><)
またすこしずつものが作れるようになったらいいなぁと思っています。これからもよろしくね^^
2008年03月07日
物理そしてビークル

ブログかかなあかんと思いつつ、ビークルのスクリプトいじってたら、ぜんぜんまとまんなかったよ。
リンクされているオブジェクトがある場合、そのなかのひとつを物理にしようとしても、ならないのはわかっていたんですが、このように他のものに触れているだけでも物理にできなくなったようです。それと、少し持ち上げて、物理にして下に落ちたとき、以前だったらぶれてころがっていくのに、今はその位置にとどまるようです。いつごろからかわからないのですが、微妙に物理に関しても調整されているようです。まず以前からそうだった、リンクされているものの一部を簡単に物理にできるようだと、空中にあるオブジェクトが急に落ちてきたりして危険なのでできないようになっているのはわかります。でも、触れているだけで、物理にできないというのは少し問題があるようです。最初から持ち物のなかにはいっている Library の Object のなかにある Kart を rez すると、なぜか動きません。わたしが始めて書いたビークルのスクリプトを入れたときも動かなかったです。原因がわからずに、ビークルってすごく難しいと思わされました。結局のところ、触れていることが原因で物理になりにくいので、 rez して乗るときに少し浮かすように変えたら、動くようになりました。この持ち物に入っている Kart も少し浮かしてやれば動くようになります。ただし、スピードがですぎることと、はねるので^^ 広いとこで試してください。

このようにけるところがっていくので、もうすこし動きを調整してやったら、球技などの競技として成り立ちそうです。

で、さっそく実験です。バンクとフリクションとフラグが抜けているのですが、一応、タッチするとビークルになって、コントロールできるようにしました。これで、数値を変えていろいろ試します。
integer i=0;
vector ichi;
default{
on_rez(integer num){
llResetScript();
}
state_entry(){
ichi=llGetPos();
llSetPos(ichi+<0.0,0.0,1.0>);
llSetVehicleType(VEHICLE_TYPE_AIRPLANE);
llSetVehicleVectorParam( VEHICLE_LINEAR_MOTOR_DIRECTION, <0, 0, 0> );
llSetVehicleFloatParam( VEHICLE_LINEAR_MOTOR_TIMESCALE,2.0 );
llSetVehicleFloatParam( VEHICLE_LINEAR_MOTOR_DECAY_TIMESCALE, 0.0 );
llSetVehicleVectorParam( VEHICLE_ANGULAR_MOTOR_DIRECTION, <0, 0, 0> );
llSetVehicleFloatParam( VEHICLE_ANGULAR_MOTOR_TIMESCALE, 0 );
llSetVehicleFloatParam( VEHICLE_ANGULAR_MOTOR_DECAY_TIMESCALE,0.0);
llSetVehicleFloatParam( VEHICLE_LINEAR_DEFLECTION_EFFICIENCY,0.0);
llSetVehicleFloatParam( VEHICLE_LINEAR_DEFLECTION_TIMESCALE, 120 );
llSetVehicleFloatParam( VEHICLE_ANGULAR_DEFLECTION_EFFICIENCY,0.0);
llSetVehicleFloatParam( VEHICLE_ANGULAR_DEFLECTION_TIMESCALE, 120);
llSetVehicleFloatParam( VEHICLE_HOVER_HEIGHT, 18 );
llSetVehicleFloatParam( VEHICLE_HOVER_EFFICIENCY, 1.0 );
llSetVehicleFloatParam( VEHICLE_HOVER_TIMESCALE, 1.0 );
llSetVehicleFloatParam( VEHICLE_BUOYANCY, 1.0 );
llSetVehicleFloatParam( VEHICLE_VERTICAL_ATTRACTION_EFFICIENCY,0.5);
llSetVehicleFloatParam( VEHICLE_VERTICAL_ATTRACTION_TIMESCALE,0.3);
}
touch_start(integer detected){
i=i+1;
if(i==1){
llSetStatus(STATUS_PHYSICS,TRUE);
llRequestPermissions(llGetOwner(),PERMISSION_TAKE_CONTROLS);
llSetTimerEvent(1.0);
}
else{
llSetStatus(STATUS_PHYSICS,FALSE);
llReleaseControls();
llSetPos(ichi);
i=0;
}
}
run_time_permissions(integer perm){
if(perm & PERMISSION_TAKE_CONTROLS){
llTakeControls(CONTROL_FWD | CONTROL_BACK | CONTROL_RIGHT | CONTROL_ROT_RIGHT | CONTROL_LEFT | CONTROL_ROT_LEFT | CONTROL_UP | CONTROL_DOWN | 0,TRUE,FALSE);
}
}
control(key id,integer held,integer change){
vector idou;
vector kaiten;
if(held & CONTROL_FWD){
idou.x=1;
}
if(held & CONTROL_BACK){
idou.x=-1;
}
if(held & CONTROL_UP){
// idou.z=1;
kaiten.y=2;
}
if(held & CONTROL_DOWN){
// idou.z=-1;
kaiten.y=-2;
}
// if(held & CONTROL_RIGHT){
// idou.y=-5;
// }
if(held & CONTROL_ROT_RIGHT){
kaiten.x=6;
// kaiten.y/=8;
}
// if(held & CONTROL_LEFT){
// idou.y=5;
// }
if(held & CONTROL_ROT_LEFT){
kaiten.x=-6;
// kaiten.y/=8;
}
llSetVehicleVectorParam(VEHICLE_LINEAR_MOTOR_DIRECTION,idou);
llSetVehicleVectorParam(VEHICLE_ANGULAR_MOTOR_DIRECTION,kaiten);
}
timer(){
llSetText((string)llVecMag(llGetVel()),<0,1.0,0>,1.0);
}
}
直線運動だけでも、問題山積です^^
VEHICLE_LINEAR_MOTOR_DIRECTION がx軸、y軸、z軸に対しての秒あたりの速さを指定できるところです。
VEHICLE_LINEAR_MOTOR_TIMESCALE がその設定したスピードに達するまでの時間をあらわします。
VEHICLE_LINEAR_MOTOR_DECAY_TIMESCALE は、逆にスピードを減速させる時間をあらわします。
VEHICLE_LINEAR_MOTOR_TIMESCALE を0にするとおそらく時間の最小値0.06秒をあらわしているらしいです。すなわち、この時間を短くすればするほど目的の速さに早く達します。
一方、VEHICLE_LINEAR_MOTOR_DECAY_TIMESCALE は、0にすると無効になるようです。すなわち、とまらなくなります。そしてこの時間の最大値は120秒のようです。とまらないといっても、すこしずつ自然に減速するようにはできています。
この相反するふたつを同時に設定することからして、悩むところです。たとえば、スピードを上げるほうを一番短くして、遅くなるほうを300とか大きくしても、すぐにとまってしまいます。すぐ早くなってかつ、少し余韻のあるとまり方を望むとしたら、早くなるほうを1秒以上にして、とまるほうを少し大きめに設定しないとうまくいかないようです。
やっぱ、ややこしいよね。もっといっぱい書きたかったけど、読んでるほうがついてこれなそうなので、とりあえず、ここまでね^^
くわしくは lsl Wiki のビークルのチュートリアルを見てください。ただし英語です^^ わたしも、何日かかけて読んだけどよくわからないです。
ビークルの説明も日本語のものがほとんどないので、もう少しときどき書くつもりです^^
2008年02月22日
ライブ見たよ&llSetPos()卒業制作

初めてSLでライブ見たよ。最初がCACAHOBOSで、キーボードのこのこが無表情でよかった^^

佐世保SIMに58人、となりの長崎と一緒にライブ会場になっているので、あわせて70人近くになっていました。

CACAHOBOSのドラムのこです。遠くから見るとめがねがじゃまで顔がわからないのですが、アップで見ると結構いい顔してます。

で、次が、有名な犬茶さんです。DOGTEAとは知らなかったよ^^ どちらもライブ感が伝わんないよね>< やっぱ生で見なくちゃね。

今、佐世保店の入り口に宇宙船置いています。
ねこねこ屋佐世保店

タッチすると表にDEMOが出ます。

60秒以内に乗ってください。

このように、空を飛べます。DEMOなので降りると消えます。
この宇宙船は、物理を使わないで、コントロールできるようにしたものです。なので、動きはかくかくしています。
物理じゃない方がいいところというのは、ほとんどないです>< しいてあげるなら、プリム数の制限がない。フレキシが使える。建物の中を突き抜けられる。物理に比べてSIMに対する負荷が少ない。ぐらいでしょうか。対して欠点は、スムーズな動きが得られない。SIM超えができない。ものを置ける高さまでしかあがれない。スピードは1回10メートルまで。ということでしょうか。
ではなぜ、作ったかというと、ここ数ヶ月の間、このブログで追求してきた、llSetPos()、llSetRot()、llSitTarget()、llTagetOmega() 等の非物理のものを扱う最終的な到達点だと思ったからです。
SLを始めたころ、なんで横に開くドアがないんだろうと思っていました。あるところで、やっと発見しました。スクリプトだけで190L$でした。さっそく試してみると、そのドアでしか設定できないものでした。そのころ、スクリプトを始めて、MIZさんの初級講座で回転ドアのスクリプトを見て、それを改造して横にスライドするドアを作りました。昔のブログで公開しているはずです。自分でどこでも、移動しても回転してもちゃんと動くスライドドアになりました。それがもとで、障子を作ったり、ふすまを作ったりしました。それから llSitTarget() も研究して300メートルまであがれるのを発見しました。SIM内なら高さは300メートル、横ならどこでも行けるテレポボールもつくりました。
あとは、自分でコントロールできる乗り物を非物理で作れば卒業できるかなと思って卒業制作みたいな感じで作って見ました。最初は、ツアーライドとか、物理の乗り物のスクリプトとかを参考にすれば簡単に作れるだろうと高をくくっていたのですが、とんでもない、自分自身が前に進むということは、座標自体が変わることです。東西南北がいつでも東西南北であるように、SLのxyzの座標も一定なのです。なんとなくローカル座標? って思うととんでもない操作性の乗り物が作れます^^ しばらくわからなくてストレスたまりまくりでした。で、車買いました。サーキットデビューもしました>< そのはなしはまたいずれ^^
ということで、のりごこちはよくないのですが、スクリプトを書く人なら簡単ではないのがわかっていただけると思います。是非非物理の卒業制作として、みなさんも考えてみてください^^
2008年01月26日
llRezObject を使ってスカイボックス出現

無料のスケールボードを置いているのですが、上空に持っていくにはどうするかと聞かれ、SLを始めた頃スカイボックスなる存在があり、座ると上空に行きスカイボックスを設置してくれるという一見便利そうに見えるものがあったのを思い出し、それを実現してみました。
まず、いつものごとく llRezObject() の設置限界をさぐってみました。第一引数が、オブジェクトのインベントリに入っている出現させたいオブジェクトの名前であり、第2引数が絶対座標になります。llSetPos() の限界が10メートルなので、まず上空10メートルで試しました。

無事10メートル上空に出現。

次は、12メートルに挑戦。やはりだめでした。エラーはデバッグチャンネルに報告しているのでしょうが、表面上はなにもおこりません。llSetPos() と同じく10メートルまででした。こうしてみると以前書いた llSitTarget() の限界が300メートルというのはかなり大きなことだと思えます。

いよいよ核心に迫ります。実は、これを書く前、普通REZするときなにもない空間には出せないので、出すオブジェクトと、座って上がるオブジェクトを別々に上空に上げて上空で合体させるプログラムを書いていました。それはそれで、別々に上がっていく様が見えておもしろかったのですが、実験してみると、上空でオブジェクトから直接スクリプトでREZできるのがわかり、図のようにしました。10メートルを10回上げています。
ここで llSleep(0.1) を入れているのは、なぜかREZのタイミングをとるのに必要みたいです。こういったところは実際に動かしてみないとわからないところです。最後は、立ち上がったら椅子を消すようにしました。上空に上がって行く途中で立ち上がってしまうと椅子とボードだけあがって行きます。(そのときは、逆に座れば椅子は消えます。)

こんな感じで、中心座標の同じ位置にボードが出現しています。

立ち上がると、椅子は消えます。これは上空100メートルにしていますが、実際サンドボックスによって状況がことなるので、好きに変更してください。わたしが経験したところでは200メートルまでしかアバターが(いくらでもあがれるHUDをつけていても)あがれなかったところがありました。そのときは編集で、ボードを300メートルにあげていたので、どうにか上を見上げて消すことができました。また、サンドボックスによっては上になにがあるかわからなかったりするので、そのときどきの状況にあわせる必要があると思います。一応これもフリーの箱に詰める予定です。
2007年11月20日
パーティクル-その2

PSYS_PART_BOUNCE_MASK を指定すると、位置座標Zの値が0の位置で跳ね返ります。(発生源を地面に置けば地面でバウンドする感じが出ます。) わたしの感覚としてはちょうどパチンコ玉を床にぶちまけた感じ^^ これも扇型でためしているので2次元に広がっています。

緑から赤に色を変化させています。色と透明度の変化をさせるためには必ずフラグのPSYS_PART_INTERP_COLOR_MASK を指定する必要があります。

次は、噴射するものが動くとどのように変化するのかを見るため、2つのボールをリンクさせて、中心となるボールが回転し、もうひとつのボールでパーティクルを発生するように用意しました。方向も見るためにテクスチャもアゲハ蝶に変えました。写真は蝶のサイズを小から大に変化するようにして、コーン型に上方から発生するようセットしています。(なお、球体で発生させる場合、建造で出したままだとY軸が90度回転しています。0にすれば上から出るようになります。)

で、このまま回転させると、このように機関車のけむりがたなびくように、うしろに残っていきます。

PSYS_PART_FOLLOW_SRC_MASK を指定するとこのようにたなびかないで回転していきます。

次は、わたしが最後までわからなかった PSYS_PART_FOLLOW_VELOCITY_MASK について説明します。
写真は、普通に上から発生させてます。先のものより数を少なくしています。

で、これが PSYS_PART_FOLLOW_VELOCITY_MASK を指定したものです。噴射する方向に向かって蝶が向きを変えているのがわかるでしょうか。

これは、さらに PSYS_SRC_OMEGA を指定して発射する方向を回転させて、更に発生源自体を動かしています。vector 型で値を入れます。これはどの値をいじればどうなるかというのは全くわかりませんでした。一応値はラジアンで指定するみたいです。
こうやって PSYS_PART_FOLLOW_VELOCITY_MASK と 組み合わせると、まきちらす感じが出ると思います。

次はホーミングを組み合わせます。PSYS_SRC_TARGET_KEY, でオブジェクトのオーナー(自分自身)を指定し、PSYS_PART_TARGET_POS_MASK でターゲットに向かうようにしています。ターゲットキーを指定しないと発生源に向かっていくようです。
この矢印は、持ち物の中に Library>Textures>Waterfalls>Particle System>Particle Arrow として入っています。下のプログラムで試す場合、パーティクルを仕込むオブジェクトのコンテンツ内にこの矢印のテクスチャを入れてください。最初この矢印はなんだろうとずっと思っていました。パーティクルの性質を確かめるためのものとして入っているのだとやっとわかりました。(違うかもしれませんが。)わたしも最初のうちは、デフォルトの光の粒でいじっていたので VELOCITY の性質が最後までわかりませんでした^^
default{
state_entry(){
llParticleSystem([]);
}
touch_start(integer detected){
state start;
}
}
state start{
state_entry(){
llParticleSystem([
PSYS_SRC_TEXTURE,"Particle Arrow",
PSYS_SRC_PATTERN,PSYS_SRC_PATTERN_DROP
,PSYS_PART_FLAGS,(0
| PSYS_PART_EMISSIVE_MASK
| PSYS_PART_FOLLOW_VELOCITY_MASK
| PSYS_PART_INTERP_SCALE_MASK
| PSYS_PART_TARGET_POS_MASK
)
,PSYS_PART_START_SCALE,<0.3,0.3,0>
,PSYS_PART_END_SCALE,<0.3,0.3,0>
,PSYS_PART_MAX_AGE,3.0
,PSYS_SRC_ACCEL,<0,0,5.0>
,PSYS_SRC_BURST_PART_COUNT,5
,PSYS_SRC_BURST_RATE,1.0
,PSYS_SRC_TARGET_KEY,llGetOwner()
]);
}
touch_start(integer detected){
state default;
}
}

蝶々で試しました。ホーミングはスピードを変化させると同時にパーティクルの寿命もいじってやらないと望みどうりの動きをしないようです。上方でだけ確認したのですが、5000メートルぐらいまでパーティクルは届くみたいです。SIM越えは確認していません。
2007年11月17日
パーティクル

クリスマスの季節。雪を降らせます。オブジェクトに仕込んでタッチすれば雪が降り、もう一度タッチすればとまります。
default{
state_entry(){
llParticleSystem([]);
}
touch_start(integer detected){
state start;
}
}
state start{
state_entry(){
llParticleSystem([
PSYS_SRC_PATTERN,PSYS_SRC_PATTERN_EXPLODE
,PSYS_PART_FLAGS,(0
| PSYS_PART_EMISSIVE_MASK
| PSYS_PART_INTERP_SCALE_MASK
)
,PSYS_PART_START_SCALE,<0.15,0.15,0>
,PSYS_PART_END_SCALE,<0.15,0.15,0>
,PSYS_SRC_ACCEL,<0,0,-0.2>
,PSYS_SRC_BURST_PART_COUNT,15
]);
}
touch_start(integer detected){
state default;
}
}

パーティクルは、パラメータをいろいろ変化させることによって、特殊効果を表現することができます。雪や花びらを降らせるだけでなく、噴水や、光の輝き、ゴースト、魔法効果、その他いろいろと創作意欲をかきたててくれます。最もシンプルな形を指定するだけでも動きます。
llParticleSystem([
PSYS_SRC_PATTERN,PSYS_SRC_PATTERN_EXPLODE
]);

llParticleSystem([]) と、パーティクル関数のパラメータをなしにすると、パーティクルは停止します。パラメータはリスト型で、性質とその値でひとつのまとまりとなります。
性質は大きく分けると4種類になります。①表示するテクスチャの名前、②発射の形、③フラグ、④性質
写真は発射の形のひとつ PSYS_SRC_PATTERN_ANGLE を正面から見たものです。
自分で、いろいろと値を変えて試すことが理解するための早道です。以下に性質を全部載せたものをあげておきます。// はコメントアウトで、これよりあとの改行までの文字はプログラムとして認識されません。逆に、これを取ればプログラムとして有効になります。これをオブジェクトに仕込んでいろいろと確かめてみてください。
default{
state_entry(){
llParticleSystem([]);
}
touch_start(integer detected){
state start;
}
}
state start{
state_entry(){
llParticleSystem([
//表示するテクスチャの名前もしくはキー(用意しなくても白い光の粒がデフォルトで入っています)
// PSYS_SRC_TEXTURE,"name",
//形(どれか一つ設定)
PSYS_SRC_PATTERN,
//2次元の扇状。YZ面に出現
//PSYS_SRC_PATTERN_ANGLE
//3次元のコーン(円錐)の内側全体に出現
//PSYS_SRC_PATTERN_ANGLE_CONE
//落下型。PSYS_SRC_ACCEL を指定しないとそこにとどまる
//PSYS_SRC_PATTERN_DROP
//すべての方向に噴射(爆発型)
//PSYS_SRC_PATTERN_EXPLODE
//フラグ(マスク)
// ,PSYS_PART_FLAGS,(0
//オブジェクトのZ=0の高さでバウンドする
// | PSYS_PART_BOUNCE_MASK
//パーティクル自身が光る(オブジェクトの明るさを最大にと同じ)
// | PSYS_PART_EMISSIVE_MASK
//プリムの動きに合わせて噴射の形も平行移動(PSYS_SRC_BURST_RADIUS を無効にする)
// | PSYS_PART_FOLLOW_SRC_MASK
//パーティクルのトップが発射方向に向きを変える(回転、あくまでも平面はこっち向き)
// | PSYS_PART_FOLLOW_VELOCITY_MASK
//色と透明度の変化をスムーズにする
// | PSYS_PART_INTERP_COLOR_MASK
//サイズの変化をスムーズにする
// | PSYS_PART_INTERP_SCALE_MASK
//パーティクルをターゲットへ向けて直線移動(PSYS_SRC_TARGET_KEYでターゲット指定)
// | PSYS_PART_TARGET_LINEAR_MASK
//パーティクルをターゲットへ向けて曲線的移動(ホーミング)(PSYS_SRC_TARGET_KEYでターゲット指定)
// | PSYS_PART_TARGET_POS_MASK
//パーティクルを風になびかせる
// | PSYS_PART_WIND_MASK
// )
//各設定
//パーティクル開始時の透明度、0~1(float)
// ,PSYS_PART_START_ALPHA,
//パーティクル消滅時の透明度、0~1(float)
// ,PSYS_PART_END_ALPHA,
//パーティクル生成時の色、0~1(vector)
// ,PSYS_PART_START_COLOR,
//パーティクル消滅時の色、0~1(vector)
// ,PSYS_PART_END_COLOR,
//パーティクル開始時のサイズ、0.03125~4m、XとYの2次元(vector)Z値は無視される
// ,PSYS_PART_START_SCALE,
//パーティクル消滅時のサイズ、0または、0.03125~4メートル、XとYの2次元(vector)Z値は無視される
// ,PSYS_PART_END_SCALE,
//1つのパーティクルの寿命、30秒まで(float)
// ,PSYS_PART_MAX_AGE,
//視界に入ってからのパーティクルシステムの有効時間(噴射し続ける時間)
// ,PSYS_SRC_MAX_AGE,
//パーティクルの加速度(vector)m/s 擬似的な重力 0 または 0.007815~100
// ,PSYS_SRC_ACCEL,
//パーティクル生成の開始角度(float 度数に変更)アングルの2パターンのみ有効0~180、+と-両方で発生
// ,PSYS_SRC_ANGLE_BEGIN,DEG_TO_RAD*
//パーティクル発生の限界の角度(float 度数に変更)アングルの2パターンのみ有効0~180、+と-両方で発生
// ,PSYS_SRC_ANGLE_END,DEG_TO_RAD*
//1回の噴射あたりのパーティクル生成数(integer)
// ,PSYS_SRC_BURST_PART_COUNT,
//パーティクル生成地点の中心からの距離、メートル(float)PSYS_SRC_PATTERN_DROPには使えない
// ,PSYS_SRC_BURST_RADIUS,
//噴射の間隔、秒(float),0秒で連続
// ,PSYS_SRC_BURST_RATE,
//噴射するときの最小スピード(float)
// ,PSYS_SRC_BURST_SPEED_MIN,
//噴射するときの最大スピード(float)
// ,PSYS_SRC_BURST_SPEED_MAX,
//パーティクルの噴射方向を回転させます。(vector)アングルの2パターンのみ有効
// ,PSYS_SRC_OMEGA,
//追尾するオブジェクトのキー(PSYS_PART_TARGET_POS_MASKが有効の時のみ使用)
// ,PSYS_SRC_TARGET_KEY,
]);
}
touch_start(integer detected){
state default;
}
}

PSYS_SRC_PATTERN_ANGLE 扇状のものを横から見たものです。
,PSYS_SRC_ANGLE_BEGIN,DEG_TO_RAD*0
,PSYS_SRC_ANGLE_END,DEG_TO_RAD*30
0度から30度を指定したので、60度に開いた扇になっています。

これは30度から60度を指定しています。左右に出ているのがわかるでしょうか。
,PSYS_SRC_ANGLE_BEGIN,DEG_TO_RAD*30
,PSYS_SRC_ANGLE_END,DEG_TO_RAD*60

これは、上のものをコーン状(3次元)のものにしたものです。写真では分かりにくいのですが、円錐形に真ん中が空洞になっているのがわかるでしょうか。
PSYS_SRC_PATTERN_ANGLE_CONE

これはその場の位置にとどまる形を指定したものです。PSYS_SRC_ACCEL を指定しないとその場にとどまります。写真は1個だけ発射されたものです。仕込んだオブジェクトを半透明にして分かりやすくしました。中心から発生しているのがわかりますでしょうか。
PSYS_SRC_PATTERN_DROP

これは上のものをそのまま発射し続けたものです。
なお、コーン状の逆パターンもあるのですが、わたしのパソコンでは確認できませんでした。新しいバージョンでは対応しなくなったのか、わたしのものでは確認できないのかどちらかわかりません。
ということで、最後にスクリプトを書くときに参考になるものをあげておきます。
miz さんのスクリプト解説記事。これを読みこなせるならこれだけで十分です。
lslwiki 英語ですが関数の詳しい用法について参考になります。英辞郎等の辞書を参考に調べてみてはいかがでしょうか。
あとは、本になりますが、「リンデンスクリプト入門(インプレスR&D)」や「セカンドライフLSLプログラミング入門(アスキー)」があります。
2007年11月09日
くるくる回転しま~す

もっとみんなでスクリプトを! ということで、単純な回転するスクリプトを。回転速度を変えたり、いろいろなものに仕込んだりしてかなり遊べるものだと思います。おもちゃで遊ぶ感覚でオブジェクトに入れて楽しんでください。回転するものとして思いつくのは、メリーゴーランド、観覧車、レコードプレーヤー、回り灯篭、・・・なんでも遊べる^^ 是非スクリプトの第一歩として、みんなで遊んでね。タッチすると回り始め、もう一度タッチするととまります。
integer i;
default{
state_entry(){
i=0;
llTargetOmega(<0.0,0.0,1.0>,0.0,1.0);
}
touch_start(integer detected){
i=i+1;
if(i==1){
llTargetOmega(<0.0,0.0,1.0>,TWO_PI/6,1.0);
}
else{
llTargetOmega(<0.0,0.0,1.0>,0.0,1.0);
i=0;
}
}
}
関数 llTargetOmega の最初のパラメータはどの軸に対して回転するのかを表します。<1.0,0.0,0.0> でたて回転。<0.0,0.0,-1.0> で逆回転の横回転。2番目のパラメータは回転速度です。TWO_PI という定数で1秒間に1回転をあらわします。6秒で1回転なら TWO_PI/6 となります。最後は物理オブジェクトでなければ 1.0 と指定します。
ということで、2番目のパラメータをいろいろ変えて遊んでみてください。2番目が 0.0 となっているのは、回転を止める働きをしています。TWO_PI のとこいじってね。

これは、いわゆる、遊園地のコーヒーカップを実現しようとしたものです。残念ながら、上のカップがアバターと一緒に回転して、かつ土台も回転するというのは実現できませんでした。リンクするとどれにタッチしても反応してしまうので、上のカップには、別にスクリプト入れました。
default{
state_entry(){
llTargetOmega(<0.0,0.0,1.0>,1.2,1.0);
}
}
ほんとに、単純に回転だけしています。このように、2番目のパラメータは数字でもかまいません。6.283で、大体1秒で1回転になります。

結局、それぞれ回転はするのですが、上のカップに座っていてもアバターはカップと一緒に回らずに、下の台と一緒に回るだけでした。リンクをはずせば、上のカップに座っていればカップと一緒に回りますが、下の台とは連動しません。まあそこまで計算するのは大変だということでしょうか。ちなみに、この写真は光速w で回転していたときのものです。1秒で2回転ぐらいだったかな。目が回ります^^

以下は、ほんとの初歩の初歩ということで、スクリプトのコピペの仕方をおさらいしておきます。きょうはじめてこのブログ読んだ方や、きょうはじめてセカンドライフをはじめた方(オオ!w)に贈ります。
球体のオブジェクトを建造してサイズを1メートルにしました。これも分からない場合は近くにいる人に聞いて^^

コンテンツタブをクリックして、新しいスクリプトのところを押します。

あらかじめ、簡単なスクリプトが入っているので、それを全部選択します。

で、たとえばここにあるスクリプト等をコピーしたものを、上書きします。Ctrlキー + v キーで貼り付けられます。

そして、保存ボタンを押せば、スクリプトに間違いがなければ、コンパイルが成功しました、と出ます。これでウインドウを閉じれば、スクリプト入りのオブジェクトになるわけです。是非、お試しください。
2007年11月05日
明かりの続き

前回に続いて明かりをやります。明かりを3つ用意しました。左側が電球を球体から作ったものに変えて、リンクしたスタンド。真ん中と右が単独の球体。
一番左と真ん中の電球にタイマーイベントを入れてみました。10秒経つと消えるようにしました。
default{
state_entry(){
llSetPrimitiveParams([PRIM_POINT_LIGHT,FALSE,<0.0,0.0,0.0>,0.0,0.0,0.0]);
}
touch_start(integer detected){
state green;
}
}
state green{
state_entry(){
llSetPrimitiveParams([PRIM_POINT_LIGHT,TRUE,<0.0,1.0,0.0>,1.0,5.0,1.0]);
llSetTimerEvent(10);
}
touch_start(integer detected){
state default;
}
timer(){
llSetTimerEvent(0);
state default;
}
}

で、つけたり消したりしたのですが、あいかわらず反応が悪いです。一番右の単独の単に緑色の明かりをつけるだけのものでも遅延(ラグ)があります。しかし、一番左のリンクしたものと、真ん中の単独のものは、もっと反応が悪いです。前回書いたように、光はついても、表面が明るくならなかったり、消しても、表面はついたままになっています。写真のスタンドは、消しているけど表面は明るいままの状態のやつです。しかも、一番右の反応のいいものをつかって、つけたり消したりをすると、それに連動して表面がついたり消えたりします。ここで、整理すると、タッチするというスイッチによって光源(いわゆる光)はちゃんと反応してついたり消えたりします。それは近くのオブジェクトの表面に反映されるので確認できます。しかし、その次に、オブジェクトの表面が明るくなるのはラグが生じて反応しません。そのラグは、他の明かりをつけたり消したりによって表面が明るくなったり消えたりするのに連動して解消されます。

次は、色を赤、緑、青(いわゆるRGB)の順にさわるたびに変化していく明かりをつくります。参考にしたのは、miz さんの初級スクリプト講座第6回です。
ユーザー定義関数がでてくるので、少し理解できなくなってくるのですが、自分なりに勝手に解釈して作ってみました。
light(vector color){
llSetPrimitiveParams([PRIM_POINT_LIGHT,TRUE,color,1.0,5.0,1.0]);
}
integer counter;
default{
state_entry(){
light(ZERO_VECTOR);
counter=0;
}
touch_start(integer detected){
counter=counter+1;
if(counter==1){
light(<1.0,0.0,0.0>);
}
else if(counter==2){
light(<0.0,1.0,0.0>);
}
else if(counter==3){
light(<0.0,0.0,1.0>);
}
else{
light(ZERO_VECTOR);
counter=0;
}
}
}
最初、light という明かりの色によって変化するユーザー定義関数の color という引数(ひきすう)を、最初に単独で vector color; というように定義したのですが、シンタックスエラーになってしまいました。引数のとこで、型を定義しないとだめなようです。
だいたい、引数という字を「ひきすう」と読むなんて知りませんでした^^ 引用するはいんと読むだろと思ってずっと「いんすう」と読んでいました。独学の場合、ことばとして誰かに発音されることがないので、間違った読みのままずっといってしまうことがよくあると思います。パソコン用語でもなんと読むんだろというのが多すぎます。IEEE ってなんと読みます?
それはともかく、プログラムにもどると、このままちゃんと動作するのですが、いつもついたままです。ただし消えているときは、黒く(光らないで)ですが。省エネになっていないのかな? よくわからないのですが、消すということを入れると、
light(vector color){
if(color==ZERO_VECTOR){
llSetPrimitiveParams([PRIM_POINT_LIGHT,FALSE,ZERO_VECTOR,0.0,0.0,0.0]);
}
else{
llSetPrimitiveParams([PRIM_POINT_LIGHT,TRUE,color,1.0,5.0,1.0]);
}
}
integer counter;
default{
state_entry(){
light(ZERO_VECTOR);
counter=0;
}
touch_start(integer detected){
counter=counter+1;
if(counter==1){
light(<1.0,0.0,0.0>);
}
else if(counter==2){
light(<0.0,1.0,0.0>);
}
else if(counter==3){
light(<0.0,0.0,1.0>);
}
else{
light(ZERO_VECTOR);
counter=0;
}
}
}
となります。関数の定義のところで、if 文を使って条件分岐させて定義したりしていてちょっととまどいました。
counter はカウントする変数です。counter = counter + 1 は counter++ でもいいです。
変数とか関数という数学ででてきた言葉と同じものを使うので、はじめのうちは混乱するかもしれません。しかも変数名に英単語を使っているので、余計にこれなにって感じになります。=(イコール)も代入に使っています。論理的に同じというのは、= = という風に二つ重ねます。関数は数字の計算だけでなく一般的な処理を指します。というように、慣れるまでとまどうと思います。
こっちの、順に色を変化させる方は、そんなに気になるほどラグがありませんでした。いろいろな条件で変化するので、かなりわかりずらいです。まあ、実際にスクリプトを組んだら、オブジェクトに入れていろいろ動作させて満足なものが得られるのかどうかを検証する以外になさそうです。

ふと、環境設定で、近隣のローカルライトをオン・オフにする設定があるのを思い出しました。(9月28日のブログに出ています。)
写真は、近隣のローカルライトをオフにしています。すなわち、光源を光らすというのと、表面を光らすというのは、クライアント側(自分のパソコン上)で別々に実現しているということです。だから条件によってラグがでてくるのだと思われます。

ちなみに、これが、近隣のローカルライトをオンにした状態です。
実証主義を貫くつもりですが、なんか疲れますw
2007年11月03日
明かりをつけるときの注意点

昨日の夜は、ソラマメの投稿しようとしてもぜんぜん画像の読み込みその他遅くて、結局トップページにも載りそこなってしまった><
気をとりなおして、明かりをつけるスクリプトをやろうと思ったら、ここでも問題点が・・・
とりあえず、miz さんの初級スクリプト講座第6回をもとに進めます。この回では明かりをつける以外に、ユーザー関数や条件分岐といった、プログラムを組む上での大事な事柄がでてきます。わたしのような初心者には、一気に理解できないので、とりあえずは、明かりをつけます^^
で、簡単なスタンドを作りました。

ただ単に、タッチするたびに、緑の明かりをつけたり消したりするスクリプトを電球に入れます。
default{
state_entry(){
llSetPrimitiveParams([PRIM_POINT_LIGHT,FALSE,<0.0,0.0,0.0>,0.0,0.0,0.0]);
}
touch_start(integer detected){
state green;
}
}
state green{
state_entry(){
llSetPrimitiveParams([PRIM_POINT_LIGHT,TRUE,<0.0,1.0,0.0>,1.0,5.0,1.0]);
}
touch_start(integer detected){
state default;
}
}
明かりをつける関数の使い方は miz さんのところに詳しくのっています。プログラム自体は、初期状態が消えている状態で、タッチすると、緑色に点灯し、更にタッチすると、消える(元の状態に戻る)という基本的な仕組みのみを取り出しています。
ところが、ここで問題が。どうもタッチしてもすぐについたり消えたりしないのです。丸い球体だけを建造したときは、スムーズについたり消えたりするのにスタンドにするとうまくいかない。原因をいろいろ考えました。スタンドで電球が他のオブジェクトと接しているからそれを計算して遅延するのではないかとか、リンクすると遅くなるのかなとか考えました。
しばらくお茶でも飲んで休んでいたら、なんとなくわかってきました。球体以外のものから最初スタンドの電球を作っていたので、それが原因ではなかろうかと、推測できました。早速実験です。球体と、もとはシリンダを変形して球体に直したものと2つ作ることにしました。
右側はシリンダから球体に変形したものです。どちらもテクスチャをブランクにして白色のみにしました。太陽も深夜にしました。
さて、結果は。左は、普通につきます。
ところが、シリンダから変形したものは見て分かるように、ついているのですが、オブジェクトの表面は明るくなっていません。
これは、逆に消えているのに、オブジェクトの表面の明かりはついたままになっている状態です。
で、立方体で試すと、やっぱりついても表面が明るくならず、おかしいです。
三角錐でも同じでした。推測なのですが、球体以外のものでは、明かりをつけたり消したりするのに適していないということです。そういう風に設定したのだと言われればしかたないのですが、球体以外のものから途中で球体に変形して明かりにする場合は要注意ということでしょう。また、スクリプトの勉強なのだから実際は関係ないだろということはありえません。実際に使えてこそのスクリプトです。SL上で実現できないことをいくら構築しても意味はないでしょう。
2007年10月27日
スライドドア

きのうに引き続き、応用でスライドドアを作ったよ。その前にオブジェクトの位置とか、ローカルとグローバルの違いはとか考えていたら、基本的なことを分かっていなかったことが分かったよ。建造でオブジェクトを出したとき、かならず、x座標は東を向いていて、y座標は北を向いて、z座標は天を指し、回転0だということがわかった^^ また一度持ち物にしまってから、出したときは、しまうときの向きや方向を覚えていてそれと同じに出るのだということも^^ こんなんでスクリプト書けるのかなと思ったあなた、正しいですw 最初、きのうの応用でそのまま書き換えただけでは、うまく動かなかったよ^^

位置をずらすことを考えたとき、オブジェクトから作ったときのまま、x、y、z座標の向きを変更しないのならば、話は簡単で、llGetRot() を llGetPos() 、llSetRot を llSetPos に変えればいい。でもよく考えるとドアはいつも南向きとは限らず、あるいは斜めに設置するかもしれない^^ ということを考えると、グローバルな位置を取得してしまうと、話が非常にややこしくなってしまいます。あ、説明すると、グローバル座標とはそのオブジェクトの中心がそのSIMの南西の左端からどれだけ来ているのかということをあらわし、ローカル座標というのはリンクされた主プリム(黄色く光るやつ)に対する子プリムの位置関係をあらわしています。ので、ドアだけだと回転したりするとわけわからなくなるので、敷居を主プリムに使って、それに対するドアのローカル座標を取得して書くことにします。で、まず敷居を作ります。以下オブジェクトの作り方は障子の回を参考にしてください。

続いて、2枚のドアを作りました。区別するため、半透明と透明でないものを作りました。なんかこうやっていると、中学のときのアクリル工作を思い出したよ。見た目アクリル板に似てるよね。

上から見ると、こんな感じにちゃんとずらして作っています。

で、さっそく左側には1.2メートルプラスするもの、右側は1.2メートルマイナスするスクリプトを入れます。
きのうのものと、ほとんど同じだよね。ただローカルポジションを取得しているとこに注意するぐらいかな。
あ、このままスクリプト使えて動くけど、使う前にリセットかけたりする必要があったり、実用的ではないから商売物には向いていないかもね^^ スクリプトの書き方だけ参考にしてね。
vector ichi;
default{
state_entry(){
ichi = llGetLocalPos();
state close;
}
}
state open{
state_entry(){
llSetPos(ichi+<1.2,0.0,0.0>);
}
touch_start(integer total_number){
state close;
}
}
state close{
state_entry(){
llSetPos(ichi);
}
touch_start(integer total_number){
state open;
}
}
一個一個リンクしていき最後に敷居をリンクして、敷居を主プリムにします。
で、動くかなと試すと、お決まりのごとく、動きませんw しばらく悩みました。理論的にはあっているはずだけど、なぜ動かない。
結局バラバラのとき、スクリプトを入れたので、その時点で、最初に llGetLocalPos() をしてしまい、自分自身に対する位置を取得してしまうわけです。もちろん<0,0,0>なわけです。ということで、リンク後、リンク部位を編集を選んで、それぞれのドアのスクリプトにリセットをかけてあげる必要があるわけです。そうすると、はじめて主プリムに対しての位置を取得できます。やり方としては、リンクしてから、リンク部位の編集でひとつずつスクリプトを入れても同じかもしれません。
晴れて、動きました^^ 苦労した分だけ、ちゃんと動くと嬉しいものです。是非みなさんもわたしと一緒に遅々としたあゆみながらも、スクリプトをお勉強しましょうね^^ あ、そんな初歩相手にしないとよいう方は読まないでね^^
最後に、こうした斜めのものでもオッケーか確かめました。ドキドキ・・・
良かった。成功のようです。
2007年10月26日
回転ドア

LSL convention Japan -2007-にも行ってきて、やっとスクリプトの学習を少し進めて行く気になりました^^ ということで、またまた miz さんの力をお借りして、初級スクリプト講座第5回を参考に、回転ドアを作りました。
まず、回転軸は中心座標をもとにするため、パスカットを使うので、向こう側に2.4メートル、高さも2.4メートル、厚さは3センチのドアを作ります。

パスカットで半分の長さにします。

テクスチャは、半透明にして、色も青っぽくしてみました。

で、いよいよスクリプトを入れるのですが、最初テキストエディタで、miz さんのを参考にそのまま書いたのですが、シンタックスエラーで作動しませんでした。よくみると、なんと関数の前の ll ←この2本の棒は、小文字の l (エル)だということが判明^^ 今まで、ずっと¥のところを Shift キー使って入力した || だとばかり思っていました。やはり、コピペでなく自分で、入力することをオススメ致します。テキストエディタを使って、SL上ではなく、RL上のパソコンでいつでもプログラミングできる環境にしましょう。テキストエディタはフリーのものがたくさんあります。窓の杜などにあるので、好きなのをお使いください。自分で書いてみると、自分なりの書式が出来てくると思います。{の位置や、字落ちをどうするかなど、自分が見やすい形を作ってください。ちなみに、これがわたしの書き方です。タイマー関数は入れてません。
rotation rot;
default{
state_entry(){
rot = llGetRot();
state close;
}
}
state open{
state_entry(){
llSetRot(rot*llEuler2Rot(<0.0,0.0,90.0>*DEG_TO_RAD));
}
touch_start(integer total_number){
state close;
}
}
state close{
state_entry(){
llSetRot(rot);
}
touch_start(integer total_number){
state open;
}
}
で、実験。ドアが開くとぶつかる位置に立ち、そのまま開けてみました。
すり抜けて、ドアは開きました。90度回転した位置に突然現れるのではなく、通過していったので、すりぬけたことになります。これも不思議のひとつ^^