Mudbox2013 その3

image942l
ZBrushでこんな感じに作ってみました。
サブディビジョンレベルは9です。
一応適当ですがディテールも追加しました。

 

サブディビジョンレベルを1にすると、
image943l
こんな感じです。
これをMudboxで再構築してみます。
objで吐き出し、それを読み込みます。
image944l
「w」キーでワイヤー表示ができます。細かすぎて良く分かりません。
思いの外objの読み込みが早いです。最速、と言っても過言ではないように思います。
image946l
メニューバー、メッシュ>「サブディビジョン レベルを再構築」
を実行します。
image948l
ガビーン、と言った感じでしょうか。
隠していたものが見つかったような、悔しさと恥ずかしさがあります。
データにそういった情報が含まれているのか、アルゴリズムの解釈がそうであるのか分かりませんが、
ZBrushで初めに取り掛かった形がそのまま出てきました。

 

因みにMudboxでは再構築するとサブディビジョンレベルが8つ作られました。
Mudboxの場合、0が一番目なので、レベルは同じ数のようです。
使用メモリも同じくらいです。Mudboxは64bit対応のようですが、モデルが3GBで足りている。ということなのでしょうか。
今度はトポロジーを変えたものをテストしてみます。

 

豆知識ですが、Mudboxで操作していると突然スカルプトができなくなることがあります。
何か悪いことをしたのだろうか、と色々と探っていると、
どうやらビューにパースが掛かっていると、拡大した時にスカルプトが出来ない。ということが分かりました。
「オブジェクトリスト」から「Perspective」を選択し、「正投影」にチェックを入れることで解決できます。
それが分かるまでにどれだけ苦労したことか、、情報が少ない?いや、情報を探っていない。
因みに、X軸への対称操作は、ブラシを選択し、表示されるプロパティ(?)の「反転機能」にチェックを入れるとできます。
見つけた時に、「あーそうだった。」と思わず声に出してしまいそうになりました。いや、出したかも。

Maya Script Python 頂点のスムージング

import maya.cmds as cmds
import maya.mel

#
#	http://giken.workarea.jp/
#	2012/5/25
#

def gkn_average_vertex(oVtx):
	cmds.polyAverageVertex(oVtx,i= 0)

def gkn_average_vertex_setvalue(oVtx):
	oVal= cmds.intField("Average_Vertex_Value",q= 1,v= 1)
	oSmoothVtx= cmds.ls(cmds.listHistory(cmds.ls(sl= 1,o= 1)),type= "polyAverageVertex")
	if oSmoothVtx != [] and set(oVtx) == set([cmds.ls(sl= 1,fl= 1)[0].split(".")[0]+"."+x for x in cmds.getAttr(oSmoothVtx[0]+".inputComponents")]):
		cmds.setAttr(oSmoothVtx[0]+".iterations",oVal)
		cmds.intSlider("Average_Vertex_Slider",e= 1,v= oVal)

def gkn_average_vertex_slidevalue(oVtx):
	oVal= cmds.intSlider("Average_Vertex_Slider",q= 1,v= 1)
	oSmoothVtx= cmds.ls(cmds.listHistory(cmds.ls(sl= 1,o= 1)),type="polyAverageVertex")
	if oSmoothVtx != [] and set(oVtx) == set([cmds.ls(sl= 1,fl= 1)[0].split(".")[0]+"."+x for x in cmds.getAttr(oSmoothVtx[0]+".inputComponents")]):
		cmds.setAttr(oSmoothVtx[0]+".iterations",oVal)
		cmds.intField("Average_Vertex_Value",e= 1,v= oVal)

def gkn_smooth_vertex_slider_val():
	oVal= cmds.floatSlider("Smooth_Vertex_Slider",q= 1,v= 1)
	cmds.floatField("Smooth_Vertex_Value",e= 1,v= oVal)

def gkn_smooth_vertex_field_val():
	oVal= cmds.floatField("Smooth_Vertex_Value",q= 1,v= 1)
	cmds.floatSlider("Smooth_Vertex_Slider",e= 1,v= oVal)

