最近のシェーダーは複数のテクスチャを利用し、
表現力をあげるのですが、
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