Python – カラーの値変換 float to RGB – RGB to float

Maya関係ないし、ただの備忘録です。
たまーに使うのですが、たまーにしか使わないので、忘れてしまう。

f = 0.5
i = 128
print int(f*256) if f <= 1.0 else 255
print i/255.0
#Result
128
0.501960784314

超初等数学ですね、、

Substance Designer – ボロノイ図1 形状を加味したひび割れ

2016_08_05_114
なんだか連日の投稿が続きます。
随分と前から地道に進めていたのですが、中々突破口を見いだせずに悶々としておりました。
SubstanceDesignerとWorldMachineは実は同じ用途のツールで、どちらもノードを組み合わせて画像を生成します。
大きな違いを上げるとしたら、方や線形方程式で、もう一方が非線形方程式(多分完全ではない)ということがあげられるかと思います。

 

その辺の話は置いといて、SubstanceDesignerでマテリアルを作成するときの弱点は形状に準じた効果を入れづらい。
ということがあるかと思います。その辺りが線形、非線形に関わってくると思うのですが、
どうもSubstanceDesignerとしては、その弱点をSubstancePainterで補おうとしているように感じます。
ただ、どうもPainterは重くて、個人的には気が引けます。やはりテクスチャペイントには3Dcoatの方が未だやりやすいと感じてしまいます。

 

前置きが長くなりました。
ともかく今回は形状(ここではハイトやノーマル)によってマテリアルのダメージ具合を変更することに成功したように思います。
高いところがひびが多く、細かい状態で、低いところがその逆です。
できてますよね?
しかもなぜだか知りませんが、端の方では放射状にひびが広がっている。偶然の副産物です。
今回の形状がそういった偶然が重なるものなのかも知れません。
今後他の形状も試してみて、うまく行けば公開します。

Maya Script – 上向きのフェースを選択する

地形などのデータを作るときは、そのフェースが地面に適しているかを判定する必要があります。
ゲームデータの話です。
以前、そういったスクリプトを書いたのですが、ベクトルでの指定で、角度ではなかったので、角度指定が出来るように変更しました。

 

ただ、問題が、、
以前書いた時に汎用となる関数、の名前が「get_ploy_comp」でした、、
「l」と「o」が反対です。
よりによって、汎用的に使える関数でスペルミスをするとはなぁ、、と気づいて愕然としました。

 

なので、今回はちゃっかり直して、公開します。
以前のものは、直しません。

import pymel.core as pm
import maya.cmds as cmds
import maya.api.OpenMaya as om2

def get_poly_comp(flag = "vtx",*args):
	node = None
	
	flags = ["vtx","edge","face","uv","vtxFace"]
	sm = [31,32,34,35,70]
	kwArgs = ["tv","te","tf","tuv","tvf"]
	
	if flag not in flags:
		return -1
	
	kw = {x:{y:1} for x,y in zip(flags,kwArgs)}
	smKW = dict(zip(flags,sm))
	
	comp = cmds.filterExpand(cmds.polyListComponentConversion(*args,**kw[flag]),sm=smKW[flag],ex=1,fp=1)
	if comp:
		node = list(set([x.split(".",1)[0] for x in comp]))
	
	return node,comp

def select_yup_face_om2(val = 45.0):
	sel = cmds.ls(sl=1)
	node,comp = get_poly_comp("face",*sel)
	
	if not comp:
		return
	
	
	yUp = set()
	axis = om2.MVector(0,1,0)

	selList = om2.MGlobal.getActiveSelectionList()

	if not selList:
		return

	selObj = []
	for x in range(selList.length()):
		mDag = selList.getDagPath(x)
		
		if mDag.hasFn(om2.MFn.kMesh):
			selObj.append(om2.MFnMesh(mDag))

	if selObj:
		for s in selObj:
			for i in range(s.numPolygons):
				xyz = s.getPolygonNormal(i)
				if pm.datatypes.degrees(xyz.angle(axis)) < val:
					yUp.add("{0:}.f[{1:}]".format(s.fullPathName(),i))
		if yUp:
			comp = list(set(comp) & yUp)
			cmds.selectMode(co=1)
			cmds.selectType(smp=0,sme=0,smf=1,smu=0,pv=0,pe=0,pf=1,puv=0)
			cmds.select(comp,r=1)
		else:
			pm.confirmDialog(t=u"Select Yup",m=u"yUpのフェースは見つかりませんでした",b="OK",db="OK",ds="OK")
			return
	else:
		pm.confirmDialog(t=u"Select Yup",m=u"ポリゴンフェース、もしくはポリゴンフェースを持ったノード\nを選択してから実行して下さい",b="OK",db="OK",ds="OK")
		return