def gkn_smooth_vertex():
	oVal= cmds.floatField("Smooth_Vertex_Value",q= 1,v= 1)
	maya.mel.eval('artPuttyToolScript 4;')
	cmds.artPuttyCtx(cmds.currentCtx(),e= 1,mtm= "smooth")
	cmds.artPuttyCtx(cmds.currentCtx(),e= 1,si= 1)
	cmds.artPuttyCtx(cmds.currentCtx(),e= 1,op= oVal)
	cmds.artPuttyCtx(cmds.currentCtx(),e= 1,clr= 1)
	if cmds.selectContext("selectContext1",ex=1,q=1) == False:
		cmds.selectContext(n="selectContext1")
	cmds.setToolTo("selectContext1")

def gkn_smooth_vertex_update_window():
	oVtx= cmds.ls(sl= 1)
	cmds.intField("Average_Vertex_Value",e= 1,v= 0)
	cmds.intSlider("Average_Vertex_Slider",e= 1,v= 0)
	if cmds.filterExpand(sm= 31) != None:
		cmds.intField("Average_Vertex_Value",e= 1,cc= "gkn_average_vertex_setvalue("+str(oVtx)+")")
		cmds.intSlider("Average_Vertex_Slider",e= 1,dc= "gkn_average_vertex_slidevalue("+str(oVtx)+")")
		cmds.button("gkn_Average_Vertex",e= 1,c= "gkn_average_vertex("+str(oVtx)+")")

def gkn_smooth_vertex_window():
	if cmds.window("Average_VertexUI",q= 1,ex= 1) :
		cmds.deleteUI("Average_VertexUI")
	svwin= cmds.window("Average_VertexUI",title= "Gkn Smooth Vtxs",w= 200,h= 50)
	cmds.columnLayout(adj= 1)
	cmds.rowLayout(nc= 2,adj= 2,cw2= (50,150))
	cmds.intField("Average_Vertex_Value",w= 50,min= 0,max= 10,v= 0,s= 1)
	cmds.intSlider("Average_Vertex_Slider",min= 0,max= 10,v= 0,w= 100)
	cmds.setParent('..')
	cmds.button("gkn_Average_Vertex",l= "Average Vertexs",w= 100)
	cmds.rowLayout(nc= 2,adj= 2,cw2= (50,150))
	cmds.floatField("Smooth_Vertex_Value",w= 50,min= 0,max= 1,v= 1,s= 0.01,pre= 2,cc= "gkn_smooth_vertex_field_val()")
	cmds.floatSlider("Smooth_Vertex_Slider",min= 0,max= 1,v= 1,w= 100,s= 0.01,dc= "gkn_smooth_vertex_slider_val()")
	cmds.setParent('..')
	cmds.button("gkn_Smooth_Vertex",l= "Smooth Vertexs",w= 100,c= "gkn_smooth_vertex()")
	cmds.scriptJob(p= "Average_VertexUI",e= ["SelectionChanged","gkn_smooth_vertex_update_window()"])
	cmds.scriptJob(p= "Average_VertexUI",e= ["Undo","gkn_smooth_vertex_update_window()"])
	cmds.scriptJob(p= "Average_VertexUI",e= ["Redo","gkn_smooth_vertex_update_window()"])
	gkn_smooth_vertex_update_window()
	cmds.showWindow(svwin)
gkn_smooth_vertex_window()

スクリプトエディタを「Python」にして、上記のコードをペーストし実行するとウィンドウが表示されます。
image938l
簡単なウィンドウです。

 

前回、頂点のスムージングが見つからない。と書きましたが、書いたそばから見つけました。
ポリゴンメニューバーの、メッシュ>頂点の平均化でした。
しかし、昔の記憶を辿ると、スキニングのスムージングのようにペイントでスムーズが出来たことを思い出し、
探してみました。
同じくポリゴンメニューバーの、メッシュ>ジオメトリのスカルプトツールでした。

 

