PhotoShopScript JavaScript – 3Dcoatのファイル処理

うーん、微妙なスクリプトだ。
3Dcoatのファイルメニューから、
テクスチャ>エクスポート>深度、カラー、スペキュラと共にレイヤーをエクスポート
を実行すると、いくつかファイルが生成されます。
(ファイル名).color.psd
(ファイル名).depth.exr
(ファイル名).layers_xml
(ファイル名).specular.psd
の4種類です。

 

やりたかったことは、フォトショップに持っていった時に、レイヤーのグループ状態や表示状態を
3Dcoatと合わせたかったのです。
ただ、グループの仕様はフォトショップと3Dcoatで違いがあり、自由にターゲットが選べる3Dcoatとは違い、
フォトショップでは、グループ同士が上下に存在していなければなりません。
そこの部分はスクリプトではどうしようもなかったので、作りませんでした。
3Dcoatで「リンクするレイヤー」が設定されているレイヤーは下のレイヤーとグループになる。
という処理になっております。

 

使用方法ですが、
吐き出した、(ファイル名).color.psdをフォトショップで開き、スクリプトを実行します。
スクリプトは、
C:\Program Files (x86)\Adobe\Adobe Photoshop CS2\プリセット\スクリプト\
等に入れれば、フォトショップのファイルメニュー、ファイル>スクリプトに表示されます。
xmlファイルに記載されている情報を読み取り、レイヤーを操作しているだけです。

 

出来れば3Dcoatから直接送られてきたデータでも同じようにしたいのですが、中々難しい、、
xmlファイルを作らなくても3bファイルをテキストエディタで開くと、先頭部分に同じ記述があるので、
それを読み込みたいが、Pythonのように特定の文字列でファイルの読み込みを止める方法が分からない。
さすがに全部読み込むのは気がひけるなぁ、、

 

ということで中途半端なスクリプトです。

function coat_file()
{
	if (!app.documents)
	{
		return;
	}
	docRef = app.activeDocument;
	xmlFileName = docRef.name;
	xmlFileName = xmlFileName.split(".")[0]
	xmlFilePath = docRef.path+"/"+xmlFileName+".layers_xml";
	fileObj = new File(xmlFilePath);
	if (fileObj.exists)
	{
		read_xml_file(fileObj);
	}else{
		alert("xmlファイルが見つかりません");
		return;
	}
}
function read_xml_file(fileObj)
{
	try{
		fileObj.open("r");
	}catch(e){
		alert(fileObj.name + " ファイルが開けませんでした")
		return;
	}
	texts = fileObj.read();
	lines = texts.split("\n");
	fileObj.close();
	layName = [];
	layGroup = [];
	layVisible = [];
	for (i=0;i<lines.length;i++)
	{
		if (lines[i].indexOf("<Name>") != -1)
		{
			layName.push(lines[i].split("<Name>")[1].split("</Name>")[0]);
		}
		if (lines[i].indexOf("<LinkedLayer>") != -1)
		{
			layGroup.push(lines[i].split("<LinkedLayer>")[1].split("</LinkedLayer>")[0]);
		}
		if (lines[i].indexOf("<Visible>") != -1)
		{
			layVisible.push(lines[i].split("<Visible>")[1].split("</Visible>")[0]);
		}
	}
	for (i=0;i<layName.length;i++)
	{
		if (layGroup[i] != "NO_LINK" && !docRef.layers[layName[i]].grouped)
		{
			docRef.activeLayer = docRef.layers[layName[i]];
			group_layer();
		}
		if (layVisible[i] != "true")
		{
			docRef.layers[layName[i]].visible = false;
		}
	}
}
function group_layer()
{
	var idGrpL = charIDToTypeID( "GrpL" );
	var desc2 = new ActionDescriptor();
	var idnull = charIDToTypeID( "null" );
	var ref1 = new ActionReference();
	var idLyr = charIDToTypeID( "Lyr " );
	var idOrdn = charIDToTypeID( "Ordn" );
	var idTrgt = charIDToTypeID( "Trgt" );
	ref1.putEnumerated( idLyr, idOrdn, idTrgt );
	desc2.putReference( idnull, ref1 );
	executeAction( idGrpL, desc2, DialogModes.NO );
}
coat_file()

テキストエディタにコピペし、(適当なファイル名).jsと拡張子を付けて保存してください。

Maya Script Python – alembic export

import pymel.core as pm
import os,os.path,sys

def abc_export():
	cspace = pm.workspace(q=1,fn=1)
	sels = pm.ls(sl=1)
	if sels and sels[0].type() == "transform":
		name = sels[0].name()
		if name.find("|")!=-1:
			name = name.rsplit("|",1)[1]
		cspace = os.path.join(cspace,"scenes").replace("\\","/")
		names = "".join([" -root "+x.name() for x in sels])
		pm.AbcExport(j="-frameRange 1.25 12.5 -uvWrite{0:} -worldSpace -file {1:}/{2:}.abc".format(names,cspace,name))
abc_export()

以前のせたAlembicのエクスポート、複数のオブジェクトが選択されていると正しく出力できない出来損ないだったので、
修正しました。
gknPoseLoadSaveに引き続き、gknAnimCopypasteも修正しました。
同じように起動方法の変更、ミラーのデフォルト変更です。

 

