2013年9月2日月曜日

Photoshop Script : EF-12 DDS書き出しツール

最近のシェーダーは複数のテクスチャを利用し、
表現力をあげるのですが、
EF-12も例外ではありません

EF-12 スタンダーとマテリアルの設定
リンク先にあるように非常にたくさんの設定があります。

が、以下の作業がとても面倒でした。

異なるテクスチャ素材から、目的のフォーマットのDDSを制作する

スーパー超絶面倒。
なのでPhotoshopのスクリプトで自動化します

目的

Photoshopで異なる複数のテクスチャから、
目的のDDSを書き出す



EF-12より、この辺りの作業です


ツール

・Windows (Nvidiaのツールが動くのがWIndowsなので)
・Photoshop CS5(スクリプトが使えれば多分OK)
・Photoshop Plugin Nvidia DDS

PluginであるNvidiaのDDSツールもスクリプトから制御出来ました。
超便利。コレだけでも調査したかいがあった〜


素材


以下のテクスチャ素材

そのままDDSに書き出す素材
・_d デカール
・_n ノーマル

Dentに合成するテクスチャ
・_h 高さ
・_ao 遮蔽

Glossに合成するテクスチャ
・_s 輝度
・_pow 硬度

です。ちょっとここらアタリ、調査不足でしたので命名規則は適当です orz


流れ


画面の開発環境はCS6です、実行はCS5でした :p


Photoshopで以上の6種類のテクスチャを開きます。

で、こういった順で処理をします。

_dnttテクスチャの作成
_h > dnt の Rチャンネルに
_ao > dnt のBチャンネルに
_dnt > DDS(DTX5_NM形式) で保存

_glossテクスチャの作成
_s >glossのRチャンネルに
_pow > glossのBチャンネルに
_gloss > DDS(DTX5_NM形式) で保存

_d > DDS(可変あり) で保存
_n > DDS(DTX5_NM形式) で保存


です。計6種類のテクスチャを
4種のDDSテクスチャにまとめ書き出しました


Photoshop Script


そのコードです
1日で作った付け焼き刃ですので、
エラー処理など、効率化などはしておりません

サンプルとして見てください
//mergeTex
//20120831 savedds
//EF12用にカスタム

debug = true


// 初期設定===========================================================
ex1 = ["dnt","h","ao","",""]
ex2 = ["gloss","s","pow","",""]
strDeffuse = "d"
strNormal = "n"

DXT1_RGB        = 0;
DXT1_RGBA_1Bit  = 1;
DXT5_RGBA       = 3;
DXT5_NM         = 24;

closeNewDoc = true;

function log(in_data){
    if (debug ) alert(in_data)
    }