で、このスクリプトを作った時は、平均化のコマンドしか知らなかったので、まずはそれを実装しました。
そののち、スカルプとツールも実装できるのでは?と思い、実装してみたら出来ました。
ただ、困ったことに使い方が全く違う。そういったものを一つのウィンドウに収めるのはいかがなものか?
と、思いましたが、基本的に自分で使うものなので、いいや、とまとめてしまいました。
こういうことをすると、忘れた時に自分が困る。そして、当時の自分に横着するな、と突っ込む。

 

では、使い方です。
ウィンドウの上のスライダーとボタンが、頂点の平均化コマンドで使用するもので、
下のほうがスカルプとツールで使用するものです。どちらも頂点を丸めることを目的としています。

 

上の方の画像にありますが、乱雑に並んだ頂点で実行してみました。
Mayaでの作り方を調べるのが面倒なので、modoで作って持ってゆきました。ジッターです。
一番左のジオメトリが持ってきたそのままです。
真ん中が頂点の平均化で、丸めたものです。10の値で3回かけました。
右がスカルプトツールで丸めたものです。1の値で3回かけました。

 

因みにこちらの画像の右側がmodoのスムースを強さ1、反復30でかけたものです。
image939l

 

使い方の説明をしようと思い、話がそれました。
頂点の平均化は、ヒストリとして動作するのでノードが残ります。
出来れば、メニューバーの、編集>種類ごとに削除>デフォーマ以外のヒストリを実行してください。
ツールを使用した後も使ったほうが良いかと思います。
で、肝心の使い方は、均したい頂点を選択し、「Average Vertexs」ボタンを押します。
その後、スライダを動かして値を調整します。リアルタイムで変更できます。
決まったらデフォーマ以外のヒストリを削除して、もう一度同じ手順を繰り返すと、更に均すことが出来ます。
はじめからもっと大きな値を入れられるようにしたほうがいいのでは?とおもわれるかも知れませんが、
どうも10以降大して変化がないので10にしました。
要するに、こちらの機能は、ボタンを押す、値を決める。という手順です。
 

そして、下のスカルプとツールです。
こちらは反対で、設定できる値は、ブラシの透明度(?)です。要するにどれくらいの強さで掛けるかと言う事です。
その値を決定し、「Smooth Vertexs」を押すと実行されます。こちらはヒストリに残りません。
※追記2012/5/25
こちらの機能は頂点選択か、オブジェクト選択で機能します。
頂点の場合は選ばれている頂点に対して作用します。

 

どうも自分が探していた機能は後者のようです。
で、今回の収穫としては、melを読みこまなくてもペイントツールにアクセスできるようになった。ということでしょうか。
因みに参考とした、ペイントツールのコマンドは、
C:\Program Files\Autodesk\Maya2013\scripts\others\
にある、artPutty~.melとある、ファイル群です。
なるほどねぇ、そうやるんだ。という感じです。

 

調子に乗って、スキンウェイトのペイントにもアクセスしてみましたが、ある程度は出来たのですが、
コンフィグに書き込まれてしまったのか、ペイント自体の機能が変わってしまいました。
こんな事もあろうかと、Mayaやmodoのコンフィグは起動時にバックアップを取るように設定しておりました。
無きゃ無いで仕方がないが、あれば助かる。

 

image940l
ZBrushで作成中です。3DcoatとMudboxのリトポ、どちらがどうなのか。比べるためのものです。
久しぶりに触ると、やっぱり面白い。Cray系のブラシの素晴らしさに改めて関心です。他を触るとその差が歴然とする。
で、自分の誤作動の原因も分かりました。
パソコンが遅いせいでした。微量な遅延があったせいで、良く誤作動を起こしていたようです。
会社では全く誤作動がないので気が付きました。
まぁ、使えているから取り立てて文句はない。

※注記
すみません、、どうやらこのスクリプトを使用してスカルプとツールを起動するとスキニングウェイトのペイントモードが壊れるように、
スカルプとツールのペイントも壊れるようです。
修正できたら上げ直しますので、使用は控えてください。

 
※さらに注記
とりあえず、melを使うことで回避できました。うーん、ちょっと悔しい。

 