どうやらクラスオブジェクトでUIを作るときにはメソッドとして起動するよりも、
初期化でやってしまったほうが良いような気がする。

 

本来はどちらにせよ、DeleteUIで消せるはずなのに、なぜかクラスオブジェクトでUIを作っていると消えないことがある。
再現性が低いので、原因がよく分からない。低くなくてもよく分からないかもしれない。
なので、初期化時にUIを表示してしまえば、複数表示されていたとしても、それはそれとして機能するので、
ソッチのほうが良いだろう。ということです。
と、自分で書いていてもよく分からないので、伝わらない。

Maya Script Pymel 2013

以前2013でpymelを使うとマテリアルが取得できない、ということを書いたかと思います。
インストールミスか何かだろう。と余りきにせずにいたのですが、新たな環境で再び2013を入れると、再び同じ症状が、、
2012も入っていたので、エラーが出ている箇所を見比べてみました。
少し違う。
なので、それを入れ替えてみました。
問題の箇所は、
C:\Program Files\Autodesk\Maya2013\Python\Lib\site-packages\pymel\internal\apicache.py
にあります。
それの69行目から、84行目をコメントアウト、もしくは削除し、
次のコードを挟みます。

    try:
        try :
            obj = dgMod.createNode ( mayaType )
        except RuntimeError:
            # DagNode
            obj = dagMod.createNode ( mayaType, parent )
            _logger.debug( "Made ghost DAG node of type '%s'" % mayaType )
        else:
            # DependNode
            _logger.debug( "Made ghost DG node of type '%s'" % mayaType )
    except Exception:
        obj = None

    if api.isValidMObject(obj) :
        return obj
    else :
        _logger.debug("Error trying to create ghost node for '%s'" %  mayaType)
        return None

2012のコードです。
すると問題なくマテリアルが取得出来ます。
で、色々と気づいたのですが、2013でウェイトエディタを使うと思ったように数値を丸めてくれない。
これを調べると、どうやらそれ以前のバージョンであったバグの回避用にしていた箇所が問題のようでした。
まったくもう、、

 

それとついでに、gknPoseLoadSaveを修正しました。
バグフィックスです。
これできちんと起動出来ます。
自分の環境ではすでに必要な物があるので、問題なく起動していましたが、そうでない場合恐らく初回起動ができない。
要するに使えない。
酷いバグだ。
ついでにalembicのインポート機能も加えました。
ただしMaya2013であることが前提です。それ以外では機能しません。
起動方法も変わったのでご注意ください。
abcファイルを選択し、「ImportFile」を行えばインポートできます。
で、エクスポートは、

import pymel.core as pm
import os,os.path

def abc_export():
	meshs = pm.ls(sl=1)
	if meshs and meshs[0].type() == "transform":
		name = meshs[0].name()
		path = pm.Env().sceneName().rsplit("/",1)[0]
		name = name.rsplit("|",1)[-1]
		path = os.path.join(path,name).replace("\\","/")
		pm.AbcExport( -j "-frameRange 1 24 -uvWrite -worldSpace -root {0:} -file {1:}.abc".format(name,path))
abc_export()

で、できます。
オブジェクトを選択し、実行すると、開いているシーンと同じディレクトリに保存されます。
ファイル名はオブジェクトの名前が付いているかと思います。
gknPoseLoadSaveの「Reload」を押すとリストに現れるかと思います。
他のツールで編集し、UVがアイランドであるにも関わらず、切れてしまっている場合は、

import pymel.core as pm

def clean_mesh() :
	sel = pm.ls(sl=1,o=1)
	if not sel:
		return
	for s in sel :
		pm.select( s, r= 1 )
		pm.polyMergeUV(d=0.001)
		pm.delete( s, ch= 1 )
	pm.select(sel)
clean_mesh()

オブジェクトを選択し、上記のスクリプトを実行すると綺麗に繋がります。

Maya Script Python numpy

numpyというライブラリーを知りました。
なんでも行列や多次元配列の扱いに特化したモジュールで、その部分の計算が格段に早くなるそうです。
で、早速インストール。
こちらのページ、Pythonのモジュールがたくさんあります。
この中ほど、numpy-MKL-1.7.1.win-amd64-py2.6.‌exeという物を入れてみました。

 

因みにこれをインストールする前にPythonの2.6をインストールする必要があります。
それはこちらにあります。
64bit環境なので、Windows X86-64 MSI Installer (2.6)をインストールしました。

 

しかし、どうやら2013ではdllを入れる必要があるようで、それだけでは使えません。
2012であれば、C:\Python26\Lib\site-packages\にできる、numpyというディレクトリを、
C:\Program Files\Autodesk\Maya2012\Python\Lib\site-packages\にコピーすれば使えます。

 

何を作ってみようか。
そんな時に思いついたのが、以前作った事がある、選択された頂点の周りの頂点の法線から平均を取り、
スムーズさせるツールです。
因みにnumpyを使わないでそれをするには、

import maya.cmds as cmds
import maya.mel