//SAVEDDS =======================================================
function saveDDS(in_path,in_ddsType){
 var idsave = charIDToTypeID( "save" );
  var desc14 = new ActionDescriptor();
  var idAs = charIDToTypeID( "As  " );
   var desc15 = new ActionDescriptor();
   var idbarF = charIDToTypeID( "barF" );
   desc15.putBoolean( idbarF, true );
   var idfdev = charIDToTypeID( "fdev" );
   desc15.putDouble( idfdev, 3.000000 );
   var idfbia = charIDToTypeID( "fbia" );
   desc15.putDouble( idfbia, 0.000000 );
   var idurad = charIDToTypeID( "urad" );
   desc15.putDouble( idurad, 5.000000 );
   var iduamo = charIDToTypeID( "uamo" );
   desc15.putDouble( iduamo, 0.500000 );
   var iduthr = charIDToTypeID( "uthr" );
   desc15.putDouble( iduthr, 0.000000 );
   var idxstf = charIDToTypeID( "xstf" );
   desc15.putDouble( idxstf, 1.000000 );
   var idxthf = charIDToTypeID( "xthf" );
   desc15.putDouble( idxthf, 1.000000 );
   var idqual = charIDToTypeID( "qual" );
   desc15.putInteger( idqual, 71 );
   var iderdi = charIDToTypeID( "erdi" );
   desc15.putBoolean( iderdi, false );
   var iderdw = charIDToTypeID( "erdw" );
   desc15.putInteger( iderdw, 1 );
   var idusfa = charIDToTypeID( "usfa" );
   desc15.putBoolean( idusfa, false );
   var idtxfm = charIDToTypeID( "txfm" );
   desc15.putInteger( idtxfm, in_ddsType );//ddsType
   var idweig = charIDToTypeID( "weig" );
   desc15.putInteger( idweig, 0 );
   var idtmty = charIDToTypeID( "tmty" );
   desc15.putInteger( idtmty, 0 );
   var idmmty = charIDToTypeID( "mmty" );
   desc15.putInteger( idmmty, 32 );
   var idsmip = charIDToTypeID( "smip" );
   desc15.putInteger( idsmip, 0 );
   var idbina = charIDToTypeID( "bina" );
   desc15.putBoolean( idbina, false );
   var idprem = charIDToTypeID( "prem" );
   desc15.putBoolean( idprem, false );
   var idfilm = charIDToTypeID( "film" );
   desc15.putBoolean( idfilm, false );
   var idalpb = charIDToTypeID( "alpb" );
   desc15.putBoolean( idalpb, false );
   var idbord = charIDToTypeID( "bord" );
   desc15.putBoolean( idbord, false );
   var idbrdr = charIDToTypeID( "brdr" );
   desc15.putDouble( idbrdr, 0.000000 );
   var idbrdg = charIDToTypeID( "brdg" );
   desc15.putDouble( idbrdg, 0.000000 );
   var idbrdb = charIDToTypeID( "brdb" );
   desc15.putDouble( idbrdb, 0.000000 );
   var idmmft = charIDToTypeID( "mmft" );
   desc15.putInteger( idmmft, 2 );
   var idfdcl = charIDToTypeID( "fdcl" );
   desc15.putBoolean( idfdcl, false );
   var idfdaf = charIDToTypeID( "fdaf" );
   desc15.putBoolean( idfdaf, false );
   var idftworl = charIDToTypeID( "f2rl" );
   desc15.putDouble( idftworl, 0.500000 );
   var idftwogl = charIDToTypeID( "f2gl" );
   desc15.putDouble( idftwogl, 0.500000 );
   var idftwobl = charIDToTypeID( "f2bl" );
   desc15.putDouble( idftwobl, 0.500000 );
   var idftwoal = charIDToTypeID( "f2al" );
   desc15.putDouble( idftwoal, 0.500000 );
   var idfddl = charIDToTypeID( "fddl" );
   desc15.putInteger( idfddl, 0 );
   var idfafm = charIDToTypeID( "fafm" );
   desc15.putDouble( idfafm, 0.150000 );
   var idbafh = charIDToTypeID( "bafh" );
   desc15.putDouble( idbafh, 0.500000 );
   var iddthc = charIDToTypeID( "dthc" );
   desc15.putBoolean( iddthc, false );
   var iddthzero = charIDToTypeID( "dth0" );
   desc15.putBoolean( iddthzero, false );
   var idsmth = charIDToTypeID( "smth" );
   desc15.putInteger( idsmth, 0 );
   var idfilg = charIDToTypeID( "filg" );
   desc15.putDouble( idfilg, 2.200000 );
   var idfieg = charIDToTypeID( "fieg" );
   desc15.putBoolean( idfieg, false );
   var idfilw = charIDToTypeID( "filw" );
   desc15.putDouble( idfilw, 10.000000 );
   var idover = charIDToTypeID( "over" );
   desc15.putBoolean( idover, false );
   var idfblr = charIDToTypeID( "fblr" );
   desc15.putDouble( idfblr, 1.000000 );
   var idnmcv = charIDToTypeID( "nmcv" );
   desc15.putBoolean( idnmcv, false );
   var idncnv = charIDToTypeID( "ncnv" );
   desc15.putInteger( idncnv, 1009 );
   var idnflt = charIDToTypeID( "nflt" );
   desc15.putInteger( idnflt, 1040 );
   var idnmal = charIDToTypeID( "nmal" );
   desc15.putInteger( idnmal, 1033 );
   var idnmbr = charIDToTypeID( "nmbr" );
   desc15.putBoolean( idnmbr, false );
   var idnmix = charIDToTypeID( "nmix" );
   desc15.putBoolean( idnmix, false );
   var idnmiy = charIDToTypeID( "nmiy" );
   desc15.putBoolean( idnmiy, false );
   var idnmiz = charIDToTypeID( "nmiz" );
   desc15.putBoolean( idnmiz, false );
   var idnmah = charIDToTypeID( "nmah" );
   desc15.putBoolean( idnmah, true );
   var idnswp = charIDToTypeID( "nswp" );
   desc15.putBoolean( idnswp, false );
   var idnmsc = charIDToTypeID( "nmsc" );
   desc15.putDouble( idnmsc, 4.000000 );
   var idnmnz = charIDToTypeID( "nmnz" );
   desc15.putInteger( idnmnz, 0 );
   var idusbi = charIDToTypeID( "usbi" );
   desc15.putBoolean( idusbi, false );
   var idlien = charIDToTypeID( "lien" );
   desc15.putBoolean( idlien, false );
   var idshdi = charIDToTypeID( "shdi" );
   desc15.putBoolean( idshdi, false );
   var idshfi = charIDToTypeID( "shfi" );
   desc15.putBoolean( idshfi, false );
   var idshmm = charIDToTypeID( "shmm" );
   desc15.putBoolean( idshmm, true );
   var idshan = charIDToTypeID( "shan" );
   desc15.putBoolean( idshan, true );
   var idclrc = charIDToTypeID( "clrc" );
   desc15.putInteger( idclrc, 0 );
   var idvdxone = charIDToTypeID( "vdx1" );
   desc15.putBoolean( idvdxone, true );
   var idvdxtwo = charIDToTypeID( "vdx2" );
   desc15.putBoolean( idvdxtwo, true );
   var idvdxthree = charIDToTypeID( "vdx3" );
   desc15.putBoolean( idvdxthree, true );
   var idvdxfive = charIDToTypeID( "vdx5" );
   desc15.putBoolean( idvdxfive, true );
   var idvfourfourfour = charIDToTypeID( "v444" );
   desc15.putBoolean( idvfourfourfour, true );
   var idvfivefivefive = charIDToTypeID( "v555" );
   desc15.putBoolean( idvfivefivefive, true );
   var idvfivesixfive = charIDToTypeID( "v565" );
   desc15.putBoolean( idvfivesixfive, true );
   var idveighteighteight = charIDToTypeID( "v888" );
   desc15.putBoolean( idveighteighteight, true );
   var idalph = charIDToTypeID( "alph" );
   desc15.putBoolean( idalph, false );
   var idusra = charIDToTypeID( "usra" );
   desc15.putBoolean( idusra, false );
   var idusfs = charIDToTypeID( "usfs" );
   desc15.putInteger( idusfs, 0 );
   var idprev = charIDToTypeID( "prev" );
   desc15.putBoolean( idprev, false );
   var idrdep = charIDToTypeID( "rdep" );
   desc15.putInteger( idrdep, 3000 );
   var idlomm = charIDToTypeID( "lomm" );
   desc15.putBoolean( idlomm, false );
   var idsflp = charIDToTypeID( "sflp" );
   desc15.putBoolean( idsflp, false );
   var idlflp = charIDToTypeID( "lflp" );
   desc15.putBoolean( idlflp, false );
   var idscar = charIDToTypeID( "scar" );
   desc15.putDouble( idscar, 1.000000 );
   var idscag = charIDToTypeID( "scag" );
   desc15.putDouble( idscag, 1.000000 );
   var idscab = charIDToTypeID( "scab" );
   desc15.putDouble( idscab, 1.000000 );
   var idscaa = charIDToTypeID( "scaa" );
   desc15.putDouble( idscaa, 1.000000 );
   var idbiar = charIDToTypeID( "biar" );
   desc15.putDouble( idbiar, 0.000000 );
   var idbiag = charIDToTypeID( "biag" );
   desc15.putDouble( idbiag, 0.000000 );
   var idbiab = charIDToTypeID( "biab" );
   desc15.putDouble( idbiab, 0.000000 );
   var idbiaa = charIDToTypeID( "biaa" );
   desc15.putDouble( idbiaa, 0.000000 );
   var idsiar = charIDToTypeID( "siar" );
   desc15.putDouble( idsiar, 1.000000 );
   var idsiag = charIDToTypeID( "siag" );
   desc15.putDouble( idsiag, 1.000000 );
   var idsiab = charIDToTypeID( "siab" );
   desc15.putDouble( idsiab, 1.000000 );
   var idsiaa = charIDToTypeID( "siaa" );
   desc15.putDouble( idsiaa, 1.000000 );
   var idbiir = charIDToTypeID( "biir" );
   desc15.putDouble( idbiir, 0.000000 );
   var idbiig = charIDToTypeID( "biig" );
   desc15.putDouble( idbiig, 0.000000 );
   var idbiib = charIDToTypeID( "biib" );
   desc15.putDouble( idbiib, 0.000000 );
   var idbiia = charIDToTypeID( "biia" );
   desc15.putDouble( idbiia, 0.000000 );
   var idoutw = charIDToTypeID( "outw" );
   desc15.putBoolean( idoutw, false );
   var idclcL = charIDToTypeID( "clcL" );
   desc15.putBoolean( idclcL, true );
  var idNVIDIADthreeD_DDS = stringIDToTypeID( "NVIDIA D3D/DDS" );
  desc14.putObject( idAs, idNVIDIADthreeD_DDS, desc15 );
  var idIn = charIDToTypeID( "In  " );
  desc14.putPath( idIn, new File( in_path ) );
 executeAction( idsave, desc14, DialogModes.NO );
}