調べてみると、rememberCtxSettingsという関数が鍵を握っているようです。
で、ネットでその関数がどこにあるのか調べてみると、C:\Program Files\Autodesk\Maya2013\scripts\startup\initContexts.mel
にありました。
Pythonに移植できないか、と、見てみましたが、長い、、面倒くさい、、
いいや、mel使えば。と諦めました。

Maya Script Python テクスチャのリロード

突然ですが、気が向いたのでMayaでのテクスチャリロードについて調べました。
以前発見した、melで書かれたものをPythonに翻訳するとこんな感じです。

import maya.cmds as cmds
import maya.mel

maya.mel.eval('eval("source AEfileTemplate.mel");')
for x in cmds.ls(type="file"):
	maya.mel.eval('AEfileTextureReloadCmd("{0:}.ftn");'.format(x))

で、そこに使われているmelを探してみました。
C:\Program Files\Autodesk\Maya2013\scripts\AETemplates\
※バージョンによって多少異なります。
に、AEfileTemplate.melというmelが存在し、その中のAEfileTextureReloadCmdという関数を使用しているのが分かります。
なので、それをPythonに翻訳してみました。

import maya.cmds as cmds

files1 = [cmds.getAttr(x+".ftn") for x in cmds.ls(type="file")]
files2 = cmds.ls(typ="file",type="mentalrayTexture")
if files1 != []:
	for file1 in files1:
		for file2 in files2:
			if file1==cmds.getAttr(file2+".ftn"):
				cmds.setAttr(file2+".ftn",file1,type="string")

こんな感じでしょうか。
さらに、それをリスト内包表記で書くと、

import maya.cmds as cmds

[cmds.setAttr(y+".ftn",z,type="string") for y in cmds.ls(typ="file",type="mentalrayTexture") for z in[cmds.getAttr(x+".ftn") for x in cmds.ls(type="file")]if z==cmds.getAttr(y+".ftn")]

というような感じになります。
うーん、どうも変だなぁ、と

import maya.cmds as cmds

[cmds.setAttr(y+".ftn",cmds.getAttr(y+".ftn"),type="string") for y in cmds.ls(typ="file",type="mentalrayTexture")]

と書いてみると、やはり動きます。
自身のアトリビュートを取得し、自身のアトリビュートにセットする。
気付け薬のようなものでしょうか?

 

面白いのは、lsコマンドのtypeはひとつしか使えないフラグでどちらともロングネームやショートネームでは怒られてしまい、使うことができません。
それを使い分けると、使えるようです。良くわからない。で、そこで取得されているファイルの違いも良くわからない。
そもそも、Maya自体構造も機能も良くわからない。興味が無い。

 

それで、modoの頂点スムースのような機能はないのか、と探していましたが見つかりませんでした。
しかし、コマンドが見つかったので、スクリプトを作ってみました。今度はそれを載せます。

Mudbox2013 その2

image937l
うーん、もう収集がつかない、、
微妙にポーズをちょこちょこと修正していたら、収集がつかなくなりました。
もはややり直したほうが早そうだ。

 

使ってみて分かったことは、解説されているサイトがない。
操作が簡単すぎて、解説する必要がない。ということでしょうか。

 

自動のリトポやスカルプトの転送なども出来るそうです。
今度試してみます。データを持ってくるのが大変そうだ。

あ、そういえば、ウェイトエディタですが、ラウンドするときにメッシュが違う頂点をどのように分岐するか思いつきました。
226行目を
if v == cmds.ls(v)[0]:
にすれば多分どんなメッシュでも大丈夫です。
そうでないと、シェイプとトランスフォームの名前が違う時にきちんと動かない場合があります。
ある程度は対処しましたが、こっちの分岐条件のほうが確実かと思います。

Mudbox2013

image936l
Mudboxです。
以前ZBrushで使ったものと同じ素体を使ってみました。

 