select_yup_face_om2(55.0)

関数「select_yup_face_om2()」に任意の引数を入れて実行してください。
今回は「55.0」垂直から55度傾いたフェースまでは許容するよ。という感じです。
実行すると、
2016_08_04_113
こんな感じで、地面として許容されるフェースが選択できるので、意図したようになるよう調整することができます。

 

で、作っていて思ったのですが、選択だと、頂点を動かす、などの調整を行い、再びスクリプトを実行して確認する必要がある。
瞬時にできて、便利だ。と思っていたのですが、そもそもそれをリアルタイムで判定して色を変えれば良いじゃないの。
と、シェーダを作ることを思い立ちました。
そのほうが圧倒的に早いですよねぇ、、ばかみたいな事をしておりました。
まぁ、せっかく作ったんだし。これはこれでいいか。と、公開です。
pymelのdatatypesを使って変換しているだけなので、大した事はしてないんですけどね。

Maya Script – 選択しているフェースが所属するマテリアルのフェースを選択

タイトル長いです。
図で説明すると、
2016_08_03_111
キューブの上下にそれぞれ違うマテリアルをアサインしております。
そのうちの一つのフェースを選択し、スクリプトを実行すると、そのジオメトリに設定されている同じマテリアルのフェースを選択して欲しい。
という欲求から作りました。
実行すると、
2016_08_03_112
こんな感じになるのが理想です。

 

マテリアル境界で頂点カラーによるブレンドをしたいと思い、作りました。
なので、フェースを選択して、ホットキーに割り当てたコマンドを実行するだけで、マテリアルに含まれるフェースを選択できるのが理想です。
それを、境界エッジに変更すれば、目的は果たせます。

 

とにかく早く欲しかったので、手っ取り早いpymelで作ってみました。

import pymel.core as pm

def material_face_select_pymel():
	sel = pm.ls(sl=1,l=1,fl=1)
	if not sel and type(sel[0]) != pm.nt.MeshFace:
		return
	selShape = pm.ls(sl=1,o=1)
	sg = selShape[0].inputs(type=pm.nt.ShadingEngine)
	if not sg:
		return
	msg = []
	for x in sg:
		if pm.sets(x,im=sel[0]):
			msg.append(x)
	pm.select(msg[0],r=1)

material_face_select_pymel()

とりあえず、急場はしのげましたが、これだと同じマテリアルを使用している他のノードのコンポーネントまで選択されてしまう。
という問題が発生します。
ただ、Mayaのバージョンは忘れましたが、選択範囲が勝手に保存されるので、一度オブジェクト選択モードに移行して、再び目的のジオメトリを
選択し、フェース選択に切り替えれば、問題ありません。

 

問題はないのですが、悔しいので時間が少し空いた時にMayaコマンドで作りなおすついでに、その辺りも解消しようと作りなおしました。

import maya.cmds as cmds

def material_face_select():
	sel = cmds.ls(sl=1,l=1,fl=1)
	mat = cmds.ls(mat=1)
	if not sel or not mat:
		return
	selType = sel[0].rsplit(".")
	if not selType:
		return
	if selType[-1][0] != "f" :
		return
	selShape = cmds.ls(sl=1,o=1)
	sg = []
	for m in mat:
		s = cmds.listConnections(m,s=1,type="shadingEngine")
		if s:
			sg.append(s[-1])
	if not sg:
		return
	nSel = []
	for s in sg:
		sFace = cmds.ls(cmds.sets(s,q=1),fl=1,l=1)
		if sel[0] in sFace:
			for f in sFace:
				if selType[0] == f.rsplit(".")[0]:
					nSel.append(f)
	if nSel:
		cmds.select(nSel,r=1)

material_face_select()

forループが二重になってる、、
うーん、これも余り時間がなかったので、色々と突っ込みどころはありますが、とりあえず目的は達成できております。
で、じゃあそれをさらにpymelでやったらどうなのだろう。と、改造しました。
そんなことする暇あるなら、コードをきちんとしろよ。と、突っ込みたくなるところではあるのですが、、

import pymel.core as pm

