雪を描く(簡易フィルタ)

今回は前回に引き続いてフィルタもどきです。前回は雨でしたが、同様の手法で雪を描くスクリプトです。ただし、雨の場合と違って円形の選択範囲を作成する必要があります。ドキュメント(リファレンス)を見ても、いまいち分からない場合には以前紹介したScripting Listenerを使って操作を記録させます。そこで生成されたJavaScriptプログラムを抽出して再利用しましょう。
抽出されたスクリプトは長くなってしまいますが、気にせず利用できるものは利用するようにします。以下のスクリプトが雪を描くものです。

// x=X座標、y=Y座標、h=雪の大きさ、opacity=明るさ
function snow(x,y,w,opacity)
{
var id1 = charIDToTypeID("setd");
var id2 = charIDToTypeID("null");
var id3 = charIDToTypeID("Chnl");
var id4 = charIDToTypeID("fsel");
var desc1 = new ActionDescriptor();
var desc2 = new ActionDescriptor();
var ref1 = new ActionReference();
ref1.putProperty( id3, id4 );
desc1.putReference( id2, ref1);

var unit = charIDToTypeID( "#Pxl");
var id5 = charIDToTypeID( "T " );
var pos = charIDToTypeID( "Top ");
desc2.putUnitDouble( pos, unit, y);
pos = charIDToTypeID( "Left" );
desc2.putUnitDouble( pos, unit, x);
pos = charIDToTypeID( "Btom" );
desc2.putUnitDouble( pos, unit, y+w);
pos = charIDToTypeID( "Rght" );
desc2.putUnitDouble( pos, unit, x+w);
var selType = charIDToTypeID( "Elps" );
var anti = charIDToTypeID( "AntA" );
desc1.putObject( id5, selType, desc2 );
desc1.putBoolean( anti, true );
executeAction( id1, desc1, DialogModes.NO );

activeDocument.selection.fill(RGBColor,ColorBlendMode.NORMAL, opacity, false);
activeDocument.activeLayer.applyBlurMore();
}

activeDocument.activeLayer.isBackgroundLayer = false;
RGBColor = new SolidColor();
RGBColor.red = 255;
RGBColor.green = 255;
RGBColor.blue = 255;
snowNum = 60;

docW = parseFloat(activeDocument.width);
docH = parseFloat(activeDocument.height);

for (i=0; i<snowNum; i++)
{
X = Math.random() * docW;
Y = Math.random() * docH;
snow(X,Y,25,100);
}


もし、雪の輪郭をくっきりさせたいのであれば

activeDocument.activeLayer.applyBlurMore();

という行を削除してください。ちょっとだけぼかしたい場合には上記の行を

activeDocument.activeLayer.applyBlur();

に変更してください。少しだけぼかした状態になります。雪の大きさですが

snow(X,Y,25,100);

の25の値を変更します。ただし、6未満の数値になってしまうと選択範囲が破綻して全面真っ白になってしまったりすることがあります。100は雪の明るさです。0で真っ黒、100で真っ白になります。
上記のスクリプトは雪の大きさが全部同じですが、雪の大きさを変えたい場合には以下のスクリプトになります。雪の大きさはランダムに変わります。

// x=X座標、y=Y座標、h=雪の大きさ、opacity=明るさ
function snow(x,y,w,opacity)
{
var id1 = charIDToTypeID("setd");
var id2 = charIDToTypeID("null");
var id3 = charIDToTypeID("Chnl");
var id4 = charIDToTypeID("fsel");
var desc1 = new ActionDescriptor();
var desc2 = new ActionDescriptor();
var ref1 = new ActionReference();
ref1.putProperty( id3, id4 );
desc1.putReference( id2, ref1);

var unit = charIDToTypeID( "#Pxl");
var id5 = charIDToTypeID( "T " );
var pos = charIDToTypeID( "Top ");
desc2.putUnitDouble( pos, unit, y);
pos = charIDToTypeID( "Left" );
desc2.putUnitDouble( pos, unit, x);
pos = charIDToTypeID( "Btom" );
desc2.putUnitDouble( pos, unit, y+w);
pos = charIDToTypeID( "Rght" );
desc2.putUnitDouble( pos, unit, x+w);
var selType = charIDToTypeID( "Elps" );
var anti = charIDToTypeID( "AntA" );
desc1.putObject( id5, selType, desc2 );
desc1.putBoolean( anti, true );
executeAction( id1, desc1, DialogModes.NO );

activeDocument.selection.fill(RGBColor,ColorBlendMode.NORMAL, opacity, false);
activeDocument.activeLayer.applyBlurMore();
}

activeDocument.activeLayer.isBackgroundLayer = false;
RGBColor = new SolidColor();
RGBColor.red = 255;
RGBColor.green = 255;
RGBColor.blue = 255;
snowNum = 60;

docW = parseFloat(activeDocument.width);
docH = parseFloat(activeDocument.height);

for (i=0; i<snowNum; i++)
{
X = Math.random() * docW;
Y = Math.random() * docH;
r = Math.random() * 10 + 6;
opac = Math.random() * 30 + 70;
snow(X,Y,r,opac);
}

雪の大きさは

r = Math.random() * 10 + 6;

の行の10の値を変更してください。+6の6は一番小さいの雪のサイズです。雪の明るさもランダムに変わるようになっていますが、100%に固定したい場合には

snow(X,Y,r,opac);

の行を

snow(X,Y,r,100);

にしてください。小さい雪は遠くにあるから暗くして、大きい雪は近くにあるから明るくしたいという場合には

opac = Math.random() * 30 + 70;

opac = Math.random() * r * 2 + 70;

のように変更します。これで小さい雪は暗くなり、大きい雪は明るく描画されます。




[サンプルをダウンロード]