前に使っていた時は、Autodeskに買収される前でした。
久しぶりなので、使い方を覚えるのが大変かなぁ、と思っていたのですが、
そもそもの使い方が単純な上に、使ってゆくうちに思い出しました。変わっていない。

 

ZBrushよりも一段下のサブディビジョンレベル7で、約3百万ポリゴンくらいです。
Geforce8800GTという随分前のGPUを使っておりますが、殆ど問題ありません。
「グラブ」ツールというZBrushで言うところの「Move」ツールをメッシュが集中する手の部分に使おうとすると、重くて使い物になりません。
サブディビジョンレベルを下げれば、問題ありません。

 

で、値段を調べてみると、11万円です。
うーん、ZBrushのように面白い機能はありませんが、いかにも、という感じのCGツールです。癖がなくて使いやすい。
でもブラシの使いやすさはやはりZBrushに分があるように思います。Ptexが使えるのが強みかな?

Maya Script Python リスト内包表記でのウェイトの四捨五入 その2

前回に引き続き、リスト内包表記をテストしてみました。
コードを見なおしているうちに、ここはもっとまとめられるのではないか?
という事に気が付き、色々といじくり回してみました。
 

大分すっきりしました。相変わらず可読性は低いです。

import maya.cmds as cmds
import maya.mel
import math

def round_weight_test():
	oSel = cmds.ls( selection=True )
	oShp = oSel[0]
	gMainProgressBar = maya.mel.eval( '$tmp = $gMainProgressBar' )
	oVcount = cmds.polyEvaluate( oSel, v=True )
	oSkt = cmds.listHistory( oShp )
	oCls = cmds.ls( oSkt, type= "skinCluster" )[0]
	oMxc = cmds.getAttr( oCls+".maxInfluences" )
	oVtx = cmds.ls( oShp + ".vtx[*]", fl=True )
	oRoundLen = 2
	cmds.progressBar( gMainProgressBar, edit=True,beginProgress=True, status='Now Rounding...', maxValue=oVcount )
	[[cmds.progressBar(gMainProgressBar,e=1,s=1),cmds.skinPercent(oCls,v1,nrm=0,zri=1,tv=zip(*l1))] if sum(l1[1])==1.0 else [cmds.progressBar(gMainProgressBar,e=1,s=1),cmds.skinPercent(oCls,v1,nrm=0,zri=1,tv=zip(l1[0],[round(1.0-sum(l1[1][:-1]),oRoundLen) if i==len(l1[1])-1 else x for i,x in enumerate(l1[1])]))]
	for (v1,l1) in [[v,zip(*sorted(dict(zip(cmds.skinPercent(oCls,v,q=1,t= None),[round(w,oRoundLen) for w in cmds.skinPercent(oCls,v,q=1,v=1) if w>0.0])).items(),key=lambda x:x[1])[-oMxc:])]
	for v in oVtx]]
	cmds.progressBar( gMainProgressBar, edit=True, endProgress=True )
round_weight_test()

しかし、驚いたことに、前回の物よりも実行速度が遅くなる、、
分岐を減らしたからだろうか?短くすれば良い。というものでもないようです。
ああ、悔しい。
 

ウェイトエディタを更新しました。
前回のままだと、恐らく一つのシーンに同一名のオブジェクトがあるとうまく機能しないかと思います。
一応機能するようにしましたが、四捨五入はできるだけオブジェクト単位でしたほうが良いかと思います。
何でMayaはオブジェクトがシェイプノードとトランスフォームノードにわかれているのだろうか。
名前が取得しにくいです。
オブジェクトとしての移動値とそれ以外。という感じなのでしょうか。扱いにくいなぁ、、
もっとスマートな方法があるのだろうか。

Maya Script Python リスト内包表記でのウェイトの四捨五入

ついに完成しました。多分。
ポリゴンのエラー表示のスクリプトを前回作りましたが、よくよく見てみるとエラーのリスト表示もリスト内包表記で書けそうなことに気が付きました。
早速実装してみると、それなりに体感で速くなったような気がしました。
なので、前回のスクリプトを更新しました。

 