def material_face_select_pymel2():
	sel = pm.ls(sl=1,l=1,fl=1)
	if not sel and type(sel[0]) != pm.nt.MeshFace:
		return
	selType = sel[0].name().rsplit(".")
	selShape = pm.ls(sl=1,o=1)
	sg = selShape[0].inputs(type=pm.nt.ShadingEngine)
	if not sg:
		return
	nSel = []
	for x in sg:
		sFace = pm.ls(x.members(),fl=1,l=1)
		if sel[0] in sFace:
			for f in sFace:
				if selType[0] == f.name().rsplit(".")[0]:
					nSel.append(f)
	if nSel:
		pm.select(nSel,r=1)

material_face_select_pymel2()

こんな感じでしょうか?どちらにせよ二重ですが、、
因みにこれは実行しないほうが良いです。
数万ポリゴンのシーンで実行すると、しばらく帰ってこなくなります。
Mayaコマンドであれば、少し待てば帰ってきます。やはりAPIで作るべきなんでしょうねぇ。

 

とりあえず、備忘録です。

Maya Script Pymel – ポリゴン数を数える

スクリプトを書いていて、記事にしようとまとめていたら、以前に似たような記事を書いたなぁ。
と、読み返してみると、ありました、、

 

その時記事にしたのは、ポリゴン数のカウントではなく、Pythonでの整数での四捨五入でした。
round関数にはマイナスが入る。ということが衝撃でした。

 

その時も実はポリゴン数のカウントでした。
その時は何でカウントしていたのだろうか?書いていないので、恐らくMayaコマンドだろうかと思います。

 

今回はPymelです。
やはりノード関連はPymelが手っ取り早い。
時間があるときにじっくりとスクリプトを作ることができれば良いのだろうけれど、大抵ツールというのは、
現場で作業をしていて、まどろっこしい部分をなんとか手早くしたい。という感じで作るので、そんな時にPymelは重宝します。

 

ただ、メッシュのシェイプノードには、numTriangles()というメソッドがあり、APIを見ても三角ポリゴンの数を返してくれる感じですが、
エラーが帰ってきます。
色々とためしてみると、numSelectedTriangles()というメソッドがどうも色々と情報を返してくれます。
引数にゼロを渡し、numSelectedTriangles(0)などとすると、
{‘vertexComponent’: 0, ‘shell’: 1, ‘triangle’: 760, ‘faceComponent’: 0, ‘vertex’: 382, ‘face’: 400, ‘triangleComponent’: 0, ‘edge’: 780, ‘uvcoord’: 439, ‘uvComponent’: 0, ‘edgeComponent’: 0}
こんな感じに、たくさん情報を返してくれます。なんか色々できそうですねぇ。

 

さて、それでは実践です。
ゲームモデルでは大抵命名規則が決まっていて、ツールが目的のノードやアトリビュートを探しやすくなっています。
今回はモデルデータのトップノードには「_mdl」というサフィックスが付く、という前提で話を進めます。
目的は、読み込んだ複数のモデルデータのそれぞれのポリゴン数を調べることと、そのポリゴン数を1.5倍した数を端数を切り捨てた数が知りたい。
というちょっとややこしいものです。
さらには、トップノード以下の命名規則はなく、中には「_mdl」のサフィックスがついたものもあったり、複数のジオメトリで構成されていたり、というものです。
随分と仕事的な感じがします。
2016_07_28_108
こんな感じです。
で、スクリプトを実行すると、
2016_07_29_109
こんな感じになります。ちょっと見にくいですね、、すみません。
コードを貼り付けるので、実際にやってみてください。

import pymel.core as pm

def poly_count():
	sel = pm.ls( "*_mdl", type=pm.nt.Transform )
	if not sel:
		return
	root = list(set([x.root() for x in sel]))
	if not root:
		return
	print "{0:=<80}".format("")
	for s in sorted( root ):
		num = []
		[ num.append( x.numSelectedTriangles(0)["triangle"] ) for x in s.listRelatives( ad=1, s=1 ) if type( x )==pm.nt.Mesh ]
		goukei = sum( num )
		gPlus = goukei * 1.5
		print "{0:-<50}".format("")
		print s.name()
		print goukei
		print int( round( gPlus, -int( len( str( int( gPlus ) ) ) / 2 )) )
	print "{0:=<80}".format("")
poly_count()

Mayaでのパターン選択。
また躓きました、、
でもやっぱり
2016_07_29_110
こういうのって、出来ると助かりますよねぇ。
そんなに頻繁に出番はないけど。
Mayaでモデリングしいて、できない事を思い出すと、ちょっとショックを受けます。

Maya Script – MODOのパターン選択

以前ちょっと挑戦した、MODOのパターン選択をMayaで再現するのを試しておりました。
Mayaも2016になり、だいぶモデリングが強化されMODOにない機能なども搭載されておりますが、
やはり、ハンドリングの軽さはMODOの方が良いなぁ、、ストレス溜まる、、

 