// メモ===========================================================
function folderserch(in_folderPath,aTex,bTex){
    }

function OpneFile(){
filename = "Macintosh HD:ps_text:headline.txt";
fileObj = new File(filename);
flag = fileObj.open("r");
if (flag == true)
{
alert("ファイルを開きました");
fileObj.close();
}else{
alert("ファイルが開けませんでした");
}
}

// チャンネルの移動===========================================================
function moveChannel(sDoc, tDoc, tChan)
    {
        app.activeDocument = sDoc
        //ソースのドキュメントの複製
        dupDoc = activeDocument.duplicate();
        //log(dupDoc.name)
        //統合
        dupDoc.flatten();
        //グレースケール
        dupDoc.changeMode(ChangeMode.GRAYSCALE);

        //コピー
        dupDoc.selection.selectAll();
        dupDoc.activeLayer.copy();
        
        //閉じる
        dupDoc.close(SaveOptions.DONOTSAVECHANGES);
        
        //移動
        //ターゲットをアクティブドキュメントに
        app.activeDocument = tDoc
        
        //チャンネルを指定
        if(tChan == "r") app.activeDocument.activeChannels = [app.activeDocument.channels.getByName( localize('$$$/ColorModes/RGB/ChannelName/Red=Red'))]
        else if(tChan == "g") app.activeDocument.activeChannels = [app.activeDocument.channels.getByName( localize('$$$/ColorModes/RGB/ChannelName/Green=Green'))]
        else if(tChan == "b") app.activeDocument.activeChannels = [app.activeDocument.channels.getByName( localize('$$$/ColorModes/RGB/ChannelName/Blue=Blue'))]
        else if(tChan == "a") { activeDocument.channels.add() }
        //app.activeDocument.activeChannels = activeDocument.channels.length - 1
            
        
        //ペースト
        activeDocument.paste()
        
        return true
        }