それである程度リスト内包表記の経験値が溜まったようで、
四捨五入のスクリプトを見てみると、これも書けるんじゃないか?と思い、書き始めました。
まぁ、どうせ無理だろう。と思っていたのですが、やってゆくうちにひとつひとつ確実にハードルを越え、
できそうで、できない。という状態を続けておりました。
それがようやく出来ました。

 

しかし、
それほど速くはない、、
5千ポリゴンくらいのモデルで0.何秒かのスピードアップです。もっと早くなると思ったのに、、
更にコードを見直し、記述を少なくしてみたのですが大して変わりません。
因みにこちらです。

import maya.cmds as cmds
import maya.mel
import math

def round_weight():
	gMainProgressBar = maya.mel.eval( '$tmp = $gMainProgressBar' )
	oSel = cmds.ls( selection=True )
	oShp = oSel[0]
	oSkt = cmds.listHistory( oShp )
	oCls = cmds.ls( oSkt, type= "skinCluster" )[0]
	oMxc = cmds.getAttr( oCls+".maxInfluences" )
	oVtx = cmds.ls( oShp + ".vtx[*]", fl=True )
	oVcount = len(oVtx)
	oRoundLen = 2
	cmds.progressBar( gMainProgressBar, edit=True,beginProgress=True, status='Now Rounding...', maxValue=oVcount )
	[[cmds.progressBar(gMainProgressBar,e=1,s=1),cmds.skinPercent(oCls,v3,nrm=0,zri=1,tv=zip(*l2))]
	if sum(l2[1])==1.0 else [cmds.progressBar(gMainProgressBar,e=1,s=1),cmds.skinPercent(oCls,v3,nrm=0,zri=1,tv=zip(l2[0],[round(1.0-sum(l2[1][:-1]),oRoundLen)
	if i==len(l1)-1 else x for i,x in enumerate(l2[1])]))]
	for v3,l2 in [[v2,zip(*l1[-oMxc:])] if len(l1)>oMxc else [v2,zip(*l1)]
	for v2,l1 in [[v1,sorted(dict(zip(oJnt,oWei)).items(),key=lambda x:x[1])]
	for (v1,oWei,oJnt) in [[v,[round(w,oRoundLen) for w in cmds.skinPercent(oCls,v,q=1,v=1) if w>0.0],cmds.skinPercent(oCls,v,q=1,t= None)]
	for v in oVtx]]]]
	cmds.progressBar( gMainProgressBar, edit=True, endProgress=True )
round_weight()

全く読みにくい。
開発していた時の物とは違い、プログレシブバーを付けたり、色々と改行を加えたりしたので、動作は保証しません。
一応大丈夫のようでした。もう面倒くさいので、しばらく見直したくない。本当に読みにくい。
ここまで可読性を損なっても、大して変わらないならやめたほうがよさそうです。
しかし、色々と勉強になりました。

Maya Script Python ポリゴンエラーの検出

image935l

# -*- coding: utf-8 -*-
import maya.cmds as cmds
import maya.mel

def gkn_list_select_es( flag,oVtx ):
	if flag == 1:
		oSel = cmds.textScrollList( "PolyList" , q = 1 , sii = 1 )
	else:
		oSel = cmds.textScrollList( "VtxList" , q = 1 , sii = 1 )
	oHi = []
	[ oHi.extend([oVtx[j-1]]) for j in oSel]
	cmds.select( oHi , r= 1 )