def nomal_smooth():
	gMainProgressBar = maya.mel.eval( '$tmp = $gMainProgressBar' )
	oSels = cmds.ls(sl=1)
	if oSels == []:
		return
	oVtxs = cmds.ls(cmds.polyListComponentConversion(oSels,tv=1),fl=1)
	cmds.undoInfo(swf=0)
	cmds.progressBar(gMainProgressBar,e=1,bp=1,ii=1,st='Now Smoothing...',max=len(oVtxs))
	for oVtx in oVtxs:
		oAroundNors = []
		[oAroundNors.append(cmds.polyNormalPerVertex(x,q=1,xyz=1)[0:3]) for x in cmds.ls(cmds.polyListComponentConversion(cmds.polyListComponentConversion(oVtx,tf=1),tv=1),fl=1)]
		oANorZip = zip(*oAroundNors)
		cmds.polyNormalPerVertex(oVtx,xyz=[sum(oANorZip[0])/len(oANorZip[0]),sum(oANorZip[1])/len(oANorZip[1]),sum(oANorZip[2])/len(oANorZip[2])])
		cmds.progressBar( gMainProgressBar, edit=True, step=1 )
		if cmds.progressBar(gMainProgressBar,q=1,ic=1):
			break
	cmds.progressBar( gMainProgressBar, edit=True, endProgress=True )
	cmds.undoInfo(swf=1)

nomal_smooth()

大量の頂点を選択すると、処理がとても重いことが分かります。
で、numpyで作りなおすと、

import numpy as np
import maya.cmds as cmds

def nomal_smooth_numpy_cmds():
	gMainProgressBar = maya.mel.eval( '$tmp = $gMainProgressBar' )
	oSels = cmds.ls(sl=1)
	if oSels == []:
		return
	oVtxs = cmds.ls(cmds.polyListComponentConversion(oSels,tv=1),fl=1)
	cmds.undoInfo(swf=0)
	cmds.progressBar(gMainProgressBar,e=1,bp=1,ii=1,st='Now Smoothing...',max=len(oVtxs))
	for oVtx in oVtxs:
		aroundVtx = cmds.ls(cmds.polyListComponentConversion(cmds.polyListComponentConversion(oVtx,tf=1),tv=1),fl=1)
		ar = np.transpose(np.array([cmds.polyNormalPerVertex(x,q=1,xyz=1)[0:3] for x in aroundVtx]))
		cmds.polyNormalPerVertex(oVtx,xyz=[np.mean(x) for x in ar])
		cmds.progressBar( gMainProgressBar, edit=True, step=1 )
		if cmds.progressBar(gMainProgressBar,q=1,ic=1):
			break
	cmds.progressBar( gMainProgressBar, edit=True, endProgress=True )
	cmds.undoInfo(swf=1)

nomal_smooth_numpy_cmds()

やってみると分かりますが、速さを実感できない、、
使い方が間違えているのだろうか?
で、それをpymelと併用すると、

import numpy as np
import pymel.core as pm

def nomal_smooth_numpy_pymel():
	gMainProgressBar = pm.mel.eval( '$tmp = $gMainProgressBar' )
	oSels = pm.ls(sl=1)
	if oSels == []:
		return
	oVtxs = pm.ls(pm.polyListComponentConversion(oSels,tv=1),fl=1)
	pm.undoInfo(swf=0)
	pm.progressBar(gMainProgressBar,e=1,bp=1,ii=1,st='Now Smoothing...',max=len(oVtxs))
	for oVtx in oVtxs:
		aroundVtx = pm.ls(pm.polyListComponentConversion(pm.polyListComponentConversion(oVtx,tf=1),tv=1),fl=1)
		ar = np.transpose(np.array([x.getNormals()[0] for x in aroundVtx]))
		pm.polyNormalPerVertex(oVtx,xyz=[np.mean(x) for x in ar])
		pm.progressBar( gMainProgressBar, edit=True, step=1 )
		if pm.progressBar(gMainProgressBar,q=1,ic=1):
			break
	pm.progressBar( gMainProgressBar, edit=True, endProgress=True )
	pm.undoInfo(swf=1)

nomal_smooth_numpy_pymel()

更に遅い、、
確かに記述はスッキリするのですが、高速化には至りませんでした。
更に色々と調べていると、Cythonというものを知りました。
Cのように、ビルドする必要がある、Pythonのようです。
物によってはとても高速になるが、それでも劇的に変わる、ということは無さそうです。
Mayaで使えるのだろうか?
変数や関数の型を静的に書く必要があるのなら、一層のことCを勉強したほうがいいのか?
うーん、気が向かない。
やっぱりPythonは書きやすい。

ZBrush – キャラクター1

2013_05_03Image_01
modoでゲームモデルを作るワークフローを試すつもりで、モデルを作り始めました。
ベースメッシュは楽なZBrushで作ろう、と思い、始めたらこんなん出ました。

 

うーん、なんだかイメージしていたものと違う、、
仏像のようになってしまった。
時間がかかりそうだなぁ、、

アニメーションが親切に解説されております

レンダリング、ライティングの基本が分かります

図版が見やすい美術解剖書です