// ターゲドキュメント作成===========================================================
function createTragetDoc(in_name)
{
    preferences.rulerUnits = Units.PIXELS;
    w = activeDocument.width.value;
    h = activeDocument.height.value;
    tagetDoc = documents.add(w,h,72,in_name);
    return tagetDoc;
    }
 
 
// ソースファイルの取得===========================================================
function getSorceDoc(in_name){
    docs = documents;
    for ( var i = 0; i < docs.length; i++){
        var dName = docs[i].name
        dName = dName.substring( 0, dName.lastIndexOf(".") );
        if( dName == in_name){
            return docs[i]
            }
        }
    
    return false
    }

// マージのメイン関数===========================================================
function merge(base,r,g,b,a,outname,fPath){
    //最初にドキュメントを作成する
    var newDocName = base + "_" + outname
    var targetDoc = createTragetDoc(newDocName)
    var sorceDoc = false
    
    //r を移動
    if ( r != ""){
        sorceName = base + "_" + r;
        sorceDoc = getSorceDoc(sorceName);
        if ( sorceDoc ){
            moveChannel(sorceDoc,targetDoc,"r")
            }
     }
 
    //g を移動
    if ( g != ""){
        sorceName = base + "_" + g;
        sorceDoc = getSorceDoc(sorceName);
        if ( sorceDoc ){
            moveChannel(sorceDoc,targetDoc,"g")
            }
     }
    
    //b を移動
    if ( b != ""){
        sorceName = base + "_" + b;
        sorceDoc = getSorceDoc(sorceName);
        if ( sorceDoc ){
            moveChannel(sorceDoc,targetDoc,"b")
            }
     }
    
    //a を移動
    if ( a != ""){
        sorceName = base + "_" + a;
        sorceDoc = getSorceDoc(sorceName);
        if ( sorceDoc ){
            moveChannel(sorceDoc,targetDoc,"a")
            }
     }
 
    //savedds
    savePath = fPath + "\\" + base + "_" + outname + ".dds";
    //log(savePath)
    if ( a == "" && b == ""){
        saveDDS(savePath,DXT5_NM);
        }
    else if (a == "") {
        saveDDS(savePath,DXT1_RGB);
        }
    else {
        svaDDS(savePath,DXT5_RGBA);
        }
    
    //ddsを閉じる
    if(closeNewDoc) activeDocument.close();
    
    return true
    }