でも、MODOも10になり、プロシージャルモデリングを始め、様々な機能が追加されましたが、
起動が重くなり、尚且つとても落ちやすい、、更には古いスクリプトで作られた、
特定の角度で隣接するフェイスのエッジを選択するツールなどで、選択されるエッジの一部選択解除などができない、、
スクリプトで選択されるのは、手で選択するのと、内部的に違いが生じるようになったのでしょうか、、困ったものだ。

 

で、本題のパターン選択です。
MODOでは、例えば一つおきにポリゴンを選択したい時に、始めの2つのポリゴンをそのように選択し、「↑」キーを押すと、
そのパターンのまま、一つ飛ばしにポリゴンが選択されます。
最初の2つのパターンをその後の選択に適応することから、パターン選択とよばれます。
何気に便利な機能なので、以前からMayaにも移植できないか、とあがいていたのですが、ようやく出来ました。

 

2016_07_20_102
一つ飛ばしは、こんな感じです。
2016_07_20_103
4つ飛ばしは、こんな感じです。
2016_07_20_104
でも、2つ飛ばしはこんな感じです、、

 

MODOでもジオメトリの面の数と、選択の面の数によっては、おかしくなるので、これは致し方のないことだとは思います。
まだフェイスだけで、エラー処理も書いていないので、拡張、デバッグが済んだら公開します。
やっぱり、MODOのようにキーを押して拡張が1つずつ実行される方が便利だなぁ。
そうそう、「polySelectSp」というコマンド、マニュアルに乗っておりませんが、

from maya import cmds
print cmds.polySelectSp( "pCylinder1.e[140]", q=1, ring=1 )

というような使い方ができます。
上記を実行すると、シリンダーのインデックスが140のエッジのリングを返してくれます。
さらに、「polySelect」というコマンドでパターンの抽出ができます。
なので、MayaコマンドとPythonの便利機能を組み合わせると、割りと簡単にできてしまうようです、、
それに気づくまでに随分と時間がかかりました。

SubstanceDesigner – 8Bit to 16Bit

8Bitのグレースケールを16Bitにして使いたい事ってありませんか?
ZBrushを開発しているPixologicにはフリーでダウンロードできるアルファライブラリがありますが、
全部8Bitです。現在はどうか知りませんが、というか昔は一括でダウンロードできましたが、今見てみるとそれがなくなっているような、、
1つずつはきついなぁ、、

 

まぁ、それは置いといて。
手早く8Bitを16Bitに変換してくれるようなものを探していたのですが、見つかりませんでした。
恐らく一番手早い方法は、グレースケールをカラーに変換して、Bitmap2Materialを使う事だと思います。
それも面倒だなぁ、とノードを作ってみました。
8to16
sbsとsbsarの2つのファイルを入れておきました。
厳密な感じではなく、基本ぼかしてブレンドさせているだけです。
ただ、加算は飽和しがちなので、乗算で計算させるようにしたところがミソでしょうか。

 

2016-04-29_002
これが8Bitのアルファからノーマルマップを作成した状態のものです。
細かい凹凸がたくさんあり、何なのだかよくわからない感じになっております。
2016-04-29_003
こちらが今回作成したノードでノーマルマップを作成したものです。
だいぶ形がわかるようになったかと思います。

 

今回のノードは8Bitのグレースケールを入力すると、8Bitのノーマルマップと16Bitのハイトマップを生成します。
ZBrushで見てみると、
2016-04-29_005
これが8Bit

2016-04-29_006
これが16Bitです。

 

もっと良いものがあれば、それに越したとこはないのですが、今のところこれでもまぁないよりはマシかなぁ、と。

 

面白いサイトを知りました。
Unity5とUE4の比較。
貼り付けてある画像の真ん中の線を左右にドラッグすることができます。
どちらのほうが優れている、とは中々言いがたいものですねぇ。

UE4 – 備忘録3

そういえば、書き忘れておりました。
UE4でパブリッシュが原因不明のエラーで失敗するのでした。
ネットで情報を集めてみると、そもそもVisualStudioのバージョンが違うだとか、割りと面倒な記述が見つかるのですが、
その中で最も簡単そうな、SubstancePluginをオフにする。を実行したらパブリッシュができました。
今回はそれで良いのですが、Substance使いたい時どうするのだろう?
SubstanceとUE4のマテリアルエディタでは、事前計算かリアルタイム計算の違いだと思いますが、
開発会社によってどこまで情報を持たせておく、というのはそれぞれなのだろうか?
日本の開発会社では未だにSubstance使っているところが少なめですねぇ。

 