def gkn_error_search():
	polys = cmds.ls( sl= 1, o= 1 )
	if polys != [] :
		tVtx = []
		lPoly = []
		tVtxElog = []
		lPolyElog = []
		lVtx = []
		fPoly = []
		lVtxElog = []
		fPolyElog = []
		selPoly = []
		polyElog = []
		selVtx = []
		vtxElog = []
		oCount = len(polys)
		gMainProgressBar = maya.mel.eval( '$tmp = $gMainProgressBar' )
		cmds.progressBar( gMainProgressBar, edit=True,beginProgress=True, status='Now Search...', maxValue=oCount )
		for p in polys :
			tVtx.extend( cmds.ls(cmds.polyInfo( p, nmv= 1), fl= 1 ) )
			tVtxElog.extend( [u"非多様体" for x in tVtx] )
			lPoly.extend( cmds.ls(cmds.polyInfo( p, lf= 1), fl= 1 ) )
			lPolyElog.extend( [u"ラミナフェース" for x in lPoly] )
			faces = cmds.ls(p + ".f[*]",fl=1)
			oVtx = cmds.ls(p + ".vtx[*]",fl=1)
			lVtx.extend([oVtx[i] for i,x in enumerate([cmds.polyNormalPerVertex( v, q=1 , al = 1 ) for v in oVtx]) if x == [True]])
			lVtxElog.extend( [u"法線ロック" for x in lVtx] )
			fPoly.extend([p+".f["+"".join(x).split()[1].split(":")[0]+"]" for x in [cmds.polyInfo(f, fv= 1) for f in cmds.ls(p+".f[*]",fl=1)] if len("".join(x).split()[2:]) > 4])
			fPolyElog.extend( [u"多角形" for x in fPoly] )
			cmds.progressBar( gMainProgressBar, edit=True, step=1 )
		cmds.select(cl=1)
		cmds.progressBar( gMainProgressBar, edit=True, endProgress=True )
		selPoly.extend(lPoly)
		selPoly.extend(fPoly)
		polyElog.extend(lPolyElog)
		polyElog.extend(fPolyElog)
		selVtx.extend(tVtx)
		selVtx.extend(lVtx)
		vtxElog.extend(tVtxElog)
		vtxElog.extend(lVtxElog)
		if selPoly == [] :
			selPoly.append(u"エラーは見つかりませんでした")
			polyElog.append("")
		if selVtx == [] :
			selVtx.append(u"エラーは見つかりませんでした")
			vtxElog.append("")
		if cmds.window("errorpolyUI", q=1, ex=1) :
			cmds.deleteUI("errorpolyUI")
		oErrorp = cmds.window("errorpolyUI", title="ErrorPolys", w=400, h= len(selPoly)*20 )
		cmds.columnLayout(adjustableColumn=True)
		oScrollLayout = cmds.scrollLayout( h= 400 )
		cmds.rowLayout( nc= 2, adj= 2, cw2= ( 300, 100 ) )
		cmds.textScrollList( "PolyList" , w = 280 , h= len(selPoly)*15+10, ams = 1 )
		cmds.textScrollList( "PolyList" , e = 1 , ra= 1 )
		cmds.textScrollList( "PolyeList" , w = 100 , h= len(selPoly)*15+10, ams = 1,en= 0 )
		cmds.textScrollList( "PolyeList" , e = 1 , ra= 1 )
		for i,r in enumerate(selPoly) :
			cmds.textScrollList( "PolyList" , e= 1, a= u"{0}".format( r ) )
			cmds.textScrollList( "PolyeList" , e= 1, a= u"{0}".format( polyElog[i] ) )
		if selPoly[0] != u"エラーは見つかりませんでした":
			cmds.textScrollList( "PolyList" , e = 1 , sc= "gkn_list_select_es( 1," + str(selPoly) +" )" )
		else :
			cmds.textScrollList( "PolyList" , e = 1 , en= 0 )
		cmds.showWindow(oErrorp)
		if cmds.window("errorvtxUI", q=1, ex=1) :
			cmds.deleteUI("errorvtxUI")
		oErrorv = cmds.window("errorvtxUI", title="ErrorVtxs", w=400, h= len(selVtx)*20 )
		cmds.columnLayout(adjustableColumn=True)
		oScrollLayout = cmds.scrollLayout( h= 400 )
		cmds.rowLayout( nc= 2, adj= 2, cw2= ( 300, 100 ) )
		cmds.textScrollList( "VtxList" , w = 280 , h= len(selVtx)*15+10, ams = 1 )
		cmds.textScrollList( "VtxList" , e = 1 , ra= 1 )
		cmds.textScrollList( "VtxeList" , w = 100 , h= len(selVtx)*15+10, ams = 1, en= 0 )
		cmds.textScrollList( "VtxeList" , e = 1 , ra= 1 )
		for i,r in enumerate(selVtx) :
			cmds.textScrollList( "VtxList" , e= 1, a= u"{0}".format( r ) )
			cmds.textScrollList( "VtxeList" , e= 1, a= u"{0}".format( vtxElog[i] ) )
		if selVtx[0] != u"エラーは見つかりませんでした":
			cmds.textScrollList( "VtxList" , e = 1 , sc= "gkn_list_select_es( 2," + str(selVtx) +" )" )
		else :
			cmds.textScrollList( "VtxList" , e = 1 , en= 0 )
		cmds.showWindow(oErrorv)