// sorce2ddsSave dds保存===========================================================
function sorce2ddsSave(baseName, dds,in_prefix, fPath){
    targetName = baseName + "_" + in_prefix;
    sorceDoc = getSorceDoc(targetName);
    if(sorceDoc == false) return;
    
    //アクティブドキュメントの変更(おまじない)
    app.activeDocument = sorceDoc;
    
    //ddsのチェック
    ddsType = 3
    if(String(dds) == "DXT1_RGB") ddsType = DXT1_RGB;
    if(String(dds) == "DXT1_RGBA_1Bit") ddsType = DXT1_RGBA_1Bit;
    if(String(dds) == "DXT5_RGBA") ddsType = DXT5_RGBA;
    if(String(dds) == "DXT5_NM") ddsType = DXT5_NM;
        
    //log(ddsType)
    
    //複製
    dupDoc = activeDocument.duplicate()
    
    //保存
    savePath = fPath + "\\" + targetName + ".dds";
    saveDDS(savePath,ddsType)

    //ddsを閉じる
    if(closeNewDoc) activeDocument.close();
    
    return true
    }


// メイン===========================================================
function main(){
    
    if (app.documents.length ==0){
        alert("Cancel No Docment")
        return;
        //ドキュメントが開かれていない場合処理なし
        }
    try { fPath = activeDocument.path }
    catch ( e ) { alert("pleas saveDocments"); return }
        
    dName = activeDocument.name
    dName = dName.substring( 0, dName.lastIndexOf(".") );
    dName = dName.substring( 0, dName.lastIndexOf("_") );
    
    uDlg = new Window('dialog','サンプル',[200,100,580,380]);
    
    uDlg.sText = uDlg.add("statictext",[10,10,275,10+45], "BaseName");  uDlg.eText = uDlg.add("edittext",[100,10,275,10+20], dName);
    
    uDlg.cBox1 = uDlg.add("checkbox",[10,50,275,50+25], "Merge 1");
    uDlg.r1  = uDlg.add("edittext",[020,80,020+30,080+20], ex1[1]);
    uDlg.g1  = uDlg.add("edittext",[070,80,070+30,080+20], ex1[2]);
    uDlg.b1  = uDlg.add("edittext",[120,80,120+30,080+20], ex1[3]);
    uDlg.a1  = uDlg.add("edittext",[170,80,170+30,080+20], ex1[4]);
    uDlg.out1 = uDlg.add("edittext",[220,80,220+60,080+20], ex1[0]);
    
    uDlg.cBox2 = uDlg.add("checkbox",[10,120,275,120+25], "Merge 2");
    uDlg.r2  = uDlg.add("edittext",[020,150,020+30,150+20], ex2[1]);
    uDlg.g2  = uDlg.add("edittext",[070,150,070+30,150+20], ex2[2]);
    uDlg.b2  = uDlg.add("edittext",[120,150,120+30,150+20], ex2[3]);
    uDlg.a2  = uDlg.add("edittext",[170,150,170+30,150+20], ex2[4]);
    uDlg.out2 = uDlg.add("edittext",[220,150,220+60,150+20],ex2[0]);
    
    uDlg.cBox3 = uDlg.add("checkbox",[10,180,100,180+25], "ddsSave");
    uDlg.deffuse  = uDlg.add("edittext",[80,180,80+30,180+20], strDeffuse);
    uDlg.dList3 = uDlg.add("dropdownlist",[130,180,130+200,180+25],["DXT1_RGB","DXT1_RGBA_1Bit","DXT5_RGBA","DXT5_NM"]);
    uDlg.dList3.selection = 0;
    
    uDlg.cBox4 = uDlg.add("checkbox",[10,210,100,210+25], "ddsSave");
    uDlg.normal  = uDlg.add("edittext",[80,210,80+30,210+20], strNormal); 
    uDlg.dList4 = uDlg.add("dropdownlist",[130,210,130+200,210+25],["DXT1_RGB","DXT1_RGBA_1Bit","DXT5_RGBA","DXT5_NM"]);
    uDlg.dList4.selection = 3  
    
    
    uDlg.okBtn = uDlg.add("button",[220,240,320,240+25], "Create", { name:"ok"});
    

    //ボタンを押されたときの設定
    
    //view_1
    uDlg.okBtn.onClick = function (){
        if(uDlg.cBox1.value) merge(uDlg.eText.text,uDlg.r1.text, uDlg.g1.text, uDlg.b1.text, uDlg.a1.text, uDlg.out1.text,fPath);
        if(uDlg.cBox2.value) merge(uDlg.eText.text,uDlg.r2.text, uDlg.g2.text, uDlg.b2.text, uDlg.a2.text, uDlg.out2.text,fPath);
        if(uDlg.cBox3.value) sorce2ddsSave(uDlg.eText.text, uDlg.dList3.selection, uDlg.deffuse.text, fPath);
        if(uDlg.cBox4.value) sorce2ddsSave(uDlg.eText.text, uDlg.dList4.selection, uDlg.normal.text,  fPath);
        refresh();
        uDlg.close()
        alert("Finish")
    }

    uDlg.show();
    }

main()


これで、テクスチャの作業に集中出来ます。
といっても、PSD1枚からの必要テクスチャの書き出しが必要かもしれませんが(w


まとめ

で、完成したのが9/1でコンテスト提出日の早朝でした :p
アフォすぎる w

まあ、とりあえずコンテストに応募しました :p
背景ですので、競合は少ないと思いますがw

一番開発に必要なのは
スケジューリングでしたとさw


追記

3D人さんから教わったんだけど。
こんな便利なツールが・・・。

QSM
Quick Save Maps v0.6.4 日本語版 - 勝手に制作!Photoshopにて複数テクスチャを手軽に書き出せる拡張ツール

もうコレで良いよね orz


情報を制したものが強い :p ってことでした。 コード参考にしよう orz

0 件のコメント:

コメントを投稿