全然関係ないですが、
2016-04-26_001
頭部のスカルプトです。ディテール適当に入れてしまったが、もっとちゃんと入れないとダメですね、、
虹彩、スカルプトしてみようかなぁ。などと思う今日このごろです。

本の紹介 – Unreal Engine 4 建築インテリアビジュアライゼーション


これをやってみました。
2016-04-21_001
本に書いてあること以外のことで色々と遊んでおりまして、時間がかかっておりました。

 

本の内容は、とても実用的で素晴らしい物だと思います。
個人的には「ワールドセッティング」のライトマスの設定など、なるほどなぁ、と勉強になりました。
あとは、コリジョンの持ってゆき方、fbxのインポートについても書かれておりますが、この辺りも知らないことが多く、
アンリアル上でマテリアルインスタンスをアサインしたものでも、インポートしなおし時にアサインしなおさなくても自動的にアサインできることを知りました。
これは随分作業効率が違う。
そういった実王的なTipsがたくさんあり、役に立ちました。

 

でも進めるに従い気づいたのですが、ライトマップはオープンワールドを作る上では、致命的な欠点であるように感じました。
フォリッジ全てにユニークマップを持たせるとなると、相当メモリ食いますよねぇ、、

 

MODO10が発売されましたね。
ベイクの強化やゲームエンジンへの受け渡しの強化と中々興味深いのですが、Maya2016 Extension2、ものすごいインパクトですねぇ、、
MODOのような足回り、選択範囲の編集機能やモデリング機能、UVの編集機能にパッキング。
うーん、、ついにMayaに追い越されたかなぁ、、

Maya Script Python – UVアイランドの整列

前回の記事の続きです。
元ネタはこちらの記事です。

MODOの標準のUV編集がそれなりに強力な上、フリーのツールがさらに強力なので、そもそもMayaでUVを編集することがないので、
MayaでのUV編集スクリプトを書く機会がありません。
何気なく見つけた記事で、これはpymelのオブジェクトを使ってやったらどうなるかぁ、というただの好奇心で作ってみました。

import pymel.core as pm
import maya.cmds as cmds

def rotAlignUV():
	oderFlag = cmds.selectPref(q=1,tso=1)
	
	if not oderFlag:
		cmds.selectPref(tso=1)
	
	sel = cmds.ls(os=1,fl=1)
	
	comp = cmds.filterExpand(cmds.polyListComponentConversion(sel,tuv=1),sm=35,ex=1)
	
	if not comp or len(comp) != 2:
		cmds.confirmDialog(t = "rotAlignUV",m = u"2点のUVを選択してから実行して下さい",b="OK",db="OK",ds="OK")
		return
	
	uvs = cmds.polyEditUV(comp[:2],q=1)
	vec1 = pm.datatypes.Vector(uvs[0],uvs[1],0)
	vec2 = pm.datatypes.Vector(uvs[2],uvs[3],0)
	cDir = vec2 - vec1
	aVec = pm.datatypes.Vector(0,1,0)
	angle = pm.datatypes.degrees(aVec.angle(cDir))
	axis = aVec.axis(cDir,normalize=1)
	
	cmds.polyEditUVShell(pu=uvs[0],pv=uvs[1],a=-1*axis[2]*angle)
	
	cmds.selectPref(tso=oderFlag)

rotAlignUV()

元のコードよりも長くなっていますが、エラー処理などを含んでいるためです。
Vectorクラスやdegressクラスを使って簡単にしてみたつもりです。最終的な変換はEulerRotationクラスを使うべきだったのかなぁ?
「-1*axis[2]*angle」などと冗長な感じがします。

 

データの扱いはpymelに任せて、実際のコンポーネントの編集はMayaコマンドに任せております。
やはりコンポーネントの編集をpymelでやるのは勇気が入ります、、
 

で、前回の記事「選択順のトラック」を関数が使用されている間は、機能オンにし、終了次第元の設定に戻す。というようにしています。
でも、このスクリプト、使ってみるともう一つ工夫が必要なことに気が付きます。
垂直軸に対して、より少ない角度の方に揃えてほしいなぁ。と感じてしまいます。
ベクトルの計算何でしょうねぇ。どんな感じか、気にはなるので多分調べると思うのですが、ツールとしてはこういた編集はMODOでやるので、
興味は無いなぁ。という感じです。

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

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

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