今回は、「ラウンドブリリアントカットのダイヤモンド」で作ったデータに少し手を加えて、一面一面研磨していく様子をアニメーションにしてみます。ちなみに、「ダイヤモンドになる瞬間」では、屈折率を1→3(ダイヤモンドは2.4)まで変化させる動画をご覧に入れました。
相似変換を使います。
上図の様に、最後に残るダイヤモンド(オレンジ)、そのダイヤモンドをすっぽり包み込むことのできる球面(青)と、オレンジのダイヤモンドを相似変換(拡大)して青の球面を包み込むサイズにした緑のダイヤモンドを作ります。
本当は、各ダイヤモンドや球面の中心座標を図の上下方向に動かすと、もっと最適なサイズがあるのですが、今回の用途では扱いにくくなるので、基準となるgirdle面の中心座標を原点に置き、3つの物体の中心座標を揃えています。
さて、動画の作成ですが、初めは緑のダイヤモンドと青の球面でAND演算を取っておきます。
and
{
attr at_rock;
bump bu_rock;
sphere 0,0,0, kr*R;
attr brilliant;
brilliant 0,0,0, 0,0,1, R;
}
AND演算は「共通部分を残す」演算なので、最初は青の球面だけが残ります。ダイヤモンドは球面の外側なので、ダイヤモンドの形はどこにも表れていない状態です。
この状態から、一面毎に相似変換の拡大率を小さくして行って、最終的にオレンジのダイヤモンドのサイズまで縮小します。すると、今度はダイヤモンド全体が球面の内側になるので、AND演算によってダイヤモンドの形状だけが残る、という寸法です。
「一面毎に相似変換の拡大率を小さく」するのがミソですので、まず、アニメーションのパートを以下のように定義します。
// constants
var fps=30; // フレーム/秒
var fn_ptn=8; // アニメーションパート数
var fn_pt1=2*fps; // アニメーションパート1(pavilion)
var fn_pt2=2*fps; // アニメーションパート2(bezel)
var fn_pt3=2*fps; // アニメーションパート3(table)
var fn_pt4=2*fps; // アニメーションパート4(star)
var fn_pt5=2*fps; // アニメーションパート5(u-girdle)
var fn_pt6=2*fps; // アニメーションパート6(l-girdle)
var fn_pt7=2*fps; // アニメーションパート7(attr)
var fn_pt8=2*fps; // アニメーションパート8(show)
パート1〜8まであって、そのパート数をfn_ptnに指定してあります。パート1〜6までの間で各面を一面づつ削っていきます。パート1ではpavilion facet(八面)、パート3ではtable/culet/girdle、パート5ではupper girdle facet(16面)を削るという様に割り当てました。最初からダイヤモンドの属性(透明)を持たせると、削られていく面の様子が見えにくいので、削っていく間は不透明な属性にしておき、パート7で属性値を透明に変換することにしました。
このパラメータを使って、総フレーム数fn_allを自動計算します。
var fn_all; // アニメーションフレーム数
var idx;
idx=1;
while (idx≦fn_ptn)
{
fn_all=fn_all + fn_pt#(idx);
idx=idx + 1;
}
さらに、各パート内の相対的なポジションを0〜1に正規化したfp1〜fp8を計算します。例えば、fp3は、パート1〜2の計算中はfp3=0、パート3の計算中にfp3=0→1へ変化して行き、パート4〜8の計算中はfp3=1に固定されるようにしています(下図)。
idx=1;
while (idx≦fn_ptn)
{
static : var fp#(idx)=fn;
var idx2=1;
while (idx2<idx)
{
fp#(idx)=fp#(idx) - fn_pt#(idx2);
idx2=idx2 + 1;
}
fp#(idx)=fp#(idx)/fn_pt#(idx);
clip fp#(idx)=0,1;
idx=idx + 1;
}
この計算処理では配列変数形式「fp#(idx)」でアクセスしていますが、「#(idx)」の部分は「正数置換機能」によって、変数idxの示す数値に置き換わっていますので、idx=3の場合は、fp#(idx)→fp#(3)→fp3と同じです。「#( )」の内部に2.48など、実数(浮動小数)値が指定された場合、整数に丸めて(四捨五入して)置換します。丸めた結果、「#( )」の内部が0〜32767の範囲を逸脱した場合はエラーになります。
このように自動計算した相対的なポジションを使って、動きを付けていきます。
k1=fp3;
clip k1=0,1;
k2=bb*(1 - k1) + 1*k1;
sim k2;
これは、table/culet/girdleの相似変換部分です。一番単純でわかりやすかったので。bbは、最初に示した概念図でオレンジのダイヤモンドを1とした時の、緑のダイヤモンドの拡大倍率です。tableなどを削るのはパート3ですので、fp3を使っています。fp3=0ではk2=bbとなり、緑のダイヤモンドの拡大率となります。fp3=1ではk2=1となるので、オレンジのダイヤモンドの拡大率となります。fp3=0→1(パート3の間)では、k2=bb→1へ変化します。sim命令は相似変換を実行する命令ですので、この命令を一面毎に配置することで、一面毎の動きを付けます。
他の面は、もう少し複雑な動きを付けていますが、読み解いてみてください。
スタートの球面は、ダイヤの原石という設定になりますので、岩のテクスチャを貼っておきます。色マッピングに加えて、凹凸マッピングも施しておきましょう。
load $(dir)$/$(file)"_rock.jpg";
cmap cm_rock, 0,0,fwid - 1,fhei - 1, fwid,fhei;
bmap bm_rock, 0,0,fwid - 1,fhei - 1, fwid,fhei;
attr at_rock=
{
refl 0.01,50,0.4;
diff 0.99,0.00;
nmap cm_rock;
msph 0,0,0, 0,-1,0, 0,0,1,1,1;
};
bump bu_rock=
{
nmap bm_rock, R/75*(1 - fp1_6);
msph 0,0,0, 0,-1,0, 0,0,1,1,1;
};
bump命令の中で使っているnmapの第二パラメータ(R/75*(1 - fp1_6))は、凹凸の最大高さです。通常、マッピングデータbm_rockは、明るい(白い)部分が一番高く、暗い(黒い)部分が低くなるように凹凸が付きます。
凹凸は、「最初の方の面を削った段階ではまだザラツキが残っており、面を削り進む間に研磨されて平らになっていく」様子を表現するため、パート1〜6の間で徐々に第二パラメータを小さくしていき、全ての面を削り終えた後には高さ(第二パラメータ)が0になるように制御しています。
完成したデータと動画です。
Xi-TRACEデータ | brilliant_face.xitr |
マッピングデータ(岩) | brilliant_face_rock.jpg |
最初の原石が球体ってのは今一つ味気ないですね……。