gkn_error_search()

すみません、適当なコードです。

 

単一、もしくは複数のオブジェクトを選択し実行して使います。
コードをスクリプトエディタにペーストすると直ぐに実行されます。
選択されているオブジェクトの非多様体頂点、頂点の法線ロック、多角形ポリゴン、ラミナフェースを検出します。
検出されれば、それらがリストとしてウィンドウに表示されます。
ウィンドウに表示されているリストを選択すると、エラーとして検出された頂点、もしくはポリゴンを選択します。

 

どれだけ早く動くのだろうか、と、forループでひとつひとつの頂点やポリゴンを見ていたのですが、
リスト内包表記に変えてみました。
大分早くはなったようです。ただ、可読性が著しく低い、、
エラーが多すぎると、ウィンドウに表示するのに時間がかかります。

 

modoもクリーンナップを自動でしてくれますが、自動ではなく選択してくれるとありがたいのですが、、
でも多角形ポリゴンは直ぐに見つけられるのが良いです。
Maya2012でも2013でも動きます。

※追記2012/5/15
リスト表示もリスト内包表記にしました

ウェイトエディタ更新 その4

またまた更新です。
Maya2013でも動作確認できました。
今までジョイントのリストを取得する際にわざわざ頂点から情報を取得していました。
速度に問題は無いかと思うのですが、その場合スキニングした後に頂点を追加してエディタで見てみると
正しく表示されませんでした。
その場合は無視するようにしました。

 

それと、スキニングする際に「ウェイトの正常化」が「インタラクティブ」以外の時は、
ウェイトを編集しても正規化が行われなかったため、強制的にインタラクティブにするようにしました。

 

そして、ウィンドウの小型化です。

 

しかし、いくらいじり倒してもMayaは好きにはなれないなぁ、、
modoの画面を見るとほっとする。

ZBrush4 久々のZBrush

image931l
そういえば、久しぶりのZBrushで久しぶりの画像の投稿です。

 

ZBrushを久しぶりに触りました。
すっかり下手になっている。元々大したことはないが。
作り始めて1時間くらいでしょうか、紆余曲折しながらやっております。
(ビューはこの角度で、この部分をこういじりたいんだよなぁ、)とか考えてしまいます。
すると、(じゃあ粘土でやれば良いじゃない。)
で、(それはそうなんだけどさぁ、、)と自問自答しております。
慣れればもっと効率的に手が動くのでしょうが、そのへんはまだまだです。

 

因みに、
image932l
これが元の形です。
できるだけセグメントを切らずにZBrushに持ってゆきました。
感想としては、確かにその方がサブディビジョンレベルを大きく上げることはできるが、
形の制御が難しい。
ある程度セグメントを切って持ってゆくのも、形を締める、という意味合いからで言うと良いのかも知れません。

 

そういえば、MudBoxを更に久しぶりに触りました。ちょっとだけですが。
どのくらいの負荷に耐えられるのだろうか、と細分化をしたところ、意外と大きく上がりました。
使い勝手は知りません。なにせもう何年も触っていません。
うーん、意外といけるのかも。と思ったくらいです。
海外でCGをやられている方々で、ZBrushとMudBoxを併用している人がいますが、あれはどんな意味があるのだろうか。
気が向いたらその辺も身を持って体験してみようかと思います。

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

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

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