やさいのつくりかた.

目次/第15章

15Shell

毛は、薄い殻を重ねて生やす

shell fur — シェル法

この章の3行まとめ
  • 枝豆のいちばんの特徴は産毛です。でも法線マップでは毛は出ません。輪郭がつるつるのままだからです。
  • そこで本体の少し外側に、毛の点々を描いた透明な殻を1枚2枚と重ねます。
  • 正面はうっすら、輪郭では殻が斜めに重なって濃くなる。これが毛に見えます。

07章で、オクラの産毛は sheen(布のような照り)で表しました。 表面が縁のあたりで柔らかく光る、という質感です。オクラはそれで足ります。 でも枝豆はそうはいきません。枝豆の毛はもっと長く、密で、 シルエットに毛が立って見えるからです。

06章の法線マップは「実際には形を変えず、光の当たり方だけ嘘をつく」技術でした。 安上がりですが、弱点があります。輪郭には効かない。 横から見たときの縁は形そのものなので、いくら法線をいじっても滑らかなままです。

やり方 — 少し大きい殻を、何枚か重ねる

そこでシェル法(shell fur)を使います。考え方はとても素朴です。

  1. 莢のメッシュを、ほんの少し外側へ膨らませたコピーを作る
  2. そこに「毛の断面の点々」を描いた半透明のテクスチャを貼る
  3. これを、膨らませる量を変えながら2〜3枚重ねる

毛を1本ずつ作るわけではありません。毛を輪切りにした点々を、 高さ違いで何枚か置いているだけです。それでも毛に見えます。 正面から見ると点々はまばらに散っているだけですが、 輪郭のあたりでは同じ点々を斜めから何枚も透かして見ることになるので、 そこだけ濃く積み上がるからです。

for (let k = 0; k < 3; k++) {
    const f = new BABYLON.StandardMaterial("edamameFuzz" + k, scene);
    f.opacityTexture = this.fuzzTex;      // 毛の点々(アルファ)
    f.alpha = cfg.fuzzAlpha * Math.pow(0.55, k);  // 外側の殻ほど薄く
    f.backFaceCulling = false;
    f.disableDepthWrite = true;             // 前後で悩まないようにする
    this.fuzzMats.push(f);
}
枝豆.js。殻ごとにアルファを 0.55 倍ずつ落としていく

実験 — 殻を重ねる

枚数を0にすると輪郭がつるつるになります。1枚でも入れると、縁だけ毛羽立って見えます。

つまずきポイント

枝豆.js は最初、opacityFresnel(見る角度で透明度を変える機能)を使って 「輪郭付近だけ毛を見せる」つもりでした。ところが Babylon.js のこの機能は alpha += left*(1-F) + F*right という足し算で、 しかも leftColor が正面側です。 白と黒を入れたところ、正面のアルファに 1.0 が足されて完全に不透明になり、 莢が霜をかぶったように真っ白になりました。 いまは素直なシェル法に戻してあります。 「便利そうな機能を、中身を確かめずに使うと壊れる」という記録です。

毛の色を純白にしない。 産毛は白っぽく見えますが、そのまま白で描くと霜に見えます。 枝豆.js は毛の色に莢の緑を3割混ぜています。 塩ゆでにしたときは fuzzAlpha を0.7倍にします。 濡れた毛は寝て束になるからです。
やってみよう
  1. 殻の枚数を0にして、輪郭が完全に滑らかになることを確かめる。
  2. 枚数1・濃さ0.9と、枚数3・濃さ0.3を見比べる。どちらが毛らしいか。
  3. 毛の長さを0.20まで伸ばす。どのあたりから「カビ」に見えはじめるか。
  4. 実物の枝豆を明るいほうへかざして、輪郭に毛が立つのを見る。